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 {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', () => {
|
||||
const operations = isTeacher => ({
|
||||
|
|
@ -25,8 +82,8 @@ describe('Snapshot', () => {
|
|||
...module,
|
||||
snapshots: [
|
||||
{
|
||||
id: 'snapshot-id',
|
||||
title: 'title',
|
||||
id: 'U25hcHNob3ROb2RlOjQ=',
|
||||
title: 'Old Title',
|
||||
created: '2020-01-01',
|
||||
mine: true,
|
||||
shared: false,
|
||||
|
|
@ -88,4 +145,26 @@ describe('Snapshot', () => {
|
|||
cy.getByDataCy('module-title').should('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 EditClassNameWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/school-class/EditClassNameWizard');
|
||||
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 SimpleLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/SimpleLayout');
|
||||
const FullScreenLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/FullScreenLayout');
|
||||
|
|
@ -66,6 +67,7 @@
|
|||
EditNoteWizard,
|
||||
EditClassNameWizard,
|
||||
EditTeamNameWizard,
|
||||
EditSnapshotTitleWizard,
|
||||
...modals
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<div class="snapshot-list-item">
|
||||
<div
|
||||
data-cy="snapshot-entry"
|
||||
class="snapshot-list-item"
|
||||
>
|
||||
<router-link
|
||||
:to="snapshotRoute"
|
||||
class="snapshot-list-item__title"
|
||||
|
|
@ -11,14 +14,30 @@
|
|||
class="snapshot-list-item__date"
|
||||
v-html="meta"
|
||||
/>
|
||||
<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 class="snapshot-list-item__actions">
|
||||
<button
|
||||
class="icon-button"
|
||||
data-cy="delete-snapshot-button"
|
||||
@click="deleteSnapshot"
|
||||
>
|
||||
<trash-icon class="snapshot-list-item__icon" />
|
||||
</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>
|
||||
</template>
|
||||
|
||||
|
|
@ -26,7 +45,13 @@
|
|||
import dateformat from '@/helpers/date-format';
|
||||
import {SNAPSHOT_DETAIL} from '@/router/module.names';
|
||||
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 PenIcon from '@/components/icons/PenIcon';
|
||||
import TrashIcon from '@/components/icons/TrashIcon';
|
||||
import { removeAtIndex } from '@/graphql/immutable-operations';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
|
@ -35,6 +60,10 @@
|
|||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
components: {
|
||||
PenIcon,
|
||||
TrashIcon,
|
||||
},
|
||||
|
||||
computed: {
|
||||
meta() {
|
||||
|
|
@ -55,6 +84,78 @@
|
|||
},
|
||||
|
||||
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() {
|
||||
this.$apollo.mutate({
|
||||
mutation: SHARE_SNAPSHOT_MUTATION,
|
||||
|
|
@ -70,10 +171,10 @@
|
|||
fragment: gql`fragment SnapshotFragment on SnapshotNode { shared }`,
|
||||
data: {
|
||||
shared,
|
||||
__typename: 'SnapshotNode'
|
||||
}
|
||||
__typename: 'SnapshotNode',
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
@ -100,6 +201,15 @@
|
|||
&__link {
|
||||
@include default-link;
|
||||
color: $color-brand;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
@include default-icon;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
<modal-input
|
||||
:value="name"
|
||||
placeholder="Klassenname"
|
||||
:placeholder="placeholder"
|
||||
data-cy="edit-name-input"
|
||||
@input="$emit('input', $event)"
|
||||
/>
|
||||
|
|
@ -43,6 +43,10 @@
|
|||
type: String,
|
||||
default: '',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: 'Namen bearbeiten'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
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: {
|
||||
editTeamName() {
|
||||
// todo: use this.$modal
|
||||
this.$store.dispatch('editTeamName');
|
||||
},
|
||||
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):
|
||||
client = create_client(user)
|
||||
client = self.get_client(user)
|
||||
query = '''
|
||||
query AssignmentWithSubmissions($id: ID!) {
|
||||
assignment(id: $id) {
|
||||
|
|
@ -72,7 +72,7 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
|||
})
|
||||
|
||||
def _fetch_assignment_teacher(self, user):
|
||||
client = create_client(user)
|
||||
client = self.get_client(user)
|
||||
query = '''
|
||||
query AssignmentWithSubmissions($id: ID!) {
|
||||
assignment(id: $id) {
|
||||
|
|
@ -116,13 +116,13 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
|||
def test_teacher_can_create_feedback(self):
|
||||
result = self._create_submission_feedback(self.teacher, False, 'Balalal', self.student_submission_id)
|
||||
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertIsNone(result.errors)
|
||||
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):
|
||||
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):
|
||||
assignment = AssignmentFactory(
|
||||
|
|
@ -136,9 +136,9 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
|||
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
self.assertIsNotNone(result.get('errors'))
|
||||
self.assertIsNotNone(result.errors)
|
||||
|
||||
def test_student_does_not_see_non_final_feedback(self):
|
||||
SubmissionFeedbackFactory(teacher=self.teacher, final=False, student_submission=self.student_submission)
|
||||
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):
|
||||
submission_feedback = SubmissionFeedbackFactory(teacher=self.teacher, final=True,
|
||||
student_submission=self.student_submission)
|
||||
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)
|
||||
|
||||
def test_teacher_can_see_feedback_for_submission(self):
|
||||
|
|
@ -178,7 +178,7 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
|||
self.student_submission.save()
|
||||
|
||||
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)
|
||||
|
||||
def test_rogue_teacher_cannot_see_feedback(self):
|
||||
|
|
@ -188,4 +188,4 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
|||
self.student_submission.save()
|
||||
|
||||
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)
|
||||
self.assertIsNotNone(result.get('errors'))
|
||||
self.assertIsNotNone(result.errors)
|
||||
|
||||
def test_share_assignment_fails(self):
|
||||
variables = {
|
||||
|
|
@ -46,7 +46,7 @@ class AssignmentReadOnlyTestCase(SkillboxTestCase):
|
|||
}
|
||||
}
|
||||
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):
|
||||
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):
|
||||
|
|
@ -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)
|
||||
|
||||
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.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',
|
||||
related_name='hidden_for_snapshots'
|
||||
)
|
||||
title = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
||||
objects = SnapshotManager()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from books.schema.mutations.chapter import UpdateChapterVisibility
|
||||
from books.schema.mutations.contentblock import MutateContentBlock, AddContentBlock, DeleteContentBlock
|
||||
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
|
||||
|
||||
|
||||
|
|
@ -17,3 +17,5 @@ class BookMutations(object):
|
|||
create_snapshot = CreateSnapshot.Field()
|
||||
apply_snapshot = ApplySnapshot.Field()
|
||||
share_snapshot = ShareSnapshot.Field()
|
||||
update_snapshot = UpdateSnapshot.Field()
|
||||
delete_snapshot = DeleteSnapshot.Field()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import graphene
|
||||
from django.db.models import Q
|
||||
from graphene import relay
|
||||
|
||||
from api.types import FailureNode, SuccessNode
|
||||
from api.utils import get_object
|
||||
from books.models import Module, ContentBlock, Chapter
|
||||
from books.models.snapshot import Snapshot
|
||||
|
|
@ -9,6 +9,30 @@ from books.schema.nodes import SnapshotNode, ModuleNode
|
|||
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 Input:
|
||||
module = graphene.String(required=True)
|
||||
|
|
@ -30,6 +54,47 @@ class CreateSnapshot(relay.ClientIDMutation):
|
|||
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 Input:
|
||||
snapshot = graphene.ID(required=True)
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ class SnapshotNode(DjangoObjectType):
|
|||
|
||||
@staticmethod
|
||||
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
|
||||
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 = """
|
||||
query SnapshotQuery($slug: String!) {
|
||||
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={
|
||||
"slug": slug
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
topic = result.get('data').get('topic')
|
||||
self.assertIsNone(result.errors)
|
||||
topic = result.data.get('topic')
|
||||
self.assertEqual(topic.get('__typename'), 'NotFound')
|
||||
self.assertEqual(topic.get('reason'), 'Not Found')
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ class ContentBlockTestCase(SkillboxTestCase):
|
|||
result = self.client.execute(CONTENT_BLOCK_QUERY, variables={
|
||||
"slug": self.slug
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
module = result.get('data').get('module')
|
||||
self.assertIsNone(result.errors)
|
||||
module = result.data.get('module')
|
||||
content_block = module['chapters'][0]['contentBlocks'][0]
|
||||
self.assertEqual(content_block['title'], 'Title')
|
||||
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
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(len(result.get('data').get('chapter').get('contentBlocks')), 1)
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertEqual(len(result.data.get('chapter').get('contentBlocks')), 1)
|
||||
|
||||
custom_content_block = ContentBlock(title='own', slug='own', user_created=True, owner=self.user)
|
||||
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
|
||||
})
|
||||
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():
|
||||
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
|
||||
})
|
||||
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):
|
||||
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.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)
|
||||
content_block = mutation_result.data['mutateContentBlock']['contentBlock']
|
||||
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)
|
||||
content_block = list_mutation_result.data['mutateContentBlock']['contentBlock']
|
||||
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.models import Snapshot, ChapterSnapshot
|
||||
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 objectives.factories import ObjectiveGroupFactory, ObjectiveFactory
|
||||
from users.factories import SchoolClassFactory
|
||||
|
|
@ -89,8 +89,8 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
|||
result = client.execute(MODULE_QUERY, variables={
|
||||
'slug': self.module.slug
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
module = result.get('data').get('module')
|
||||
self.assertIsNone(result.errors)
|
||||
module = result.data.get('module')
|
||||
chapter = module.get('chapters')[0]
|
||||
self.assertIsNotNone(chapter)
|
||||
content_blocks = chapter.get('contentBlocks')
|
||||
|
|
@ -144,8 +144,8 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
|||
self._test_module_visibility(self.client, 'skillbox')
|
||||
|
||||
def _test_create_snapshot(self, result, num_snapshots=1):
|
||||
self.assertIsNone(result.get('errors'))
|
||||
snapshot = result.get('data').get('createSnapshot').get('snapshot')
|
||||
self.assertIsNone(result.errors)
|
||||
snapshot = result.data.get('createSnapshot').get('snapshot')
|
||||
chapter = snapshot.get('chapters')[0]
|
||||
|
||||
self.assertIsNotNone(snapshot.get('created'))
|
||||
|
|
@ -206,7 +206,7 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
|||
'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)
|
||||
original_creator = module['chapters'][0]['contentBlocks'][2].get('originalCreator')
|
||||
self.assertIsNotNone(original_creator)
|
||||
|
|
@ -219,8 +219,8 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
|||
snapshot_result = self.client.execute(SNAPSHOT_MODULE_QUERY, variables={
|
||||
'id': id
|
||||
})
|
||||
self.assertIsNone(snapshot_result.get('errors'))
|
||||
snapshot = snapshot_result.get('data').get('snapshot')
|
||||
self.assertIsNone(snapshot_result.errors)
|
||||
snapshot = snapshot_result.data.get('snapshot')
|
||||
chapters = snapshot.get('chapters')
|
||||
self.assertEqual(len(chapters), 2)
|
||||
chapter = chapters[0]
|
||||
|
|
@ -259,8 +259,8 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
|||
'selectedClass': to_global_id('SchoolClassNode', third_class.pk),
|
||||
}
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
snapshot_id = result['data']['createSnapshot']['snapshot']['id']
|
||||
self.assertIsNone(result.errors)
|
||||
snapshot_id = result.data['createSnapshot']['snapshot']['id']
|
||||
|
||||
result = self.client.execute(APPLY_SNAPSHOT_MUTATION, variables={
|
||||
'input': {
|
||||
|
|
@ -268,13 +268,13 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
|||
'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={
|
||||
'slug': self.module.slug
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
module = result['data']['module']
|
||||
self.assertIsNone(result.errors)
|
||||
module = result.data['module']
|
||||
chapter1, chapter2 = module['chapters']
|
||||
visible, hidden, custom, custom_hidden = chapter1['contentBlocks']
|
||||
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={
|
||||
'slug': self.module.slug
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
chapter = result['data']['module']['chapters'][0]
|
||||
self.assertIsNone(result.errors)
|
||||
chapter = result.data['module']['chapters'][0]
|
||||
self.assertEqual(len(chapter['contentBlocks']), 4)
|
||||
|
||||
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),
|
||||
}
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
snapshot_id = result['data']['createSnapshot']['snapshot']['id']
|
||||
self.assertIsNone(result.errors)
|
||||
snapshot_id = result.data['createSnapshot']['snapshot']['id']
|
||||
|
||||
teacher2 = User.objects.get(username='teacher2')
|
||||
teacher2_client = self.get_client(user=teacher2)
|
||||
|
|
@ -307,16 +307,15 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
|||
'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={
|
||||
'slug': self.module.slug
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
chapter = result['data']['module']['chapters'][0]
|
||||
self.assertIsNone(result.errors)
|
||||
chapter = result.data['module']['chapters'][0]
|
||||
self.assertEqual(len(chapter['contentBlocks']), 4)
|
||||
|
||||
|
||||
def test_snapshot_chapter_visibility_after_apply(self):
|
||||
result = self.graphene_client.execute(CREATE_SNAPSHOT_MUTATION, variables={
|
||||
'input': {
|
||||
|
|
@ -335,10 +334,11 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
|||
a_result = self.get_client(self.teacher2).execute(MODULE_QUERY, variables={
|
||||
'slug': self.module.slug
|
||||
})
|
||||
self.assertIsNone(a_result.get('errors'))
|
||||
a_chapter = a_result['data']['module']['chapters'][0]
|
||||
self.assertIsNone(a_result.errors)
|
||||
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['descriptionHiddenFor']), hidden)
|
||||
self.assertEqual(self.second_class_name in map(lambda x: x['name'], a_chapter['descriptionHiddenFor']),
|
||||
hidden)
|
||||
|
||||
assert_chapter_hidden(True)
|
||||
|
||||
|
|
@ -348,8 +348,8 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
|||
'selectedClass': to_global_id('SchoolClassNode', self.skillbox_class.pk),
|
||||
}
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
snapshot = result['data']['createSnapshot']['snapshot']
|
||||
self.assertIsNone(result.errors)
|
||||
snapshot = result.data['createSnapshot']['snapshot']
|
||||
snapshot_id = snapshot['id']
|
||||
chapter = snapshot['chapters'][0]
|
||||
self.assertEqual(chapter['titleHidden'], False)
|
||||
|
|
@ -361,7 +361,7 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
|||
'selectedClass': to_global_id('SchoolClassNode', self.second_class.pk),
|
||||
}
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertIsNone(result.errors)
|
||||
|
||||
assert_chapter_hidden(False)
|
||||
|
||||
|
|
@ -384,8 +384,8 @@ class SnapshotTestCase(SkillboxTestCase):
|
|||
result = self.client.execute(MODULE_SNAPSHOTS_QUERY, variables={
|
||||
"slug": self.slug
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
snapshots = result['data']['module']['snapshots']
|
||||
self.assertIsNone(result.errors)
|
||||
snapshots = result.data['module']['snapshots']
|
||||
self.assertEqual(len(snapshots), 1)
|
||||
self.assertEqual(snapshots[0]['creator'], f'{self.teacher.first_name} {self.teacher.last_name}')
|
||||
|
||||
|
|
@ -397,8 +397,8 @@ class SnapshotTestCase(SkillboxTestCase):
|
|||
'shared': True
|
||||
}
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
data = result['data']['shareSnapshot']
|
||||
self.assertIsNone(result.errors)
|
||||
data = result.data['shareSnapshot']
|
||||
self.assertTrue(data['success'])
|
||||
self.assertTrue(data['snapshot']['shared'])
|
||||
snapshot = Snapshot.objects.get(pk=self.snapshot.pk)
|
||||
|
|
@ -413,7 +413,7 @@ class SnapshotTestCase(SkillboxTestCase):
|
|||
'shared': True
|
||||
}
|
||||
})
|
||||
self.assertIsNotNone(result.get('errors'))
|
||||
self.assertIsNotNone(result.errors)
|
||||
|
||||
def test_snapshot_without_creator(self):
|
||||
self.snapshot.creator = None
|
||||
|
|
@ -422,5 +422,50 @@ class SnapshotTestCase(SkillboxTestCase):
|
|||
result = self.client.execute(MODULE_SNAPSHOTS_QUERY, variables={
|
||||
"slug": self.slug
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(len(result.get('data').get('module').get('snapshots')), 1)
|
||||
self.assertIsNone(result.errors)
|
||||
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):
|
||||
return GQLResult(self.execute(*args, **kwargs))
|
||||
|
||||
def execute(self, *args, **kwargs):
|
||||
res = super(GQLClient, self).execute(*args, **kwargs)
|
||||
return GQLResult(res)
|
||||
|
||||
|
||||
|
||||
class SkillboxTestCase(TestCase):
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ mutation UpdateProjectMutation($input: UpdateProjectInput!){
|
|||
'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
|
||||
})
|
||||
self.assertIsNotNone(result.errors)
|
||||
|
|
@ -115,7 +115,7 @@ mutation UpdateProjectMutation($input: UpdateProjectInput!){
|
|||
'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
|
||||
})
|
||||
self.assertIsNone(result.errors)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ query ProjectQuery($id: ID!) {
|
|||
|
||||
class ProjectQueryTestCase(SkillboxTestCase):
|
||||
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
|
||||
})
|
||||
self.assertIsNone(result.errors)
|
||||
|
|
@ -57,22 +57,22 @@ class ProjectQueryTestCase(SkillboxTestCase):
|
|||
|
||||
result = self.get_client(self.student1).execute(self.query)
|
||||
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(result.get('data').get('projects')[0].get('title'), self.project1.title)
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertEqual(result.data.get('projects')[0].get('title'), self.project1.title)
|
||||
|
||||
def test_should_not_see_other_projects(self):
|
||||
self.assertEqual(Project.objects.count(), 1)
|
||||
|
||||
result = self.get_client(self.student2).execute(self.query)
|
||||
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(len(result.get('data').get('projects')), 0)
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertEqual(len(result.data.get('projects')), 0)
|
||||
|
||||
def test_teacher_should_not_see_unfinished_projects(self):
|
||||
result = self.get_client().execute(self.query)
|
||||
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(len(result.get('data').get('projects')), 0)
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertEqual(len(result.data.get('projects')), 0)
|
||||
|
||||
def test_teacher_should_only_see_finished_projects(self):
|
||||
self.project1.final = True
|
||||
|
|
@ -81,8 +81,8 @@ class ProjectQueryTestCase(SkillboxTestCase):
|
|||
|
||||
result = self.get_client().execute(self.query)
|
||||
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(result.get('data').get('projects')[0].get('title'),
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertEqual(result.data.get('projects')[0].get('title'),
|
||||
self.project1.title)
|
||||
|
||||
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)
|
||||
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(len(result.get('data').get('projects')), 0)
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertEqual(len(result.data.get('projects')), 0)
|
||||
|
||||
def test_direct_project_access(self):
|
||||
# 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
|
||||
})
|
||||
self.assertEqual(result.data['project']['student']['email'], self.student1.email)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ mutation AddComment($input: AddCommentInput!) {
|
|||
'comment': self.text
|
||||
}
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertEqual(room_entry.comments.count(), 1)
|
||||
comment = room_entry.comments.first()
|
||||
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})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
comment_node = result.get('data').get('roomEntry').get('comments')[0]
|
||||
self.assertIsNone(result.errors)
|
||||
comment_node = result.data.get('roomEntry').get('comments')[0]
|
||||
self.assertEqual(comment_node['text'], self.text)
|
||||
|
||||
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})
|
||||
gql_result = GQLResult(result)
|
||||
self.assertIsNone(gql_result.errors)
|
||||
self.assertIsNone(gql_result.data.get('roomEntry'))
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertIsNone(result.data.get('roomEntry'))
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class NewRoomMutationTestCase(SkillboxTestCase):
|
|||
self.assertEqual(Room.objects.count(), 0)
|
||||
title = 'some title'
|
||||
appearance = 'blue'
|
||||
res = self.get_client().execute(self.mutation, variables={
|
||||
result = self.get_client().execute(self.mutation, variables={
|
||||
'input': {
|
||||
'room': {
|
||||
'title': title,
|
||||
|
|
@ -64,7 +64,6 @@ class NewRoomMutationTestCase(SkillboxTestCase):
|
|||
}
|
||||
}
|
||||
})
|
||||
result = GQLResult(res)
|
||||
self.assertIsNone(result.errors)
|
||||
room = GQLRoom(result.data.get('addRoom').get('room'))
|
||||
self.assertEqual(room.title, title)
|
||||
|
|
@ -75,7 +74,7 @@ class NewRoomMutationTestCase(SkillboxTestCase):
|
|||
|
||||
def test_create_new_room_for_other_school_class(self):
|
||||
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': {
|
||||
'room': {
|
||||
'title': 'BIG NO NO!',
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ mutation AddRoomEntry($input: AddRoomEntryInput!){
|
|||
'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': {
|
||||
'roomEntry': room_entry
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,41 +30,37 @@ query RoomQuery ($slug: String!) {
|
|||
"""
|
||||
|
||||
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
|
||||
})
|
||||
result = GQLResult(res)
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertFalse(result.data.get('room').get('restricted'))
|
||||
|
||||
def test_successful_mutation(self):
|
||||
res = self.get_client().execute(self.mutation, variables={
|
||||
result = self.get_client().execute(self.mutation, variables={
|
||||
'input': {
|
||||
'id': self.room_id,
|
||||
'restricted': True
|
||||
}
|
||||
})
|
||||
result = GQLResult(res)
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertEqual(result.data.get('updateRoomVisibility').get('room').get('restricted'), True)
|
||||
|
||||
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': {
|
||||
'id': self.room_id,
|
||||
'restricted': True
|
||||
}
|
||||
})
|
||||
result = GQLResult(res)
|
||||
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': {
|
||||
'id': self.room_id,
|
||||
'restricted': True
|
||||
}
|
||||
})
|
||||
result = GQLResult(res)
|
||||
self.assertIsNotNone(result.errors)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -34,10 +34,9 @@ query RoomQuery ($slug: String!) {
|
|||
"""
|
||||
|
||||
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
|
||||
})
|
||||
result = GQLResult(res)
|
||||
self.assertIsNone(result.errors)
|
||||
room = GQLRoom(result.data.get('room'))
|
||||
self.assertEqual(room.restricted, restricted)
|
||||
|
|
|
|||
|
|
@ -444,6 +444,18 @@ type DeleteRoomPayload {
|
|||
clientMutationId: String
|
||||
}
|
||||
|
||||
input DeleteSnapshotInput {
|
||||
id: ID!
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type DeleteSnapshotPayload {
|
||||
result: DeleteSnapshotResult
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
union DeleteSnapshotResult = Success | NotOwner
|
||||
|
||||
type DjangoDebug {
|
||||
sql: [DjangoDebugSQL]
|
||||
}
|
||||
|
|
@ -469,6 +481,10 @@ type DuplicateName {
|
|||
reason: String
|
||||
}
|
||||
|
||||
interface FailureNode {
|
||||
reason: String
|
||||
}
|
||||
|
||||
type FieldError {
|
||||
code: String
|
||||
}
|
||||
|
|
@ -683,6 +699,8 @@ type Mutation {
|
|||
createSnapshot(input: CreateSnapshotInput!): CreateSnapshotPayload
|
||||
applySnapshot(input: ApplySnapshotInput!): ApplySnapshotPayload
|
||||
shareSnapshot(input: ShareSnapshotInput!): ShareSnapshotPayload
|
||||
updateSnapshot(input: UpdateSnapshotInput!): UpdateSnapshotPayload
|
||||
deleteSnapshot(input: DeleteSnapshotInput!): DeleteSnapshotPayload
|
||||
_debug: DjangoDebug
|
||||
}
|
||||
|
||||
|
|
@ -706,6 +724,10 @@ type NotFound {
|
|||
reason: String
|
||||
}
|
||||
|
||||
type NotOwner implements FailureNode {
|
||||
reason: String
|
||||
}
|
||||
|
||||
type NoteNode implements Node {
|
||||
id: ID!
|
||||
text: String!
|
||||
|
|
@ -1065,6 +1087,14 @@ type SubmissionFeedbackNode implements Node {
|
|||
id: ID!
|
||||
}
|
||||
|
||||
type Success implements SuccessNode {
|
||||
message: String
|
||||
}
|
||||
|
||||
interface SuccessNode {
|
||||
message: String
|
||||
}
|
||||
|
||||
type SurveyNode implements Node {
|
||||
id: ID!
|
||||
title: String!
|
||||
|
|
@ -1431,6 +1461,19 @@ type UpdateSettingPayload {
|
|||
clientMutationId: String
|
||||
}
|
||||
|
||||
input UpdateSnapshotInput {
|
||||
id: ID!
|
||||
title: String
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
type UpdateSnapshotPayload {
|
||||
snapshot: UpdateSnapshotResult
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
union UpdateSnapshotResult = SnapshotNode | NotOwner
|
||||
|
||||
input UpdateSolutionVisibilityInput {
|
||||
slug: String
|
||||
enabled: Boolean
|
||||
|
|
|
|||
|
|
@ -62,13 +62,13 @@ class ModifySchoolClassTest(SkillboxTestCase):
|
|||
'name': class_name
|
||||
}
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertIsNone(result.errors)
|
||||
|
||||
school_class = get_object(SchoolClass, id)
|
||||
self.assertEqual(school_class.name, class_name)
|
||||
|
||||
def test_update_school_class_not_in_class_fails(self):
|
||||
client = Client(schema=schema)
|
||||
client = self.get_client()
|
||||
teacher = TeacherFactory(username='conan')
|
||||
context = Context(user=teacher)
|
||||
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)
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertIsNone(result.errors)
|
||||
|
||||
def test_update_school_class_fail(self):
|
||||
class_name = 'Nanana'
|
||||
|
|
@ -96,7 +96,7 @@ class ModifySchoolClassTest(SkillboxTestCase):
|
|||
'name': class_name
|
||||
}
|
||||
})
|
||||
self.assertIsNotNone(result.get('errors'))
|
||||
self.assertIsNotNone(result.errors)
|
||||
|
||||
def test_create_school_class(self):
|
||||
self.assertEqual(SchoolClass.objects.count(), 2)
|
||||
|
|
@ -107,8 +107,8 @@ class ModifySchoolClassTest(SkillboxTestCase):
|
|||
'name': class_name
|
||||
}
|
||||
})
|
||||
self.assertIsNone(query_result.get('errors'))
|
||||
result = query_result.get('data').get('createSchoolClass').get('result')
|
||||
self.assertIsNone(query_result.errors)
|
||||
result = query_result.data.get('createSchoolClass').get('result')
|
||||
self.assertEqual(result.get('__typename'), 'SchoolClassNode')
|
||||
id = result.get('id')
|
||||
self.assertEqual(SchoolClass.objects.count(), 3)
|
||||
|
|
@ -129,8 +129,8 @@ class ModifySchoolClassTest(SkillboxTestCase):
|
|||
'name': class_name
|
||||
}
|
||||
})
|
||||
self.assertIsNone(query_result.get('errors'))
|
||||
result = query_result.get('data').get('createSchoolClass').get('result')
|
||||
self.assertIsNone(query_result.errors)
|
||||
result = query_result.data.get('createSchoolClass').get('result')
|
||||
self.assertEqual(result.get('__typename'), 'DuplicateName')
|
||||
reason = result.get('reason')
|
||||
self.assertEqual(reason, 'Dieser Name wird bereits verwendet.')
|
||||
|
|
@ -144,4 +144,4 @@ class ModifySchoolClassTest(SkillboxTestCase):
|
|||
'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):
|
||||
result = self.make_query()
|
||||
first_class = self.user.school_classes.first()
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(result.get('data').get('me').get('selectedClass').get('name'), first_class.name)
|
||||
self.assertFalse(result.get('data').get('me').get('selectedClass').get('readOnly'))
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertEqual(result.data.get('me').get('selectedClass').get('name'), first_class.name)
|
||||
self.assertFalse(result.data.get('me').get('selectedClass').get('readOnly'))
|
||||
|
||||
def test_returns_selected_class(self):
|
||||
selected_class = self.user.school_classes.all()[1]
|
||||
setting = UserSetting.objects.create(user=self.user, selected_class=selected_class)
|
||||
setting.save()
|
||||
result = self.make_query()
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(result.get('data').get('me').get('selectedClass').get('name'),
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertEqual(result.data.get('me').get('selectedClass').get('name'),
|
||||
selected_class.name)
|
||||
|
||||
def test_user_can_select_class(self):
|
||||
|
|
@ -70,19 +70,19 @@ class UserSettingTests(SkillboxTestCase):
|
|||
|
||||
selected_class = self.user.school_classes.all()[1]
|
||||
mutation_result = self.make_mutation(selected_class.pk)
|
||||
self.assertIsNone(mutation_result.get('errors'))
|
||||
self.assertIsNone(mutation_result.errors)
|
||||
query_result = self.make_query()
|
||||
self.assertIsNone(query_result.get('errors'))
|
||||
self.assertEqual(query_result.get('data').get('me').get('selectedClass').get('name'),
|
||||
self.assertIsNone(query_result.errors)
|
||||
self.assertEqual(query_result.data.get('me').get('selectedClass').get('name'),
|
||||
selected_class.name)
|
||||
|
||||
def test_user_can_select_class_even_no_settings_exist(self):
|
||||
selected_class = self.user.school_classes.all()[1]
|
||||
mutation_result = self.make_mutation(selected_class.pk)
|
||||
self.assertIsNone(mutation_result.get('errors'))
|
||||
self.assertIsNone(mutation_result.errors)
|
||||
query_result = self.make_query()
|
||||
self.assertIsNone(query_result.get('errors'))
|
||||
self.assertEqual(query_result.get('data').get('me').get('selectedClass').get('name'),
|
||||
self.assertIsNone(query_result.errors)
|
||||
self.assertEqual(query_result.data.get('me').get('selectedClass').get('name'),
|
||||
selected_class.name)
|
||||
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ class UserSettingTests(SkillboxTestCase):
|
|||
setting.save()
|
||||
|
||||
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):
|
||||
selected_class = self.class2
|
||||
|
|
@ -106,6 +106,6 @@ class UserSettingTests(SkillboxTestCase):
|
|||
setting.save()
|
||||
|
||||
result = self.make_query()
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertTrue(result.get('data').get('me').get('selectedClass').get('readOnly'))
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertTrue(result.data.get('me').get('selectedClass').get('readOnly'))
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue