Merged in feature/rooms-read-only (pull request #88)
Feature/rooms read only
This commit is contained in:
commit
b50ba068a0
|
|
@ -2,6 +2,13 @@ import { GraphQLError } from 'graphql';
|
||||||
|
|
||||||
const schema = require('../../../fixtures/schema.json');
|
const schema = require('../../../fixtures/schema.json');
|
||||||
|
|
||||||
|
const redeemCoupon = coupon => {
|
||||||
|
if (coupon !== '') {
|
||||||
|
cy.get('[data-cy="coupon-input"]').type(coupon);
|
||||||
|
}
|
||||||
|
cy.get('[data-cy="coupon-button"]').click();
|
||||||
|
};
|
||||||
|
|
||||||
describe('Email Verifcation', () => {
|
describe('Email Verifcation', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.server();
|
cy.server();
|
||||||
|
|
@ -22,7 +29,7 @@ describe('Email Verifcation', () => {
|
||||||
cy.apolloLogin('rahel.cueni', 'test');
|
cy.apolloLogin('rahel.cueni', 'test');
|
||||||
|
|
||||||
cy.visit('/license-activation');
|
cy.visit('/license-activation');
|
||||||
cy.redeemCoupon('12345asfd');
|
redeemCoupon('12345asfd');
|
||||||
cy.assertStartPage();
|
cy.assertStartPage();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -31,7 +38,7 @@ describe('Email Verifcation', () => {
|
||||||
cy.apolloLogin('rahel.cueni', 'test');
|
cy.apolloLogin('rahel.cueni', 'test');
|
||||||
|
|
||||||
cy.visit('/license-activation');
|
cy.visit('/license-activation');
|
||||||
cy.redeemCoupon('');
|
redeemCoupon('');
|
||||||
cy.get('[data-cy="coupon-local-errors"]').contains('Coupon ist ein Pflichtfeld.');
|
cy.get('[data-cy="coupon-local-errors"]').contains('Coupon ist ein Pflichtfeld.');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -46,7 +53,7 @@ describe('Email Verifcation', () => {
|
||||||
cy.apolloLogin('rahel.cueni', 'test');
|
cy.apolloLogin('rahel.cueni', 'test');
|
||||||
|
|
||||||
cy.visit('/license-activation');
|
cy.visit('/license-activation');
|
||||||
cy.redeemCoupon('12345asfd');
|
redeemCoupon('12345asfd');
|
||||||
cy.get('[data-cy="coupon-remote-errors"]').contains('Der angegebene Coupon-Code ist ungültig.');
|
cy.get('[data-cy="coupon-remote-errors"]').contains('Der angegebene Coupon-Code ist ungültig.');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -61,7 +68,7 @@ describe('Email Verifcation', () => {
|
||||||
cy.apolloLogin('rahel.cueni', 'test');
|
cy.apolloLogin('rahel.cueni', 'test');
|
||||||
|
|
||||||
cy.visit('/license-activation');
|
cy.visit('/license-activation');
|
||||||
cy.redeemCoupon('12345asfd');
|
redeemCoupon('12345asfd');
|
||||||
cy.get('[data-cy="coupon-remote-errors"]').contains('Es ist ein Fehler aufgetreten. Bitte versuchen Sie es nochmals oder kontaktieren Sie den Administrator.');
|
cy.get('[data-cy="coupon-remote-errors"]').contains('Es ist ein Fehler aufgetreten. Bitte versuchen Sie es nochmals oder kontaktieren Sie den Administrator.');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ describe('Assignment feedback read-only - Teacher', () => {
|
||||||
// cy.get('@textarea').should('have.attr', 'readonly');
|
// cy.get('@textarea').should('have.attr', 'readonly');
|
||||||
|
|
||||||
cy.isSubmissionReadOnly(myText);
|
cy.isSubmissionReadOnly(myText);
|
||||||
cy.canReopen(false);
|
cy.getByDataCy('final-submission-reopen').should('not.exist');
|
||||||
});
|
});
|
||||||
it('can edit', () => {
|
it('can edit', () => {
|
||||||
cy.mockGraphqlOps({
|
cy.mockGraphqlOps({
|
||||||
|
|
@ -63,6 +63,7 @@ describe('Assignment feedback read-only - Teacher', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.visit('submission/submission-id');
|
cy.visit('submission/submission-id');
|
||||||
cy.canReopen(false);
|
|
||||||
|
cy.getByDataCy('final-submission-reopen').should('exist');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ describe('Assignments read-only - Student', () => {
|
||||||
cy.visit('module/module-with-assignment');
|
cy.visit('module/module-with-assignment');
|
||||||
|
|
||||||
cy.isSubmissionReadOnly(myText);
|
cy.isSubmissionReadOnly(myText);
|
||||||
cy.canReopen(false);
|
cy.getByDataCy('final-submission-reopen').should('not.exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can revoke turn in', () => {
|
it('can revoke turn in', () => {
|
||||||
|
|
@ -110,6 +110,6 @@ describe('Assignments read-only - Student', () => {
|
||||||
|
|
||||||
cy.visit('module/module-with-assignment');
|
cy.visit('module/module-with-assignment');
|
||||||
cy.getByDataCy('final-submission').should('exist');
|
cy.getByDataCy('final-submission').should('exist');
|
||||||
cy.canReopen(false);
|
cy.getByDataCy('final-submission-reopen').should('not.exist');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
import mocks from '../../../fixtures/mocks';
|
||||||
|
|
||||||
|
const SELECTED_CLASS_ID = 'selectedClassId';
|
||||||
|
|
||||||
|
const getOperations = ({readOnly, classReadOnly}) => ({
|
||||||
|
MeQuery: {
|
||||||
|
me: {
|
||||||
|
onboardingVisited: true,
|
||||||
|
readOnly,
|
||||||
|
isTeacher: true,
|
||||||
|
selectedClass: {
|
||||||
|
id: SELECTED_CLASS_ID,
|
||||||
|
readOnly: classReadOnly,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RoomEntriesQuery: {
|
||||||
|
room: {
|
||||||
|
id: 'roomId',
|
||||||
|
slug: '',
|
||||||
|
title: 'room title',
|
||||||
|
entryCount: 3,
|
||||||
|
appearance: 'blue',
|
||||||
|
description: 'room description',
|
||||||
|
schoolClass: {
|
||||||
|
id: SELECTED_CLASS_ID,
|
||||||
|
name: 'selected class',
|
||||||
|
},
|
||||||
|
roomEntries: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: 'entryId',
|
||||||
|
slug: '',
|
||||||
|
title: 'entry title',
|
||||||
|
contents: [],
|
||||||
|
author: {
|
||||||
|
id: 'authorId',
|
||||||
|
firstName: 'first',
|
||||||
|
lastName: 'last',
|
||||||
|
avatarUrl: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const checkRoomReadOnly = ({editable, readOnly, classReadOnly = false}) => {
|
||||||
|
const operations = getOperations({readOnly, classReadOnly});
|
||||||
|
|
||||||
|
cy.mockGraphqlOps({
|
||||||
|
operations,
|
||||||
|
});
|
||||||
|
|
||||||
|
const exist = editable ? 'exist' : 'not.exist';
|
||||||
|
cy.visit('room/some-room');
|
||||||
|
cy.get('.room-entry').should('exist');
|
||||||
|
cy.getByDataCy('add-room-entry-button').should(exist);
|
||||||
|
cy.getByDataCy('room-actions').should(exist);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Room Team Management - Read only', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.setup();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can edit room', () => {
|
||||||
|
checkRoomReadOnly({editable: true, readOnly: false});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can not edit room', () => {
|
||||||
|
checkRoomReadOnly({editable: false, readOnly: true});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can not edit room of inactive class', () => {
|
||||||
|
checkRoomReadOnly({editable: false, readOnly: false, classReadOnly: true});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
import mocks from '../../../fixtures/mocks';
|
||||||
|
|
||||||
|
const SELECTED_CLASS_ID = 'selectedClassId';
|
||||||
|
|
||||||
|
const getOperations = ({readOnly, classReadOnly}) => ({
|
||||||
|
MeQuery: {
|
||||||
|
me: {
|
||||||
|
onboardingVisited: true,
|
||||||
|
readOnly,
|
||||||
|
isTeacher: true,
|
||||||
|
selectedClass: {
|
||||||
|
id: SELECTED_CLASS_ID,
|
||||||
|
readOnly: classReadOnly,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RoomsQuery: {
|
||||||
|
rooms: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: '',
|
||||||
|
slug: '',
|
||||||
|
title: 'some room',
|
||||||
|
entryCount: 3,
|
||||||
|
appearance: 'red',
|
||||||
|
description: 'some description',
|
||||||
|
schoolClass: {
|
||||||
|
id: SELECTED_CLASS_ID,
|
||||||
|
name: 'bla'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const checkRoomsReadOnly = ({editable, readOnly, classReadOnly = false}) => {
|
||||||
|
const operations = getOperations({readOnly, classReadOnly});
|
||||||
|
|
||||||
|
cy.mockGraphqlOps({
|
||||||
|
operations,
|
||||||
|
});
|
||||||
|
|
||||||
|
const exist = editable ? 'exist' : 'not.exist';
|
||||||
|
cy.visit('rooms');
|
||||||
|
cy.log('visit');
|
||||||
|
cy.get('.room-widget').should('exist');
|
||||||
|
cy.getByDataCy('add-room').should(exist);
|
||||||
|
cy.getByDataCy('widget-footer').should(exist);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Room Team Management - Read only', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.setup();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can edit room', () => {
|
||||||
|
checkRoomsReadOnly({editable: true, readOnly: false});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can not edit room', () => {
|
||||||
|
checkRoomsReadOnly({editable: false, readOnly: true});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can not edit room of inactive class', () => {
|
||||||
|
checkRoomsReadOnly({editable: false, readOnly: false, classReadOnly: true});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -32,7 +32,7 @@ const getOperations = ({readOnly}) => ({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('checkSchoolClassTeamReadOnly', (readOnly) => {
|
const checkSchoolClassTeamReadOnly = (readOnly) => {
|
||||||
cy.mockGraphqlOps({
|
cy.mockGraphqlOps({
|
||||||
operations: getOperations({readOnly}),
|
operations: getOperations({readOnly}),
|
||||||
});
|
});
|
||||||
|
|
@ -47,7 +47,7 @@ Cypress.Commands.add('checkSchoolClassTeamReadOnly', (readOnly) => {
|
||||||
cy.getByDataCy('current-class-name').should('exist');
|
cy.getByDataCy('current-class-name').should('exist');
|
||||||
cy.getByDataCy('create-class-link').should(exist);
|
cy.getByDataCy('create-class-link').should(exist);
|
||||||
cy.getByDataCy('my-team-link').should(exist);
|
cy.getByDataCy('my-team-link').should(exist);
|
||||||
});
|
};
|
||||||
|
|
||||||
describe('School Class and Team Management - Read only', () => {
|
describe('School Class and Team Management - Read only', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|
@ -62,21 +62,10 @@ describe('School Class and Team Management - Read only', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can see menu items', () => {
|
it('can see menu items', () => {
|
||||||
cy.checkSchoolClassTeamReadOnly(false);
|
checkSchoolClassTeamReadOnly(false);
|
||||||
// cy.visit('me/class');
|
|
||||||
// cy.getByDataCy('group-list-name').should('exist').should('contain', selectedClassName);
|
|
||||||
// cy.getByDataCy('show-code-button').should('exist');
|
|
||||||
// cy.getByDataCy('edit-group-name-link').should('exist');
|
|
||||||
// cy.openSidebar();
|
|
||||||
// cy.getByDataCy('class-selection').click();
|
|
||||||
// cy.getByDataCy('current-class-name').should('exist');
|
|
||||||
// cy.getByDataCy('create-class-link').should('exist');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can not see menu items', () => {
|
it('can not see menu items', () => {
|
||||||
// cy.mockGraphqlOps({
|
checkSchoolClassTeamReadOnly(true);
|
||||||
// operations: getOperations({readOnly: true}),
|
|
||||||
// });
|
|
||||||
cy.checkSchoolClassTeamReadOnly(true);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
// todo: once above issue is fixed, go back to the original repo -> npm install cypress-graphql-mock
|
// todo: once above issue is fixed, go back to the original repo -> npm install cypress-graphql-mock
|
||||||
// import 'cypress-graphql-mock';
|
// import 'cypress-graphql-mock';
|
||||||
import '@iam4x/cypress-graphql-mock';
|
import '@iam4x/cypress-graphql-mock';
|
||||||
|
import mocks from '../fixtures/mocks';
|
||||||
|
|
||||||
Cypress.Commands.add('apolloLogin', (username, password) => {
|
Cypress.Commands.add('apolloLogin', (username, password) => {
|
||||||
const payload = {
|
const payload = {
|
||||||
|
|
@ -118,51 +119,6 @@ Cypress.Commands.add('enterPassword', (password) => {
|
||||||
cy.get('[data-cy="login-button"]').click();
|
cy.get('[data-cy="login-button"]').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('register', (prefix, firstname, lastname, street, city, postcode, password, passwordConfirmation, acceptTerms) => {
|
|
||||||
let selection = prefix === 1 ? 'Herr' : 'Frau';
|
|
||||||
|
|
||||||
cy.get('[data-cy="prefix-selection"]').select(selection);
|
|
||||||
|
|
||||||
if (firstname !== '') {
|
|
||||||
cy.get('[data-cy="firstname-input"]').type(firstname);
|
|
||||||
}
|
|
||||||
if (lastname !== '') {
|
|
||||||
cy.get('[data-cy="lastname-input"]').type(lastname);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (street !== '') {
|
|
||||||
cy.get('[data-cy="street-input"]').type(street);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (city !== '') {
|
|
||||||
cy.get('[data-cy="city-input"]').type(city);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (postcode !== '') {
|
|
||||||
cy.get('[data-cy="postcode-input"]').type(postcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (password !== '') {
|
|
||||||
cy.get('[data-cy="password-input"]').type(password);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (acceptTerms) {
|
|
||||||
cy.get('[data-cy="acceptedTerms-input"] > input').first().check({force: true}).then(() => {
|
|
||||||
cy.get('[data-cy="acceptedTerms-input"] > input:checkbox').should('be.checked');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
cy.get('[data-cy="passwordConfirmation-input"]').type(passwordConfirmation);
|
|
||||||
cy.get('[data-cy="register-button"]').click();
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('redeemCoupon', coupon => {
|
|
||||||
if (coupon !== '') {
|
|
||||||
cy.get('[data-cy="coupon-input"]').type(coupon);
|
|
||||||
}
|
|
||||||
cy.get('[data-cy="coupon-button"]').click();
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('assertStartPage', (onboarding) => {
|
Cypress.Commands.add('assertStartPage', (onboarding) => {
|
||||||
if (onboarding) {
|
if (onboarding) {
|
||||||
cy.get('[data-cy=onboarding-page]').should('exist');
|
cy.get('[data-cy=onboarding-page]').should('exist');
|
||||||
|
|
@ -190,11 +146,6 @@ Cypress.Commands.add('fakeLogin', () => {
|
||||||
cy.setCookie('loginStatus', 'true');
|
cy.setCookie('loginStatus', 'true');
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('canReopen', (exists) => {
|
|
||||||
let check = exists ? 'exist' : 'not.exist';
|
|
||||||
cy.getByDataCy('final-submission-reopen').should(check);
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('isSubmissionReadOnly', (myText) => {
|
Cypress.Commands.add('isSubmissionReadOnly', (myText) => {
|
||||||
cy.get('.submission-form__textarea--readonly').as('textarea');
|
cy.get('.submission-form__textarea--readonly').as('textarea');
|
||||||
|
|
||||||
|
|
@ -206,3 +157,15 @@ Cypress.Commands.add('isSubmissionReadOnly', (myText) => {
|
||||||
Cypress.Commands.add('openSidebar', () => {
|
Cypress.Commands.add('openSidebar', () => {
|
||||||
cy.getByDataCy('user-widget-avatar').click();
|
cy.getByDataCy('user-widget-avatar').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Cypress.Commands.add('setup', () => {
|
||||||
|
cy.fakeLogin('nino.teacher', 'test');
|
||||||
|
cy.server();
|
||||||
|
cy.viewport('macbook-15');
|
||||||
|
cy.task('getSchema').then(schema => {
|
||||||
|
cy.mockGraphql({
|
||||||
|
schema,
|
||||||
|
mocks,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
// todo: clean up this file
|
||||||
|
|
||||||
const getSchoolClassNode = (id, schoolClassName) => ({
|
const getSchoolClassNode = (id, schoolClassName) => ({
|
||||||
'id': btoa(`SchoolClassNode:${id}`),
|
'id': btoa(`SchoolClassNode:${id}`),
|
||||||
'name': schoolClassName,
|
'name': schoolClassName,
|
||||||
|
|
@ -52,43 +54,6 @@ export const getMe = ({schoolClasses, teacher}) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAssignments = () => {
|
|
||||||
return {
|
|
||||||
'assignments': {
|
|
||||||
'edges': [
|
|
||||||
{
|
|
||||||
'node': {
|
|
||||||
'id': 'QXNzaWdubWVudE5vZGU6MQ==',
|
|
||||||
'title': 'Ein Auftragstitel',
|
|
||||||
'assignment': 'Ein Auftrag',
|
|
||||||
'solution': null,
|
|
||||||
'submission': {
|
|
||||||
'id': 'U3R1ZGVudFN1Ym1pc3Npb25Ob2RlOjE=',
|
|
||||||
'text': 'Hir ist ein Feler gewesen',
|
|
||||||
'final': false,
|
|
||||||
'document': '',
|
|
||||||
'submissionFeedback': {
|
|
||||||
'id': 'U3VibWlzc2lvbkZlZWRiYWNrTm9kZTox',
|
|
||||||
'text': '\ud83d\ude42\ud83d\ude10\ud83e\udd2c\ud83d\udc4d\ud83e\udd22\ud83e\udd22\ud83e\udd22\ud83e\udd22\ud83d\ude2e\ud83e\udd17',
|
|
||||||
'teacher': {
|
|
||||||
'firstName': 'Nico',
|
|
||||||
'lastName': 'Zickgraf',
|
|
||||||
'__typename': 'UserNode',
|
|
||||||
},
|
|
||||||
'__typename': 'SubmissionFeedbackNode',
|
|
||||||
},
|
|
||||||
'__typename': 'StudentSubmissionNode',
|
|
||||||
},
|
|
||||||
'__typename': 'AssignmentNode',
|
|
||||||
},
|
|
||||||
'__typename': 'AssignmentNodeEdge',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'__typename': 'AssignmentNodeConnection',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getModules = () => {
|
export const getModules = () => {
|
||||||
return {
|
return {
|
||||||
'lohn-und-budget': {
|
'lohn-und-budget': {
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ declare namespace Cypress {
|
||||||
|
|
||||||
fakeLogin(username: string, password: string): void
|
fakeLogin(username: string, password: string): void
|
||||||
|
|
||||||
canReopen(exists: boolean): void
|
|
||||||
|
|
||||||
isSubmissionReadOnly(myText: string): void
|
isSubmissionReadOnly(myText: string): void
|
||||||
|
|
||||||
openSidebar(): void
|
openSidebar(): void
|
||||||
|
|
||||||
|
setup(): void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -118,7 +118,7 @@
|
||||||
"babel-core": "^7.0.0-bridge.0",
|
"babel-core": "^7.0.0-bridge.0",
|
||||||
"babel-jest": "^24.8.0",
|
"babel-jest": "^24.8.0",
|
||||||
"canvas": "^2.5.0",
|
"canvas": "^2.5.0",
|
||||||
"cypress": "^6.2.1",
|
"cypress": "^8.0.0",
|
||||||
"graphql-config": "^3.2.0",
|
"graphql-config": "^3.2.0",
|
||||||
"jest": "^24.8.0",
|
"jest": "^24.8.0",
|
||||||
"jest-serializer-vue": "^2.0.2",
|
"jest-serializer-vue": "^2.0.2",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="room-actions">
|
<div
|
||||||
|
class="room-actions"
|
||||||
|
data-cy="room-actions">
|
||||||
<a
|
<a
|
||||||
class="room-actions__more-link"
|
class="room-actions__more-link"
|
||||||
@click="toggleMenu">
|
@click="toggleMenu">
|
||||||
|
|
@ -68,8 +70,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import "~styles/helpers";
|
||||||
@import "@/styles/_mixins.scss";
|
|
||||||
|
|
||||||
.room-actions {
|
.room-actions {
|
||||||
&__more-link {
|
&__more-link {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@
|
||||||
<room-group-widget v-bind="schoolClass"/>
|
<room-group-widget v-bind="schoolClass"/>
|
||||||
<entry-count-widget :entry-count="entryCount"/>
|
<entry-count-widget :entry-count="entryCount"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
<widget-footer v-if="canEditRoom">
|
<widget-footer
|
||||||
|
data-cy="widget-footer"
|
||||||
|
v-if="canEditRoom">
|
||||||
<room-actions :id="id"/>
|
<room-actions :id="id"/>
|
||||||
</widget-footer>
|
</widget-footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -49,7 +51,7 @@
|
||||||
return `room-widget--${this.appearance}`;
|
return `room-widget--${this.appearance}`;
|
||||||
},
|
},
|
||||||
canEditRoom() {
|
canEditRoom() {
|
||||||
return this.me.permissions.includes('users.can_manage_school_class_content');
|
return this.me.isTeacher && !this.me.readOnly && !this.me.selectedClass.readOnly;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ fragment UserParts on PrivateUserNode {
|
||||||
}
|
}
|
||||||
selectedClass {
|
selectedClass {
|
||||||
id
|
id
|
||||||
|
readOnly
|
||||||
}
|
}
|
||||||
recentModules(orderBy: "-visited") {
|
recentModules(orderBy: "-visited") {
|
||||||
edges {
|
edges {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@
|
||||||
{{ room.description }}
|
{{ room.description }}
|
||||||
</p>
|
</p>
|
||||||
<div class="room__meta">
|
<div class="room__meta">
|
||||||
<room-actions :id="room.id"/>
|
<room-actions
|
||||||
|
:id="room.id"
|
||||||
|
v-if="canEdit"/>
|
||||||
<room-group-widget v-bind="room.schoolClass"/>
|
<room-group-widget v-bind="room.schoolClass"/>
|
||||||
<entry-count-widget :entry-count="roomEntryCount"/>
|
<entry-count-widget :entry-count="roomEntryCount"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -14,7 +16,7 @@
|
||||||
<div class="room__content">
|
<div class="room__content">
|
||||||
<add-room-entry-button
|
<add-room-entry-button
|
||||||
:parent="room"
|
:parent="room"
|
||||||
v-if="room.id">
|
v-if="room.id && canEdit">
|
||||||
<!--
|
<!--
|
||||||
the v-if is there for the case where the room hasn't loaded yet, but there is already an attempt to create
|
the v-if is there for the case where the room hasn't loaded yet, but there is already an attempt to create
|
||||||
a new room entry. mainly happens during cypress testing, but could also happen on a very slow connection
|
a new room entry. mainly happens during cypress testing, but could also happen on a very slow connection
|
||||||
|
|
@ -30,11 +32,18 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ROOM_ENTRIES_QUERY from '@/graphql/gql/queries/roomEntriesQuery.gql';
|
import ROOM_ENTRIES_QUERY from '@/graphql/gql/queries/roomEntriesQuery.gql';
|
||||||
import roomMixin from '@/mixins/room';
|
import room from '@/mixins/room';
|
||||||
|
import me from '@/mixins/me';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['slug'],
|
props: ['slug'],
|
||||||
mixins: [roomMixin],
|
mixins: [room, me],
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
canEdit() {
|
||||||
|
return !this.me.readOnly && !this.me.selectedClass.readOnly;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
apollo: {
|
apollo: {
|
||||||
modules: {
|
modules: {
|
||||||
|
|
@ -59,5 +68,5 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_room.scss";
|
@import "~styles/room";
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@
|
||||||
return this.me.selectedClass.id;
|
return this.me.selectedClass.id;
|
||||||
},
|
},
|
||||||
canAddRoom() {
|
canAddRoom() {
|
||||||
return this.me.permissions.includes('users.can_manage_school_class_content');
|
return this.me.isTeacher && !this.me.readOnly && !this.me.selectedClass.readOnly;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_mixins.scss";
|
@import "~styles/helpers";
|
||||||
|
|
||||||
.rooms-page {
|
.rooms-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class UpdateSolutionVisibility(relay.ClientIDMutation):
|
||||||
slug = args.get('slug')
|
slug = args.get('slug')
|
||||||
enabled = args.get('enabled')
|
enabled = args.get('enabled')
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
selected_class = user.selected_class()
|
selected_class = user.selected_class
|
||||||
if 'users.can_manage_school_class_content' not in user.get_role_permissions():
|
if 'users.can_manage_school_class_content' not in user.get_role_permissions():
|
||||||
raise PermissionError()
|
raise PermissionError()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ class ModuleNode(DjangoObjectType):
|
||||||
return self.get_parent().specific
|
return self.get_parent().specific
|
||||||
|
|
||||||
def resolve_solutions_enabled(self, info, **kwargs):
|
def resolve_solutions_enabled(self, info, **kwargs):
|
||||||
school_class = info.context.user.selected_class()
|
school_class = info.context.user.selected_class
|
||||||
return self.solutions_enabled_for.filter(pk=school_class.pk).exists() if school_class is not None else False
|
return self.solutions_enabled_for.filter(pk=school_class.pk).exists() if school_class is not None else False
|
||||||
|
|
||||||
def resolve_bookmark(self, info, **kwags):
|
def resolve_bookmark(self, info, **kwags):
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ class ModuleSolutionVisibilityTest(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.teacher = User.objects.get(username="teacher")
|
self.teacher = User.objects.get(username="teacher")
|
||||||
self.selected_class = self.teacher.selected_class()
|
self.selected_class = self.teacher.selected_class
|
||||||
self.student = User.objects.get(username="student1")
|
self.student = User.objects.get(username="student1")
|
||||||
student_request = RequestFactory().get('/')
|
student_request = RequestFactory().get('/')
|
||||||
student_request.user = self.student
|
student_request.user = self.student
|
||||||
|
|
@ -54,7 +54,7 @@ class ModuleSolutionVisibilityTest(TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_hide_solutions_for_students_and_then_show_them(self):
|
def test_hide_solutions_for_students_and_then_show_them(self):
|
||||||
self.assertEqual(self.student.selected_class(), self.teacher.selected_class())
|
self.assertEqual(self.student.selected_class, self.teacher.selected_class)
|
||||||
|
|
||||||
student_result = self.student_client.execute(self.query, variables={
|
student_result = self.student_client.execute(self.query, variables={
|
||||||
'id': self.content_block_id
|
'id': self.content_block_id
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from users.models import User
|
||||||
|
|
||||||
|
|
||||||
def are_solutions_enabled_for(user: User, module: Module):
|
def are_solutions_enabled_for(user: User, module: Module):
|
||||||
school_class = user.selected_class()
|
school_class = user.selected_class
|
||||||
return module.solutions_enabled_for.filter(pk=school_class.pk).exists()
|
return module.solutions_enabled_for.filter(pk=school_class.pk).exists()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -370,7 +370,6 @@ type CreateTeamPayload {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CustomMutation {
|
type CustomMutation {
|
||||||
redeemCoupon(input: CouponInput!): CouponPayload
|
|
||||||
spellCheck(input: SpellCheckInput!): SpellCheckPayload
|
spellCheck(input: SpellCheckInput!): SpellCheckPayload
|
||||||
addNote(input: AddNoteInput!): AddNotePayload
|
addNote(input: AddNoteInput!): AddNotePayload
|
||||||
updateNote(input: UpdateNoteInput!): UpdateNotePayload
|
updateNote(input: UpdateNoteInput!): UpdateNotePayload
|
||||||
|
|
@ -920,6 +919,7 @@ type SchoolClassNode implements Node {
|
||||||
rooms(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, appearance: String): RoomNodeConnection!
|
rooms(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, appearance: String): RoomNodeConnection!
|
||||||
pk: Int
|
pk: Int
|
||||||
members: [ClassMemberNode]
|
members: [ClassMemberNode]
|
||||||
|
readOnly: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type SchoolClassNodeConnection {
|
type SchoolClassNodeConnection {
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@ from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.models import AbstractUser, Permission
|
from django.contrib.auth.models import AbstractUser, Permission
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.functional import cached_property
|
||||||
from django.utils.timezone import make_aware, is_aware
|
from django.utils.timezone import make_aware, is_aware
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from users.licenses import MYSKILLBOX_LICENSES
|
from users.licenses import MYSKILLBOX_LICENSES
|
||||||
from users.managers import RoleManager, UserRoleManager, UserManager, LicenseManager
|
from users.managers import RoleManager, UserRoleManager, UserManager, LicenseManager
|
||||||
|
|
@ -75,7 +77,8 @@ class User(AbstractUser):
|
||||||
def is_teacher(self):
|
def is_teacher(self):
|
||||||
return self.user_roles.filter(role__key='teacher').exists()
|
return self.user_roles.filter(role__key='teacher').exists()
|
||||||
|
|
||||||
def selected_class(self):
|
@cached_property
|
||||||
|
def selected_class(self) -> Union['SchoolClass', None]:
|
||||||
try:
|
try:
|
||||||
settings = UserSetting.objects.get(user=self)
|
settings = UserSetting.objects.get(user=self)
|
||||||
return settings.selected_class
|
return settings.selected_class
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import graphene
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.utils.dateformat import format
|
from django.utils.dateformat import format
|
||||||
from django_filters import FilterSet, OrderingFilter
|
from django_filters import FilterSet, OrderingFilter
|
||||||
from graphene import relay, ObjectType
|
from graphene import ObjectType, relay
|
||||||
from graphene_django import DjangoObjectType
|
from graphene_django import DjangoObjectType
|
||||||
from graphene_django.filter import DjangoFilterConnectionField
|
from graphene_django.filter import DjangoFilterConnectionField
|
||||||
from graphql_relay import to_global_id
|
from graphql_relay import to_global_id
|
||||||
|
|
@ -13,13 +13,14 @@ from basicknowledge.models import BasicKnowledge
|
||||||
from basicknowledge.queries import InstrumentNode
|
from basicknowledge.queries import InstrumentNode
|
||||||
from books.models import Module
|
from books.models import Module
|
||||||
from books.schema.queries import ModuleNode
|
from books.schema.queries import ModuleNode
|
||||||
from users.models import User, SchoolClass, SchoolClassMember, Team
|
from users.models import SchoolClass, SchoolClassMember, Team, User
|
||||||
|
|
||||||
|
|
||||||
class SchoolClassNode(DjangoObjectType):
|
class SchoolClassNode(DjangoObjectType):
|
||||||
pk = graphene.Int()
|
pk = graphene.Int()
|
||||||
members = graphene.List('users.schema.ClassMemberNode')
|
members = graphene.List('users.schema.ClassMemberNode')
|
||||||
code = graphene.String()
|
code = graphene.String()
|
||||||
|
read_only = graphene.Boolean()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SchoolClass
|
model = SchoolClass
|
||||||
|
|
@ -32,13 +33,19 @@ class SchoolClassNode(DjangoObjectType):
|
||||||
def resolve_members(self, info, **kwargs):
|
def resolve_members(self, info, **kwargs):
|
||||||
return SchoolClassMember.objects.filter(school_class=self)
|
return SchoolClassMember.objects.filter(school_class=self)
|
||||||
|
|
||||||
def resolve_code(self, info, **kwargs):
|
def resolve_code(self: SchoolClass, info, **kwargs):
|
||||||
if not info.context.user.is_teacher():
|
if not info.context.user.is_teacher():
|
||||||
return None
|
return None
|
||||||
if self.code is None:
|
if self.code is None:
|
||||||
self.generate_code()
|
self.generate_code()
|
||||||
return self.code
|
return self.code
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def resolve_read_only(root: SchoolClass, info, **kwargs):
|
||||||
|
user = info.context.user
|
||||||
|
member = SchoolClassMember.objects.get(user=user, school_class=root)
|
||||||
|
return not member.active
|
||||||
|
|
||||||
|
|
||||||
class TeamNode(DjangoObjectType):
|
class TeamNode(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -107,25 +114,28 @@ class PrivateUserNode(DjangoObjectType):
|
||||||
def resolve_permissions(self, info):
|
def resolve_permissions(self, info):
|
||||||
return self.get_all_permissions()
|
return self.get_all_permissions()
|
||||||
|
|
||||||
def resolve_selected_class(self, info):
|
@staticmethod
|
||||||
return self.selected_class()
|
def resolve_selected_class(root: User, info):
|
||||||
|
return root.selected_class
|
||||||
|
|
||||||
def resolve_expiry_date(self, info):
|
@staticmethod
|
||||||
if not self.hep_id: # concerns users that already have an (old) account
|
def resolve_expiry_date(root: User, info):
|
||||||
|
if not root.hep_id: # concerns users that already have an (old) account
|
||||||
return format(datetime(2020, 7, 31), 'U') # just set some expiry date
|
return format(datetime(2020, 7, 31), 'U') # just set some expiry date
|
||||||
else:
|
else:
|
||||||
return self.license_expiry_date
|
return root.license_expiry_date
|
||||||
|
|
||||||
def resolve_is_teacher(self, info):
|
def resolve_is_teacher(root: User, info):
|
||||||
return self.is_teacher()
|
return root.is_teacher()
|
||||||
|
|
||||||
def resolve_school_classes(self, info):
|
@staticmethod
|
||||||
if self.selected_class() is None: # then we don't have any class to return
|
def resolve_school_classes(root: User, info):
|
||||||
|
if root.selected_class is None: # then we don't have any class to return
|
||||||
return SchoolClass.objects.none()
|
return SchoolClass.objects.none()
|
||||||
return SchoolClass.objects.filter(
|
return SchoolClass.objects.filter(
|
||||||
Q(schoolclassmember__active=True, schoolclassmember__user=self) | Q(pk=self.selected_class().pk)).distinct()
|
Q(schoolclassmember__active=True, schoolclassmember__user=root) | Q(pk=root.selected_class.pk)).distinct()
|
||||||
|
|
||||||
def resolve_old_classes(self, info):
|
def resolve_old_classes(self: User, info):
|
||||||
return SchoolClass.objects.filter(schoolclassmember__active=False, schoolclassmember__user=self)
|
return SchoolClass.objects.filter(schoolclassmember__active=False, schoolclassmember__user=self)
|
||||||
|
|
||||||
def resolve_recent_modules(self, info, **kwargs):
|
def resolve_recent_modules(self, info, **kwargs):
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ class JoinSchoolClassTest(TestCase):
|
||||||
self.assertEqual(result['success'], True)
|
self.assertEqual(result['success'], True)
|
||||||
self.assertEqual(result['schoolClass']['name'], 'Klasse 2B')
|
self.assertEqual(result['schoolClass']['name'], 'Klasse 2B')
|
||||||
self.assertEqual(self.user.school_classes.count(), 2)
|
self.assertEqual(self.user.school_classes.count(), 2)
|
||||||
self.assertEqual(self.user.selected_class().code, 'YYYY')
|
self.assertEqual(self.user.selected_class.code, 'YYYY')
|
||||||
|
|
||||||
def test_class_already_joined(self):
|
def test_class_already_joined(self):
|
||||||
code = 'YYYY'
|
code = 'YYYY'
|
||||||
|
|
|
||||||
|
|
@ -82,3 +82,5 @@ class MySchoolClasses(TestCase):
|
||||||
self.assertEqual(len(old_classes), 1)
|
self.assertEqual(len(old_classes), 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ from graphql_relay import to_global_id
|
||||||
from api.schema import schema
|
from api.schema import schema
|
||||||
from api.utils import get_graphql_mutation, get_object
|
from api.utils import get_graphql_mutation, get_object
|
||||||
from core.factories import UserFactory, TeacherFactory
|
from core.factories import UserFactory, TeacherFactory
|
||||||
|
from core.tests.base_test import SkillboxTestCase
|
||||||
from users.models import SchoolClass, User
|
from users.models import SchoolClass, User
|
||||||
from users.services import create_users
|
from users.services import create_users
|
||||||
|
|
||||||
|
|
@ -38,18 +39,14 @@ class SchoolClassesTest(TestCase):
|
||||||
self.assertEqual(f'{self.prefix} {user.pk}', class_name)
|
self.assertEqual(f'{self.prefix} {user.pk}', class_name)
|
||||||
|
|
||||||
|
|
||||||
class ModifySchoolClassTest(TestCase):
|
class ModifySchoolClassTest(SkillboxTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
create_users()
|
create_users()
|
||||||
self.teacher = User.objects.get(username='teacher')
|
self.teacher = User.objects.get(username='teacher')
|
||||||
self.student = User.objects.get(username='student1')
|
self.student = User.objects.get(username='student1')
|
||||||
|
|
||||||
request = RequestFactory().get('/')
|
self.client = self.get_client(user=self.teacher)
|
||||||
request.user = self.teacher
|
self.student_client = self.get_client(user=self.student)
|
||||||
student_request = RequestFactory().get('/')
|
|
||||||
student_request.user = self.student
|
|
||||||
self.client = Client(schema=schema, context_value=request)
|
|
||||||
self.student_client = Client(schema=schema, context_value=student_request)
|
|
||||||
|
|
||||||
def test_update_school_class(self):
|
def test_update_school_class(self):
|
||||||
class_name = 'The Colbert Show'
|
class_name = 'The Colbert Show'
|
||||||
|
|
@ -115,7 +112,7 @@ class ModifySchoolClassTest(TestCase):
|
||||||
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)
|
||||||
self.assertEqual(school_class.get_teacher(), self.teacher)
|
self.assertEqual(school_class.get_teacher(), self.teacher)
|
||||||
self.assertEqual(self.teacher.selected_class().name, class_name)
|
self.assertEqual(self.teacher.selected_class.name, class_name)
|
||||||
|
|
||||||
def test_create_school_class_fail(self):
|
def test_create_school_class_fail(self):
|
||||||
self.assertEqual(SchoolClass.objects.count(), 2)
|
self.assertEqual(SchoolClass.objects.count(), 2)
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,18 @@
|
||||||
from django.contrib.sessions.middleware import SessionMiddleware
|
|
||||||
from django.test import TestCase, RequestFactory
|
|
||||||
from graphene.test import Client
|
|
||||||
from graphql_relay import to_global_id
|
from graphql_relay import to_global_id
|
||||||
|
|
||||||
from api.schema import schema
|
|
||||||
from core.factories import UserFactory
|
from core.factories import UserFactory
|
||||||
|
from core.tests.base_test import SkillboxTestCase
|
||||||
from users.factories import SchoolClassFactory
|
from users.factories import SchoolClassFactory
|
||||||
from users.models import UserSetting
|
from users.models import SchoolClassMember, UserSetting
|
||||||
|
|
||||||
|
|
||||||
class UserSettingTests(TestCase):
|
class UserSettingTests(SkillboxTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.user = UserFactory(username='aschi')
|
self.user = UserFactory(username='aschi')
|
||||||
self.class1 = SchoolClassFactory(users=[self.user])
|
self.class1 = SchoolClassFactory(users=[self.user])
|
||||||
self.class2 = SchoolClassFactory(users=[self.user])
|
self.class2 = SchoolClassFactory(users=[self.user])
|
||||||
self.class3 = SchoolClassFactory(users=[])
|
self.class3 = SchoolClassFactory(users=[])
|
||||||
|
|
||||||
request = RequestFactory().get('/')
|
|
||||||
request.user = self.user
|
|
||||||
|
|
||||||
# adding session
|
|
||||||
middleware = SessionMiddleware()
|
|
||||||
middleware.process_request(request)
|
|
||||||
request.session.save()
|
|
||||||
self.client = Client(schema=schema, context_value=request)
|
|
||||||
|
|
||||||
def make_mutation(self, class_id):
|
def make_mutation(self, class_id):
|
||||||
mutation = '''
|
mutation = '''
|
||||||
|
|
@ -37,7 +26,7 @@ class UserSettingTests(TestCase):
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
return self.client.execute(mutation, variables={
|
return self.get_client(user=self.user).execute(mutation, variables={
|
||||||
'input': {
|
'input': {
|
||||||
'id': to_global_id('SchoolClassNode', class_id)
|
'id': to_global_id('SchoolClassNode', class_id)
|
||||||
}
|
}
|
||||||
|
|
@ -50,18 +39,20 @@ class UserSettingTests(TestCase):
|
||||||
selectedClass {
|
selectedClass {
|
||||||
name
|
name
|
||||||
id
|
id
|
||||||
|
readOnly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
return self.client.execute(query)
|
return self.get_client(user=self.user).execute(query)
|
||||||
|
|
||||||
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.get('errors'))
|
||||||
self.assertEqual(result.get('data').get('me').get('selectedClass').get('name'), first_class.name)
|
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'))
|
||||||
|
|
||||||
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]
|
||||||
|
|
@ -73,7 +64,6 @@ class UserSettingTests(TestCase):
|
||||||
selected_class.name)
|
selected_class.name)
|
||||||
|
|
||||||
def test_user_can_select_class(self):
|
def test_user_can_select_class(self):
|
||||||
|
|
||||||
selected_class = self.user.school_classes.first()
|
selected_class = self.user.school_classes.first()
|
||||||
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()
|
||||||
|
|
@ -87,7 +77,6 @@ class UserSettingTests(TestCase):
|
||||||
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.get('errors'))
|
||||||
|
|
@ -106,4 +95,17 @@ class UserSettingTests(TestCase):
|
||||||
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.get('errors'))
|
||||||
|
|
||||||
|
def test_inactive_class_as_selected_class(self):
|
||||||
|
selected_class = self.class2
|
||||||
|
membership = SchoolClassMember.objects.get(user=self.user, school_class=selected_class)
|
||||||
|
self.assertTrue(membership.active)
|
||||||
|
membership.active = False
|
||||||
|
membership.save()
|
||||||
|
|
||||||
|
setting = UserSetting.objects.create(user=self.user, selected_class=selected_class)
|
||||||
|
setting.save()
|
||||||
|
|
||||||
|
result = self.make_query()
|
||||||
|
self.assertIsNone(result.get('errors'))
|
||||||
|
self.assertTrue(result.get('data').get('me').get('selectedClass').get('readOnly'))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue