Merged in feature/snapshot-title (pull request #107)
Feature/snapshot title Approved-by: Daniel Egger
This commit is contained in:
commit
7cf2d5df4b
|
|
@ -1,5 +1,62 @@
|
||||||
import module from '../../../fixtures/module.minimal';
|
import module from '../../../fixtures/module.minimal';
|
||||||
import {getMinimalMe} from '../../../support/helpers';
|
import {getMinimalMe} from '../../../support/helpers';
|
||||||
|
import {hasOperationName} from '../../../support/graphql';
|
||||||
|
|
||||||
|
const mockDeleteSnapshot = (success) => {
|
||||||
|
cy.intercept('POST', '/api/graphql', (req) => {
|
||||||
|
if (hasOperationName(req, 'DeleteSnapshot')) {
|
||||||
|
let result;
|
||||||
|
if (success) {
|
||||||
|
result = {
|
||||||
|
message: 'yay!',
|
||||||
|
__typename: 'Success'
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
result = {
|
||||||
|
reason: 'Not the owner',
|
||||||
|
__typename: 'NotOwner'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
req.reply({
|
||||||
|
data: {
|
||||||
|
deleteSnapshot: {
|
||||||
|
result
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockUpdateSnapshot = (title) => {
|
||||||
|
cy.intercept('POST', '/api/graphql', (req) => {
|
||||||
|
if (hasOperationName(req, 'UpdateSnapshot')) {
|
||||||
|
let snapshot;
|
||||||
|
if (title) {
|
||||||
|
snapshot = {
|
||||||
|
__typename: 'SnapshotNode',
|
||||||
|
id: 'U25hcHNob3ROb2RlOjQ=',
|
||||||
|
title,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
snapshot = {
|
||||||
|
__typename: 'NotOwner',
|
||||||
|
reason: 'Not the owner'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
req.reply({
|
||||||
|
data: {
|
||||||
|
updateSnapshot: {
|
||||||
|
snapshot,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
describe('Snapshot', () => {
|
describe('Snapshot', () => {
|
||||||
const operations = isTeacher => ({
|
const operations = isTeacher => ({
|
||||||
|
|
@ -25,8 +82,8 @@ describe('Snapshot', () => {
|
||||||
...module,
|
...module,
|
||||||
snapshots: [
|
snapshots: [
|
||||||
{
|
{
|
||||||
id: 'snapshot-id',
|
id: 'U25hcHNob3ROb2RlOjQ=',
|
||||||
title: 'title',
|
title: 'Old Title',
|
||||||
created: '2020-01-01',
|
created: '2020-01-01',
|
||||||
mine: true,
|
mine: true,
|
||||||
shared: false,
|
shared: false,
|
||||||
|
|
@ -88,4 +145,26 @@ describe('Snapshot', () => {
|
||||||
cy.getByDataCy('module-title').should('exist');
|
cy.getByDataCy('module-title').should('exist');
|
||||||
cy.getByDataCy('snapshot-header').should('not.exist');
|
cy.getByDataCy('snapshot-header').should('not.exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Renames Snapshot', () => {
|
||||||
|
cy.mockGraphqlOps(operations(true));
|
||||||
|
const newTitle = 'New Title';
|
||||||
|
mockUpdateSnapshot(newTitle);
|
||||||
|
cy.visit('module/miteinander-reden/snapshots');
|
||||||
|
cy.getByDataCy('snapshot-link').should('have.text', 'Old Title');
|
||||||
|
cy.getByDataCy('rename-snapshot-button').click();
|
||||||
|
cy.getByDataCy('edit-name-input').clear().type(newTitle);
|
||||||
|
cy.getByDataCy('modal-save-button').click();
|
||||||
|
cy.getByDataCy('snapshot-link').should('have.text', 'New Title');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Deletes Snapshot', () => {
|
||||||
|
cy.mockGraphqlOps(operations(true));
|
||||||
|
mockDeleteSnapshot(true);
|
||||||
|
cy.visit('module/miteinander-reden/snapshots');
|
||||||
|
cy.getByDataCy('snapshot-entry').should('have.length', 1);
|
||||||
|
cy.getByDataCy('delete-snapshot-button').click();
|
||||||
|
cy.getByDataCy('modal-save-button').click();
|
||||||
|
cy.getByDataCy('snapshot-entry').should('have.length', 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
const EditNoteWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/notes/EditNoteWizard');
|
const EditNoteWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/notes/EditNoteWizard');
|
||||||
const EditClassNameWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/school-class/EditClassNameWizard');
|
const EditClassNameWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/school-class/EditClassNameWizard');
|
||||||
const EditTeamNameWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/profile/EditTeamNameWizard');
|
const EditTeamNameWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/profile/EditTeamNameWizard');
|
||||||
|
const EditSnapshotTitleWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/snapshots/EditSnapshotTitleWizard');
|
||||||
const DefaultLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/DefaultLayout');
|
const DefaultLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/DefaultLayout');
|
||||||
const SimpleLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/SimpleLayout');
|
const SimpleLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/SimpleLayout');
|
||||||
const FullScreenLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/FullScreenLayout');
|
const FullScreenLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/FullScreenLayout');
|
||||||
|
|
@ -66,6 +67,7 @@
|
||||||
EditNoteWizard,
|
EditNoteWizard,
|
||||||
EditClassNameWizard,
|
EditClassNameWizard,
|
||||||
EditTeamNameWizard,
|
EditTeamNameWizard,
|
||||||
|
EditSnapshotTitleWizard,
|
||||||
...modals
|
...modals
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div class="snapshot-list-item">
|
<div
|
||||||
|
data-cy="snapshot-entry"
|
||||||
|
class="snapshot-list-item"
|
||||||
|
>
|
||||||
<router-link
|
<router-link
|
||||||
:to="snapshotRoute"
|
:to="snapshotRoute"
|
||||||
class="snapshot-list-item__title"
|
class="snapshot-list-item__title"
|
||||||
|
|
@ -11,14 +14,30 @@
|
||||||
class="snapshot-list-item__date"
|
class="snapshot-list-item__date"
|
||||||
v-html="meta"
|
v-html="meta"
|
||||||
/>
|
/>
|
||||||
<a
|
<div class="snapshot-list-item__actions">
|
||||||
class="snapshot-list-item__link"
|
<button
|
||||||
v-if="snapshot.mine"
|
class="icon-button"
|
||||||
@click="share"
|
data-cy="delete-snapshot-button"
|
||||||
>
|
@click="deleteSnapshot"
|
||||||
<template v-if="snapshot.shared">Nicht mehr teilen</template>
|
>
|
||||||
<template v-else>Mit Team teilen</template>
|
<trash-icon class="snapshot-list-item__icon" />
|
||||||
</a>
|
</button>
|
||||||
|
<button
|
||||||
|
class="icon-button"
|
||||||
|
data-cy="rename-snapshot-button"
|
||||||
|
@click="changeTitle"
|
||||||
|
>
|
||||||
|
<pen-icon class="snapshot-list-item__icon" />
|
||||||
|
</button>
|
||||||
|
<a
|
||||||
|
class="snapshot-list-item__link"
|
||||||
|
v-if="snapshot.mine"
|
||||||
|
@click="share"
|
||||||
|
>
|
||||||
|
<template v-if="snapshot.shared">Nicht mehr teilen</template>
|
||||||
|
<template v-else>Mit Team teilen</template>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -26,7 +45,13 @@
|
||||||
import dateformat from '@/helpers/date-format';
|
import dateformat from '@/helpers/date-format';
|
||||||
import {SNAPSHOT_DETAIL} from '@/router/module.names';
|
import {SNAPSHOT_DETAIL} from '@/router/module.names';
|
||||||
import SHARE_SNAPSHOT_MUTATION from 'gql/mutations/snapshots/share.gql';
|
import SHARE_SNAPSHOT_MUTATION from 'gql/mutations/snapshots/share.gql';
|
||||||
|
import UPDATE_SNAPSHOT_MUTATION from 'gql/mutations/snapshots/update.gql';
|
||||||
|
import DELETE_SNAPSHOT_MUTATION from 'gql/mutations/snapshots/delete.gql';
|
||||||
|
import SNAPSHOTS_QUERY from 'gql/queries/moduleSnapshots.gql';
|
||||||
import gql from 'graphql-tag';
|
import gql from 'graphql-tag';
|
||||||
|
import PenIcon from '@/components/icons/PenIcon';
|
||||||
|
import TrashIcon from '@/components/icons/TrashIcon';
|
||||||
|
import { removeAtIndex } from '@/graphql/immutable-operations';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -35,6 +60,10 @@
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
components: {
|
||||||
|
PenIcon,
|
||||||
|
TrashIcon,
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
meta() {
|
meta() {
|
||||||
|
|
@ -55,6 +84,78 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
changeTitle() {
|
||||||
|
this.$modal.open('edit-snapshot-title-wizard', {name: this.snapshot.title})
|
||||||
|
.then((title) => {
|
||||||
|
console.log(title);
|
||||||
|
this.$apollo.mutate({
|
||||||
|
mutation: UPDATE_SNAPSHOT_MUTATION,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
id: this.snapshot.id,
|
||||||
|
title: title,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update(store, {data: {updateSnapshot: {snapshot}}}) {
|
||||||
|
if (snapshot.__typename === 'SnapshotNode') {
|
||||||
|
const {id, title} = snapshot;
|
||||||
|
store.writeFragment({
|
||||||
|
id,
|
||||||
|
fragment: gql`fragment SnapshotFragment on SnapshotNode {title}`,
|
||||||
|
data: {
|
||||||
|
title,
|
||||||
|
__typename: 'SnapshotNode',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch();
|
||||||
|
},
|
||||||
|
deleteSnapshot() {
|
||||||
|
this.$modal.open('confirm')
|
||||||
|
.then(() => {
|
||||||
|
this.$apollo.mutate({
|
||||||
|
mutation: DELETE_SNAPSHOT_MUTATION,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
id: this.snapshot.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: (store, {data: {deleteSnapshot: {result}}}) => {
|
||||||
|
if (result.__typename === 'Success') {
|
||||||
|
const slug = this.$route.params.slug;
|
||||||
|
const query = SNAPSHOTS_QUERY;
|
||||||
|
const variables = {
|
||||||
|
slug,
|
||||||
|
};
|
||||||
|
const {module} = store.readQuery({
|
||||||
|
query,
|
||||||
|
variables,
|
||||||
|
});
|
||||||
|
const index = module.snapshots.findIndex(snapshot => snapshot.id === this.snapshot.id);
|
||||||
|
const snapshots = removeAtIndex(module.snapshots, index);
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
module: {
|
||||||
|
...module,
|
||||||
|
snapshots
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
store.writeQuery({
|
||||||
|
query,
|
||||||
|
variables,
|
||||||
|
data
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch();
|
||||||
|
},
|
||||||
share() {
|
share() {
|
||||||
this.$apollo.mutate({
|
this.$apollo.mutate({
|
||||||
mutation: SHARE_SNAPSHOT_MUTATION,
|
mutation: SHARE_SNAPSHOT_MUTATION,
|
||||||
|
|
@ -70,10 +171,10 @@
|
||||||
fragment: gql`fragment SnapshotFragment on SnapshotNode { shared }`,
|
fragment: gql`fragment SnapshotFragment on SnapshotNode { shared }`,
|
||||||
data: {
|
data: {
|
||||||
shared,
|
shared,
|
||||||
__typename: 'SnapshotNode'
|
__typename: 'SnapshotNode',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -100,6 +201,15 @@
|
||||||
&__link {
|
&__link {
|
||||||
@include default-link;
|
@include default-link;
|
||||||
color: $color-brand;
|
color: $color-brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
@include default-icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<modal-input
|
<modal-input
|
||||||
:value="name"
|
:value="name"
|
||||||
placeholder="Klassenname"
|
:placeholder="placeholder"
|
||||||
data-cy="edit-name-input"
|
data-cy="edit-name-input"
|
||||||
@input="$emit('input', $event)"
|
@input="$emit('input', $event)"
|
||||||
/>
|
/>
|
||||||
|
|
@ -43,6 +43,10 @@
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: 'Namen bearbeiten'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Modal,
|
Modal,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
<template>
|
||||||
|
<edit-name-wizard
|
||||||
|
:name="name"
|
||||||
|
type="Snapshot"
|
||||||
|
placeholder="Titel bearbeiten"
|
||||||
|
@input="name = $event"
|
||||||
|
@cancel="hideModal"
|
||||||
|
@save="save"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import EditNameWizard from '@/components/profile/EditNameWizard';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
EditNameWizard,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
name: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.name = this.$modal.state.payload.name;
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
save() {
|
||||||
|
this.$modal.confirm(this.name);
|
||||||
|
},
|
||||||
|
hideModal() {
|
||||||
|
this.$modal.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '~styles/helpers';
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
mutation DeleteSnapshot($input: DeleteSnapshotInput!) {
|
||||||
|
deleteSnapshot(input: $input) {
|
||||||
|
result {
|
||||||
|
__typename
|
||||||
|
...on NotOwner {
|
||||||
|
reason
|
||||||
|
}
|
||||||
|
...on Success {
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
mutation UpdateSnapshot($input: UpdateSnapshotInput!) {
|
||||||
|
updateSnapshot(input: $input) {
|
||||||
|
snapshot {
|
||||||
|
...on SnapshotNode {
|
||||||
|
title
|
||||||
|
id
|
||||||
|
}
|
||||||
|
...on NotOwner {
|
||||||
|
reason
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -71,6 +71,7 @@
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
editTeamName() {
|
editTeamName() {
|
||||||
|
// todo: use this.$modal
|
||||||
this.$store.dispatch('editTeamName');
|
this.$store.dispatch('editTeamName');
|
||||||
},
|
},
|
||||||
leaveTeam() {
|
leaveTeam() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import graphene
|
||||||
|
|
||||||
|
|
||||||
|
class FailureNode(graphene.Interface):
|
||||||
|
reason = graphene.String()
|
||||||
|
|
||||||
|
|
||||||
|
class SuccessNode(graphene.Interface):
|
||||||
|
message = graphene.String()
|
||||||
|
|
@ -51,7 +51,7 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
||||||
})
|
})
|
||||||
|
|
||||||
def _fetch_assignment_student(self, user):
|
def _fetch_assignment_student(self, user):
|
||||||
client = create_client(user)
|
client = self.get_client(user)
|
||||||
query = '''
|
query = '''
|
||||||
query AssignmentWithSubmissions($id: ID!) {
|
query AssignmentWithSubmissions($id: ID!) {
|
||||||
assignment(id: $id) {
|
assignment(id: $id) {
|
||||||
|
|
@ -72,7 +72,7 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
||||||
})
|
})
|
||||||
|
|
||||||
def _fetch_assignment_teacher(self, user):
|
def _fetch_assignment_teacher(self, user):
|
||||||
client = create_client(user)
|
client = self.get_client(user)
|
||||||
query = '''
|
query = '''
|
||||||
query AssignmentWithSubmissions($id: ID!) {
|
query AssignmentWithSubmissions($id: ID!) {
|
||||||
assignment(id: $id) {
|
assignment(id: $id) {
|
||||||
|
|
@ -116,13 +116,13 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
||||||
def test_teacher_can_create_feedback(self):
|
def test_teacher_can_create_feedback(self):
|
||||||
result = self._create_submission_feedback(self.teacher, False, 'Balalal', self.student_submission_id)
|
result = self._create_submission_feedback(self.teacher, False, 'Balalal', self.student_submission_id)
|
||||||
|
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
self.assertIsNotNone(
|
self.assertIsNotNone(
|
||||||
result.get('data').get('updateSubmissionFeedback').get('updatedSubmissionFeedback').get('id'))
|
result.data.get('updateSubmissionFeedback').get('updatedSubmissionFeedback').get('id'))
|
||||||
|
|
||||||
def test_student_cannot_create_feedback(self):
|
def test_student_cannot_create_feedback(self):
|
||||||
result = self._create_submission_feedback(self.student1, False, 'Balalal', self.student_submission_id)
|
result = self._create_submission_feedback(self.student1, False, 'Balalal', self.student_submission_id)
|
||||||
self.assertIsNotNone(result.get('errors'))
|
self.assertIsNotNone(result.errors)
|
||||||
|
|
||||||
def test_teacher_can_update_feedback(self):
|
def test_teacher_can_update_feedback(self):
|
||||||
assignment = AssignmentFactory(
|
assignment = AssignmentFactory(
|
||||||
|
|
@ -136,9 +136,9 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
||||||
|
|
||||||
result = self._create_submission_feedback(self.teacher, True, 'Some', submission_feedback_id)
|
result = self._create_submission_feedback(self.teacher, True, 'Some', submission_feedback_id)
|
||||||
|
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
|
|
||||||
submission_feedback_response = result.get('data').get('updateSubmissionFeedback').get(
|
submission_feedback_response = result.data.get('updateSubmissionFeedback').get(
|
||||||
'updatedSubmissionFeedback')
|
'updatedSubmissionFeedback')
|
||||||
|
|
||||||
self.assertTrue(submission_feedback_response.get('final'))
|
self.assertTrue(submission_feedback_response.get('final'))
|
||||||
|
|
@ -156,19 +156,19 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
||||||
|
|
||||||
result = self._create_submission_feedback(self.teacher2, True, 'Some', submission_feedback_id)
|
result = self._create_submission_feedback(self.teacher2, True, 'Some', submission_feedback_id)
|
||||||
|
|
||||||
self.assertIsNotNone(result.get('errors'))
|
self.assertIsNotNone(result.errors)
|
||||||
|
|
||||||
def test_student_does_not_see_non_final_feedback(self):
|
def test_student_does_not_see_non_final_feedback(self):
|
||||||
SubmissionFeedbackFactory(teacher=self.teacher, final=False, student_submission=self.student_submission)
|
SubmissionFeedbackFactory(teacher=self.teacher, final=False, student_submission=self.student_submission)
|
||||||
result = self._fetch_assignment_student(self.student1)
|
result = self._fetch_assignment_student(self.student1)
|
||||||
|
|
||||||
self.assertIsNone(result.get('data').get('submissionFeedback'))
|
self.assertIsNone(result.data.get('submissionFeedback'))
|
||||||
|
|
||||||
def test_student_does_see_final_feedback(self):
|
def test_student_does_see_final_feedback(self):
|
||||||
submission_feedback = SubmissionFeedbackFactory(teacher=self.teacher, final=True,
|
submission_feedback = SubmissionFeedbackFactory(teacher=self.teacher, final=True,
|
||||||
student_submission=self.student_submission)
|
student_submission=self.student_submission)
|
||||||
result = self._fetch_assignment_student(self.student1)
|
result = self._fetch_assignment_student(self.student1)
|
||||||
self.assertEqual(result.get('data').get('assignment').get('submission').get('submissionFeedback')
|
self.assertEqual(result.data.get('assignment').get('submission').get('submissionFeedback')
|
||||||
.get('text'), submission_feedback.text)
|
.get('text'), submission_feedback.text)
|
||||||
|
|
||||||
def test_teacher_can_see_feedback_for_submission(self):
|
def test_teacher_can_see_feedback_for_submission(self):
|
||||||
|
|
@ -178,7 +178,7 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
||||||
self.student_submission.save()
|
self.student_submission.save()
|
||||||
|
|
||||||
result = self._fetch_assignment_teacher(self.teacher)
|
result = self._fetch_assignment_teacher(self.teacher)
|
||||||
self.assertEqual(result.get('data').get('assignment').get('submissions')[0].get('submissionFeedback')
|
self.assertEqual(result.data.get('assignment').get('submissions')[0].get('submissionFeedback')
|
||||||
.get('text'), submission_feedback.text)
|
.get('text'), submission_feedback.text)
|
||||||
|
|
||||||
def test_rogue_teacher_cannot_see_feedback(self):
|
def test_rogue_teacher_cannot_see_feedback(self):
|
||||||
|
|
@ -188,4 +188,4 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
||||||
self.student_submission.save()
|
self.student_submission.save()
|
||||||
|
|
||||||
result = self._fetch_assignment_teacher(self.teacher2)
|
result = self._fetch_assignment_teacher(self.teacher2)
|
||||||
self.assertIsNone(result.get('data').get('assignment').get('submissions')[0].get('submissionFeedback'))
|
self.assertIsNone(result.data.get('assignment').get('submissions')[0].get('submissionFeedback'))
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ class AssignmentReadOnlyTestCase(SkillboxTestCase):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = self.get_client(self.student1).execute(UPDATE_ASSIGNMENT_MUTATION, variables=variables)
|
result = self.get_client(self.student1).execute(UPDATE_ASSIGNMENT_MUTATION, variables=variables)
|
||||||
self.assertIsNotNone(result.get('errors'))
|
self.assertIsNotNone(result.errors)
|
||||||
|
|
||||||
def test_share_assignment_fails(self):
|
def test_share_assignment_fails(self):
|
||||||
variables = {
|
variables = {
|
||||||
|
|
@ -46,7 +46,7 @@ class AssignmentReadOnlyTestCase(SkillboxTestCase):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = self.get_client(self.student1).execute(UPDATE_ASSIGNMENT_MUTATION, variables=variables)
|
result = self.get_client(self.student1).execute(UPDATE_ASSIGNMENT_MUTATION, variables=variables)
|
||||||
self.assertIsNotNone(result.get('errors'))
|
self.assertIsNotNone(result.errors)
|
||||||
|
|
||||||
def test_edit_feedback_fails(self):
|
def test_edit_feedback_fails(self):
|
||||||
student_submission = StudentSubmissionFactory(assignment=self.assignment, student=self.student1,
|
student_submission = StudentSubmissionFactory(assignment=self.assignment, student=self.student1,
|
||||||
|
|
@ -62,7 +62,7 @@ class AssignmentReadOnlyTestCase(SkillboxTestCase):
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
self.assertIsNotNone(result.get('errors'))
|
self.assertIsNotNone(result.errors)
|
||||||
|
|
||||||
|
|
||||||
def test_share_feedback_fails(self):
|
def test_share_feedback_fails(self):
|
||||||
|
|
@ -79,4 +79,4 @@ class AssignmentReadOnlyTestCase(SkillboxTestCase):
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
self.assertIsNotNone(result.get('errors'))
|
self.assertIsNotNone(result.errors)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,6 @@ class InstrumentTypesQueryTestCase(SkillboxTestCase):
|
||||||
InstrumentFactory(new_type=second_type)
|
InstrumentFactory(new_type=second_type)
|
||||||
|
|
||||||
def test_instrument_types_empty_not_returned(self):
|
def test_instrument_types_empty_not_returned(self):
|
||||||
result = self.get_client().get_result(INSTRUMENT_TYPES_QUERY)
|
result = self.get_client().execute(INSTRUMENT_TYPES_QUERY)
|
||||||
self.assertIsNone(result.errors)
|
self.assertIsNone(result.errors)
|
||||||
self.assertEqual(len(result.data['instrumentTypes']), 2)
|
self.assertEqual(len(result.data['instrumentTypes']), 2)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.13 on 2022-05-24 19:47
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('books', '0032_auto_20211213_1342'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='snapshot',
|
||||||
|
name='title',
|
||||||
|
field=models.CharField(blank=True, max_length=255, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -119,6 +119,7 @@ class Snapshot(models.Model):
|
||||||
'objectives.Objective',
|
'objectives.Objective',
|
||||||
related_name='hidden_for_snapshots'
|
related_name='hidden_for_snapshots'
|
||||||
)
|
)
|
||||||
|
title = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
|
||||||
objects = SnapshotManager()
|
objects = SnapshotManager()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from books.schema.mutations.chapter import UpdateChapterVisibility
|
from books.schema.mutations.chapter import UpdateChapterVisibility
|
||||||
from books.schema.mutations.contentblock import MutateContentBlock, AddContentBlock, DeleteContentBlock
|
from books.schema.mutations.contentblock import MutateContentBlock, AddContentBlock, DeleteContentBlock
|
||||||
from books.schema.mutations.module import UpdateSolutionVisibility, UpdateLastModule, SyncModuleVisibility
|
from books.schema.mutations.module import UpdateSolutionVisibility, UpdateLastModule, SyncModuleVisibility
|
||||||
from books.schema.mutations.snapshot import CreateSnapshot, ApplySnapshot, ShareSnapshot
|
from books.schema.mutations.snapshot import CreateSnapshot, ApplySnapshot, ShareSnapshot, UpdateSnapshot, DeleteSnapshot
|
||||||
from books.schema.mutations.topic import UpdateLastTopic
|
from books.schema.mutations.topic import UpdateLastTopic
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -17,3 +17,5 @@ class BookMutations(object):
|
||||||
create_snapshot = CreateSnapshot.Field()
|
create_snapshot = CreateSnapshot.Field()
|
||||||
apply_snapshot = ApplySnapshot.Field()
|
apply_snapshot = ApplySnapshot.Field()
|
||||||
share_snapshot = ShareSnapshot.Field()
|
share_snapshot = ShareSnapshot.Field()
|
||||||
|
update_snapshot = UpdateSnapshot.Field()
|
||||||
|
delete_snapshot = DeleteSnapshot.Field()
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import graphene
|
import graphene
|
||||||
from django.db.models import Q
|
|
||||||
from graphene import relay
|
from graphene import relay
|
||||||
|
|
||||||
|
from api.types import FailureNode, SuccessNode
|
||||||
from api.utils import get_object
|
from api.utils import get_object
|
||||||
from books.models import Module, ContentBlock, Chapter
|
from books.models import Module, ContentBlock, Chapter
|
||||||
from books.models.snapshot import Snapshot
|
from books.models.snapshot import Snapshot
|
||||||
|
|
@ -9,6 +9,30 @@ from books.schema.nodes import SnapshotNode, ModuleNode
|
||||||
from users.models import SchoolClass
|
from users.models import SchoolClass
|
||||||
|
|
||||||
|
|
||||||
|
class NotOwner(graphene.ObjectType):
|
||||||
|
class Meta:
|
||||||
|
interfaces = (FailureNode,)
|
||||||
|
|
||||||
|
|
||||||
|
class Success(graphene.ObjectType):
|
||||||
|
class Meta:
|
||||||
|
interfaces = (SuccessNode,)
|
||||||
|
|
||||||
|
|
||||||
|
NotOwnerFailure = NotOwner(reason="Not the owner")
|
||||||
|
DeleteSnapshotSuccess = Success(message='Snapshot deleted successfully')
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateSnapshotResult(graphene.Union):
|
||||||
|
class Meta:
|
||||||
|
types = (SnapshotNode, NotOwner,)
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteSnapshotResult(graphene.Union):
|
||||||
|
class Meta:
|
||||||
|
types = (Success, NotOwner,)
|
||||||
|
|
||||||
|
|
||||||
class CreateSnapshot(relay.ClientIDMutation):
|
class CreateSnapshot(relay.ClientIDMutation):
|
||||||
class Input:
|
class Input:
|
||||||
module = graphene.String(required=True)
|
module = graphene.String(required=True)
|
||||||
|
|
@ -30,6 +54,47 @@ class CreateSnapshot(relay.ClientIDMutation):
|
||||||
return cls(snapshot=snapshot, success=True)
|
return cls(snapshot=snapshot, success=True)
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateSnapshot(relay.ClientIDMutation):
|
||||||
|
class Input:
|
||||||
|
id = graphene.ID(required=True)
|
||||||
|
title = graphene.String()
|
||||||
|
|
||||||
|
snapshot = graphene.Field(UpdateSnapshotResult)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def mutate_and_get_payload(cls, root, info, **args):
|
||||||
|
id = args.get('id')
|
||||||
|
title = args.get('title')
|
||||||
|
user = info.context.user
|
||||||
|
|
||||||
|
snapshot = get_object(Snapshot, id)
|
||||||
|
if snapshot.creator != user:
|
||||||
|
return cls(snapshot=NotOwnerFailure)
|
||||||
|
if title is not None:
|
||||||
|
snapshot.title = title
|
||||||
|
snapshot.save()
|
||||||
|
return cls(snapshot=snapshot)
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteSnapshot(relay.ClientIDMutation):
|
||||||
|
class Input:
|
||||||
|
id = graphene.ID(required=True)
|
||||||
|
|
||||||
|
result = graphene.Field(DeleteSnapshotResult)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def mutate_and_get_payload(cls, root, info, **args):
|
||||||
|
id = args.get('id')
|
||||||
|
user = info.context.user
|
||||||
|
|
||||||
|
snapshot = get_object(Snapshot, id)
|
||||||
|
if snapshot.creator != user:
|
||||||
|
return cls(result=NotOwnerFailure)
|
||||||
|
|
||||||
|
snapshot.delete()
|
||||||
|
return cls(result=DeleteSnapshotSuccess)
|
||||||
|
|
||||||
|
|
||||||
class ApplySnapshot(relay.ClientIDMutation):
|
class ApplySnapshot(relay.ClientIDMutation):
|
||||||
class Input:
|
class Input:
|
||||||
snapshot = graphene.ID(required=True)
|
snapshot = graphene.ID(required=True)
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ class SnapshotNode(DjangoObjectType):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_title(parent: Snapshot, info, **kwargs):
|
def resolve_title(parent: Snapshot, info, **kwargs):
|
||||||
return f'Snapshot {parent.id}'
|
return parent.title if parent.title is not None else f'Snapshot {parent.id}'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_meta_title(parent, info, **kwargs):
|
def resolve_meta_title(parent, info, **kwargs):
|
||||||
|
|
|
||||||
|
|
@ -113,17 +113,6 @@ query SnapshotDetail($id: ID!) {
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SHARE_SNAPSHOT_MUTATION = """
|
|
||||||
mutation ShareSnapshot($input: ShareSnapshotInput!) {
|
|
||||||
shareSnapshot(input: $input) {
|
|
||||||
success
|
|
||||||
snapshot {
|
|
||||||
shared
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
MODULE_SNAPSHOTS_QUERY = """
|
MODULE_SNAPSHOTS_QUERY = """
|
||||||
query SnapshotQuery($slug: String!) {
|
query SnapshotQuery($slug: String!) {
|
||||||
module(slug: $slug) {
|
module(slug: $slug) {
|
||||||
|
|
@ -136,3 +125,46 @@ query SnapshotQuery($slug: String!) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
SHARE_SNAPSHOT_MUTATION = """
|
||||||
|
mutation ShareSnapshot($input: ShareSnapshotInput!) {
|
||||||
|
shareSnapshot(input: $input) {
|
||||||
|
success
|
||||||
|
snapshot {
|
||||||
|
shared
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
UPDATE_SNAPSHOT_MUTATION = """
|
||||||
|
mutation UpdateSnapshot($input: UpdateSnapshotInput!) {
|
||||||
|
updateSnapshot(input: $input) {
|
||||||
|
snapshot {
|
||||||
|
...on SnapshotNode {
|
||||||
|
title
|
||||||
|
id
|
||||||
|
}
|
||||||
|
...on NotOwner {
|
||||||
|
reason
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
DELETE_SNAPSHOT_MUTATION = """
|
||||||
|
mutation DeleteSnapshot($input: DeleteSnapshotInput!) {
|
||||||
|
deleteSnapshot(input: $input) {
|
||||||
|
result {
|
||||||
|
__typename
|
||||||
|
...on NotOwner {
|
||||||
|
reason
|
||||||
|
}
|
||||||
|
...on Success {
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ class ContentBlockTestCase(SkillboxTestCase):
|
||||||
result = self.client.execute(TOPIC_QUERY, variables={
|
result = self.client.execute(TOPIC_QUERY, variables={
|
||||||
"slug": slug
|
"slug": slug
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
topic = result.get('data').get('topic')
|
topic = result.data.get('topic')
|
||||||
self.assertEqual(topic.get('__typename'), 'NotFound')
|
self.assertEqual(topic.get('__typename'), 'NotFound')
|
||||||
self.assertEqual(topic.get('reason'), 'Not Found')
|
self.assertEqual(topic.get('reason'), 'Not Found')
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,8 @@ class ContentBlockTestCase(SkillboxTestCase):
|
||||||
result = self.client.execute(CONTENT_BLOCK_QUERY, variables={
|
result = self.client.execute(CONTENT_BLOCK_QUERY, variables={
|
||||||
"slug": self.slug
|
"slug": self.slug
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
module = result.get('data').get('module')
|
module = result.data.get('module')
|
||||||
content_block = module['chapters'][0]['contentBlocks'][0]
|
content_block = module['chapters'][0]['contentBlocks'][0]
|
||||||
self.assertEqual(content_block['title'], 'Title')
|
self.assertEqual(content_block['title'], 'Title')
|
||||||
self.assertIsNotNone(content_block['type'])
|
self.assertIsNotNone(content_block['type'])
|
||||||
|
|
|
||||||
|
|
@ -45,26 +45,26 @@ class OwnContentTestCase(SkillboxTestCase):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
result = self.client.execute(chapterQuery, variables={
|
result = self.get_client().execute(chapterQuery, variables={
|
||||||
"id": self.chapter_id
|
"id": self.chapter_id
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
self.assertEqual(len(result.get('data').get('chapter').get('contentBlocks')), 1)
|
self.assertEqual(len(result.data.get('chapter').get('contentBlocks')), 1)
|
||||||
|
|
||||||
custom_content_block = ContentBlock(title='own', slug='own', user_created=True, owner=self.user)
|
custom_content_block = ContentBlock(title='own', slug='own', user_created=True, owner=self.user)
|
||||||
self.chapter.specific.add_child(instance=custom_content_block)
|
self.chapter.specific.add_child(instance=custom_content_block)
|
||||||
result = self.client.execute(chapterQuery, variables={
|
result = self.get_client().execute(chapterQuery, variables={
|
||||||
"id": self.chapter_id
|
"id": self.chapter_id
|
||||||
})
|
})
|
||||||
self.assertEqual(len(result.get('data').get('chapter').get('contentBlocks')), 2)
|
self.assertEqual(len(result.data.get('chapter').get('contentBlocks')), 2)
|
||||||
|
|
||||||
for school_class in self.user.school_classes.all():
|
for school_class in self.user.school_classes.all():
|
||||||
custom_content_block.visible_for.add(school_class)
|
custom_content_block.visible_for.add(school_class)
|
||||||
|
|
||||||
result = self.client.execute(chapterQuery, variables={
|
result = self.get_client().execute(chapterQuery, variables={
|
||||||
"id": self.chapter_id
|
"id": self.chapter_id
|
||||||
})
|
})
|
||||||
self.assertEqual(len(result.get('data').get('chapter').get('contentBlocks')), 2)
|
self.assertEqual(len(result.data.get('chapter').get('contentBlocks')), 2)
|
||||||
|
|
||||||
def test_mutate_own_content_block(self):
|
def test_mutate_own_content_block(self):
|
||||||
query = """
|
query = """
|
||||||
|
|
@ -76,7 +76,7 @@ class OwnContentTestCase(SkillboxTestCase):
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
res = self.get_client().get_result(query, variables={'id': self.content_block_id})
|
res = self.get_client().execute(query, variables={'id': self.content_block_id})
|
||||||
self.assertIsNone(res.errors)
|
self.assertIsNone(res.errors)
|
||||||
self.assertEqual(res.data['contentBlock']['title'], 'bla')
|
self.assertEqual(res.data['contentBlock']['title'], 'bla')
|
||||||
|
|
||||||
|
|
@ -112,7 +112,7 @@ class OwnContentTestCase(SkillboxTestCase):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation_result = self.get_client().get_result(mutation, variables=variables)
|
mutation_result = self.get_client().execute(mutation, variables=variables)
|
||||||
self.assertIsNone(mutation_result.errors)
|
self.assertIsNone(mutation_result.errors)
|
||||||
content_block = mutation_result.data['mutateContentBlock']['contentBlock']
|
content_block = mutation_result.data['mutateContentBlock']['contentBlock']
|
||||||
self.assertEqual(content_block['title'], 'new title')
|
self.assertEqual(content_block['title'], 'new title')
|
||||||
|
|
@ -137,7 +137,7 @@ class OwnContentTestCase(SkillboxTestCase):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
list_mutation_result = self.get_client().get_result(mutation, variables=other_variables)
|
list_mutation_result = self.get_client().execute(mutation, variables=other_variables)
|
||||||
self.assertIsNone(list_mutation_result.errors)
|
self.assertIsNone(list_mutation_result.errors)
|
||||||
content_block = list_mutation_result.data['mutateContentBlock']['contentBlock']
|
content_block = list_mutation_result.data['mutateContentBlock']['contentBlock']
|
||||||
self.assertEqual(content_block['title'], 'title for list content')
|
self.assertEqual(content_block['title'], 'title for list content')
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from api.utils import get_object
|
||||||
from books.factories import ModuleFactory, ChapterFactory, ContentBlockFactory
|
from books.factories import ModuleFactory, ChapterFactory, ContentBlockFactory
|
||||||
from books.models import Snapshot, ChapterSnapshot
|
from books.models import Snapshot, ChapterSnapshot
|
||||||
from books.tests.queries import MODULE_QUERY, SNAPSHOT_MODULE_QUERY, CREATE_SNAPSHOT_MUTATION, APPLY_SNAPSHOT_MUTATION, \
|
from books.tests.queries import MODULE_QUERY, SNAPSHOT_MODULE_QUERY, CREATE_SNAPSHOT_MUTATION, APPLY_SNAPSHOT_MUTATION, \
|
||||||
MODULE_SNAPSHOTS_QUERY, SHARE_SNAPSHOT_MUTATION
|
MODULE_SNAPSHOTS_QUERY, SHARE_SNAPSHOT_MUTATION, UPDATE_SNAPSHOT_MUTATION, DELETE_SNAPSHOT_MUTATION
|
||||||
from core.tests.base_test import SkillboxTestCase
|
from core.tests.base_test import SkillboxTestCase
|
||||||
from objectives.factories import ObjectiveGroupFactory, ObjectiveFactory
|
from objectives.factories import ObjectiveGroupFactory, ObjectiveFactory
|
||||||
from users.factories import SchoolClassFactory
|
from users.factories import SchoolClassFactory
|
||||||
|
|
@ -89,8 +89,8 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
||||||
result = client.execute(MODULE_QUERY, variables={
|
result = client.execute(MODULE_QUERY, variables={
|
||||||
'slug': self.module.slug
|
'slug': self.module.slug
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
module = result.get('data').get('module')
|
module = result.data.get('module')
|
||||||
chapter = module.get('chapters')[0]
|
chapter = module.get('chapters')[0]
|
||||||
self.assertIsNotNone(chapter)
|
self.assertIsNotNone(chapter)
|
||||||
content_blocks = chapter.get('contentBlocks')
|
content_blocks = chapter.get('contentBlocks')
|
||||||
|
|
@ -144,8 +144,8 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
||||||
self._test_module_visibility(self.client, 'skillbox')
|
self._test_module_visibility(self.client, 'skillbox')
|
||||||
|
|
||||||
def _test_create_snapshot(self, result, num_snapshots=1):
|
def _test_create_snapshot(self, result, num_snapshots=1):
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
snapshot = result.get('data').get('createSnapshot').get('snapshot')
|
snapshot = result.data.get('createSnapshot').get('snapshot')
|
||||||
chapter = snapshot.get('chapters')[0]
|
chapter = snapshot.get('chapters')[0]
|
||||||
|
|
||||||
self.assertIsNotNone(snapshot.get('created'))
|
self.assertIsNotNone(snapshot.get('created'))
|
||||||
|
|
@ -206,7 +206,7 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
||||||
'selectedClass': to_global_id('SchoolClassNode', self.second_class.pk),
|
'selectedClass': to_global_id('SchoolClassNode', self.second_class.pk),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
module = self._test_module_visibility(self.get_client(self.teacher2), self.second_class_name)
|
module = self._test_module_visibility(self.get_client(self.teacher2), self.second_class_name)
|
||||||
original_creator = module['chapters'][0]['contentBlocks'][2].get('originalCreator')
|
original_creator = module['chapters'][0]['contentBlocks'][2].get('originalCreator')
|
||||||
self.assertIsNotNone(original_creator)
|
self.assertIsNotNone(original_creator)
|
||||||
|
|
@ -219,8 +219,8 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
||||||
snapshot_result = self.client.execute(SNAPSHOT_MODULE_QUERY, variables={
|
snapshot_result = self.client.execute(SNAPSHOT_MODULE_QUERY, variables={
|
||||||
'id': id
|
'id': id
|
||||||
})
|
})
|
||||||
self.assertIsNone(snapshot_result.get('errors'))
|
self.assertIsNone(snapshot_result.errors)
|
||||||
snapshot = snapshot_result.get('data').get('snapshot')
|
snapshot = snapshot_result.data.get('snapshot')
|
||||||
chapters = snapshot.get('chapters')
|
chapters = snapshot.get('chapters')
|
||||||
self.assertEqual(len(chapters), 2)
|
self.assertEqual(len(chapters), 2)
|
||||||
chapter = chapters[0]
|
chapter = chapters[0]
|
||||||
|
|
@ -259,8 +259,8 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
||||||
'selectedClass': to_global_id('SchoolClassNode', third_class.pk),
|
'selectedClass': to_global_id('SchoolClassNode', third_class.pk),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
snapshot_id = result['data']['createSnapshot']['snapshot']['id']
|
snapshot_id = result.data['createSnapshot']['snapshot']['id']
|
||||||
|
|
||||||
result = self.client.execute(APPLY_SNAPSHOT_MUTATION, variables={
|
result = self.client.execute(APPLY_SNAPSHOT_MUTATION, variables={
|
||||||
'input': {
|
'input': {
|
||||||
|
|
@ -268,13 +268,13 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
||||||
'selectedClass': to_global_id('SchoolClassNode', self.skillbox_class.pk),
|
'selectedClass': to_global_id('SchoolClassNode', self.skillbox_class.pk),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
|
|
||||||
result = self.client.execute(MODULE_QUERY, variables={
|
result = self.client.execute(MODULE_QUERY, variables={
|
||||||
'slug': self.module.slug
|
'slug': self.module.slug
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
module = result['data']['module']
|
module = result.data['module']
|
||||||
chapter1, chapter2 = module['chapters']
|
chapter1, chapter2 = module['chapters']
|
||||||
visible, hidden, custom, custom_hidden = chapter1['contentBlocks']
|
visible, hidden, custom, custom_hidden = chapter1['contentBlocks']
|
||||||
self.assertTrue(self.skillbox_class.name not in [sc['name'] for sc in visible['hiddenFor']])
|
self.assertTrue(self.skillbox_class.name not in [sc['name'] for sc in visible['hiddenFor']])
|
||||||
|
|
@ -286,8 +286,8 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
||||||
result = self.graphene_client.execute(MODULE_QUERY, variables={
|
result = self.graphene_client.execute(MODULE_QUERY, variables={
|
||||||
'slug': self.module.slug
|
'slug': self.module.slug
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
chapter = result['data']['module']['chapters'][0]
|
chapter = result.data['module']['chapters'][0]
|
||||||
self.assertEqual(len(chapter['contentBlocks']), 4)
|
self.assertEqual(len(chapter['contentBlocks']), 4)
|
||||||
|
|
||||||
result = self.graphene_client.execute(CREATE_SNAPSHOT_MUTATION, variables={
|
result = self.graphene_client.execute(CREATE_SNAPSHOT_MUTATION, variables={
|
||||||
|
|
@ -296,8 +296,8 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
||||||
'selectedClass': to_global_id('SchoolClassNode', self.skillbox_class.pk),
|
'selectedClass': to_global_id('SchoolClassNode', self.skillbox_class.pk),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
snapshot_id = result['data']['createSnapshot']['snapshot']['id']
|
snapshot_id = result.data['createSnapshot']['snapshot']['id']
|
||||||
|
|
||||||
teacher2 = User.objects.get(username='teacher2')
|
teacher2 = User.objects.get(username='teacher2')
|
||||||
teacher2_client = self.get_client(user=teacher2)
|
teacher2_client = self.get_client(user=teacher2)
|
||||||
|
|
@ -307,16 +307,15 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
||||||
'selectedClass': to_global_id('SchoolClassNode', self.second_class.pk),
|
'selectedClass': to_global_id('SchoolClassNode', self.second_class.pk),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
|
|
||||||
result = self.graphene_client.execute(MODULE_QUERY, variables={
|
result = self.graphene_client.execute(MODULE_QUERY, variables={
|
||||||
'slug': self.module.slug
|
'slug': self.module.slug
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
chapter = result['data']['module']['chapters'][0]
|
chapter = result.data['module']['chapters'][0]
|
||||||
self.assertEqual(len(chapter['contentBlocks']), 4)
|
self.assertEqual(len(chapter['contentBlocks']), 4)
|
||||||
|
|
||||||
|
|
||||||
def test_snapshot_chapter_visibility_after_apply(self):
|
def test_snapshot_chapter_visibility_after_apply(self):
|
||||||
result = self.graphene_client.execute(CREATE_SNAPSHOT_MUTATION, variables={
|
result = self.graphene_client.execute(CREATE_SNAPSHOT_MUTATION, variables={
|
||||||
'input': {
|
'input': {
|
||||||
|
|
@ -335,10 +334,11 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
||||||
a_result = self.get_client(self.teacher2).execute(MODULE_QUERY, variables={
|
a_result = self.get_client(self.teacher2).execute(MODULE_QUERY, variables={
|
||||||
'slug': self.module.slug
|
'slug': self.module.slug
|
||||||
})
|
})
|
||||||
self.assertIsNone(a_result.get('errors'))
|
self.assertIsNone(a_result.errors)
|
||||||
a_chapter = a_result['data']['module']['chapters'][0]
|
a_chapter = a_result.data['module']['chapters'][0]
|
||||||
self.assertEqual(self.second_class_name in map(lambda x: x['name'], a_chapter['titleHiddenFor']), hidden)
|
self.assertEqual(self.second_class_name in map(lambda x: x['name'], a_chapter['titleHiddenFor']), hidden)
|
||||||
self.assertEqual(self.second_class_name in map(lambda x: x['name'], a_chapter['descriptionHiddenFor']), hidden)
|
self.assertEqual(self.second_class_name in map(lambda x: x['name'], a_chapter['descriptionHiddenFor']),
|
||||||
|
hidden)
|
||||||
|
|
||||||
assert_chapter_hidden(True)
|
assert_chapter_hidden(True)
|
||||||
|
|
||||||
|
|
@ -348,8 +348,8 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
||||||
'selectedClass': to_global_id('SchoolClassNode', self.skillbox_class.pk),
|
'selectedClass': to_global_id('SchoolClassNode', self.skillbox_class.pk),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
snapshot = result['data']['createSnapshot']['snapshot']
|
snapshot = result.data['createSnapshot']['snapshot']
|
||||||
snapshot_id = snapshot['id']
|
snapshot_id = snapshot['id']
|
||||||
chapter = snapshot['chapters'][0]
|
chapter = snapshot['chapters'][0]
|
||||||
self.assertEqual(chapter['titleHidden'], False)
|
self.assertEqual(chapter['titleHidden'], False)
|
||||||
|
|
@ -361,7 +361,7 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
||||||
'selectedClass': to_global_id('SchoolClassNode', self.second_class.pk),
|
'selectedClass': to_global_id('SchoolClassNode', self.second_class.pk),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
|
|
||||||
assert_chapter_hidden(False)
|
assert_chapter_hidden(False)
|
||||||
|
|
||||||
|
|
@ -384,8 +384,8 @@ class SnapshotTestCase(SkillboxTestCase):
|
||||||
result = self.client.execute(MODULE_SNAPSHOTS_QUERY, variables={
|
result = self.client.execute(MODULE_SNAPSHOTS_QUERY, variables={
|
||||||
"slug": self.slug
|
"slug": self.slug
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
snapshots = result['data']['module']['snapshots']
|
snapshots = result.data['module']['snapshots']
|
||||||
self.assertEqual(len(snapshots), 1)
|
self.assertEqual(len(snapshots), 1)
|
||||||
self.assertEqual(snapshots[0]['creator'], f'{self.teacher.first_name} {self.teacher.last_name}')
|
self.assertEqual(snapshots[0]['creator'], f'{self.teacher.first_name} {self.teacher.last_name}')
|
||||||
|
|
||||||
|
|
@ -397,8 +397,8 @@ class SnapshotTestCase(SkillboxTestCase):
|
||||||
'shared': True
|
'shared': True
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
data = result['data']['shareSnapshot']
|
data = result.data['shareSnapshot']
|
||||||
self.assertTrue(data['success'])
|
self.assertTrue(data['success'])
|
||||||
self.assertTrue(data['snapshot']['shared'])
|
self.assertTrue(data['snapshot']['shared'])
|
||||||
snapshot = Snapshot.objects.get(pk=self.snapshot.pk)
|
snapshot = Snapshot.objects.get(pk=self.snapshot.pk)
|
||||||
|
|
@ -413,7 +413,7 @@ class SnapshotTestCase(SkillboxTestCase):
|
||||||
'shared': True
|
'shared': True
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNotNone(result.get('errors'))
|
self.assertIsNotNone(result.errors)
|
||||||
|
|
||||||
def test_snapshot_without_creator(self):
|
def test_snapshot_without_creator(self):
|
||||||
self.snapshot.creator = None
|
self.snapshot.creator = None
|
||||||
|
|
@ -422,5 +422,50 @@ class SnapshotTestCase(SkillboxTestCase):
|
||||||
result = self.client.execute(MODULE_SNAPSHOTS_QUERY, variables={
|
result = self.client.execute(MODULE_SNAPSHOTS_QUERY, variables={
|
||||||
"slug": self.slug
|
"slug": self.slug
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
self.assertEqual(len(result.get('data').get('module').get('snapshots')), 1)
|
self.assertEqual(len(result.data.get('module').get('snapshots')), 1)
|
||||||
|
|
||||||
|
def _setup_title_change(self):
|
||||||
|
self.assertIsNone(self.snapshot.title)
|
||||||
|
new_title = 'New Snapshot Title'
|
||||||
|
result = self.get_client().execute(UPDATE_SNAPSHOT_MUTATION, variables={
|
||||||
|
'input': {
|
||||||
|
'id': to_global_id('Snapshot', self.snapshot.id),
|
||||||
|
'title': new_title
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
|
||||||
|
def test_update_snapshot_title(self):
|
||||||
|
result = self._setup_title_change()
|
||||||
|
self.assertIsNone(result.errors)
|
||||||
|
self.assertEqual(result.data.get('updateSnapshot').get('snapshot').get('title'), 'New Snapshot Title')
|
||||||
|
|
||||||
|
def test_update_snapshot_not_owner_fails(self):
|
||||||
|
self.snapshot.creator = self.teacher2
|
||||||
|
self.snapshot.save()
|
||||||
|
result = self._setup_title_change()
|
||||||
|
self.assertIsNone(result.errors)
|
||||||
|
self.assertEqual(result.data.get('updateSnapshot').get('snapshot').get('reason'), 'Not the owner')
|
||||||
|
|
||||||
|
def test_delete_snapshot(self):
|
||||||
|
result = self.get_client().execute(DELETE_SNAPSHOT_MUTATION, variables={
|
||||||
|
'input': {
|
||||||
|
'id': to_global_id('Snapshot', self.snapshot.id),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.assertIsNone(result.errors)
|
||||||
|
self.assertEqual(result.data.get('deleteSnapshot').get('result').get('__typename'), 'Success')
|
||||||
|
|
||||||
|
def test_delete_snapshot_not_owner_fails(self):
|
||||||
|
self.snapshot.creator = self.teacher2
|
||||||
|
self.snapshot.save()
|
||||||
|
result = self.get_client().execute(DELETE_SNAPSHOT_MUTATION, variables={
|
||||||
|
'input': {
|
||||||
|
'id': to_global_id('Snapshot', self.snapshot.id),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.assertIsNone(result.errors)
|
||||||
|
result = result.data.get('deleteSnapshot').get('result')
|
||||||
|
self.assertEqual(result.get('__typename'), 'NotOwner')
|
||||||
|
self.assertEqual(result.get('reason'), 'Not the owner')
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,10 @@ class GQLClient(Client):
|
||||||
def get_result(self, *args, **kwargs):
|
def get_result(self, *args, **kwargs):
|
||||||
return GQLResult(self.execute(*args, **kwargs))
|
return GQLResult(self.execute(*args, **kwargs))
|
||||||
|
|
||||||
|
def execute(self, *args, **kwargs):
|
||||||
|
res = super(GQLClient, self).execute(*args, **kwargs)
|
||||||
|
return GQLResult(res)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SkillboxTestCase(TestCase):
|
class SkillboxTestCase(TestCase):
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ mutation UpdateProjectMutation($input: UpdateProjectInput!){
|
||||||
'title': 'BAD! THIS IS BAD!'
|
'title': 'BAD! THIS IS BAD!'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = self.get_client(self.student2).get_result(mutation, variables={
|
result = self.get_client(self.student2).execute(mutation, variables={
|
||||||
'input': input
|
'input': input
|
||||||
})
|
})
|
||||||
self.assertIsNotNone(result.errors)
|
self.assertIsNotNone(result.errors)
|
||||||
|
|
@ -115,7 +115,7 @@ mutation UpdateProjectMutation($input: UpdateProjectInput!){
|
||||||
'title': 'Good! THIS IS good!'
|
'title': 'Good! THIS IS good!'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = self.get_client(self.student).get_result(mutation, variables={
|
result = self.get_client(self.student).execute(mutation, variables={
|
||||||
'input': input
|
'input': input
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.errors)
|
self.assertIsNone(result.errors)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ query ProjectQuery($id: ID!) {
|
||||||
|
|
||||||
class ProjectQueryTestCase(SkillboxTestCase):
|
class ProjectQueryTestCase(SkillboxTestCase):
|
||||||
def _test_direct_project_access(self, user: User, should_have_access: bool):
|
def _test_direct_project_access(self, user: User, should_have_access: bool):
|
||||||
result = self.get_client(user).get_result(project_query, variables={
|
result = self.get_client(user).execute(project_query, variables={
|
||||||
'id': self.project1.graphql_id
|
'id': self.project1.graphql_id
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.errors)
|
self.assertIsNone(result.errors)
|
||||||
|
|
@ -57,22 +57,22 @@ class ProjectQueryTestCase(SkillboxTestCase):
|
||||||
|
|
||||||
result = self.get_client(self.student1).execute(self.query)
|
result = self.get_client(self.student1).execute(self.query)
|
||||||
|
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
self.assertEqual(result.get('data').get('projects')[0].get('title'), self.project1.title)
|
self.assertEqual(result.data.get('projects')[0].get('title'), self.project1.title)
|
||||||
|
|
||||||
def test_should_not_see_other_projects(self):
|
def test_should_not_see_other_projects(self):
|
||||||
self.assertEqual(Project.objects.count(), 1)
|
self.assertEqual(Project.objects.count(), 1)
|
||||||
|
|
||||||
result = self.get_client(self.student2).execute(self.query)
|
result = self.get_client(self.student2).execute(self.query)
|
||||||
|
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
self.assertEqual(len(result.get('data').get('projects')), 0)
|
self.assertEqual(len(result.data.get('projects')), 0)
|
||||||
|
|
||||||
def test_teacher_should_not_see_unfinished_projects(self):
|
def test_teacher_should_not_see_unfinished_projects(self):
|
||||||
result = self.get_client().execute(self.query)
|
result = self.get_client().execute(self.query)
|
||||||
|
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
self.assertEqual(len(result.get('data').get('projects')), 0)
|
self.assertEqual(len(result.data.get('projects')), 0)
|
||||||
|
|
||||||
def test_teacher_should_only_see_finished_projects(self):
|
def test_teacher_should_only_see_finished_projects(self):
|
||||||
self.project1.final = True
|
self.project1.final = True
|
||||||
|
|
@ -81,8 +81,8 @@ class ProjectQueryTestCase(SkillboxTestCase):
|
||||||
|
|
||||||
result = self.get_client().execute(self.query)
|
result = self.get_client().execute(self.query)
|
||||||
|
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
self.assertEqual(result.get('data').get('projects')[0].get('title'),
|
self.assertEqual(result.data.get('projects')[0].get('title'),
|
||||||
self.project1.title)
|
self.project1.title)
|
||||||
|
|
||||||
def test_other_teacher_should_not_see_projects(self):
|
def test_other_teacher_should_not_see_projects(self):
|
||||||
|
|
@ -92,8 +92,8 @@ class ProjectQueryTestCase(SkillboxTestCase):
|
||||||
|
|
||||||
result = self.get_client(self.teacher2).execute(self.query)
|
result = self.get_client(self.teacher2).execute(self.query)
|
||||||
|
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
self.assertEqual(len(result.get('data').get('projects')), 0)
|
self.assertEqual(len(result.data.get('projects')), 0)
|
||||||
|
|
||||||
def test_direct_project_access(self):
|
def test_direct_project_access(self):
|
||||||
# student can access own project directly
|
# student can access own project directly
|
||||||
|
|
@ -128,7 +128,7 @@ query ProjectQuery($id: ID!) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
result = self.get_client(self.student1).get_result(query, variables={
|
result = self.get_client(self.student1).execute(query, variables={
|
||||||
'id': self.project1.graphql_id
|
'id': self.project1.graphql_id
|
||||||
})
|
})
|
||||||
self.assertEqual(result.data['project']['student']['email'], self.student1.email)
|
self.assertEqual(result.data['project']['student']['email'], self.student1.email)
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ mutation AddComment($input: AddCommentInput!) {
|
||||||
'comment': self.text
|
'comment': self.text
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
self.assertEqual(room_entry.comments.count(), 1)
|
self.assertEqual(room_entry.comments.count(), 1)
|
||||||
comment = room_entry.comments.first()
|
comment = room_entry.comments.first()
|
||||||
self.assertEqual(comment.text, self.text)
|
self.assertEqual(comment.text, self.text)
|
||||||
|
|
@ -53,8 +53,8 @@ query CommentsQuery($id: ID!) {
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
result = self.get_client().execute(query, variables={"id": self.room_entry_id})
|
result = self.get_client().execute(query, variables={"id": self.room_entry_id})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
comment_node = result.get('data').get('roomEntry').get('comments')[0]
|
comment_node = result.data.get('roomEntry').get('comments')[0]
|
||||||
self.assertEqual(comment_node['text'], self.text)
|
self.assertEqual(comment_node['text'], self.text)
|
||||||
|
|
||||||
def test_get_comment_for_other_user(self):
|
def test_get_comment_for_other_user(self):
|
||||||
|
|
@ -70,6 +70,5 @@ query CommentsQuery($id: ID!) {
|
||||||
"""
|
"""
|
||||||
|
|
||||||
result = self.get_client(self.student_second_class).execute(query, variables={"id": self.room_entry_id})
|
result = self.get_client(self.student_second_class).execute(query, variables={"id": self.room_entry_id})
|
||||||
gql_result = GQLResult(result)
|
self.assertIsNone(result.errors)
|
||||||
self.assertIsNone(gql_result.errors)
|
self.assertIsNone(result.data.get('roomEntry'))
|
||||||
self.assertIsNone(gql_result.data.get('roomEntry'))
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ class NewRoomMutationTestCase(SkillboxTestCase):
|
||||||
self.assertEqual(Room.objects.count(), 0)
|
self.assertEqual(Room.objects.count(), 0)
|
||||||
title = 'some title'
|
title = 'some title'
|
||||||
appearance = 'blue'
|
appearance = 'blue'
|
||||||
res = self.get_client().execute(self.mutation, variables={
|
result = self.get_client().execute(self.mutation, variables={
|
||||||
'input': {
|
'input': {
|
||||||
'room': {
|
'room': {
|
||||||
'title': title,
|
'title': title,
|
||||||
|
|
@ -64,7 +64,6 @@ class NewRoomMutationTestCase(SkillboxTestCase):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
result = GQLResult(res)
|
|
||||||
self.assertIsNone(result.errors)
|
self.assertIsNone(result.errors)
|
||||||
room = GQLRoom(result.data.get('addRoom').get('room'))
|
room = GQLRoom(result.data.get('addRoom').get('room'))
|
||||||
self.assertEqual(room.title, title)
|
self.assertEqual(room.title, title)
|
||||||
|
|
@ -75,7 +74,7 @@ class NewRoomMutationTestCase(SkillboxTestCase):
|
||||||
|
|
||||||
def test_create_new_room_for_other_school_class(self):
|
def test_create_new_room_for_other_school_class(self):
|
||||||
self.assertEqual(Room.objects.count(), 0)
|
self.assertEqual(Room.objects.count(), 0)
|
||||||
result = self.get_client(self.teacher2).get_result(self.mutation, variables={
|
result = self.get_client(self.teacher2).execute(self.mutation, variables={
|
||||||
'input': {
|
'input': {
|
||||||
'room': {
|
'room': {
|
||||||
'title': 'BIG NO NO!',
|
'title': 'BIG NO NO!',
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ mutation AddRoomEntry($input: AddRoomEntryInput!){
|
||||||
'room': self.room.graphql_id
|
'room': self.room.graphql_id
|
||||||
}
|
}
|
||||||
|
|
||||||
result = self.get_client(self.yet_another_user).get_result(mutation, variables={
|
result = self.get_client(self.yet_another_user).execute(mutation, variables={
|
||||||
'input': {
|
'input': {
|
||||||
'roomEntry': room_entry
|
'roomEntry': room_entry
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,41 +30,37 @@ query RoomQuery ($slug: String!) {
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_restricted_query(self):
|
def test_restricted_query(self):
|
||||||
res = self.get_client().execute(self.query, variables={
|
result = self.get_client().execute(self.query, variables={
|
||||||
'slug': self.room.slug
|
'slug': self.room.slug
|
||||||
})
|
})
|
||||||
result = GQLResult(res)
|
|
||||||
self.assertIsNone(result.errors)
|
self.assertIsNone(result.errors)
|
||||||
self.assertFalse(result.data.get('room').get('restricted'))
|
self.assertFalse(result.data.get('room').get('restricted'))
|
||||||
|
|
||||||
def test_successful_mutation(self):
|
def test_successful_mutation(self):
|
||||||
res = self.get_client().execute(self.mutation, variables={
|
result = self.get_client().execute(self.mutation, variables={
|
||||||
'input': {
|
'input': {
|
||||||
'id': self.room_id,
|
'id': self.room_id,
|
||||||
'restricted': True
|
'restricted': True
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
result = GQLResult(res)
|
|
||||||
self.assertIsNone(result.errors)
|
self.assertIsNone(result.errors)
|
||||||
self.assertEqual(result.data.get('updateRoomVisibility').get('room').get('restricted'), True)
|
self.assertEqual(result.data.get('updateRoomVisibility').get('room').get('restricted'), True)
|
||||||
|
|
||||||
def test_permission_denied(self):
|
def test_permission_denied(self):
|
||||||
res = self.get_client(self.student1).execute(self.mutation, variables={
|
result = self.get_client(self.student1).execute(self.mutation, variables={
|
||||||
'input': {
|
'input': {
|
||||||
'id': self.room_id,
|
'id': self.room_id,
|
||||||
'restricted': True
|
'restricted': True
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
result = GQLResult(res)
|
|
||||||
self.assertIsNotNone(result.errors)
|
self.assertIsNotNone(result.errors)
|
||||||
|
|
||||||
res = self.get_client(self.teacher2).execute(self.mutation, variables={
|
result = self.get_client(self.teacher2).execute(self.mutation, variables={
|
||||||
'input': {
|
'input': {
|
||||||
'id': self.room_id,
|
'id': self.room_id,
|
||||||
'restricted': True
|
'restricted': True
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
result = GQLResult(res)
|
|
||||||
self.assertIsNotNone(result.errors)
|
self.assertIsNotNone(result.errors)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,9 @@ query RoomQuery ($slug: String!) {
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _test_room(self, user, length, restricted=True):
|
def _test_room(self, user, length, restricted=True):
|
||||||
res = self.get_client(user).execute(self.query, variables={
|
result = self.get_client(user).execute(self.query, variables={
|
||||||
'slug': self.room.slug
|
'slug': self.room.slug
|
||||||
})
|
})
|
||||||
result = GQLResult(res)
|
|
||||||
self.assertIsNone(result.errors)
|
self.assertIsNone(result.errors)
|
||||||
room = GQLRoom(result.data.get('room'))
|
room = GQLRoom(result.data.get('room'))
|
||||||
self.assertEqual(room.restricted, restricted)
|
self.assertEqual(room.restricted, restricted)
|
||||||
|
|
|
||||||
|
|
@ -444,6 +444,18 @@ type DeleteRoomPayload {
|
||||||
clientMutationId: String
|
clientMutationId: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input DeleteSnapshotInput {
|
||||||
|
id: ID!
|
||||||
|
clientMutationId: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeleteSnapshotPayload {
|
||||||
|
result: DeleteSnapshotResult
|
||||||
|
clientMutationId: String
|
||||||
|
}
|
||||||
|
|
||||||
|
union DeleteSnapshotResult = Success | NotOwner
|
||||||
|
|
||||||
type DjangoDebug {
|
type DjangoDebug {
|
||||||
sql: [DjangoDebugSQL]
|
sql: [DjangoDebugSQL]
|
||||||
}
|
}
|
||||||
|
|
@ -469,6 +481,10 @@ type DuplicateName {
|
||||||
reason: String
|
reason: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface FailureNode {
|
||||||
|
reason: String
|
||||||
|
}
|
||||||
|
|
||||||
type FieldError {
|
type FieldError {
|
||||||
code: String
|
code: String
|
||||||
}
|
}
|
||||||
|
|
@ -683,6 +699,8 @@ type Mutation {
|
||||||
createSnapshot(input: CreateSnapshotInput!): CreateSnapshotPayload
|
createSnapshot(input: CreateSnapshotInput!): CreateSnapshotPayload
|
||||||
applySnapshot(input: ApplySnapshotInput!): ApplySnapshotPayload
|
applySnapshot(input: ApplySnapshotInput!): ApplySnapshotPayload
|
||||||
shareSnapshot(input: ShareSnapshotInput!): ShareSnapshotPayload
|
shareSnapshot(input: ShareSnapshotInput!): ShareSnapshotPayload
|
||||||
|
updateSnapshot(input: UpdateSnapshotInput!): UpdateSnapshotPayload
|
||||||
|
deleteSnapshot(input: DeleteSnapshotInput!): DeleteSnapshotPayload
|
||||||
_debug: DjangoDebug
|
_debug: DjangoDebug
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -706,6 +724,10 @@ type NotFound {
|
||||||
reason: String
|
reason: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NotOwner implements FailureNode {
|
||||||
|
reason: String
|
||||||
|
}
|
||||||
|
|
||||||
type NoteNode implements Node {
|
type NoteNode implements Node {
|
||||||
id: ID!
|
id: ID!
|
||||||
text: String!
|
text: String!
|
||||||
|
|
@ -1065,6 +1087,14 @@ type SubmissionFeedbackNode implements Node {
|
||||||
id: ID!
|
id: ID!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Success implements SuccessNode {
|
||||||
|
message: String
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SuccessNode {
|
||||||
|
message: String
|
||||||
|
}
|
||||||
|
|
||||||
type SurveyNode implements Node {
|
type SurveyNode implements Node {
|
||||||
id: ID!
|
id: ID!
|
||||||
title: String!
|
title: String!
|
||||||
|
|
@ -1431,6 +1461,19 @@ type UpdateSettingPayload {
|
||||||
clientMutationId: String
|
clientMutationId: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input UpdateSnapshotInput {
|
||||||
|
id: ID!
|
||||||
|
title: String
|
||||||
|
clientMutationId: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateSnapshotPayload {
|
||||||
|
snapshot: UpdateSnapshotResult
|
||||||
|
clientMutationId: String
|
||||||
|
}
|
||||||
|
|
||||||
|
union UpdateSnapshotResult = SnapshotNode | NotOwner
|
||||||
|
|
||||||
input UpdateSolutionVisibilityInput {
|
input UpdateSolutionVisibilityInput {
|
||||||
slug: String
|
slug: String
|
||||||
enabled: Boolean
|
enabled: Boolean
|
||||||
|
|
|
||||||
|
|
@ -62,13 +62,13 @@ class ModifySchoolClassTest(SkillboxTestCase):
|
||||||
'name': class_name
|
'name': class_name
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
|
|
||||||
school_class = get_object(SchoolClass, id)
|
school_class = get_object(SchoolClass, id)
|
||||||
self.assertEqual(school_class.name, class_name)
|
self.assertEqual(school_class.name, class_name)
|
||||||
|
|
||||||
def test_update_school_class_not_in_class_fails(self):
|
def test_update_school_class_not_in_class_fails(self):
|
||||||
client = Client(schema=schema)
|
client = self.get_client()
|
||||||
teacher = TeacherFactory(username='conan')
|
teacher = TeacherFactory(username='conan')
|
||||||
context = Context(user=teacher)
|
context = Context(user=teacher)
|
||||||
school_class = SchoolClass.objects.get(name='skillbox')
|
school_class = SchoolClass.objects.get(name='skillbox')
|
||||||
|
|
@ -81,7 +81,7 @@ class ModifySchoolClassTest(SkillboxTestCase):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = client.execute(UPDATE_SCHOOL_CLASS_MUTATION, variables=variables, context=context)
|
result = client.execute(UPDATE_SCHOOL_CLASS_MUTATION, variables=variables, context=context)
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
|
|
||||||
def test_update_school_class_fail(self):
|
def test_update_school_class_fail(self):
|
||||||
class_name = 'Nanana'
|
class_name = 'Nanana'
|
||||||
|
|
@ -96,7 +96,7 @@ class ModifySchoolClassTest(SkillboxTestCase):
|
||||||
'name': class_name
|
'name': class_name
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNotNone(result.get('errors'))
|
self.assertIsNotNone(result.errors)
|
||||||
|
|
||||||
def test_create_school_class(self):
|
def test_create_school_class(self):
|
||||||
self.assertEqual(SchoolClass.objects.count(), 2)
|
self.assertEqual(SchoolClass.objects.count(), 2)
|
||||||
|
|
@ -107,8 +107,8 @@ class ModifySchoolClassTest(SkillboxTestCase):
|
||||||
'name': class_name
|
'name': class_name
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNone(query_result.get('errors'))
|
self.assertIsNone(query_result.errors)
|
||||||
result = query_result.get('data').get('createSchoolClass').get('result')
|
result = query_result.data.get('createSchoolClass').get('result')
|
||||||
self.assertEqual(result.get('__typename'), 'SchoolClassNode')
|
self.assertEqual(result.get('__typename'), 'SchoolClassNode')
|
||||||
id = result.get('id')
|
id = result.get('id')
|
||||||
self.assertEqual(SchoolClass.objects.count(), 3)
|
self.assertEqual(SchoolClass.objects.count(), 3)
|
||||||
|
|
@ -129,8 +129,8 @@ class ModifySchoolClassTest(SkillboxTestCase):
|
||||||
'name': class_name
|
'name': class_name
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNone(query_result.get('errors'))
|
self.assertIsNone(query_result.errors)
|
||||||
result = query_result.get('data').get('createSchoolClass').get('result')
|
result = query_result.data.get('createSchoolClass').get('result')
|
||||||
self.assertEqual(result.get('__typename'), 'DuplicateName')
|
self.assertEqual(result.get('__typename'), 'DuplicateName')
|
||||||
reason = result.get('reason')
|
reason = result.get('reason')
|
||||||
self.assertEqual(reason, 'Dieser Name wird bereits verwendet.')
|
self.assertEqual(reason, 'Dieser Name wird bereits verwendet.')
|
||||||
|
|
@ -144,4 +144,4 @@ class ModifySchoolClassTest(SkillboxTestCase):
|
||||||
'name': 'No School'
|
'name': 'No School'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.assertIsNotNone(result.get('errors'))
|
self.assertIsNotNone(result.errors)
|
||||||
|
|
|
||||||
|
|
@ -50,17 +50,17 @@ class UserSettingTests(SkillboxTestCase):
|
||||||
def test_selects_first_class_on_first_call(self):
|
def test_selects_first_class_on_first_call(self):
|
||||||
result = self.make_query()
|
result = self.make_query()
|
||||||
first_class = self.user.school_classes.first()
|
first_class = self.user.school_classes.first()
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
self.assertEqual(result.get('data').get('me').get('selectedClass').get('name'), first_class.name)
|
self.assertEqual(result.data.get('me').get('selectedClass').get('name'), first_class.name)
|
||||||
self.assertFalse(result.get('data').get('me').get('selectedClass').get('readOnly'))
|
self.assertFalse(result.data.get('me').get('selectedClass').get('readOnly'))
|
||||||
|
|
||||||
def test_returns_selected_class(self):
|
def test_returns_selected_class(self):
|
||||||
selected_class = self.user.school_classes.all()[1]
|
selected_class = self.user.school_classes.all()[1]
|
||||||
setting = UserSetting.objects.create(user=self.user, selected_class=selected_class)
|
setting = UserSetting.objects.create(user=self.user, selected_class=selected_class)
|
||||||
setting.save()
|
setting.save()
|
||||||
result = self.make_query()
|
result = self.make_query()
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
self.assertEqual(result.get('data').get('me').get('selectedClass').get('name'),
|
self.assertEqual(result.data.get('me').get('selectedClass').get('name'),
|
||||||
selected_class.name)
|
selected_class.name)
|
||||||
|
|
||||||
def test_user_can_select_class(self):
|
def test_user_can_select_class(self):
|
||||||
|
|
@ -70,19 +70,19 @@ class UserSettingTests(SkillboxTestCase):
|
||||||
|
|
||||||
selected_class = self.user.school_classes.all()[1]
|
selected_class = self.user.school_classes.all()[1]
|
||||||
mutation_result = self.make_mutation(selected_class.pk)
|
mutation_result = self.make_mutation(selected_class.pk)
|
||||||
self.assertIsNone(mutation_result.get('errors'))
|
self.assertIsNone(mutation_result.errors)
|
||||||
query_result = self.make_query()
|
query_result = self.make_query()
|
||||||
self.assertIsNone(query_result.get('errors'))
|
self.assertIsNone(query_result.errors)
|
||||||
self.assertEqual(query_result.get('data').get('me').get('selectedClass').get('name'),
|
self.assertEqual(query_result.data.get('me').get('selectedClass').get('name'),
|
||||||
selected_class.name)
|
selected_class.name)
|
||||||
|
|
||||||
def test_user_can_select_class_even_no_settings_exist(self):
|
def test_user_can_select_class_even_no_settings_exist(self):
|
||||||
selected_class = self.user.school_classes.all()[1]
|
selected_class = self.user.school_classes.all()[1]
|
||||||
mutation_result = self.make_mutation(selected_class.pk)
|
mutation_result = self.make_mutation(selected_class.pk)
|
||||||
self.assertIsNone(mutation_result.get('errors'))
|
self.assertIsNone(mutation_result.errors)
|
||||||
query_result = self.make_query()
|
query_result = self.make_query()
|
||||||
self.assertIsNone(query_result.get('errors'))
|
self.assertIsNone(query_result.errors)
|
||||||
self.assertEqual(query_result.get('data').get('me').get('selectedClass').get('name'),
|
self.assertEqual(query_result.data.get('me').get('selectedClass').get('name'),
|
||||||
selected_class.name)
|
selected_class.name)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -93,7 +93,7 @@ class UserSettingTests(SkillboxTestCase):
|
||||||
setting.save()
|
setting.save()
|
||||||
|
|
||||||
mutation_result = self.make_mutation(self.class3.pk)
|
mutation_result = self.make_mutation(self.class3.pk)
|
||||||
self.assertIsNotNone(mutation_result.get('errors'))
|
self.assertIsNotNone(mutation_result.errors)
|
||||||
|
|
||||||
def test_inactive_class_as_selected_class(self):
|
def test_inactive_class_as_selected_class(self):
|
||||||
selected_class = self.class2
|
selected_class = self.class2
|
||||||
|
|
@ -106,6 +106,6 @@ class UserSettingTests(SkillboxTestCase):
|
||||||
setting.save()
|
setting.save()
|
||||||
|
|
||||||
result = self.make_query()
|
result = self.make_query()
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.errors)
|
||||||
self.assertTrue(result.get('data').get('me').get('selectedClass').get('readOnly'))
|
self.assertTrue(result.data.get('me').get('selectedClass').get('readOnly'))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue