commit
2eaea595e1
6
Pipfile
6
Pipfile
|
|
@ -27,7 +27,7 @@ graphene-django = "==2.15.0"
|
|||
django-filter = "~=21.1"
|
||||
djangorestframework = "~=3.8"
|
||||
pillow = "==9.1.0"
|
||||
wagtail = "~=2.15"
|
||||
wagtail = "~=4.2"
|
||||
django-cors-headers = "~=3.0"
|
||||
django-storages = "*"
|
||||
boto3 = "*"
|
||||
|
|
@ -35,7 +35,7 @@ django-compressor = "*"
|
|||
django-libsass = "*"
|
||||
bleach = "*"
|
||||
newrelic = "*"
|
||||
sentry-sdk = "==1.5.12"
|
||||
sentry-sdk = "==1.17.0"
|
||||
python-http-client = "==3.2.1"
|
||||
ipython = "*"
|
||||
requests = "*"
|
||||
|
|
@ -44,3 +44,5 @@ django-silk = "*"
|
|||
wagtail-autocomplete = "*"
|
||||
jedi = "==0.17.2"
|
||||
Authlib = "*"
|
||||
django-stubs = {extras = ["compatible-mypy"], version = "*"}
|
||||
black = "*"
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -6,11 +6,9 @@
|
|||
image:
|
||||
name: iterativ/skillbox-test@sha256:60d6bb808a9f0ff7b158192866a18eb7a5381a12621184c17bf5a4fb55384362
|
||||
|
||||
|
||||
clone:
|
||||
depth: full
|
||||
|
||||
|
||||
definitions:
|
||||
services:
|
||||
postgres:
|
||||
|
|
@ -22,171 +20,175 @@ definitions:
|
|||
cypress: $HOME/.cache/Cypress
|
||||
clientmodules: client/node_modules
|
||||
steps:
|
||||
- &lint
|
||||
name: lint
|
||||
caches:
|
||||
- clientmodules
|
||||
script:
|
||||
- npm install --prefix client
|
||||
- npm run lint --prefix client
|
||||
- &unittest-python
|
||||
name: run python unit tests
|
||||
caches:
|
||||
- pip
|
||||
services:
|
||||
- postgres
|
||||
script: # Modify the commands below to build your repository.
|
||||
- &setup-tests source setup-for-tests.sh
|
||||
- ./server/run_unittests_coverage.sh
|
||||
- &cypress-test
|
||||
name: run cypress end-to-end tests
|
||||
caches:
|
||||
- pip
|
||||
- node
|
||||
- clientmodules
|
||||
- npm
|
||||
- cypress
|
||||
artifacts:
|
||||
- client/cypress/**/*.png
|
||||
- client/cypress/**/*.mp4
|
||||
services:
|
||||
- postgres
|
||||
script:
|
||||
- echo "This pipeline rules!"
|
||||
- *setup-tests
|
||||
- npm ci --prefix client
|
||||
- npm run "install:cypress" --prefix client
|
||||
- psql -U $DATABASE_USER -h $DATABASE_HOST -c "create database $DATABASE_NAME"
|
||||
- python server/manage.py dummy_data
|
||||
- python server/manage.py runserver 2>&1 > /dev/null &
|
||||
- npm run build --prefix client
|
||||
- curl http://localhost:8000/beta-login
|
||||
- npm run --prefix client test:cypress:e2e
|
||||
- &frontend-test
|
||||
name: run cypress frontend tests
|
||||
caches:
|
||||
- node
|
||||
- clientmodules
|
||||
- npm
|
||||
- cypress
|
||||
artifacts:
|
||||
- client/cypress/**/*.png
|
||||
- client/cypress/**/*.mp4
|
||||
script:
|
||||
- npm ci --prefix client
|
||||
- npm run "install:cypress" --prefix client
|
||||
- npm run dev --prefix client 2>&1 > /dev/null &
|
||||
- sleep 30
|
||||
- curl http://localhost:8080/beta-login
|
||||
- npm run --prefix client test:cypress:frontend
|
||||
- &frontend-test-parallel
|
||||
name: run cypress frontend tests
|
||||
caches:
|
||||
- node
|
||||
- clientmodules
|
||||
- npm
|
||||
- cypress
|
||||
artifacts:
|
||||
- client/cypress/**/*.png
|
||||
- client/cypress/**/*.mp4
|
||||
script:
|
||||
- npm ci --prefix client
|
||||
- npm run "install:cypress" --prefix client
|
||||
- npm run dev --prefix client 2>&1 > /dev/null &
|
||||
- sleep 30
|
||||
- curl http://localhost:8080/beta-login
|
||||
- source bin/run-cypress-parallel.sh
|
||||
- &jest-test
|
||||
name: run jest tests
|
||||
caches:
|
||||
- node
|
||||
- clientmodules
|
||||
script:
|
||||
- echo "This pipeline rules!"
|
||||
- *setup-tests
|
||||
- npm install --prefix client
|
||||
- cd client
|
||||
- npm run test:unit
|
||||
- &deploy-dev
|
||||
name: deploy to dev on Heroku
|
||||
deployment: dev
|
||||
trigger: manual
|
||||
script:
|
||||
- git push --force https://heroku:$HEROKU_API_KEY@git.heroku.com/skillbox-dev.git HEAD:master
|
||||
- &deploy-academy
|
||||
name: deploy to iterativ-academy on Heroku
|
||||
deployment: academy-stage
|
||||
script:
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/iterativ-academy.git HEAD:master
|
||||
- &deploy-stage
|
||||
name: deploy to stage on Heroku
|
||||
deployment: stage
|
||||
script:
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/skillbox-stage.git develop:master
|
||||
- &deploy-preprod-manual
|
||||
name: deploy to pre-prod environments on heroku
|
||||
trigger: manual
|
||||
deployment: preprod
|
||||
script:
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/skillbox-preprod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-kv-preprod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-dha-preprod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-dhf-preprod.git HEAD:master
|
||||
- &deploy-prod-manual
|
||||
name: deploy to prod environments on heroku
|
||||
trigger: manual
|
||||
deployment: prod
|
||||
script:
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/skillbox-prod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-kv-prod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-dha-prod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-dhf-prod.git HEAD:master
|
||||
- &lint
|
||||
name: lint
|
||||
caches:
|
||||
- clientmodules
|
||||
script:
|
||||
- npm install --prefix client
|
||||
- npm run lint --prefix client
|
||||
- &unittest-python
|
||||
name: run python unit tests
|
||||
caches:
|
||||
- pip
|
||||
services:
|
||||
- postgres
|
||||
script: # Modify the commands below to build your repository.
|
||||
- &setup-tests source setup-for-tests.sh
|
||||
- ./server/run_unittests_coverage.sh
|
||||
- &cypress-test
|
||||
name: run cypress end-to-end tests
|
||||
caches:
|
||||
- pip
|
||||
- node
|
||||
- clientmodules
|
||||
- npm
|
||||
- cypress
|
||||
artifacts:
|
||||
- client/cypress/**/*.png
|
||||
- client/cypress/**/*.mp4
|
||||
services:
|
||||
- postgres
|
||||
script:
|
||||
- echo "This pipeline rules!"
|
||||
- *setup-tests
|
||||
- npm ci --prefix client
|
||||
- npm run "install:cypress" --prefix client
|
||||
- psql -U $DATABASE_USER -h $DATABASE_HOST -c "create database $DATABASE_NAME"
|
||||
- python server/manage.py dummy_data
|
||||
- python server/manage.py runserver 2>&1 > /dev/null &
|
||||
- npm run build --prefix client
|
||||
- curl http://localhost:8000/beta-login
|
||||
- npm run --prefix client test:cypress:e2e
|
||||
- &frontend-test
|
||||
name: run cypress frontend tests
|
||||
caches:
|
||||
- node
|
||||
- clientmodules
|
||||
- npm
|
||||
- cypress
|
||||
artifacts:
|
||||
- client/cypress/**/*.png
|
||||
- client/cypress/**/*.mp4
|
||||
script:
|
||||
- npm ci --prefix client
|
||||
- npm run "install:cypress" --prefix client
|
||||
- npm run dev --prefix client 2>&1 > /dev/null &
|
||||
- sleep 30
|
||||
- curl http://localhost:8080/beta-login
|
||||
- npm run --prefix client test:cypress:frontend
|
||||
- &frontend-test-parallel
|
||||
name: run cypress frontend tests
|
||||
caches:
|
||||
- node
|
||||
- clientmodules
|
||||
- npm
|
||||
- cypress
|
||||
artifacts:
|
||||
- client/cypress/**/*.png
|
||||
- client/cypress/**/*.mp4
|
||||
script:
|
||||
- npm ci --prefix client
|
||||
- npm run "install:cypress" --prefix client
|
||||
- npm run dev --prefix client 2>&1 > /dev/null &
|
||||
- sleep 30
|
||||
- curl http://localhost:8080/beta-login
|
||||
- source bin/run-cypress-parallel.sh
|
||||
- &jest-test
|
||||
name: run jest tests
|
||||
caches:
|
||||
- node
|
||||
- clientmodules
|
||||
script:
|
||||
- echo "This pipeline rules!"
|
||||
- *setup-tests
|
||||
- npm install --prefix client
|
||||
- cd client
|
||||
- npm run test:unit
|
||||
- &deploy-dev
|
||||
name: deploy to dev on Heroku
|
||||
deployment: dev
|
||||
trigger: manual
|
||||
script:
|
||||
- git push --force https://heroku:$HEROKU_API_KEY@git.heroku.com/skillbox-dev.git HEAD:master
|
||||
- &deploy-academy
|
||||
name: deploy to iterativ-academy on Heroku
|
||||
deployment: academy-stage
|
||||
script:
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/iterativ-academy.git HEAD:master
|
||||
- &deploy-stage
|
||||
name: deploy to stage on Heroku
|
||||
deployment: stage
|
||||
script:
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/skillbox-stage.git develop:master
|
||||
- &deploy-preprod-manual
|
||||
name: deploy to pre-prod environments on heroku
|
||||
trigger: manual
|
||||
deployment: preprod
|
||||
script:
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/skillbox-preprod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-kv-preprod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-dha-preprod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-dhf-preprod.git HEAD:master
|
||||
- &deploy-prod-manual
|
||||
name: deploy to prod environments on heroku
|
||||
trigger: manual
|
||||
deployment: prod
|
||||
script:
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/skillbox-prod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-kv-prod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-dha-prod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-dhf-prod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/skillbox-preprod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-kv-preprod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-dha-preprod.git HEAD:master
|
||||
- git push https://heroku:$HEROKU_API_KEY@git.heroku.com/my-dhf-preprod.git HEAD:master
|
||||
|
||||
pipelines:
|
||||
default:
|
||||
- parallel:
|
||||
- step: *lint
|
||||
- step: *unittest-python
|
||||
- step: *cypress-test
|
||||
- step: *frontend-test
|
||||
- step: *jest-test
|
||||
- step: *deploy-dev
|
||||
- parallel:
|
||||
- step: *lint
|
||||
- step: *unittest-python
|
||||
- step: *cypress-test
|
||||
- step: *frontend-test
|
||||
- step: *jest-test
|
||||
- step: *deploy-dev
|
||||
|
||||
branches:
|
||||
master:
|
||||
- parallel:
|
||||
- step: *unittest-python
|
||||
- step: *cypress-test
|
||||
- step: *frontend-test
|
||||
- step: *jest-test
|
||||
- step: *deploy-preprod-manual
|
||||
- parallel:
|
||||
- step: *unittest-python
|
||||
- step: *cypress-test
|
||||
- step: *frontend-test
|
||||
- step: *jest-test
|
||||
- step: *deploy-preprod-manual
|
||||
|
||||
develop:
|
||||
- parallel:
|
||||
- step: *lint
|
||||
- step: *unittest-python
|
||||
- step: *cypress-test
|
||||
- step: *frontend-test
|
||||
- step: *jest-test
|
||||
- parallel:
|
||||
- step: *deploy-stage
|
||||
- step: *deploy-academy
|
||||
- step: *deploy-preprod-manual
|
||||
- parallel:
|
||||
- step: *lint
|
||||
- step: *unittest-python
|
||||
- step: *cypress-test
|
||||
- step: *frontend-test
|
||||
- step: *jest-test
|
||||
- parallel:
|
||||
- step: *deploy-stage
|
||||
- step: *deploy-academy
|
||||
- step: *deploy-preprod-manual
|
||||
|
||||
tags:
|
||||
v202*:
|
||||
- parallel:
|
||||
- step: *unittest-python
|
||||
- step: *cypress-test
|
||||
- step: *jest-test
|
||||
- step: *unittest-python
|
||||
- step: *cypress-test
|
||||
- step: *jest-test
|
||||
- step: *deploy-prod-manual
|
||||
|
||||
custom:
|
||||
cypress-parallel:
|
||||
- parallel:
|
||||
- step: *frontend-test-parallel
|
||||
- step: *frontend-test-parallel
|
||||
- step: *frontend-test-parallel
|
||||
- step: *frontend-test-parallel
|
||||
- step: *frontend-test-parallel
|
||||
- step: *frontend-test-parallel
|
||||
- parallel:
|
||||
- step: *frontend-test-parallel
|
||||
- step: *frontend-test-parallel
|
||||
- step: *frontend-test-parallel
|
||||
- step: *frontend-test-parallel
|
||||
- step: *frontend-test-parallel
|
||||
- step: *frontend-test-parallel
|
||||
|
|
|
|||
|
|
@ -11,6 +11,19 @@ const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
|||
|
||||
const env = require('../config/prod.env');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const SentryWebpackPlugin = require('@sentry/webpack-plugin');
|
||||
|
||||
const sentryPlugin = [];
|
||||
if (process.env.SENTRY_AUTH_TOKEN) {
|
||||
sentryPlugin.push(
|
||||
new SentryWebpackPlugin({
|
||||
org: 'iterativ',
|
||||
project: 'skillbox-vue',
|
||||
include: config.build.assetsRoot,
|
||||
authToken: process.env.SENTRY_AUTH_TOKEN,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const webpackConfig = merge(baseWebpackConfig, {
|
||||
devtool: config.build.productionSourceMap ? config.build.devtool : false,
|
||||
|
|
@ -24,6 +37,7 @@ const webpackConfig = merge(baseWebpackConfig, {
|
|||
minimizer: [new CssMinimizerPlugin()],
|
||||
},
|
||||
plugins: [
|
||||
...sentryPlugin,
|
||||
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': env,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ const values = {
|
|||
MATOMO_SITE_ID: JSON.stringify(process.env.MATOMO_SITE_ID),
|
||||
LOGOUT_REDIRECT_URL: JSON.stringify(process.env.LOGOUT_REDIRECT_URL),
|
||||
VUE_APP_FLAVOR: JSON.stringify(process.env.APP_FLAVOR),
|
||||
SENTRY_DSN: JSON.stringify(process.env.SENTRY_JAVASCRIPT_DSN),
|
||||
SENTRY_ENVIRONMENT: JSON.stringify(process.env.SENTRY_ENV),
|
||||
/*
|
||||
* ENV variables used in JS code need to be stringyfied, as they will be replaced (in place) in the code,
|
||||
* and JS needs quotes around strings
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
import ContentBlock from '@/components/ContentBlock.vue';
|
||||
|
||||
describe('<ContentBlock />', () => {
|
||||
it('renders', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.mount(ContentBlock, {
|
||||
props: {
|
||||
contentBlock: {},
|
||||
parent: null,
|
||||
editMode: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -135,7 +135,7 @@ describe('Instruments Page', () => {
|
|||
cy.getByDataCy('instrument')
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getByDataCy('instrument-subheader').should('contain', 'Instrumente - Sprache & Kommunikation');
|
||||
cy.getByDataCy('instrument-subheader').should('contain', 'Instrumente – Sprache & Kommunikation');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ describe('Instruments on Module page', () => {
|
|||
cy.getByDataCy('content-block')
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getByDataCy('instrument-label').should('contain', 'Instrumente - Sprache & Kommunikation');
|
||||
cy.getByDataCy('instrument-label').should('contain', 'Instrumente – Sprache & Kommunikation');
|
||||
});
|
||||
cy.getByDataCy('content-block')
|
||||
.eq(1)
|
||||
|
|
|
|||
|
|
@ -113,6 +113,26 @@ const mockGraphqlOps = (options) => {
|
|||
cy.get('@mockGraphqlOps').invoke('setOperations' as any, options);
|
||||
};
|
||||
|
||||
const login = (username: string, password: string, visitLogin = false) => {
|
||||
if (visitLogin) {
|
||||
cy.visit('/beta-login');
|
||||
}
|
||||
|
||||
if (username !== '') {
|
||||
cy.get('[data-cy=email-input]').type(username);
|
||||
}
|
||||
|
||||
if (password !== '') {
|
||||
cy.get('[data-cy=password-input]').type(password);
|
||||
}
|
||||
cy.get('[data-cy=login-button]').click();
|
||||
};
|
||||
|
||||
const fakeLogin = () => {
|
||||
cy.log('Logging in (fake)');
|
||||
cy.setCookie('loginStatus', 'true');
|
||||
};
|
||||
|
||||
declare global {
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
|
|
@ -136,9 +156,9 @@ declare global {
|
|||
|
||||
selectClass(schoolClass: string): void;
|
||||
|
||||
login(username: string, password: string, visitLogin?: boolean): void;
|
||||
login: typeof login;
|
||||
|
||||
fakeLogin(username: string, password: string): void;
|
||||
fakeLogin: typeof fakeLogin;
|
||||
|
||||
isSubmissionReadOnly(myText: string): void;
|
||||
|
||||
|
|
@ -180,20 +200,7 @@ Cypress.Commands.add('apolloLogin', (username, password) => {
|
|||
});
|
||||
|
||||
// todo: replace with apollo call
|
||||
Cypress.Commands.add('login', (username, password, visitLogin = false) => {
|
||||
if (visitLogin) {
|
||||
cy.visit('/beta-login');
|
||||
}
|
||||
|
||||
if (username !== '') {
|
||||
cy.get('[data-cy=email-input]').type(username);
|
||||
}
|
||||
|
||||
if (password !== '') {
|
||||
cy.get('[data-cy=password-input]').type(password);
|
||||
}
|
||||
cy.get('[data-cy=login-button]').click();
|
||||
});
|
||||
Cypress.Commands.add('login', login);
|
||||
|
||||
Cypress.Commands.add('getByDataCy', getByDataCy);
|
||||
|
||||
|
|
@ -203,10 +210,7 @@ Cypress.Commands.add('selectClass', (schoolClass) => {
|
|||
cy.getByDataCy('class-selection-entry').contains(schoolClass).click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('fakeLogin', () => {
|
||||
cy.log('Logging in (fake)');
|
||||
cy.setCookie('loginStatus', 'true');
|
||||
});
|
||||
Cypress.Commands.add('fakeLogin', fakeLogin);
|
||||
|
||||
Cypress.Commands.add('isSubmissionReadOnly', (myText) => {
|
||||
cy.get('.submission-form__textarea--readonly').as('textarea');
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
"@graphql-tools/jest-transform": "^1.2.2",
|
||||
"@graphql-tools/mock": "^8.6.5",
|
||||
"@graphql-tools/schema": "^8.3.7",
|
||||
"@sentry/vue": "^7.45.0",
|
||||
"@sentry/webpack-plugin": "^1.20.0",
|
||||
"@tiptap/core": "^2.0.0-beta.174",
|
||||
"@tiptap/extension-bullet-list": "^2.0.0-beta.26",
|
||||
"@tiptap/extension-document": "^2.0.0-beta.15",
|
||||
|
|
@ -3214,6 +3216,173 @@
|
|||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/tracing": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.45.0.tgz",
|
||||
"integrity": "sha512-0aIDY2OvUX7k2XHaimOlWkboXoQvJ9dEKvfpu0Wh0YxfUTGPa+wplUdg3WVdkk018sq1L11MKmj4MPZyYUvXhw==",
|
||||
"dependencies": {
|
||||
"@sentry/core": "7.45.0",
|
||||
"@sentry/types": "7.45.0",
|
||||
"@sentry/utils": "7.45.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/tracing/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/browser": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.45.0.tgz",
|
||||
"integrity": "sha512-/dUrUwnI34voMj+jSJT7b5Jun+xy1utVyzzwTq3Oc22N+SB17ZOX9svZ4jl1Lu6tVJPVjPyvL6zlcbrbMwqFjg==",
|
||||
"dependencies": {
|
||||
"@sentry-internal/tracing": "7.45.0",
|
||||
"@sentry/core": "7.45.0",
|
||||
"@sentry/replay": "7.45.0",
|
||||
"@sentry/types": "7.45.0",
|
||||
"@sentry/utils": "7.45.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/browser/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/cli": {
|
||||
"version": "1.75.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.75.0.tgz",
|
||||
"integrity": "sha512-vT8NurHy00GcN8dNqur4CMIYvFH3PaKdkX3qllVvi4syybKqjwoz+aWRCvprbYv0knweneFkLt1SmBWqazUMfA==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"mkdirp": "^0.5.5",
|
||||
"node-fetch": "^2.6.7",
|
||||
"progress": "^2.0.3",
|
||||
"proxy-from-env": "^1.1.0",
|
||||
"which": "^2.0.2"
|
||||
},
|
||||
"bin": {
|
||||
"sentry-cli": "bin/sentry-cli"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/cli/node_modules/mkdirp": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/cli/node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/@sentry/core": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.45.0.tgz",
|
||||
"integrity": "sha512-xJfdTS4lRmHvZI/A5MazdnKhBJFkisKu6G9EGNLlZLre+6W4PH5sb7QX4+xoBdqG7v10Jvdia112vi762ojO2w==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "7.45.0",
|
||||
"@sentry/utils": "7.45.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/core/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/replay": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.45.0.tgz",
|
||||
"integrity": "sha512-smM7FIcFIyKu30BqCl8BzLo1gH/z9WwXdGX6V0fNvHab9fJZ09+xjFn+LmIyo6N8H8jjwsup0+yQ12kiF/ZsEw==",
|
||||
"dependencies": {
|
||||
"@sentry/core": "7.45.0",
|
||||
"@sentry/types": "7.45.0",
|
||||
"@sentry/utils": "7.45.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/types": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.45.0.tgz",
|
||||
"integrity": "sha512-iFt7msfUK8LCodFF3RKUyaxy9tJv/gpWhzxUFyNxtuVwlpmd+q6mtsFGn8Af3pbpm8A+MKyz1ebMwXj0PQqknw==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/utils": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.45.0.tgz",
|
||||
"integrity": "sha512-aTY7qqtNUudd09SH5DVSKMm3iQ6ZeWufduc0I9bPZe6UMM09BDc4KmjmrzRkdQ+VaOmHo7+v+HZKQk5f+AbuTQ==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "7.45.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/utils/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/vue": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/vue/-/vue-7.45.0.tgz",
|
||||
"integrity": "sha512-31wn10AjdMnCy5bzrMt3QLmX34ijuoxLOK4xE/E7NbtwAuPxd+mnc67CMy6UVfo8Ng36HFZFeNMewdqF676V5Q==",
|
||||
"dependencies": {
|
||||
"@sentry/browser": "7.45.0",
|
||||
"@sentry/core": "7.45.0",
|
||||
"@sentry/types": "7.45.0",
|
||||
"@sentry/utils": "7.45.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "2.x || 3.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/vue/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/webpack-plugin": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/webpack-plugin/-/webpack-plugin-1.20.0.tgz",
|
||||
"integrity": "sha512-Ssj1mJVFsfU6vMCOM2d+h+KQR7QHSfeIP16t4l20Uq/neqWXZUQ2yvQfe4S3BjdbJXz/X4Rw8Hfy1Sd0ocunYw==",
|
||||
"dependencies": {
|
||||
"@sentry/cli": "^1.74.6",
|
||||
"webpack-sources": "^2.0.0 || ^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sinclair/typebox": {
|
||||
"version": "0.24.50",
|
||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.50.tgz",
|
||||
|
|
@ -20442,6 +20611,148 @@
|
|||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
|
||||
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
|
||||
},
|
||||
"@sentry-internal/tracing": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.45.0.tgz",
|
||||
"integrity": "sha512-0aIDY2OvUX7k2XHaimOlWkboXoQvJ9dEKvfpu0Wh0YxfUTGPa+wplUdg3WVdkk018sq1L11MKmj4MPZyYUvXhw==",
|
||||
"requires": {
|
||||
"@sentry/core": "7.45.0",
|
||||
"@sentry/types": "7.45.0",
|
||||
"@sentry/utils": "7.45.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/browser": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.45.0.tgz",
|
||||
"integrity": "sha512-/dUrUwnI34voMj+jSJT7b5Jun+xy1utVyzzwTq3Oc22N+SB17ZOX9svZ4jl1Lu6tVJPVjPyvL6zlcbrbMwqFjg==",
|
||||
"requires": {
|
||||
"@sentry-internal/tracing": "7.45.0",
|
||||
"@sentry/core": "7.45.0",
|
||||
"@sentry/replay": "7.45.0",
|
||||
"@sentry/types": "7.45.0",
|
||||
"@sentry/utils": "7.45.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/cli": {
|
||||
"version": "1.75.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.75.0.tgz",
|
||||
"integrity": "sha512-vT8NurHy00GcN8dNqur4CMIYvFH3PaKdkX3qllVvi4syybKqjwoz+aWRCvprbYv0knweneFkLt1SmBWqazUMfA==",
|
||||
"requires": {
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"mkdirp": "^0.5.5",
|
||||
"node-fetch": "^2.6.7",
|
||||
"progress": "^2.0.3",
|
||||
"proxy-from-env": "^1.1.0",
|
||||
"which": "^2.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.6"
|
||||
}
|
||||
},
|
||||
"proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/core": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.45.0.tgz",
|
||||
"integrity": "sha512-xJfdTS4lRmHvZI/A5MazdnKhBJFkisKu6G9EGNLlZLre+6W4PH5sb7QX4+xoBdqG7v10Jvdia112vi762ojO2w==",
|
||||
"requires": {
|
||||
"@sentry/types": "7.45.0",
|
||||
"@sentry/utils": "7.45.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/replay": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.45.0.tgz",
|
||||
"integrity": "sha512-smM7FIcFIyKu30BqCl8BzLo1gH/z9WwXdGX6V0fNvHab9fJZ09+xjFn+LmIyo6N8H8jjwsup0+yQ12kiF/ZsEw==",
|
||||
"requires": {
|
||||
"@sentry/core": "7.45.0",
|
||||
"@sentry/types": "7.45.0",
|
||||
"@sentry/utils": "7.45.0"
|
||||
}
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.45.0.tgz",
|
||||
"integrity": "sha512-iFt7msfUK8LCodFF3RKUyaxy9tJv/gpWhzxUFyNxtuVwlpmd+q6mtsFGn8Af3pbpm8A+MKyz1ebMwXj0PQqknw=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.45.0.tgz",
|
||||
"integrity": "sha512-aTY7qqtNUudd09SH5DVSKMm3iQ6ZeWufduc0I9bPZe6UMM09BDc4KmjmrzRkdQ+VaOmHo7+v+HZKQk5f+AbuTQ==",
|
||||
"requires": {
|
||||
"@sentry/types": "7.45.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/vue": {
|
||||
"version": "7.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/vue/-/vue-7.45.0.tgz",
|
||||
"integrity": "sha512-31wn10AjdMnCy5bzrMt3QLmX34ijuoxLOK4xE/E7NbtwAuPxd+mnc67CMy6UVfo8Ng36HFZFeNMewdqF676V5Q==",
|
||||
"requires": {
|
||||
"@sentry/browser": "7.45.0",
|
||||
"@sentry/core": "7.45.0",
|
||||
"@sentry/types": "7.45.0",
|
||||
"@sentry/utils": "7.45.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/webpack-plugin": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/webpack-plugin/-/webpack-plugin-1.20.0.tgz",
|
||||
"integrity": "sha512-Ssj1mJVFsfU6vMCOM2d+h+KQR7QHSfeIP16t4l20Uq/neqWXZUQ2yvQfe4S3BjdbJXz/X4Rw8Hfy1Sd0ocunYw==",
|
||||
"requires": {
|
||||
"@sentry/cli": "^1.74.6",
|
||||
"webpack-sources": "^2.0.0 || ^3.0.0"
|
||||
}
|
||||
},
|
||||
"@sinclair/typebox": {
|
||||
"version": "0.24.50",
|
||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.50.tgz",
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@
|
|||
"@graphql-tools/jest-transform": "^1.2.2",
|
||||
"@graphql-tools/mock": "^8.6.5",
|
||||
"@graphql-tools/schema": "^8.3.7",
|
||||
"@sentry/vue": "^7.45.0",
|
||||
"@sentry/webpack-plugin": "^1.20.0",
|
||||
"@tiptap/core": "^2.0.0-beta.174",
|
||||
"@tiptap/extension-bullet-list": "^2.0.0-beta.26",
|
||||
"@tiptap/extension-document": "^2.0.0-beta.15",
|
||||
|
|
|
|||
|
|
@ -59,14 +59,14 @@
|
|||
/>
|
||||
</div>
|
||||
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<h3
|
||||
class="content-block__instrument-label"
|
||||
data-cy="instrument-label"
|
||||
:style="instrumentLabelStyle"
|
||||
v-if="instrumentLabel !== ''"
|
||||
>
|
||||
{{ instrumentLabel }}
|
||||
</h3>
|
||||
v-html="instrumentLabel"
|
||||
/>
|
||||
<h4
|
||||
class="content-block__title"
|
||||
v-if="!contentBlock.indent"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
<script>
|
||||
import LOGOUT_MUTATION from '@/graphql/gql/mutations/logoutUser.gql';
|
||||
import { matomoTrackUser } from '@/helpers/matomo-client';
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
|
|
@ -21,6 +22,7 @@ export default {
|
|||
})
|
||||
.then(({ data }) => {
|
||||
if (data.logout.success) {
|
||||
matomoTrackUser('');
|
||||
location.replace('/logout');
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ import debounce from 'lodash/debounce';
|
|||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { sanitize } from '@/helpers/text';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import { matomoTrackEvent } from '@/helpers/matomo-client';
|
||||
|
||||
const SubmissionForm = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/assignment/SubmissionForm.vue')
|
||||
|
|
@ -189,6 +190,10 @@ export default {
|
|||
*/
|
||||
this.assignment.submission.text = answer;
|
||||
this._save(this.assignment.submission);
|
||||
|
||||
if (this.assignment.submission.text.length > 0) {
|
||||
matomoTrackEvent('Auftrag', 'Text mit Eingabe gespeichert', this.assignment.id);
|
||||
}
|
||||
},
|
||||
changeDocumentUrl(documentUrl) {
|
||||
this.assignment.submission.document = documentUrl;
|
||||
|
|
@ -210,6 +215,7 @@ export default {
|
|||
},
|
||||
},
|
||||
});
|
||||
matomoTrackEvent('Auftrag', 'Ergebnis mit Lehrperson geteilt', this.assignment.id);
|
||||
},
|
||||
reopen() {
|
||||
this.$apollo.mutate({
|
||||
|
|
@ -259,6 +265,7 @@ export default {
|
|||
.then(() => {
|
||||
this.spellcheckLoading = false;
|
||||
});
|
||||
matomoTrackEvent('Auftrag', 'Rechtschreibung geprüft', this.assignment.id);
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@
|
|||
}"
|
||||
class="instrument-entry"
|
||||
>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<h4
|
||||
class="instrument-entry__category"
|
||||
:style="{ color: instrument.type.category.foreground }"
|
||||
data-cy="instrument-subheader"
|
||||
>
|
||||
{{ categoryName }}
|
||||
</h4>
|
||||
v-html="categoryName"
|
||||
/>
|
||||
<h3 class="instrument-entry__title">
|
||||
{{ instrument.title }}
|
||||
</h3>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="instrument-filter">
|
||||
<filter-group
|
||||
title="Alle anzeigen"
|
||||
:title="$flavor.textInstrumentFilterShowAll"
|
||||
data-cy="filter-all-instruments"
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ export default {
|
|||
|
||||
&__hero-source {
|
||||
@include tiny-text;
|
||||
ling-height: 25px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
&__meta-title {
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ import me from '@/mixins/me';
|
|||
|
||||
import APPLY_SNAPSHOT_MUTATION from 'gql/mutations/snapshots/applySnapshot.gql';
|
||||
import { MODULE_PAGE } from '@/router/module.names';
|
||||
import { matomoTrackEvent } from '@/helpers/matomo-client';
|
||||
|
||||
const _getChange = (snapshot, index) => {
|
||||
try {
|
||||
|
|
@ -131,6 +132,11 @@ export default {
|
|||
},
|
||||
},
|
||||
}) => {
|
||||
if (this.snapshot.mine) {
|
||||
matomoTrackEvent('Modul Snapshot', 'Snapshot angewendet', slug);
|
||||
} else {
|
||||
matomoTrackEvent('Modul Snapshot', 'Team Snapshot angewendet', slug);
|
||||
}
|
||||
this.$router.push({
|
||||
name: MODULE_PAGE,
|
||||
params: {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ import gql from 'graphql-tag';
|
|||
import PenIcon from '@/components/icons/PenIcon';
|
||||
import TrashIcon from '@/components/icons/TrashIcon';
|
||||
import { removeAtIndex } from '@/graphql/immutable-operations';
|
||||
import { matomoTrackEvent } from '@/helpers/matomo-client';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
|
@ -134,49 +135,53 @@ export default {
|
|||
title: 'Snapshot löschen',
|
||||
})
|
||||
.then(() => {
|
||||
this.$apollo.mutate({
|
||||
mutation: DELETE_SNAPSHOT_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
id: this.snapshot.id,
|
||||
},
|
||||
},
|
||||
update: (
|
||||
store,
|
||||
{
|
||||
data: {
|
||||
deleteSnapshot: { result },
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: DELETE_SNAPSHOT_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
id: this.snapshot.id,
|
||||
},
|
||||
}
|
||||
) => {
|
||||
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,
|
||||
},
|
||||
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);
|
||||
|
||||
store.writeQuery({
|
||||
query,
|
||||
variables,
|
||||
data,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
const data = {
|
||||
module: {
|
||||
...module,
|
||||
snapshots,
|
||||
},
|
||||
};
|
||||
|
||||
store.writeQuery({
|
||||
query,
|
||||
variables,
|
||||
data,
|
||||
});
|
||||
}
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
matomoTrackEvent('Modul Snapshot', 'Snapshot gelöscht', this.$route.params.slug);
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
|
|
@ -213,6 +218,13 @@ export default {
|
|||
});
|
||||
},
|
||||
});
|
||||
|
||||
const slug = this.$route.params.slug;
|
||||
if (this.snapshot.shared) {
|
||||
matomoTrackEvent('Modul Snapshot', 'Snapshot mit Team geteilt', slug);
|
||||
} else {
|
||||
matomoTrackEvent('Modul Snapshot', 'Snapshot nicht mehr geteilt', slug);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ import me from '@/mixins/me';
|
|||
|
||||
import CREATE_SNAPSHOT_MUTATION from '@/graphql/gql/mutations/createSnapshot.gql';
|
||||
import MODULE_SNAPSHOTS_QUERY from '@/graphql/gql/queries/moduleSnapshots.gql';
|
||||
import log from 'loglevel';
|
||||
import { matomoTrackEvent } from '@/helpers/matomo-client';
|
||||
|
||||
export default {
|
||||
mixins: [me],
|
||||
|
|
@ -109,12 +111,15 @@ export default {
|
|||
createSnapshot: { snapshot },
|
||||
},
|
||||
}) => {
|
||||
log.debug('snapshot created', snapshot);
|
||||
|
||||
this.showPopover = false;
|
||||
this.$modal.open('snapshot-created', {
|
||||
snapshot,
|
||||
});
|
||||
}
|
||||
);
|
||||
matomoTrackEvent('Modul Snapshot', 'Snapshot erstellt', this.$route.params.slug);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import Toggle from '@/components/ui/Toggle';
|
|||
// import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery.gql';
|
||||
import { gql } from '@apollo/client/core';
|
||||
import { setModuleEditMode } from '@/graphql/cache-operations';
|
||||
import { matomoTrackEvent } from '@/helpers/matomo-client';
|
||||
|
||||
const QUERY = gql`
|
||||
query ModuleEditModeQuery($slug: String) {
|
||||
|
|
@ -56,6 +57,11 @@ export default {
|
|||
methods: {
|
||||
toggle(newChecked) {
|
||||
setModuleEditMode(this.slug, newChecked);
|
||||
if (newChecked) {
|
||||
matomoTrackEvent('Modul Anpassen', 'Eingeschaltet', this.slug);
|
||||
} else {
|
||||
matomoTrackEvent('Modul Anpassen', 'Ausgeschaltet', this.slug);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,10 +20,12 @@
|
|||
<script>
|
||||
import me from '@/mixins/me';
|
||||
|
||||
import { TYPES, CONTENT_TYPE } from '@/consts/types';
|
||||
import { CONTENT_TYPE, TYPES } from '@/consts/types';
|
||||
import { createVisibilityMutation, hidden } from '@/helpers/visibility';
|
||||
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import { matomoTrackModuleVisibilityEvent } from '@/helpers/matomo-client';
|
||||
|
||||
const EyeIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/EyeIcon'));
|
||||
const ClosedEyeIcon = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "icons" */ '@/components/icons/ClosedEyeIcon')
|
||||
|
|
@ -76,6 +78,8 @@ export default {
|
|||
mutation,
|
||||
variables,
|
||||
});
|
||||
|
||||
matomoTrackModuleVisibilityEvent(this.type, this.block, hidden);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ const resizeElement = (el: HTMLElement) => {
|
|||
};
|
||||
|
||||
export default {
|
||||
update: resizeElement,
|
||||
updated: resizeElement,
|
||||
mounted: resizeElement,
|
||||
created(el: HTMLElement) {
|
||||
el.classList.add('skillbox-auto-grow');
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { typeDefs } from '@/graphql/typedefs';
|
|||
import { resolvers } from '@/graphql/resolvers';
|
||||
import cache from './cache';
|
||||
import log from 'loglevel';
|
||||
import * as Sentry from '@sentry/vue';
|
||||
|
||||
import { router } from '@/router';
|
||||
|
||||
|
|
@ -45,9 +46,11 @@ export default function(uri, networkErrorCallback) {
|
|||
}
|
||||
|
||||
if (graphQLErrors) {
|
||||
graphQLErrors.forEach(({ message, locations, path }) =>
|
||||
log.warn(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`)
|
||||
);
|
||||
graphQLErrors.forEach(({ message, locations, path }) => {
|
||||
const err = `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`;
|
||||
log.warn(err);
|
||||
Sentry.captureMessage(err);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
query RoomEntryQuery($slug: String!) {
|
||||
roomEntry(slug: $slug) {
|
||||
...RoomEntryParts
|
||||
room {
|
||||
slug
|
||||
}
|
||||
comments {
|
||||
text
|
||||
owner {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const defaultFlavorValues: FlavorValues = {
|
|||
textModules: 'Module',
|
||||
textInstrument: 'Instrument',
|
||||
textInstruments: 'Instrumente',
|
||||
textInstrumentFilterShowAll: 'Alle anzeigen',
|
||||
|
||||
// mySkillbox flags
|
||||
showFooter: true,
|
||||
|
|
@ -36,6 +37,7 @@ export const myKvValues: FlavorValues = {
|
|||
textModules: 'Lernfelder',
|
||||
textInstrument: 'Grundlagenwissen',
|
||||
textInstruments: 'Grundlagenwissen',
|
||||
textInstrumentFilterShowAll: 'Alles anzeigen',
|
||||
|
||||
// myKV flags
|
||||
showFooter: false,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const instrumentType = (instrument) => {
|
|||
};
|
||||
|
||||
const instrumentCategory = (instrument) => {
|
||||
return `${flavor.textInstruments} - ${instrumentType(instrument)}`;
|
||||
return `${flavor.textInstruments} – ${instrumentType(instrument)}`;
|
||||
};
|
||||
|
||||
export default instrumentType;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
import log from 'loglevel';
|
||||
import {
|
||||
CHAPTER_DESCRIPTION_TYPE,
|
||||
CHAPTER_TITLE_TYPE,
|
||||
CONTENT_TYPE,
|
||||
OBJECTIVE_GROUP_TYPE,
|
||||
OBJECTIVE_TYPE,
|
||||
} from '@/consts/types';
|
||||
|
||||
export type matomoUserRole = 'Student' | 'Teacher';
|
||||
|
||||
let matomoLastUrl = '';
|
||||
let matomoLastUserId = '';
|
||||
let matomoLastEventData = '';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
_paq: any[];
|
||||
}
|
||||
}
|
||||
|
||||
window._paq = window._paq || [];
|
||||
|
||||
export function matomoTrackPageView(absolutePath: string = '/', title?: string) {
|
||||
// see https://developer.matomo.org/guides/spa-tracking for details
|
||||
const url = window.location.origin + absolutePath;
|
||||
|
||||
if (matomoLastUrl !== url) {
|
||||
// do not track the same url twice
|
||||
log.debug('trackMatomoPageView', { url, matomoLastUrl, title });
|
||||
window._paq.push(['setCustomUrl', url]);
|
||||
window._paq.push(['trackPageView', title]);
|
||||
matomoLastUrl = url;
|
||||
}
|
||||
}
|
||||
|
||||
export function matomoTrackEvent(category: string, action: string, name?: string, value?: number) {
|
||||
const data = { category, action, name, value };
|
||||
const dataJSON = JSON.stringify(data);
|
||||
|
||||
if (matomoLastEventData !== dataJSON) {
|
||||
log.debug('matomoTrackEvent', { category, action, name, value });
|
||||
// @ts-ignore
|
||||
window._paq.push(['trackEvent', category, action, name, value]);
|
||||
matomoLastEventData = dataJSON;
|
||||
}
|
||||
}
|
||||
|
||||
export function matomoTrackModuleVisibilityEvent(blockType: string, block: any, hidden: boolean) {
|
||||
let eventAction = '';
|
||||
let eventName = undefined;
|
||||
|
||||
switch (blockType) {
|
||||
case CONTENT_TYPE:
|
||||
eventAction = hidden ? 'Inhalt ausgeblendet' : 'Inhalt eingeblendet';
|
||||
eventName = block.title;
|
||||
break;
|
||||
case OBJECTIVE_TYPE:
|
||||
eventAction = hidden ? 'Lernziel ausgeblendet' : 'Lernziel eingeblendet';
|
||||
eventName = block.text;
|
||||
break;
|
||||
case OBJECTIVE_GROUP_TYPE:
|
||||
eventAction = hidden ? 'Lernzielgruppe ausgeblendet' : 'Lernzielgruppe eingeblendet';
|
||||
eventName = block.displayTitle;
|
||||
break;
|
||||
case CHAPTER_TITLE_TYPE:
|
||||
eventAction = hidden ? 'Kapitelüberschrift ausgeblendet' : 'Kapitelüberschrift eingeblendet';
|
||||
eventName = block.title;
|
||||
break;
|
||||
case CHAPTER_DESCRIPTION_TYPE:
|
||||
eventAction = hidden ? 'Kapitelbeschreibung ausgeblendet' : 'Kapitelbeschreibung eingeblendet';
|
||||
eventName = block.title;
|
||||
break;
|
||||
}
|
||||
|
||||
matomoTrackEvent('Modul Anpassen - Sichtbarkeit', eventAction, eventName);
|
||||
}
|
||||
|
||||
export function matomoTrackUser(userId: string, role: matomoUserRole = 'Student') {
|
||||
// see https://developer.matomo.org/guides/tracking-javascript-guide#user-id for the process
|
||||
if (matomoLastUserId !== userId) {
|
||||
log.debug('matomoTrackUser', { userId, matomoLastUserId, role });
|
||||
|
||||
if (userId) {
|
||||
// @ts-ignore
|
||||
window._paq.push(['setUserId', userId]);
|
||||
// @ts-ignore
|
||||
window._paq.push(['setCustomDimension', 1, role]);
|
||||
} else {
|
||||
// @ts-ignore
|
||||
window._paq.push(['deleteCustomDimension', 1]);
|
||||
// User has just logged out, we reset the User ID
|
||||
// @ts-ignore
|
||||
window._paq.push(['resetUserId']);
|
||||
// we also force a new visit to be created for the pageviews after logout
|
||||
// @ts-ignore
|
||||
window._paq.push(['appendToTrackingUrl', 'new_visit=1']);
|
||||
// @ts-ignore
|
||||
window._paq.push(['trackPageView']);
|
||||
// we finally make sure to not again create a new visit afterwards (important for Single Page Applications)
|
||||
// @ts-ignore
|
||||
window._paq.push(['appendToTrackingUrl', '']);
|
||||
}
|
||||
|
||||
matomoLastUserId = userId;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ export interface FlavorValues {
|
|||
textModules: string;
|
||||
textInstrument: string;
|
||||
textInstruments: string;
|
||||
textInstrumentFilterShowAll: string;
|
||||
showFooter: boolean;
|
||||
showObjectivesTitle: boolean;
|
||||
showInstrumentFilterSidebar: boolean;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||
import { computed } from 'vue';
|
||||
import { useQuery } from '@vue/apollo-composable';
|
||||
import { matomoTrackPageView, matomoTrackUser } from '@/helpers/matomo-client';
|
||||
|
||||
export interface Me {
|
||||
selectedClass: {
|
||||
|
|
@ -110,7 +111,6 @@ const meMixin = {
|
|||
return getTopicRoute(this.$data.me);
|
||||
},
|
||||
schoolClass(): any {
|
||||
console.log('schoolClass legacy');
|
||||
// @ts-ignore
|
||||
return getSelectedClass(this.$data.me);
|
||||
},
|
||||
|
|
@ -137,6 +137,13 @@ const meMixin = {
|
|||
// @ts-ignore
|
||||
return this.$getRidOfEdges(data).me;
|
||||
},
|
||||
// @ts-ignore
|
||||
result({ data }) {
|
||||
const me = data.me || defaultMe.me;
|
||||
if (me.id) {
|
||||
matomoTrackUser(me.id ?? '', me.isTeacher ? 'Teacher' : 'Student');
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import ADD_COMMENT_MUTATION from 'gql/mutations/addComment.gql';
|
|||
import CommentInput from '@/components/rooms/CommentInput';
|
||||
import Comment from '@/components/rooms/Comment';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import { matomoTrackPageView } from '@/helpers/matomo-client';
|
||||
const TextBlock = defineAsyncComponent(() =>
|
||||
import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/TextBlock')
|
||||
);
|
||||
|
|
@ -148,6 +149,9 @@ export default {
|
|||
variables: {
|
||||
slug: this.$route.params.slug,
|
||||
},
|
||||
result() {
|
||||
matomoTrackPageView(`/room/${this.roomEntry.room.slug}/${this.roomEntry.slug}`);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
<script>
|
||||
import ModuleNavigation from '@/components/modules/ModuleNavigation.vue';
|
||||
import ModuleSubNavigation from '@/components/modules/ModuleSubNavigation.vue';
|
||||
import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery.gql';
|
||||
import { matomoTrackPageView } from '@/helpers/matomo-client';
|
||||
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -16,6 +19,12 @@ export default {
|
|||
ModuleSubNavigation,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
module: {},
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
showNavigation() {
|
||||
return !this.$route.meta.hideNavigation && !this.$route.meta.showSubNavigation;
|
||||
|
|
@ -24,6 +33,21 @@ export default {
|
|||
return !!this.$route.meta.showSubNavigation;
|
||||
},
|
||||
},
|
||||
|
||||
apollo: {
|
||||
module() {
|
||||
return {
|
||||
query: MODULE_DETAILS_QUERY,
|
||||
variables: {
|
||||
slug: this.$route.params.slug,
|
||||
},
|
||||
result() {
|
||||
matomoTrackPageView(`/topic/${this.module.topic.slug}/${this.module.slug}`);
|
||||
},
|
||||
fetchPolicy: 'cache-first',
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import { isTeacher } from '@/helpers/is-teacher';
|
|||
import { meQuery } from '@/graphql/queries';
|
||||
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import { matomoTrackEvent } from '@/helpers/matomo-client';
|
||||
const Solution = defineAsyncComponent(() =>
|
||||
import(
|
||||
/* webpackChunkName: "content-components"
|
||||
|
|
@ -120,6 +121,7 @@ export default {
|
|||
mounted() {
|
||||
if (this.surveyData) {
|
||||
this.loadSurveyFromServer(this.surveyData);
|
||||
matomoTrackEvent('Übung', 'Übung angezeigt', this.id);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -172,42 +174,42 @@ export default {
|
|||
data: JSON.stringify(data),
|
||||
};
|
||||
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: UPDATE_ANSWER,
|
||||
variables: {
|
||||
input: {
|
||||
answer,
|
||||
this.$apollo.mutate({
|
||||
mutation: UPDATE_ANSWER,
|
||||
variables: {
|
||||
input: {
|
||||
answer,
|
||||
},
|
||||
},
|
||||
update: (
|
||||
store,
|
||||
{
|
||||
data: {
|
||||
updateAnswer: { answer },
|
||||
},
|
||||
},
|
||||
update: (
|
||||
store,
|
||||
{
|
||||
data: {
|
||||
updateAnswer: { answer },
|
||||
},
|
||||
}
|
||||
) => {
|
||||
const query = SURVEY_QUERY;
|
||||
const variables = { id: this.id };
|
||||
const { survey } = store.readQuery({ query, variables });
|
||||
if (survey) {
|
||||
const newData = {
|
||||
// data is already in use in parent scope
|
||||
survey: {
|
||||
...survey,
|
||||
answer,
|
||||
},
|
||||
};
|
||||
store.writeQuery({ query, variables, data: newData });
|
||||
}
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
if (exit) {
|
||||
this.$router.go(-1);
|
||||
}
|
||||
});
|
||||
) => {
|
||||
const query = SURVEY_QUERY;
|
||||
const variables = { id: this.id };
|
||||
const { survey } = store.readQuery({ query, variables });
|
||||
if (survey) {
|
||||
const newData = {
|
||||
// data is already in use in parent scope
|
||||
survey: {
|
||||
...survey,
|
||||
answer,
|
||||
},
|
||||
};
|
||||
store.writeQuery({ query, variables, data: newData });
|
||||
}
|
||||
},
|
||||
});
|
||||
if (exit) {
|
||||
matomoTrackEvent('Übung', 'Übung erfolgreich abgeschlossen', this.id);
|
||||
this.$router.go(-1);
|
||||
} else {
|
||||
matomoTrackEvent('Übung', 'Übungsschritt abgeschlossen', this.id);
|
||||
}
|
||||
};
|
||||
|
||||
survey.onComplete.add((sender, options) => {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ import TopicNavigation from '@/components/book-navigation/TopicNavigation';
|
|||
|
||||
import UPDATE_LAST_TOPIC_MUTATION from '@/graphql/gql/mutations/updateLastTopic.gql';
|
||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||
|
||||
const PlayIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/Play'));
|
||||
const BulbIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/BulbIcon'));
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export default [
|
|||
public: true,
|
||||
illustration: 'hello',
|
||||
illustrationAlign: 'top',
|
||||
matomoUrl: '/auth/hello',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -24,6 +25,7 @@ export default [
|
|||
meta: {
|
||||
layout: 'public',
|
||||
public: true,
|
||||
matomoUrl: '/auth/beta-login',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -45,6 +47,7 @@ export default [
|
|||
meta: {
|
||||
public: true,
|
||||
layout: 'public',
|
||||
matomoUrl: '/auth/verify-email',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -59,6 +62,7 @@ export default [
|
|||
meta: {
|
||||
public: true,
|
||||
layout: 'public',
|
||||
matomoUrl: '/auth/unknown-auth-error',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -67,6 +71,7 @@ export default [
|
|||
name: LICENSE_ACTIVATION,
|
||||
meta: {
|
||||
layout: 'public',
|
||||
matomoUrl: '/auth/license-activation',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { EMAIL_NOT_VERIFIED_STATE, NO_VALID_LICENSE_STATE, SUCCESS_STATE } from
|
|||
|
||||
import start from '@/pages/start';
|
||||
import { PAGE_LOAD_TIMEOUT } from '@/consts/navigation.consts';
|
||||
import { matomoTrackPageView } from '@/helpers/matomo-client';
|
||||
|
||||
const instrument = () => import(/* webpackChunkName: "instruments" */ '@/pages/instrument');
|
||||
const instrumentOverview = () => import(/* webpackChunkName: "instruments" */ '@/pages/instrumentOverview');
|
||||
|
|
@ -36,6 +37,7 @@ const notFoundRoute = {
|
|||
component: p404,
|
||||
meta: {
|
||||
layout: 'blank',
|
||||
matomoUrl: '/not-found',
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -44,6 +46,7 @@ const routes = [
|
|||
path: '/',
|
||||
name: 'home',
|
||||
component: start,
|
||||
meta: { matomoUrl: '/' },
|
||||
},
|
||||
...moduleRoutes,
|
||||
...authRoutes,
|
||||
|
|
@ -56,11 +59,28 @@ const routes = [
|
|||
path: '/instruments/',
|
||||
name: 'instrument-overview',
|
||||
component: instrumentOverview,
|
||||
meta: { matomoUrl: '/instrument/' },
|
||||
},
|
||||
{
|
||||
path: '/instrument/:slug',
|
||||
name: 'instrument',
|
||||
component: instrument,
|
||||
meta: { layout: LAYOUT_SIMPLE, matomoUrlCallback: (to) => `/instrument/${to.params.slug}` },
|
||||
},
|
||||
{ path: '/instrument/:slug', name: 'instrument', component: instrument, meta: { layout: LAYOUT_SIMPLE } },
|
||||
{ path: '/submission/:id', name: 'submission', component: submission, meta: { layout: LAYOUT_SIMPLE } },
|
||||
{ path: '/topic/:topicSlug', name: 'topic', component: topic, alias: '/book/topic/:topicSlug' },
|
||||
{ path: '/join-class', name: 'join-class', component: joinClass, meta: { layout: LAYOUT_SIMPLE } },
|
||||
{
|
||||
path: '/topic/:topicSlug',
|
||||
name: 'topic',
|
||||
component: topic,
|
||||
alias: '/book/topic/:topicSlug',
|
||||
meta: { matomoUrlCallback: (to) => `/topic/${to.params.topicSlug}/` },
|
||||
},
|
||||
{
|
||||
path: '/join-class',
|
||||
name: 'join-class',
|
||||
component: joinClass,
|
||||
meta: { layout: LAYOUT_SIMPLE, matomoUrl: '/join-class' },
|
||||
},
|
||||
{
|
||||
path: '/survey/:id',
|
||||
component: surveyPage,
|
||||
|
|
@ -72,6 +92,7 @@ const routes = [
|
|||
path: '/news',
|
||||
component: news,
|
||||
name: 'news',
|
||||
meta: { matomoUrl: '/news' },
|
||||
},
|
||||
{
|
||||
path: '/oauth-redirect',
|
||||
|
|
@ -126,4 +147,14 @@ router.afterEach(() => {
|
|||
store.dispatch('showMobileNavigation', false);
|
||||
});
|
||||
|
||||
router.afterEach((to) => {
|
||||
if (to.meta.matomoUrl) {
|
||||
matomoTrackPageView(to.meta.matomoUrl);
|
||||
}
|
||||
|
||||
if (to.meta.matomoUrlCallback) {
|
||||
matomoTrackPageView(to.meta.matomoUrlCallback(to));
|
||||
}
|
||||
});
|
||||
|
||||
export { router, postLoginRedirectUrlKey };
|
||||
|
|
|
|||
|
|
@ -18,43 +18,48 @@ export default [
|
|||
path: '/me',
|
||||
component: profilePage,
|
||||
children: [
|
||||
{ path: 'profile', name: 'profile', component: profile, meta: { isProfile: true } },
|
||||
{ path: 'class', alias: 'my-class', name: 'my-class', component: myClass, meta: { isProfile: true } },
|
||||
{ path: 'activity', name: 'activity', component: activity, meta: { isProfile: true } },
|
||||
{ path: '', name: 'profile-activity', component: activity, meta: { isProfile: true } },
|
||||
{ path: 'profile', name: 'profile', component: profile, meta: { isProfile: true, matomoUrl: '/me/profile' } },
|
||||
{ path: 'class', alias: 'my-class', name: 'my-class', component: myClass, meta: { isProfile: true, matomoUrl: '/me/class' } },
|
||||
{ path: 'activity', name: 'activity', component: activity, meta: { isProfile: true, matomoUrl: '/me/activity' } },
|
||||
{ path: '', name: 'profile-activity', component: activity, meta: { isProfile: true, matomoUrl: '/me/activity'} },
|
||||
{
|
||||
path: 'old-classes',
|
||||
name: 'old-classes',
|
||||
component: oldClasses,
|
||||
meta: { isProfile: true },
|
||||
meta: { isProfile: true, matomoUrl: '/me/old-classes' },
|
||||
},
|
||||
{
|
||||
path: 'class/create',
|
||||
alias: 'create-class',
|
||||
name: 'create-class',
|
||||
component: createClass,
|
||||
meta: { layout: LAYOUT_SIMPLE },
|
||||
meta: { layout: LAYOUT_SIMPLE, matomoUrl: '/me/class/create' },
|
||||
},
|
||||
{
|
||||
path: 'class/code',
|
||||
alias: 'show-code',
|
||||
name: SHOW_SCHOOL_CLASS_CODE,
|
||||
component: showSchoolClassCode,
|
||||
meta: { layout: LAYOUT_SIMPLE },
|
||||
meta: { layout: LAYOUT_SIMPLE, matomoUrl: '/me/class/code' },
|
||||
},
|
||||
{ path: 'team', name: MY_TEAM, component: myTeam, meta: { isProfile: true, matomoUrl: '/me/team' } },
|
||||
{
|
||||
path: 'team/join',
|
||||
name: JOIN_TEAM,
|
||||
component: joinTeam,
|
||||
meta: { isProfile: true, layout: LAYOUT_SIMPLE, matomoUrl: '/me/team/join' }
|
||||
},
|
||||
{ path: 'team', name: MY_TEAM, component: myTeam, meta: { isProfile: true } },
|
||||
{ path: 'team/join', name: JOIN_TEAM, component: joinTeam, meta: { isProfile: true, layout: LAYOUT_SIMPLE } },
|
||||
{
|
||||
path: 'team/create',
|
||||
name: CREATE_TEAM,
|
||||
component: createTeam,
|
||||
meta: { isProfile: true, layout: LAYOUT_SIMPLE },
|
||||
meta: { isProfile: true, layout: LAYOUT_SIMPLE, matomoUrl: '/me/team/create' }
|
||||
},
|
||||
{
|
||||
path: 'team/code',
|
||||
name: SHOW_TEAM_CODE,
|
||||
component: showTeamCode,
|
||||
meta: { layout: LAYOUT_SIMPLE },
|
||||
meta: { layout: LAYOUT_SIMPLE, matomoUrl: '/me/team/code' }
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export default [
|
|||
meta: {
|
||||
layout: 'split',
|
||||
next: ONBOARDING_STEP_1,
|
||||
matomoUrl: '/onboarding/start',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -28,6 +29,7 @@ export default [
|
|||
layout: 'split',
|
||||
next: ONBOARDING_STEP_2,
|
||||
illustration: 'contents',
|
||||
matomoUrl: '/onboarding/learning',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -38,6 +40,7 @@ export default [
|
|||
layout: 'split',
|
||||
next: ONBOARDING_STEP_3,
|
||||
illustration: 'rooms',
|
||||
matomoUrl: '/onboarding/collaboration',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -48,6 +51,7 @@ export default [
|
|||
layout: 'split',
|
||||
next: 'home',
|
||||
illustration: 'portfolio',
|
||||
matomoUrl: '/onboarding/portfolio',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -7,10 +7,26 @@ const newProject = () => import(/* webpackChunkName: "portfolio" */ '@/pages/por
|
|||
const editProject = () => import(/* webpackChunkName: "portfolio" */ '@/pages/portfolio/editProject');
|
||||
|
||||
const portfolioRoutes = [
|
||||
{ path: '/portfolio', name: PROJECTS_PAGE, component: portfolio, meta: { hideFooter: true } },
|
||||
{ path: '/portfolio/:slug', name: 'project', component: project, props: true },
|
||||
{ path: '/new-project/', name: NEW_PROJECT_PAGE, component: newProject },
|
||||
{ path: '/edit-project/:slug', name: 'edit-project', component: editProject, props: true },
|
||||
{ path: '/portfolio', name: PROJECTS_PAGE, component: portfolio, meta: { hideFooter: true, matomoUrl: '/portfolio/' } },
|
||||
{
|
||||
path: '/portfolio/:slug',
|
||||
name: 'project',
|
||||
component: project,
|
||||
props: true ,
|
||||
meta: {
|
||||
matomoUrlCallback: (route) => `/portfolio/${route.params.slug}`,
|
||||
}
|
||||
},
|
||||
{ path: '/new-project/', name: NEW_PROJECT_PAGE, component: newProject, meta: { matomoUrl: '/portfolio/' } },
|
||||
{
|
||||
path: '/edit-project/:slug',
|
||||
name: 'edit-project',
|
||||
component: editProject,
|
||||
props: true,
|
||||
meta: {
|
||||
matomoUrlCallback: (route) => `/portfolio/${route.params.slug}`,
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const routes = flavorValues.showPortfolio ? portfolioRoutes : [];
|
||||
|
|
|
|||
|
|
@ -16,24 +16,29 @@ const newRoomEntry = () => import(/* webpackChunkName: "rooms" */ '@/pages/rooms
|
|||
const editRoomEntry = () => import(/* webpackChunkName: "rooms" */ '@/pages/rooms/editRoomEntry');
|
||||
const moduleRoom = () => import(/* webpackChunkName: "rooms" */ '@/pages/module/moduleRoom');
|
||||
|
||||
function matomoRoomWithSlugCallback(route) {
|
||||
return `/room/${route.params.slug}/`;
|
||||
}
|
||||
|
||||
export default [
|
||||
{ path: '/rooms', name: ROOMS_PAGE, component: rooms, meta: { filter: true, hideFooter: true } },
|
||||
{ path: '/rooms', name: ROOMS_PAGE, component: rooms, meta: { filter: true, hideFooter: true, matomoUrl: '/room/' }},
|
||||
{ path: '/new-room/', name: NEW_ROOM_PAGE, component: newRoom },
|
||||
{ path: '/edit-room/:id', name: 'edit-room', component: editRoom, props: true },
|
||||
{ path: '/room/:slug', name: ROOM_PAGE, component: room, props: true },
|
||||
{ path: '/room/:slug/add', name: ADD_ROOM_ENTRY_PAGE, component: newRoomEntry, props: true },
|
||||
{ path: '/room/:slug/edit/:entrySlug', name: UPDATE_ROOM_ENTRY_PAGE, component: editRoomEntry, props: true },
|
||||
{ path: '/room/:slug', name: ROOM_PAGE, component: room, props: true, meta: { matomoUrlCallback: matomoRoomWithSlugCallback }},
|
||||
{ path: '/room/:slug/add', name: ADD_ROOM_ENTRY_PAGE, component: newRoomEntry, props: true, meta: { matomoUrlCallback: matomoRoomWithSlugCallback }},
|
||||
{ path: '/room/:slug/edit/:entrySlug', name: UPDATE_ROOM_ENTRY_PAGE, component: editRoomEntry, meta: { matomoUrlCallback: matomoRoomWithSlugCallback }},
|
||||
{
|
||||
path: '/module-room/:slug',
|
||||
name: MODULE_ROOM_PAGE,
|
||||
component: moduleRoom,
|
||||
props: true,
|
||||
meta: { layout: 'fullScreen' },
|
||||
meta: { layout: 'fullScreen', matomoUrlCallback: matomoRoomWithSlugCallback },
|
||||
},
|
||||
{
|
||||
path: '/module-room/:slug/add',
|
||||
name: ADD_MODULE_ROOM_ENTRY_PAGE,
|
||||
component: newRoomEntry,
|
||||
props: (route) => ({ slug: route.params.slug, isModule: true }),
|
||||
meta: { matomoUrlCallback: matomoRoomWithSlugCallback },
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { createApolloProvider } from '@vue/apollo-option';
|
|||
import apolloClients from './apollo';
|
||||
import flavorPlugin from '@/plugins/flavor';
|
||||
import VueMatomo from 'vue-matomo';
|
||||
import * as Sentry from '@sentry/vue';
|
||||
|
||||
const { publicApolloClient, privateApolloClient } = apolloClients;
|
||||
|
||||
|
|
@ -17,6 +18,13 @@ const apolloProvider = createApolloProvider({
|
|||
defaultClient: privateApolloClient,
|
||||
});
|
||||
const registerPlugins = (app: any) => {
|
||||
if (process.env.SENTRY_DSN) {
|
||||
Sentry.init({
|
||||
app,
|
||||
dsn: process.env.SENTRY_DSN,
|
||||
environment: process.env.SENTRY_ENVIRONMENT || 'localhost',
|
||||
});
|
||||
}
|
||||
app.use(store);
|
||||
app.use(VueModal);
|
||||
app.use(VueRemoveEdges);
|
||||
|
|
@ -25,10 +33,14 @@ const registerPlugins = (app: any) => {
|
|||
app.use(router);
|
||||
app.use(flavorPlugin);
|
||||
if (process.env.MATOMO_HOST) {
|
||||
// MS-628: we use VueMatomo "only" to setup the Matomo tracker
|
||||
// we will not use any of the provided functions
|
||||
app.use(VueMatomo, {
|
||||
host: process.env.MATOMO_HOST,
|
||||
siteId: process.env.MATOMO_SITE_ID,
|
||||
router: router,
|
||||
enableHeartBeatTimer: true,
|
||||
// we don't want the default vue-matomo router behaviour
|
||||
router: null,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -82,6 +82,20 @@ button {
|
|||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
sup,
|
||||
sub {
|
||||
font-size: toRem(14px);
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
sup {
|
||||
vertical-align: super;
|
||||
}
|
||||
|
||||
sub {
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
.small-emph {
|
||||
font-size: toRem($base-font-size-pixels);
|
||||
margin-bottom: 7.5px;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import logging
|
|||
from graphene.types import Scalar
|
||||
from graphene_django.converter import convert_django_field
|
||||
from graphql_relay import to_global_id
|
||||
from wagtail.core.fields import StreamField
|
||||
from wagtail.fields import StreamField
|
||||
from wagtail.documents.models import Document
|
||||
from wagtail.images.models import Image
|
||||
|
||||
|
|
|
|||
|
|
@ -2,24 +2,31 @@ from django.conf import settings
|
|||
from django.conf.urls import url
|
||||
from django.urls import include
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from graphene_django.views import GraphQLView
|
||||
|
||||
from api.schema_public import schema
|
||||
|
||||
from core.views import PrivateGraphQLView
|
||||
from core.views import SentryGraphQLView, PrivateGraphQLView
|
||||
|
||||
app_name = 'api'
|
||||
app_name = "api"
|
||||
urlpatterns = [
|
||||
url(r'^graphql-public', csrf_exempt(GraphQLView.as_view(schema=schema))),
|
||||
url(r'^graphql', csrf_exempt(PrivateGraphQLView.as_view())),
|
||||
|
||||
url(r"^graphql-public", csrf_exempt(SentryGraphQLView.as_view(schema=schema))),
|
||||
url(r"^graphql", csrf_exempt(PrivateGraphQLView.as_view())),
|
||||
# oauth
|
||||
url(r'^oauth/', include('oauth.urls', namespace="oauth")),
|
||||
url(r"^oauth/", include("oauth.urls", namespace="oauth")),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
urlpatterns += [url(r'^graphiql-public', csrf_exempt(GraphQLView.as_view(schema=schema, graphiql=True,
|
||||
pretty=True)))]
|
||||
urlpatterns += [url(r'^graphiql', csrf_exempt(PrivateGraphQLView.as_view(graphiql=True, pretty=True)))]
|
||||
|
||||
|
||||
urlpatterns += [
|
||||
url(
|
||||
r"^graphiql-public",
|
||||
csrf_exempt(
|
||||
SentryGraphQLView.as_view(schema=schema, graphiql=True, pretty=True)
|
||||
),
|
||||
)
|
||||
]
|
||||
urlpatterns += [
|
||||
url(
|
||||
r"^graphiql",
|
||||
csrf_exempt(PrivateGraphQLView.as_view(graphiql=True, pretty=True)),
|
||||
)
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Generated by Django 2.2.19 on 2021-03-15 21:43
|
||||
|
||||
from django.db import migrations
|
||||
import wagtail.core.fields
|
||||
import wagtail.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -14,6 +14,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='assignment',
|
||||
name='solution',
|
||||
field=wagtail.core.fields.RichTextField(blank=True, null=True),
|
||||
field=wagtail.fields.RichTextField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Generated by Django 3.2.13 on 2022-06-15 15:40
|
||||
|
||||
from django.db import migrations
|
||||
import wagtail.core.fields
|
||||
import wagtail.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -14,6 +14,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='assignment',
|
||||
name='assignment',
|
||||
field=wagtail.core.fields.RichTextField(),
|
||||
field=wagtail.fields.RichTextField(),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
# Generated by Django 3.2.16 on 2023-04-12 14:01
|
||||
|
||||
from django.db import migrations
|
||||
import django.db.models.deletion
|
||||
import modelcluster.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('books', '0042_alter_contentblock_contents'),
|
||||
('assignments', '0016_alter_assignment_options'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='assignment',
|
||||
name='module',
|
||||
field=modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.PROTECT, related_name='assignments', to='books.module'),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,14 +1,15 @@
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.db import models
|
||||
from django_extensions.db.models import TimeStampedModel
|
||||
from wagtail.admin.edit_handlers import FieldPanel
|
||||
from wagtail.core.fields import RichTextField
|
||||
from wagtail.admin.panels import FieldPanel
|
||||
from wagtail.fields import RichTextField
|
||||
from wagtail.snippets.models import register_snippet
|
||||
from wagtailautocomplete.edit_handlers import AutocompletePanel
|
||||
from wagtail.search import index
|
||||
|
||||
from core.constants import DEFAULT_RICH_TEXT_FEATURES
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from modelcluster.fields import ParentalKey
|
||||
|
||||
|
||||
@register_snippet
|
||||
|
|
@ -17,53 +18,69 @@ class Assignment(index.Indexed, TimeStampedModel):
|
|||
assignment = RichTextField(features=DEFAULT_RICH_TEXT_FEATURES)
|
||||
solution = RichTextField(null=True, blank=True, features=DEFAULT_RICH_TEXT_FEATURES)
|
||||
deleted = models.BooleanField(default=False)
|
||||
owner = models.ForeignKey(get_user_model(),
|
||||
on_delete=models.PROTECT, null=True,
|
||||
blank=True) # probably don't want to delete all assignments if a user gets deleted
|
||||
module = models.ForeignKey('books.Module', related_name='assignments', on_delete=models.CASCADE)
|
||||
owner = models.ForeignKey(
|
||||
get_user_model(), on_delete=models.PROTECT, null=True, blank=True
|
||||
) # probably don't want to delete all assignments if a user gets deleted
|
||||
module = ParentalKey(
|
||||
"books.Module", related_name="assignments", on_delete=models.PROTECT
|
||||
)
|
||||
user_created = models.BooleanField(default=False)
|
||||
taskbase_id = models.CharField(max_length=255, null=True, blank=True)
|
||||
|
||||
search_fields = [
|
||||
index.SearchField('title', partial_match=True),
|
||||
index.SearchField('assignment', partial_match=True),
|
||||
index.SearchField("title", partial_match=True),
|
||||
index.SearchField("assignment", partial_match=True),
|
||||
]
|
||||
|
||||
panels = [
|
||||
FieldPanel('title'),
|
||||
FieldPanel('assignment'),
|
||||
FieldPanel('solution'),
|
||||
FieldPanel('module'),
|
||||
AutocompletePanel('owner')
|
||||
FieldPanel("title"),
|
||||
FieldPanel("assignment"),
|
||||
FieldPanel("solution"),
|
||||
FieldPanel("module"),
|
||||
AutocompletePanel("owner"),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return self.title if not self.user_created else '{} (erstellt von {})'.format(self.title, self.owner)
|
||||
return (
|
||||
self.title
|
||||
if not self.user_created
|
||||
else "{} (erstellt von {})".format(self.title, self.owner)
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('assignment')
|
||||
verbose_name_plural = _('assignments')
|
||||
ordering = ['-created']
|
||||
verbose_name = _("assignment")
|
||||
verbose_name_plural = _("assignments")
|
||||
ordering = ["-created"]
|
||||
|
||||
|
||||
class StudentSubmission(TimeStampedModel):
|
||||
text = models.TextField(blank=True)
|
||||
document = models.URLField(blank=True, default='', max_length=255)
|
||||
assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE, related_name='submissions')
|
||||
student = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='submissions')
|
||||
document = models.URLField(blank=True, default="", max_length=255)
|
||||
assignment = models.ForeignKey(
|
||||
Assignment, on_delete=models.CASCADE, related_name="submissions"
|
||||
)
|
||||
student = models.ForeignKey(
|
||||
get_user_model(), on_delete=models.CASCADE, related_name="submissions"
|
||||
)
|
||||
final = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return '{} - {}'.format(self.student.full_name, self.text)
|
||||
return "{} - {}".format(self.student.full_name, self.text)
|
||||
|
||||
|
||||
class SubmissionFeedback(TimeStampedModel):
|
||||
text = models.TextField(blank=True)
|
||||
# teacher who created the feedback
|
||||
teacher = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='feedbacks')
|
||||
student_submission = models.OneToOneField(StudentSubmission, on_delete=models.CASCADE, primary_key=True,
|
||||
related_name='submission_feedback')
|
||||
teacher = models.ForeignKey(
|
||||
get_user_model(), on_delete=models.CASCADE, related_name="feedbacks"
|
||||
)
|
||||
student_submission = models.OneToOneField(
|
||||
StudentSubmission,
|
||||
on_delete=models.CASCADE,
|
||||
primary_key=True,
|
||||
related_name="submission_feedback",
|
||||
)
|
||||
final = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return '{} - {}'.format(self.student_submission.student.full_name, self.text)
|
||||
return "{} - {}".format(self.student_submission.student.full_name, self.text)
|
||||
|
|
|
|||
|
|
@ -10,51 +10,54 @@
|
|||
|
||||
from graphql_relay import to_global_id
|
||||
|
||||
from api.test_utils import create_client, DefaultUserTestCase
|
||||
from assignments.models import Assignment, StudentSubmission
|
||||
from api.test_utils import create_client
|
||||
from core.tests.base_test import SkillboxTestCase
|
||||
from users.factories import SchoolClassFactory
|
||||
from users.models import SchoolClassMember
|
||||
from .queries.mutations import UPDATE_SUBMISSION_FEEDBACK_MUTATION
|
||||
from ..factories import AssignmentFactory, StudentSubmissionFactory, SubmissionFeedbackFactory
|
||||
from ..factories import (
|
||||
AssignmentFactory,
|
||||
StudentSubmissionFactory,
|
||||
SubmissionFeedbackFactory,
|
||||
)
|
||||
|
||||
|
||||
class SubmissionFeedbackTestCase(SkillboxTestCase):
|
||||
def setUp(self):
|
||||
self.createDefault()
|
||||
|
||||
self.assignment = AssignmentFactory(
|
||||
owner=self.teacher
|
||||
)
|
||||
self.assignment_id = to_global_id('AssignmentNode', self.assignment.pk)
|
||||
self.assignment = AssignmentFactory(owner=self.teacher)
|
||||
self.assignment_id = to_global_id("AssignmentNode", self.assignment.pk)
|
||||
|
||||
self.student_submission = StudentSubmissionFactory(assignment=self.assignment, student=self.student1,
|
||||
final=False)
|
||||
self.student_submission_id = to_global_id('StudentSubmissionNode', self.student_submission.pk)
|
||||
self.student_submission = StudentSubmissionFactory(
|
||||
assignment=self.assignment, student=self.student1, final=False
|
||||
)
|
||||
self.student_submission_id = to_global_id(
|
||||
"StudentSubmissionNode", self.student_submission.pk
|
||||
)
|
||||
|
||||
school_class = SchoolClassFactory()
|
||||
for user in [self.student1, self.teacher]:
|
||||
SchoolClassMember.objects.create(
|
||||
user=user,
|
||||
school_class=school_class
|
||||
)
|
||||
SchoolClassMember.objects.create(user=user, school_class=school_class)
|
||||
user.set_selected_class(school_class)
|
||||
|
||||
|
||||
def _create_submission_feedback(self, user, final, text, student_submission_id):
|
||||
return self.get_client(user).execute(UPDATE_SUBMISSION_FEEDBACK_MUTATION, variables={
|
||||
'input': {
|
||||
"submissionFeedback": {
|
||||
"studentSubmission": student_submission_id,
|
||||
"text": text,
|
||||
"final": final
|
||||
return self.get_client(user).execute(
|
||||
UPDATE_SUBMISSION_FEEDBACK_MUTATION,
|
||||
variables={
|
||||
"input": {
|
||||
"submissionFeedback": {
|
||||
"studentSubmission": student_submission_id,
|
||||
"text": text,
|
||||
"final": final,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
def _fetch_assignment_student(self, user):
|
||||
client = self.get_client(user)
|
||||
query = '''
|
||||
query = """
|
||||
query AssignmentWithSubmissions($id: ID!) {
|
||||
assignment(id: $id) {
|
||||
title
|
||||
|
|
@ -68,14 +71,12 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
|||
}
|
||||
}
|
||||
}
|
||||
'''
|
||||
return client.execute(query, variables={
|
||||
'id': self.assignment_id
|
||||
})
|
||||
"""
|
||||
return client.execute(query, variables={"id": self.assignment_id})
|
||||
|
||||
def _fetch_assignment_teacher(self, user):
|
||||
client = self.get_client(user)
|
||||
query = '''
|
||||
query = """
|
||||
query AssignmentWithSubmissions($id: ID!) {
|
||||
assignment(id: $id) {
|
||||
title
|
||||
|
|
@ -89,14 +90,12 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
|||
}
|
||||
}
|
||||
}
|
||||
'''
|
||||
return client.execute(query, variables={
|
||||
'id': self.assignment_id
|
||||
})
|
||||
"""
|
||||
return client.execute(query, variables={"id": self.assignment_id})
|
||||
|
||||
def _fetch_submission_teacher(self, user):
|
||||
client = self.get_client(user)
|
||||
query = '''
|
||||
query = """
|
||||
query StudentSubmission($id: ID!) {
|
||||
studentSubmission(id: $id) {
|
||||
id
|
||||
|
|
@ -107,14 +106,12 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
|||
}
|
||||
}
|
||||
}
|
||||
'''
|
||||
return client.execute(query, variables={
|
||||
'id': self.student_submission_id
|
||||
})
|
||||
"""
|
||||
return client.execute(query, variables={"id": self.student_submission_id})
|
||||
|
||||
def _fetch_submission_feedback(self, user):
|
||||
client = create_client(user)
|
||||
query = '''
|
||||
query = """
|
||||
query AssignmentWithSubmissions($id: ID!) {
|
||||
assignment(id: $id) {
|
||||
title
|
||||
|
|
@ -128,96 +125,136 @@ class SubmissionFeedbackTestCase(SkillboxTestCase):
|
|||
}
|
||||
}
|
||||
}
|
||||
'''
|
||||
return client.execute(query, variables={
|
||||
'id': self.assignment_id
|
||||
})
|
||||
"""
|
||||
return client.execute(query, variables={"id": self.assignment_id})
|
||||
|
||||
def test_teacher_can_create_feedback(self):
|
||||
result = self._create_submission_feedback(self.teacher, False, 'Balalal', self.student_submission_id)
|
||||
result = self._create_submission_feedback(
|
||||
self.teacher, False, "Balalal", self.student_submission_id
|
||||
)
|
||||
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertIsNotNone(
|
||||
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.errors)
|
||||
self.assertEqual(len(result.errors), 1)
|
||||
self.assertEqual(result.errors[0].get('message'), 'Missing permissions')
|
||||
|
||||
def test_teacher_can_update_feedback(self):
|
||||
assignment = AssignmentFactory(
|
||||
owner=self.teacher
|
||||
result.data.get("updateSubmissionFeedback")
|
||||
.get("updatedSubmissionFeedback")
|
||||
.get("id")
|
||||
)
|
||||
|
||||
student_submission = StudentSubmissionFactory(assignment=assignment, student=self.student1, final=False)
|
||||
submission_feedback = SubmissionFeedbackFactory(teacher=self.teacher, final=False,
|
||||
student_submission=student_submission)
|
||||
submission_feedback_id = to_global_id('SubmissionFeedback', submission_feedback.pk)
|
||||
def test_student_cannot_create_feedback(self):
|
||||
result = self._create_submission_feedback(
|
||||
self.student1, False, "Balalal", self.student_submission_id
|
||||
)
|
||||
self.assertIsNotNone(result.errors)
|
||||
self.assertEqual(len(result.errors), 1)
|
||||
self.assertEqual(result.errors[0].get("message"), "Missing permissions")
|
||||
|
||||
result = self._create_submission_feedback(self.teacher, True, 'Some', submission_feedback_id)
|
||||
def test_teacher_can_update_feedback(self):
|
||||
assignment = AssignmentFactory(owner=self.teacher)
|
||||
|
||||
student_submission = StudentSubmissionFactory(
|
||||
assignment=assignment, student=self.student1, final=False
|
||||
)
|
||||
submission_feedback = SubmissionFeedbackFactory(
|
||||
teacher=self.teacher, final=False, student_submission=student_submission
|
||||
)
|
||||
submission_feedback_id = to_global_id(
|
||||
"SubmissionFeedback", submission_feedback.pk
|
||||
)
|
||||
|
||||
result = self._create_submission_feedback(
|
||||
self.teacher, True, "Some", submission_feedback_id
|
||||
)
|
||||
|
||||
self.assertIsNone(result.errors)
|
||||
|
||||
submission_feedback_response = result.data.get('updateSubmissionFeedback').get(
|
||||
'updatedSubmissionFeedback')
|
||||
|
||||
self.assertTrue(submission_feedback_response.get('final'))
|
||||
self.assertEqual(submission_feedback_response.get('text'), 'Some')
|
||||
|
||||
def test_external_teacher_cannot_update_feedback(self):
|
||||
assignment = AssignmentFactory(
|
||||
owner=self.teacher
|
||||
submission_feedback_response = result.data.get("updateSubmissionFeedback").get(
|
||||
"updatedSubmissionFeedback"
|
||||
)
|
||||
|
||||
student_submission = StudentSubmissionFactory(assignment=assignment, student=self.student1, final=False)
|
||||
submission_feedback = SubmissionFeedbackFactory(teacher=self.teacher, final=False,
|
||||
student_submission=student_submission)
|
||||
submission_feedback_id = to_global_id('SubmissionFeedback', submission_feedback.pk)
|
||||
self.assertTrue(submission_feedback_response.get("final"))
|
||||
self.assertEqual(submission_feedback_response.get("text"), "Some")
|
||||
|
||||
result = self._create_submission_feedback(self.teacher2, True, 'Some', submission_feedback_id)
|
||||
def test_external_teacher_cannot_update_feedback(self):
|
||||
assignment = AssignmentFactory(owner=self.teacher)
|
||||
|
||||
student_submission = StudentSubmissionFactory(
|
||||
assignment=assignment, student=self.student1, final=False
|
||||
)
|
||||
submission_feedback = SubmissionFeedbackFactory(
|
||||
teacher=self.teacher, final=False, student_submission=student_submission
|
||||
)
|
||||
submission_feedback_id = to_global_id(
|
||||
"SubmissionFeedback", submission_feedback.pk
|
||||
)
|
||||
|
||||
result = self._create_submission_feedback(
|
||||
self.teacher2, True, "Some", submission_feedback_id
|
||||
)
|
||||
|
||||
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)
|
||||
SubmissionFeedbackFactory(
|
||||
teacher=self.teacher,
|
||||
final=False,
|
||||
student_submission=self.student_submission,
|
||||
)
|
||||
result = self._fetch_assignment_student(self.student1)
|
||||
|
||||
self.assertIsNone(result.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)
|
||||
submission_feedback = SubmissionFeedbackFactory(
|
||||
teacher=self.teacher, final=True, student_submission=self.student_submission
|
||||
)
|
||||
result = self._fetch_assignment_student(self.student1)
|
||||
self.assertEqual(result.data.get('assignment').get('submission').get('submissionFeedback')
|
||||
.get('text'), submission_feedback.text)
|
||||
self.assertEqual(
|
||||
result.data.get("assignment")
|
||||
.get("submission")
|
||||
.get("submissionFeedback")
|
||||
.get("text"),
|
||||
submission_feedback.text,
|
||||
)
|
||||
|
||||
def test_teacher_can_see_feedback_for_submission(self):
|
||||
submission_feedback = SubmissionFeedbackFactory(teacher=self.teacher, final=False,
|
||||
student_submission=self.student_submission)
|
||||
submission_feedback = SubmissionFeedbackFactory(
|
||||
teacher=self.teacher,
|
||||
final=False,
|
||||
student_submission=self.student_submission,
|
||||
)
|
||||
self.student_submission.final = True
|
||||
self.student_submission.save()
|
||||
|
||||
result = self._fetch_assignment_teacher(self.teacher)
|
||||
self.assertEqual(result.data.get('assignment').get('submissions')[0].get('submissionFeedback')
|
||||
.get('text'), submission_feedback.text)
|
||||
self.assertEqual(
|
||||
result.data.get("assignment")
|
||||
.get("submissions")[0]
|
||||
.get("submissionFeedback")
|
||||
.get("text"),
|
||||
submission_feedback.text,
|
||||
)
|
||||
|
||||
def test_external_teacher_cannot_see_assignment_with_feedback(self):
|
||||
SubmissionFeedbackFactory(teacher=self.teacher, final=False,
|
||||
student_submission=self.student_submission)
|
||||
SubmissionFeedbackFactory(
|
||||
teacher=self.teacher,
|
||||
final=False,
|
||||
student_submission=self.student_submission,
|
||||
)
|
||||
self.student_submission.final = True
|
||||
self.student_submission.save()
|
||||
|
||||
result = self._fetch_assignment_teacher(self.teacher2)
|
||||
self.assertEqual(result.data.get('assignment').get('submissions'), [])
|
||||
self.assertEqual(result.data.get("assignment").get("submissions"), [])
|
||||
|
||||
def test_external_teacher_cannot_see_feedback(self):
|
||||
SubmissionFeedbackFactory(teacher=self.teacher, final=False,
|
||||
student_submission=self.student_submission)
|
||||
SubmissionFeedbackFactory(
|
||||
teacher=self.teacher,
|
||||
final=False,
|
||||
student_submission=self.student_submission,
|
||||
)
|
||||
self.student_submission.final = True
|
||||
self.student_submission.save()
|
||||
|
||||
result = self._fetch_submission_teacher(self.teacher2)
|
||||
self.assertIsNone(result.errors)
|
||||
self.assertIsNone(result.data.get('studentSubmission'))
|
||||
self.assertIsNone(result.data.get("studentSubmission"))
|
||||
|
|
|
|||
|
|
@ -1,35 +1,23 @@
|
|||
from django.conf import settings
|
||||
import json
|
||||
|
||||
from django.test import TestCase, RequestFactory
|
||||
from graphene.test import Client
|
||||
|
||||
from api import schema
|
||||
from api.schema import schema
|
||||
from api.test_utils import DefaultUserTestCase, create_client
|
||||
from assignments.factories import AssignmentFactory, StudentSubmissionFactory
|
||||
from assignments.models import Assignment
|
||||
from books.factories import ModuleFactory
|
||||
from books.models import ContentBlock, Chapter
|
||||
from core.factories import UserFactory
|
||||
from users.models import User
|
||||
from users.services import create_users
|
||||
|
||||
|
||||
class MyAssignmentsTest(DefaultUserTestCase):
|
||||
def setUp(self):
|
||||
super(MyAssignmentsTest, self).setUp()
|
||||
self.assignment = AssignmentFactory(
|
||||
owner=self.teacher
|
||||
)
|
||||
self.assignment = AssignmentFactory(owner=self.teacher)
|
||||
|
||||
self.submission1 = StudentSubmissionFactory(student=self.student1, assignment=self.assignment)
|
||||
self.submission2 = StudentSubmissionFactory(student=self.student2, assignment=self.assignment)
|
||||
self.submission1 = StudentSubmissionFactory(
|
||||
student=self.student1, assignment=self.assignment
|
||||
)
|
||||
self.submission2 = StudentSubmissionFactory(
|
||||
student=self.student2, assignment=self.assignment
|
||||
)
|
||||
|
||||
self.client = create_client(self.student1)
|
||||
|
||||
def query_my_assignments(self):
|
||||
query = '''
|
||||
query = """
|
||||
query MyActivityQuery {
|
||||
myActivity {
|
||||
edges {
|
||||
|
|
@ -138,20 +126,27 @@ class MyAssignmentsTest(DefaultUserTestCase):
|
|||
}
|
||||
}
|
||||
|
||||
'''
|
||||
"""
|
||||
|
||||
result = self.client.execute(query)
|
||||
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertIsNone(result.get("errors"))
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def get_content(result):
|
||||
return result.get('data').get('myActivity').get('edges')
|
||||
return result.get("data").get("myActivity").get("edges")
|
||||
|
||||
def test_my_assignment_query(self):
|
||||
result = self.query_my_assignments()
|
||||
contents = self.get_content(result)
|
||||
self.assertEqual(len(contents), 1)
|
||||
self.assertEquals(contents[0].get('node').get('mySubmissions').get('edges')[0].get('node').get('text'), self.submission1.text)
|
||||
|
||||
self.assertEquals(
|
||||
contents[0]
|
||||
.get("node")
|
||||
.get("mySubmissions")
|
||||
.get("edges")[0]
|
||||
.get("node")
|
||||
.get("text"),
|
||||
self.submission1.text,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ from datetime import timedelta, date
|
|||
from graphql_relay import to_global_id
|
||||
|
||||
from assignments.factories import AssignmentFactory, StudentSubmissionFactory
|
||||
from assignments.tests.queries.mutations import UPDATE_ASSIGNMENT_MUTATION, UPDATE_SUBMISSION_FEEDBACK_MUTATION
|
||||
from assignments.tests.queries.mutations import (
|
||||
UPDATE_ASSIGNMENT_MUTATION,
|
||||
UPDATE_SUBMISSION_FEEDBACK_MUTATION,
|
||||
)
|
||||
from core.tests.base_test import SkillboxTestCase
|
||||
from users.models import User
|
||||
|
||||
|
||||
class AssignmentReadOnlyTestCase(SkillboxTestCase):
|
||||
|
|
@ -18,7 +20,7 @@ class AssignmentReadOnlyTestCase(SkillboxTestCase):
|
|||
self.teacher.license_expiry_date = yesterday
|
||||
self.teacher.save()
|
||||
self.assignment = AssignmentFactory()
|
||||
self.assignment_id = to_global_id('AssignmentNode', self.assignment.id)
|
||||
self.assignment_id = to_global_id("AssignmentNode", self.assignment.id)
|
||||
|
||||
def test_edit_assignment_fails(self):
|
||||
variables = {
|
||||
|
|
@ -27,11 +29,13 @@ class AssignmentReadOnlyTestCase(SkillboxTestCase):
|
|||
"answer": "bla",
|
||||
"document": "",
|
||||
"final": False,
|
||||
"id": self.assignment_id
|
||||
"id": self.assignment_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
result = self.get_client(self.student1).execute(UPDATE_ASSIGNMENT_MUTATION, variables=variables)
|
||||
result = self.get_client(self.student1).execute(
|
||||
UPDATE_ASSIGNMENT_MUTATION, variables=variables
|
||||
)
|
||||
self.assertIsNotNone(result.errors)
|
||||
|
||||
def test_share_assignment_fails(self):
|
||||
|
|
@ -41,42 +45,55 @@ class AssignmentReadOnlyTestCase(SkillboxTestCase):
|
|||
"answer": "bla",
|
||||
"document": "",
|
||||
"final": True,
|
||||
"id": self.assignment_id
|
||||
"id": self.assignment_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
result = self.get_client(self.student1).execute(UPDATE_ASSIGNMENT_MUTATION, variables=variables)
|
||||
result = self.get_client(self.student1).execute(
|
||||
UPDATE_ASSIGNMENT_MUTATION, variables=variables
|
||||
)
|
||||
self.assertIsNotNone(result.errors)
|
||||
|
||||
def test_edit_feedback_fails(self):
|
||||
student_submission = StudentSubmissionFactory(assignment=self.assignment, student=self.student1,
|
||||
final=True)
|
||||
student_submission_id = to_global_id('StudentSubmissionNode', student_submission.id)
|
||||
result = self.get_client(self.teacher).execute(UPDATE_SUBMISSION_FEEDBACK_MUTATION, variables={
|
||||
'input': {
|
||||
"submissionFeedback": {
|
||||
"studentSubmission": student_submission_id,
|
||||
"text": "Feedback",
|
||||
"final": False
|
||||
student_submission = StudentSubmissionFactory(
|
||||
assignment=self.assignment, student=self.student1, final=True
|
||||
)
|
||||
student_submission_id = to_global_id(
|
||||
"StudentSubmissionNode", student_submission.id
|
||||
)
|
||||
result = self.get_client(self.teacher).execute(
|
||||
UPDATE_SUBMISSION_FEEDBACK_MUTATION,
|
||||
variables={
|
||||
"input": {
|
||||
"submissionFeedback": {
|
||||
"studentSubmission": student_submission_id,
|
||||
"text": "Feedback",
|
||||
"final": False,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
self.assertIsNotNone(result.errors)
|
||||
|
||||
|
||||
def test_share_feedback_fails(self):
|
||||
student_submission = StudentSubmissionFactory(assignment=self.assignment, student=self.student1,
|
||||
final=True)
|
||||
student_submission_id = to_global_id('StudentSubmissionNode', student_submission.id)
|
||||
result = self.get_client(self.teacher).execute(UPDATE_SUBMISSION_FEEDBACK_MUTATION, variables={
|
||||
'input': {
|
||||
"submissionFeedback": {
|
||||
"studentSubmission": student_submission_id,
|
||||
"text": "Feedback",
|
||||
"final": True
|
||||
student_submission = StudentSubmissionFactory(
|
||||
assignment=self.assignment, student=self.student1, final=True
|
||||
)
|
||||
student_submission_id = to_global_id(
|
||||
"StudentSubmissionNode", student_submission.id
|
||||
)
|
||||
result = self.get_client(self.teacher).execute(
|
||||
UPDATE_SUBMISSION_FEEDBACK_MUTATION,
|
||||
variables={
|
||||
"input": {
|
||||
"submissionFeedback": {
|
||||
"studentSubmission": student_submission_id,
|
||||
"text": "Feedback",
|
||||
"final": True,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
self.assertIsNotNone(result.errors)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ class Migration(migrations.Migration):
|
|||
name='BasicKnowledge',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')),
|
||||
('contents', wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())]))], blank=True, null=True)),
|
||||
('contents', wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock())])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())]))], blank=True, null=True)),
|
||||
('type', models.CharField(choices=[('language_communication', 'Sprache & Kommunikation'), ('society', 'Gesellschaft')], max_length=100)),
|
||||
],
|
||||
options={
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# Generated by Django 2.0.6 on 2019-07-22 09:32
|
||||
|
||||
from django.db import migrations
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
|
||||
|
||||
|
|
@ -16,6 +16,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='basicknowledge',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['bold', 'ul']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('section_title', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['bold', 'ul']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('section_title', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# Generated by Django 2.0.6 on 2019-11-28 16:01
|
||||
|
||||
from django.db import migrations
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
|
||||
|
||||
|
|
@ -16,6 +16,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='basicknowledge',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['bold', 'ul']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('section_title', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['bold', 'ul']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('section_title', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# Generated by Django 2.1.15 on 2020-05-20 09:54
|
||||
|
||||
from django.db import migrations
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
|
||||
|
||||
|
|
@ -16,6 +16,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='basicknowledge',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['bold', 'ul', 'brand', 'secondary']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('section_title', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['bold', 'ul', 'brand', 'secondary']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('section_title', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Generated by Django 2.2.12 on 2020-09-29 07:54
|
||||
|
||||
from django.db import migrations
|
||||
import wagtail.core.fields
|
||||
import wagtail.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -14,6 +14,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AddField(
|
||||
model_name='basicknowledge',
|
||||
name='intro',
|
||||
field=wagtail.core.fields.RichTextField(blank=True, default=''),
|
||||
field=wagtail.fields.RichTextField(blank=True, default=''),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# Generated by Django 3.2.13 on 2022-07-28 08:48
|
||||
|
||||
from django.db import migrations
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.documents.blocks
|
||||
import wagtail.images.blocks
|
||||
|
||||
|
|
@ -17,6 +17,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='basicknowledge',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['bold', 'ul', 'brand', 'secondary']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('section_title', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('cms_document_block', wagtail.documents.blocks.DocumentChooserBlock())], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['bold', 'ul', 'brand', 'secondary']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('section_title', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('cms_document_block', wagtail.documents.blocks.DocumentChooserBlock())], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
import books.blocks
|
||||
from django.db import migrations
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
|
||||
|
||||
|
|
@ -29,6 +29,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='basicknowledge',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['bold', 'ul', 'brand', 'secondary']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('section_title', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock())], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['bold', 'ul', 'brand', 'secondary']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('section_title', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock())], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 3.2.16 on 2023-02-21 16:04
|
||||
|
||||
import books.blocks
|
||||
from django.db import migrations
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basicknowledge', '0025_auto_20220914_1338'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='basicknowledge',
|
||||
name='contents',
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['bold', 'ul', 'brand', 'secondary']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('section_title', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock())], blank=True, null=True, use_json_field=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 3.2.16 on 2023-04-12 14:01
|
||||
|
||||
import books.blocks
|
||||
from django.db import migrations
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basicknowledge', '0026_alter_basicknowledge_contents'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='basicknowledge',
|
||||
name='contents',
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold', 'subscript', 'superscript', 'brand', 'secondary']))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('section_title', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock())], blank=True, null=True, use_json_field=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,35 +1,44 @@
|
|||
from django.db import models
|
||||
from django.utils.text import slugify
|
||||
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel
|
||||
from wagtail.core.fields import RichTextField, StreamField
|
||||
from wagtail.admin.panels import FieldPanel
|
||||
from wagtail.fields import RichTextField, StreamField
|
||||
from wagtail.images.blocks import ImageChooserBlock
|
||||
|
||||
from books.blocks import CMSDocumentBlock, DocumentBlock, GeniallyBlock, InfogramBlock, InstrumentTextBlock, LinkBlock, \
|
||||
SectionTitleBlock, \
|
||||
SubtitleBlock, ThinglinkBlock, VideoBlock
|
||||
from books.blocks import (
|
||||
CMSDocumentBlock,
|
||||
DocumentBlock,
|
||||
GeniallyBlock,
|
||||
InfogramBlock,
|
||||
InstrumentTextBlock,
|
||||
LinkBlock,
|
||||
SectionTitleBlock,
|
||||
SubtitleBlock,
|
||||
ThinglinkBlock,
|
||||
VideoBlock,
|
||||
)
|
||||
from core.constants import DEFAULT_RICH_TEXT_FEATURES
|
||||
from core.wagtail_utils import StrictHierarchyPage
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
LANGUAGE_COMMUNICATION = 'language_communication'
|
||||
SOCIETY = 'society'
|
||||
INTERDISCIPLINARY = 'interdisciplinary'
|
||||
LANGUAGE_COMMUNICATION_LABEL = 'Sprache & Kommunikation'
|
||||
SOCIETY_LABEL = 'Gesellschaft'
|
||||
INTERDISCIPLINARY_LABEL = 'Überfachliche Instrumente'
|
||||
LANGUAGE_COMMUNICATION = "language_communication"
|
||||
SOCIETY = "society"
|
||||
INTERDISCIPLINARY = "interdisciplinary"
|
||||
LANGUAGE_COMMUNICATION_LABEL = "Sprache & Kommunikation"
|
||||
SOCIETY_LABEL = "Gesellschaft"
|
||||
INTERDISCIPLINARY_LABEL = "Überfachliche Instrumente"
|
||||
|
||||
|
||||
class InstrumentCategory(models.Model):
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
background = models.CharField('background color', max_length=7)
|
||||
foreground = models.CharField('foreground color', max_length=7)
|
||||
background = models.CharField("background color", max_length=7)
|
||||
foreground = models.CharField("foreground color", max_length=7)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = _('instrument categories')
|
||||
verbose_name = _('instrument category')
|
||||
verbose_name_plural = _("instrument categories")
|
||||
verbose_name = _("instrument category")
|
||||
|
||||
|
||||
def default_category():
|
||||
|
|
@ -38,8 +47,8 @@ def default_category():
|
|||
|
||||
class InstrumentType(models.Model):
|
||||
class Meta:
|
||||
verbose_name = _('instrument type')
|
||||
verbose_name_plural = _('instrument types')
|
||||
verbose_name = _("instrument type")
|
||||
verbose_name_plural = _("instrument types")
|
||||
|
||||
CATEGORY_CHOICES = (
|
||||
(LANGUAGE_COMMUNICATION, LANGUAGE_COMMUNICATION_LABEL),
|
||||
|
|
@ -53,7 +62,7 @@ class InstrumentType(models.Model):
|
|||
on_delete=models.PROTECT,
|
||||
null=False,
|
||||
default=default_category,
|
||||
related_name='instrument_types'
|
||||
related_name="instrument_types",
|
||||
)
|
||||
|
||||
@property
|
||||
|
|
@ -64,42 +73,46 @@ class InstrumentType(models.Model):
|
|||
return self.type
|
||||
|
||||
|
||||
|
||||
class BasicKnowledge(StrictHierarchyPage):
|
||||
class Meta:
|
||||
verbose_name = _('instrument')
|
||||
verbose_name_plural = _('instruments')
|
||||
verbose_name = _("instrument")
|
||||
verbose_name_plural = _("instruments")
|
||||
|
||||
parent_page_types = ['books.book']
|
||||
parent_page_types = ["books.book"]
|
||||
|
||||
intro = RichTextField(features=DEFAULT_RICH_TEXT_FEATURES, default='', blank=True)
|
||||
intro = RichTextField(
|
||||
features=DEFAULT_RICH_TEXT_FEATURES, default="", blank=True)
|
||||
|
||||
contents = StreamField([
|
||||
('text_block', InstrumentTextBlock()),
|
||||
('image_block', ImageChooserBlock()),
|
||||
('link_block', LinkBlock()),
|
||||
('video_block', VideoBlock()),
|
||||
('document_block', DocumentBlock()),
|
||||
('section_title', SectionTitleBlock()),
|
||||
('infogram_block', InfogramBlock()),
|
||||
('genially_block', GeniallyBlock()),
|
||||
('thinglink_block', ThinglinkBlock()),
|
||||
('subtitle', SubtitleBlock()),
|
||||
('cms_document_block', CMSDocumentBlock()),
|
||||
], null=True, blank=True)
|
||||
contents = StreamField(
|
||||
[
|
||||
("text_block", InstrumentTextBlock()),
|
||||
("image_block", ImageChooserBlock()),
|
||||
("link_block", LinkBlock()),
|
||||
("video_block", VideoBlock()),
|
||||
("document_block", DocumentBlock()),
|
||||
("section_title", SectionTitleBlock()),
|
||||
("infogram_block", InfogramBlock()),
|
||||
("genially_block", GeniallyBlock()),
|
||||
("thinglink_block", ThinglinkBlock()),
|
||||
("subtitle", SubtitleBlock()),
|
||||
("cms_document_block", CMSDocumentBlock()),
|
||||
],
|
||||
null=True,
|
||||
blank=True,
|
||||
use_json_field=True,
|
||||
)
|
||||
|
||||
new_type = models.ForeignKey(InstrumentType, null=True, on_delete=models.PROTECT, related_name='instruments')
|
||||
new_type = models.ForeignKey(
|
||||
InstrumentType, null=True, on_delete=models.PROTECT, related_name="instruments"
|
||||
)
|
||||
|
||||
old_type = models.CharField(
|
||||
max_length=100,
|
||||
choices=InstrumentType.CATEGORY_CHOICES,
|
||||
blank=True
|
||||
max_length=100, choices=InstrumentType.CATEGORY_CHOICES, blank=True
|
||||
)
|
||||
|
||||
content_panels = [
|
||||
FieldPanel('title', classname="full title"),
|
||||
FieldPanel('new_type'),
|
||||
FieldPanel('intro'),
|
||||
StreamFieldPanel('contents')
|
||||
FieldPanel("title", classname="full title"),
|
||||
FieldPanel("new_type"),
|
||||
FieldPanel("intro"),
|
||||
FieldPanel("contents"),
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
from wagtail.contrib.modeladmin.options import ModelAdmin, ModelAdminGroup, modeladmin_register
|
||||
from wagtail.core import hooks
|
||||
from wagtail.contrib.modeladmin.options import (
|
||||
ModelAdmin,
|
||||
ModelAdminGroup,
|
||||
modeladmin_register,
|
||||
)
|
||||
from wagtail import hooks
|
||||
|
||||
from .models import BasicKnowledge, InstrumentCategory, InstrumentType
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
|
@ -7,33 +11,45 @@ from core.logger import get_logger
|
|||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class InstrumentAdmin(ModelAdmin):
|
||||
model = BasicKnowledge
|
||||
list_display = ('title', 'new_type', 'status_string')
|
||||
search_fields = ('title', 'new_type__name')
|
||||
list_display = ("title", "new_type", "status_string")
|
||||
search_fields = ("title", "new_type__name")
|
||||
|
||||
|
||||
class InstrumentCategoryAdmin(ModelAdmin):
|
||||
model = InstrumentCategory
|
||||
list_display = ('name', 'background', 'foreground')
|
||||
list_display = ("name", "background", "foreground")
|
||||
|
||||
|
||||
class InstrumentTypeAdmin(ModelAdmin):
|
||||
model = InstrumentType
|
||||
list_display = ('name', 'category',)
|
||||
list_display = (
|
||||
"name",
|
||||
"category",
|
||||
)
|
||||
inspect_view_enabled = True
|
||||
inspect_view_fields = ('name', 'category', 'instruments',)
|
||||
inspect_view_fields = (
|
||||
"name",
|
||||
"category",
|
||||
"instruments",
|
||||
)
|
||||
|
||||
|
||||
class InstrumentGroup(ModelAdminGroup):
|
||||
menu_label = _('Instruments')
|
||||
items = (InstrumentAdmin, InstrumentTypeAdmin, InstrumentCategoryAdmin,)
|
||||
menu_label = _("Instruments")
|
||||
items = (
|
||||
InstrumentAdmin,
|
||||
InstrumentTypeAdmin,
|
||||
InstrumentCategoryAdmin,
|
||||
)
|
||||
|
||||
|
||||
modeladmin_register(InstrumentGroup)
|
||||
|
||||
|
||||
@hooks.register('construct_page_chooser_queryset')
|
||||
@hooks.register("construct_page_chooser_queryset")
|
||||
def order_by_created(pages, request):
|
||||
logger.debug('constructing page chooser queryset')
|
||||
return pages.live().order_by('-latest_revision_created_at')
|
||||
logger.debug("constructing page chooser queryset")
|
||||
return pages.all().order_by("-latest_revision_created_at")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from wagtail.core import blocks
|
||||
from wagtail import blocks
|
||||
from wagtail.documents.blocks import DocumentChooserBlock
|
||||
from wagtail.snippets.blocks import SnippetChooserBlock
|
||||
|
||||
|
|
@ -6,16 +6,29 @@ from assignments.models import Assignment
|
|||
from core.constants import DEFAULT_RICH_TEXT_FEATURES, INSTRUMENTS_RICH_TEXT_FEATURES
|
||||
from surveys.models import Survey
|
||||
|
||||
"""
|
||||
Using a StructBlock inside a StreamField (e.g. inside a ContentBlock):
|
||||
as an illustration
|
||||
data = {'text': 'This is me'}
|
||||
self.contents.append(('solution', data))
|
||||
|
||||
by itself:
|
||||
block = SolutionBlock()
|
||||
data = {'text': 'This is me'}
|
||||
value = block.to_python(data)
|
||||
cleaned_value = block.clean(value)
|
||||
"""
|
||||
|
||||
|
||||
class CMSDocumentBlock(DocumentChooserBlock):
|
||||
class Meta:
|
||||
label = 'CMS Document'
|
||||
label = "CMS Document"
|
||||
|
||||
|
||||
# link_block
|
||||
class LinkBlock(blocks.StructBlock):
|
||||
class Meta:
|
||||
icon = 'link'
|
||||
icon = "link"
|
||||
|
||||
text = blocks.TextBlock()
|
||||
url = blocks.URLBlock()
|
||||
|
|
@ -24,14 +37,14 @@ class LinkBlock(blocks.StructBlock):
|
|||
# 'text_block' 'solution'
|
||||
class TextBlock(blocks.StructBlock):
|
||||
class Meta:
|
||||
icon = 'doc-full'
|
||||
icon = "doc-full"
|
||||
|
||||
text = blocks.RichTextBlock(features=DEFAULT_RICH_TEXT_FEATURES)
|
||||
|
||||
|
||||
class SolutionBlock(blocks.StructBlock):
|
||||
class Meta:
|
||||
icon = 'tick'
|
||||
icon = "tick"
|
||||
|
||||
text = blocks.RichTextBlock(features=DEFAULT_RICH_TEXT_FEATURES)
|
||||
document = CMSDocumentBlock(required=False)
|
||||
|
|
@ -40,17 +53,19 @@ class SolutionBlock(blocks.StructBlock):
|
|||
# 'basic_knowledge'
|
||||
class BasicKnowledgeBlock(blocks.StructBlock):
|
||||
class Meta:
|
||||
icon = 'placeholder'
|
||||
label = 'Instrument'
|
||||
icon = "placeholder"
|
||||
label = "Instrument"
|
||||
|
||||
description = blocks.RichTextBlock(required=False)
|
||||
basic_knowledge = blocks.PageChooserBlock(required=True, page_type='basicknowledge.BasicKnowledge')
|
||||
basic_knowledge = blocks.PageChooserBlock(
|
||||
required=True, page_type="basicknowledge.BasicKnowledge"
|
||||
)
|
||||
|
||||
|
||||
# 'image_url'
|
||||
class ImageUrlBlock(blocks.StructBlock):
|
||||
class Meta:
|
||||
icon = 'image'
|
||||
icon = "image"
|
||||
|
||||
title = blocks.TextBlock()
|
||||
url = blocks.URLBlock()
|
||||
|
|
@ -59,7 +74,7 @@ class ImageUrlBlock(blocks.StructBlock):
|
|||
# 'assignment'
|
||||
class AssignmentBlock(blocks.StructBlock):
|
||||
class Meta:
|
||||
icon = 'download'
|
||||
icon = "download"
|
||||
|
||||
assignment_id = SnippetChooserBlock(Assignment)
|
||||
|
||||
|
|
@ -67,7 +82,7 @@ class AssignmentBlock(blocks.StructBlock):
|
|||
# 'survey'
|
||||
class SurveyBlock(blocks.StructBlock):
|
||||
class Meta:
|
||||
icon = 'form'
|
||||
icon = "form"
|
||||
|
||||
survey_id = SnippetChooserBlock(Survey)
|
||||
|
||||
|
|
@ -75,7 +90,7 @@ class SurveyBlock(blocks.StructBlock):
|
|||
# 'video_block'
|
||||
class VideoBlock(blocks.StructBlock):
|
||||
class Meta:
|
||||
icon = 'media'
|
||||
icon = "media"
|
||||
|
||||
url = blocks.URLBlock()
|
||||
|
||||
|
|
@ -83,7 +98,7 @@ class VideoBlock(blocks.StructBlock):
|
|||
# 'document_block'
|
||||
class DocumentBlock(blocks.StructBlock):
|
||||
class Meta:
|
||||
icon = 'doc-full'
|
||||
icon = "doc-full"
|
||||
|
||||
url = blocks.URLBlock()
|
||||
|
||||
|
|
@ -111,21 +126,21 @@ class SubtitleBlock(blocks.StructBlock):
|
|||
|
||||
class InstrumentTextBlock(blocks.StructBlock):
|
||||
class Meta:
|
||||
icon = 'doc-full'
|
||||
icon = "doc-full"
|
||||
|
||||
text = blocks.RichTextBlock(features=INSTRUMENTS_RICH_TEXT_FEATURES)
|
||||
|
||||
|
||||
class ModuleRoomSlugBlock(blocks.StructBlock):
|
||||
class Meta:
|
||||
icon = 'link'
|
||||
icon = "link"
|
||||
|
||||
title = blocks.TextBlock()
|
||||
|
||||
|
||||
class InstructionBlock(blocks.StructBlock):
|
||||
class Meta:
|
||||
icon = 'help'
|
||||
icon = "help"
|
||||
|
||||
url = blocks.URLBlock(required=False)
|
||||
text = blocks.TextBlock(required=False)
|
||||
|
|
|
|||
|
|
@ -4,17 +4,43 @@ import factory
|
|||
import wagtail_factories
|
||||
from django.contrib.auth import get_user_model
|
||||
from factory import CREATE_STRATEGY
|
||||
from wagtail.core import blocks
|
||||
from wagtail.core.models import Page, Site
|
||||
from wagtail.core.rich_text import RichText
|
||||
from wagtail import blocks
|
||||
from wagtail.models import Page, Site
|
||||
from wagtail.rich_text import RichText
|
||||
|
||||
from assignments.models import Assignment
|
||||
from basicknowledge.models import BasicKnowledge, INTERDISCIPLINARY, INTERDISCIPLINARY_LABEL, InstrumentCategory, \
|
||||
InstrumentType, \
|
||||
LANGUAGE_COMMUNICATION, LANGUAGE_COMMUNICATION_LABEL, SOCIETY, SOCIETY_LABEL
|
||||
from books.blocks import AssignmentBlock, BasicKnowledgeBlock, ImageUrlBlock, LinkBlock, VideoBlock
|
||||
from basicknowledge.models import (
|
||||
BasicKnowledge,
|
||||
INTERDISCIPLINARY,
|
||||
INTERDISCIPLINARY_LABEL,
|
||||
InstrumentCategory,
|
||||
InstrumentType,
|
||||
LANGUAGE_COMMUNICATION,
|
||||
LANGUAGE_COMMUNICATION_LABEL,
|
||||
SOCIETY,
|
||||
SOCIETY_LABEL,
|
||||
)
|
||||
from books.blocks import (
|
||||
AssignmentBlock,
|
||||
BasicKnowledgeBlock,
|
||||
ImageUrlBlock,
|
||||
LinkBlock,
|
||||
SurveyBlock,
|
||||
VideoBlock,
|
||||
)
|
||||
from books.models import Book, Chapter, ContentBlock, Module, TextBlock, Topic
|
||||
from core.factories import BasePageFactory, DummyImageFactory, fake, fake_paragraph, fake_title
|
||||
from core.factories import (
|
||||
BasePageFactory,
|
||||
DummyImageFactory,
|
||||
fake,
|
||||
fake_paragraph,
|
||||
fake_title,
|
||||
)
|
||||
from core.logger import get_logger
|
||||
from surveys.factories import SurveyFactory
|
||||
from surveys.models import Survey
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class BookFactory(BasePageFactory):
|
||||
|
|
@ -24,18 +50,25 @@ class BookFactory(BasePageFactory):
|
|||
@staticmethod
|
||||
def create_default_structure():
|
||||
site = wagtail_factories.SiteFactory.create(is_default_site=True)
|
||||
Page.objects.get(title='Root').delete()
|
||||
Page.objects.get(title="Root").delete()
|
||||
|
||||
book = BookFactory.create(parent=site.root_page, title='A book')
|
||||
topic = TopicFactory.create(parent=book, order=1, title='A topic')
|
||||
module = ModuleFactory.create(parent=topic,
|
||||
title="A module",
|
||||
meta_title="Modul 1",
|
||||
teaser="Whatever",
|
||||
intro="<p>Hello</p>")
|
||||
book = BookFactory.create(parent=site.root_page, title="A book")
|
||||
topic = TopicFactory.create(parent=book, order=1, title="A topic")
|
||||
module = ModuleFactory.create(
|
||||
parent=topic,
|
||||
title="A module",
|
||||
meta_title="Modul 1",
|
||||
teaser="Whatever",
|
||||
intro="<p>Hello</p>",
|
||||
)
|
||||
chapter = ChapterFactory.create(parent=module, title="A chapter")
|
||||
content_block = ContentBlockFactory.create(parent=chapter, module=module, title="A content block", type="task",
|
||||
contents=[])
|
||||
content_block = ContentBlockFactory.create(
|
||||
parent=chapter,
|
||||
module=module,
|
||||
title="A content block",
|
||||
type="task",
|
||||
contents=[],
|
||||
)
|
||||
|
||||
return book, topic, module, chapter, content_block
|
||||
|
||||
|
|
@ -45,7 +78,9 @@ class TopicFactory(BasePageFactory):
|
|||
model = Topic
|
||||
|
||||
order = 0
|
||||
teaser = factory.LazyAttribute(lambda x: fake.sentence(nb_words=random.randint(8, 12)))
|
||||
teaser = factory.LazyAttribute(
|
||||
lambda x: fake.sentence(nb_words=random.randint(8, 12))
|
||||
)
|
||||
description = factory.LazyAttribute(lambda x: fake.text(max_nb_chars=200))
|
||||
|
||||
|
||||
|
|
@ -54,7 +89,9 @@ class ModuleFactory(BasePageFactory):
|
|||
model = Module
|
||||
|
||||
meta_title = factory.LazyAttribute(lambda x: fake.text(max_nb_chars=20))
|
||||
teaser = factory.LazyAttribute(lambda x: fake.sentence(nb_words=random.randint(8, 12)))
|
||||
teaser = factory.LazyAttribute(
|
||||
lambda x: fake.sentence(nb_words=random.randint(8, 12))
|
||||
)
|
||||
intro = factory.LazyAttribute(lambda x: fake.text(max_nb_chars=200))
|
||||
|
||||
hero_image = factory.SubFactory(DummyImageFactory)
|
||||
|
|
@ -75,11 +112,14 @@ class TextBlockFactory(wagtail_factories.StructBlockFactory):
|
|||
class InstrumentCategoryFactory(factory.DjangoModelFactory):
|
||||
class Meta:
|
||||
model = InstrumentCategory
|
||||
django_get_or_create = ('name',)
|
||||
django_get_or_create = ("name",)
|
||||
|
||||
name = factory.Iterator(
|
||||
[LANGUAGE_COMMUNICATION_LABEL, SOCIETY_LABEL, INTERDISCIPLINARY_LABEL]
|
||||
)
|
||||
foreground = factory.Iterator(["FF0000", "FFFFFF", "000000"])
|
||||
background = factory.Iterator(["FF0000", "FFFFFF", "000000"])
|
||||
|
||||
name = factory.Iterator([LANGUAGE_COMMUNICATION_LABEL, SOCIETY_LABEL, INTERDISCIPLINARY_LABEL])
|
||||
foreground = factory.Iterator(['FF0000', 'FFFFFF', '000000'])
|
||||
background = factory.Iterator(['FF0000', 'FFFFFF', '000000'])
|
||||
|
||||
class InstrumentTypeFactory(factory.DjangoModelFactory):
|
||||
class Meta:
|
||||
|
|
@ -99,7 +139,7 @@ class InstrumentFactory(BasePageFactory):
|
|||
|
||||
@classmethod
|
||||
def _create(cls, model_class, *args, **kwargs):
|
||||
kwargs['parent'] = Site.objects.get(is_default_site=True).root_page
|
||||
kwargs["parent"] = Site.objects.get(is_default_site=True).root_page
|
||||
return super()._create(model_class, *args, **kwargs)
|
||||
|
||||
|
||||
|
|
@ -113,7 +153,7 @@ class BasicKnowledgeBlockFactory(wagtail_factories.StructBlockFactory):
|
|||
|
||||
class ImageUrlBlockFactory(wagtail_factories.StructBlockFactory):
|
||||
title = fake_title()
|
||||
url = factory.LazyAttribute(lambda x: 'https://picsum.photos/600/400/?random')
|
||||
url = factory.LazyAttribute(lambda x: "https://picsum.photos/600/400/?random")
|
||||
|
||||
class Meta:
|
||||
model = ImageUrlBlock
|
||||
|
|
@ -121,127 +161,202 @@ class ImageUrlBlockFactory(wagtail_factories.StructBlockFactory):
|
|||
|
||||
class LinkBlockFactory(wagtail_factories.StructBlockFactory):
|
||||
text = fake_title()
|
||||
url = factory.LazyAttribute(lambda x: 'https://picsum.photos/600/400/?random')
|
||||
url = factory.LazyAttribute(lambda x: "https://picsum.photos/600/400/?random")
|
||||
|
||||
class Meta:
|
||||
model = LinkBlock
|
||||
|
||||
|
||||
class AssignmentBlockFactory(wagtail_factories.StructBlockFactory):
|
||||
class Meta:
|
||||
model = AssignmentBlock
|
||||
|
||||
class EntityBlockFactory(wagtail_factories.StructBlockFactory):
|
||||
@classmethod
|
||||
def _build(cls, model_class, *args, **kwargs):
|
||||
block = model_class()
|
||||
return blocks.StructValue(
|
||||
block,
|
||||
# todo: build in a more generic fashion
|
||||
[
|
||||
(name, kwargs['assignment']) for name, child_block in block.child_blocks.items()
|
||||
],
|
||||
)
|
||||
logger.debug(cls.id_key)
|
||||
logger.debug(cls.entity_key)
|
||||
logger.debug(kwargs)
|
||||
value = block.to_python({cls.id_key: kwargs.get(cls.entity_key).id})
|
||||
clean_value = block.clean(value)
|
||||
return clean_value
|
||||
|
||||
|
||||
class AssignmentBlockFactory(EntityBlockFactory):
|
||||
class Meta:
|
||||
model = AssignmentBlock
|
||||
|
||||
id_key = "assignment_id"
|
||||
entity_key = "assignment"
|
||||
|
||||
|
||||
class SurveyBlockFactory(EntityBlockFactory):
|
||||
class Meta:
|
||||
model = SurveyBlock
|
||||
|
||||
id_key = "survey_id"
|
||||
entity_key = "survey"
|
||||
|
||||
|
||||
class VideoBlockFactory(wagtail_factories.StructBlockFactory):
|
||||
url = factory.LazyAttribute(lambda x: 'https://www.youtube.com/watch?v=lO9d-AJai8Q')
|
||||
url = factory.LazyAttribute(lambda x: "https://www.youtube.com/watch?v=lO9d-AJai8Q")
|
||||
|
||||
class Meta:
|
||||
model = VideoBlock
|
||||
|
||||
|
||||
block_types = ['text_block', 'basic_knowledge', 'student_entry', 'image_url_block', 'solution']
|
||||
block_types = [
|
||||
"text_block",
|
||||
"basic_knowledge",
|
||||
"student_entry",
|
||||
"image_url_block",
|
||||
"solution",
|
||||
]
|
||||
|
||||
|
||||
class ContentBlockFactory(BasePageFactory):
|
||||
class Meta:
|
||||
model = ContentBlock
|
||||
|
||||
type = factory.LazyAttribute(lambda x: random.choice(['normal', 'instrument', 'task',]))
|
||||
type = factory.LazyAttribute(
|
||||
lambda x: random.choice(
|
||||
[
|
||||
"normal",
|
||||
"instrument",
|
||||
"task",
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
contents = wagtail_factories.StreamFieldFactory({
|
||||
'text_block': TextBlockFactory,
|
||||
'basic_knowledge': BasicKnowledgeBlockFactory,
|
||||
'assignment': AssignmentBlockFactory,
|
||||
'image_block': wagtail_factories.ImageChooserBlockFactory,
|
||||
'image_url_block': ImageUrlBlockFactory,
|
||||
'link_block': LinkBlockFactory,
|
||||
'video_block': VideoBlockFactory,
|
||||
'solution': TextBlockFactory
|
||||
})
|
||||
contents = wagtail_factories.StreamFieldFactory(
|
||||
{
|
||||
"text_block": TextBlockFactory,
|
||||
"basic_knowledge": BasicKnowledgeBlockFactory,
|
||||
"assignment": AssignmentBlockFactory,
|
||||
"image_block": wagtail_factories.ImageChooserBlockFactory,
|
||||
"image_url_block": ImageUrlBlockFactory,
|
||||
"link_block": LinkBlockFactory,
|
||||
"video_block": VideoBlockFactory,
|
||||
"solution": TextBlockFactory,
|
||||
"survey": SurveyBlockFactory,
|
||||
}
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def stream_field_magic(cls, module, kwargs, stream_field_name):
|
||||
if stream_field_name in kwargs:
|
||||
"""
|
||||
"""
|
||||
stream_field_name is most likely 'contents'
|
||||
this means: if there is a property named contents, use the defined ones in this block.
|
||||
otherwise, go into the other block and randomize the contents
|
||||
"""
|
||||
for idx, resource in enumerate(kwargs[stream_field_name]):
|
||||
value = resource['value']
|
||||
block_type = resource['type']
|
||||
value = resource["value"]
|
||||
block_type = resource["type"]
|
||||
|
||||
if block_type == 'assignment':
|
||||
if block_type == "assignment":
|
||||
user = get_user_model().objects.first()
|
||||
assignment = Assignment.objects.create(
|
||||
title=value['title'],
|
||||
assignment=value['assignment'],
|
||||
title=value["title"],
|
||||
assignment=value["assignment"],
|
||||
owner=user,
|
||||
module=module
|
||||
module=module,
|
||||
)
|
||||
kwargs['{}__{}__{}__{}'.format(stream_field_name, idx, block_type, 'assignment')] = assignment
|
||||
kwargs[
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, idx, block_type, "assignment"
|
||||
)
|
||||
] = assignment
|
||||
elif block_type == "survey":
|
||||
survey = Survey.objects.create(
|
||||
title=value["title"], data=value["data"], module=module
|
||||
)
|
||||
kwargs[
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, idx, block_type, "survey"
|
||||
)
|
||||
] = survey
|
||||
else:
|
||||
for jdx, field in enumerate(value):
|
||||
|
||||
if block_type == 'text_block':
|
||||
kwargs['{}__{}__{}__{}'.format(stream_field_name, idx, block_type, field)] = RichText(
|
||||
value[field])
|
||||
elif block_type == 'solution':
|
||||
kwargs['{}__{}__{}__{}'.format(stream_field_name, idx, block_type, field)] = RichText(
|
||||
value[field])
|
||||
elif block_type == 'basic_knowledge':
|
||||
if field == 'description':
|
||||
if block_type == "text_block":
|
||||
kwargs[
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, idx, block_type, field
|
||||
)
|
||||
] = RichText(value[field])
|
||||
elif block_type == "solution":
|
||||
kwargs[
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, idx, block_type, field
|
||||
)
|
||||
] = RichText(value[field])
|
||||
elif block_type == "basic_knowledge":
|
||||
if field == "description":
|
||||
kwargs[
|
||||
'{}__{}__{}__{}'.format(stream_field_name, idx, block_type, field)] = RichText(
|
||||
value[field])
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, idx, block_type, field
|
||||
)
|
||||
] = RichText(value[field])
|
||||
else:
|
||||
kwargs[
|
||||
'{}__{}__{}__{}'.format(stream_field_name, idx, block_type,
|
||||
field)] = 'https://google.ch'
|
||||
elif block_type == 'image_url_block':
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, idx, block_type, field
|
||||
)
|
||||
] = "https://google.ch"
|
||||
elif block_type == "image_url_block":
|
||||
kwargs[
|
||||
'{}__{}__{}__{}'.format(stream_field_name, idx, block_type, field)] = value[field]
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, idx, block_type, field
|
||||
)
|
||||
] = value[field]
|
||||
|
||||
else:
|
||||
kwargs[
|
||||
'{}__{}__{}__{}'.format(stream_field_name, idx, block_type, field)] = value[field]
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, idx, block_type, field
|
||||
)
|
||||
] = value[field]
|
||||
|
||||
del kwargs[stream_field_name]
|
||||
else: # random contents from generator
|
||||
for i in range(0, random.randint(3, 7)):
|
||||
block_type = random.choice(block_types)
|
||||
if block_type == 'text_block':
|
||||
kwargs['{}__{}__{}__{}'.format(stream_field_name, i, 'text_block', 'text')] = RichText(
|
||||
fake_paragraph())
|
||||
elif block_type == 'basic_knowledge':
|
||||
kwargs['{}__{}__{}__{}'.format(stream_field_name, i, 'basic_knowledge', 'description')] = RichText(
|
||||
fake_paragraph())
|
||||
elif block_type == 'assignment':
|
||||
kwargs['{}__{}__{}__{}'.format(stream_field_name, i, 'assignment', 'task_text')] = RichText(
|
||||
fake_paragraph())
|
||||
elif block_type == 'image_url_block':
|
||||
if block_type == "text_block":
|
||||
kwargs[
|
||||
'{}__{}__{}__{}'.format(stream_field_name, i, 'image_url_block', 'title')] = fake_paragraph()
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, i, "text_block", "text"
|
||||
)
|
||||
] = RichText(fake_paragraph())
|
||||
elif block_type == "basic_knowledge":
|
||||
kwargs[
|
||||
'{}__{}__{}__{}'.format(stream_field_name, i, 'image_url_block',
|
||||
'url')] = 'https://picsum.photos/400/?random={}'.format(
|
||||
''.join(random.choice('abcdefghiklmn') for _ in range(6)))
|
||||
elif block_type == 'solution':
|
||||
kwargs['{}__{}__{}__{}'.format(stream_field_name, i, 'solution', 'text')] = RichText(
|
||||
fake_paragraph())
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, i, "basic_knowledge", "description"
|
||||
)
|
||||
] = RichText(fake_paragraph())
|
||||
elif block_type == "assignment":
|
||||
kwargs[
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, i, "assignment", "task_text"
|
||||
)
|
||||
] = RichText(fake_paragraph())
|
||||
elif block_type == "image_url_block":
|
||||
kwargs[
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, i, "image_url_block", "title"
|
||||
)
|
||||
] = fake_paragraph()
|
||||
kwargs[
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, i, "image_url_block", "url"
|
||||
)
|
||||
] = "https://picsum.photos/400/?random={}".format(
|
||||
"".join(random.choice("abcdefghiklmn") for _ in range(6))
|
||||
)
|
||||
elif block_type == "solution":
|
||||
kwargs[
|
||||
"{}__{}__{}__{}".format(
|
||||
stream_field_name, i, "solution", "text"
|
||||
)
|
||||
] = RichText(fake_paragraph())
|
||||
|
||||
@classmethod
|
||||
def create(cls, module, **kwargs):
|
||||
cls.stream_field_magic(module, kwargs, 'contents')
|
||||
cls.stream_field_magic(module, kwargs, "contents")
|
||||
return cls._generate(CREATE_STRATEGY, kwargs)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from wagtail.core.models import PageManager
|
||||
from wagtail.models import PageManager
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from core.logger import get_logger
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ class Migration(migrations.Migration):
|
|||
fields=[
|
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')),
|
||||
('user_created', models.BooleanField(default=False)),
|
||||
('contents', wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.core.blocks.IntegerBlock())])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('task', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())]))], blank=True, null=True)),
|
||||
('contents', wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock())])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock()), ('url', wagtail.blocks.URLBlock())])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.blocks.IntegerBlock())])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('task', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock())], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())]))], blank=True, null=True)),
|
||||
('type', models.CharField(choices=[('plain', 'Normal'), ('yellow', 'Gelb'), ('green', 'Grün'), ('blue', 'Blau')], default='plain', max_length=100)),
|
||||
],
|
||||
options={
|
||||
|
|
@ -61,7 +61,7 @@ class Migration(migrations.Migration):
|
|||
('order', models.PositiveIntegerField(help_text='Order of the module')),
|
||||
('meta_title', models.CharField(help_text="e.g. 'Intro' or 'Modul 1'", max_length=255)),
|
||||
('teaser', models.TextField()),
|
||||
('intro', wagtail.core.fields.RichTextField()),
|
||||
('intro', wagtail.fields.RichTextField()),
|
||||
('hero_image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.Image')),
|
||||
],
|
||||
options={
|
||||
|
|
@ -76,7 +76,7 @@ class Migration(migrations.Migration):
|
|||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')),
|
||||
('order', models.PositiveIntegerField(help_text='Order of the topic')),
|
||||
('teaser', models.TextField()),
|
||||
('description', wagtail.core.fields.RichTextField()),
|
||||
('description', wagtail.fields.RichTextField()),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Thema',
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# Generated by Django 2.0.6 on 2018-10-25 11:55
|
||||
|
||||
from django.db import migrations
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
|
||||
|
||||
|
|
@ -16,6 +16,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock()), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.core.blocks.IntegerBlock())])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('task', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock())])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock()), ('basic_knowledge', wagtail.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.blocks.IntegerBlock())])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('task', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock())], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
import assignments.models
|
||||
from django.db import migrations
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
import wagtail.snippets.blocks
|
||||
|
||||
|
|
@ -18,6 +18,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock()), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('task', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock())])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock()), ('basic_knowledge', wagtail.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('task', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock())], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
import assignments.models
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
import wagtail.snippets.blocks
|
||||
|
||||
|
|
@ -25,6 +25,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock()), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock())])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock()), ('basic_knowledge', wagtail.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock())], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
import assignments.models
|
||||
from django.db import migrations
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
import wagtail.snippets.blocks
|
||||
|
||||
|
|
@ -18,6 +18,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock()), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock())])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock()), ('basic_knowledge', wagtail.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock())], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
import assignments.models
|
||||
from django.db import migrations, models
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
import wagtail.snippets.blocks
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock())], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock())])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock())], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())]))], blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
import assignments.models
|
||||
from django.db import migrations
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
import wagtail.snippets.blocks
|
||||
|
||||
|
|
@ -18,6 +18,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('content_list_item', wagtail.core.blocks.StreamBlock([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())]))]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('content_list_item', wagtail.blocks.StreamBlock([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())]))]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
import assignments.models
|
||||
from django.db import migrations
|
||||
import surveys.models
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
import wagtail.snippets.blocks
|
||||
|
||||
|
|
@ -19,6 +19,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())])), ('content_list_item', wagtail.core.blocks.StreamBlock([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())]))]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('content_list_item', wagtail.blocks.StreamBlock([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())]))]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
import assignments.models
|
||||
from django.db import migrations
|
||||
import surveys.models
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
import wagtail.snippets.blocks
|
||||
|
||||
|
|
@ -19,6 +19,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())])), ('content_list_item', wagtail.core.blocks.StreamBlock([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())]))]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('content_list_item', wagtail.blocks.StreamBlock([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())]))]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
import assignments.models
|
||||
from django.db import migrations
|
||||
import surveys.models
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
import wagtail.snippets.blocks
|
||||
|
||||
|
|
@ -19,6 +19,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('instruction', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock()), ('text', wagtail.core.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())])), ('content_list_item', wagtail.core.blocks.StreamBlock([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('instruction', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock()), ('text', wagtail.core.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())]))]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock()), ('text', wagtail.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('content_list_item', wagtail.blocks.StreamBlock([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock()), ('text', wagtail.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())]))]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
import assignments.models
|
||||
from django.db import migrations
|
||||
import surveys.models
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
import wagtail.snippets.blocks
|
||||
|
||||
|
|
@ -19,6 +19,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('instruction', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock()), ('text', wagtail.core.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())])), ('content_list_item', wagtail.core.blocks.StreamBlock([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('instruction', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock()), ('text', wagtail.core.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())]))]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold']))], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock()), ('text', wagtail.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('content_list_item', wagtail.blocks.StreamBlock([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold']))], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock()), ('text', wagtail.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())]))]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ from django.db import migrations, models
|
|||
import django.db.models.deletion
|
||||
import surveys.models
|
||||
import taggit.managers
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.core.models.collections
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.models.collections
|
||||
import wagtail.documents.blocks
|
||||
import wagtail.images.blocks
|
||||
import wagtail.search.index
|
||||
|
|
@ -28,7 +28,7 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('instruction', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock()), ('text', wagtail.core.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())])), ('cms_document_block', wagtail.documents.blocks.DocumentChooserBlock()), ('content_list_item', wagtail.core.blocks.StreamBlock([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('instruction', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock()), ('text', wagtail.core.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())])), ('cms_document_block', wagtail.documents.blocks.DocumentChooserBlock())]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold']))], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock()), ('text', wagtail.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('cms_document_block', wagtail.documents.blocks.DocumentChooserBlock()), ('content_list_item', wagtail.blocks.StreamBlock([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold']))], icon='tick')), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock()), ('text', wagtail.blocks.TextBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('cms_document_block', wagtail.documents.blocks.DocumentChooserBlock())]))], blank=True, null=True),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='CustomDocument',
|
||||
|
|
@ -40,7 +40,7 @@ class Migration(migrations.Migration):
|
|||
('file_size', models.PositiveIntegerField(editable=False, null=True)),
|
||||
('file_hash', models.CharField(blank=True, editable=False, max_length=40)),
|
||||
('display_text', models.CharField(default='', max_length=1024)),
|
||||
('collection', models.ForeignKey(default=wagtail.core.models.collections.get_root_collection_id, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.collection', verbose_name='collection')),
|
||||
('collection', models.ForeignKey(default=wagtail.models.collections.get_root_collection_id, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.collection', verbose_name='collection')),
|
||||
('tags', taggit.managers.TaggableManager(blank=True, help_text=None, through='taggit.TaggedItem', to='taggit.Tag', verbose_name='tags')),
|
||||
('uploaded_by_user', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='uploaded by user')),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import assignments.models
|
|||
import books.blocks
|
||||
from django.db import migrations
|
||||
import surveys.models
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.documents.blocks
|
||||
import wagtail.images.blocks
|
||||
import wagtail.snippets.blocks
|
||||
|
|
@ -21,6 +21,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold'])), ('document', books.blocks.CMSDocumentBlock(required=False))])), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('instruction', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock(required=False)), ('text', wagtail.core.blocks.TextBlock(required=False)), ('document', wagtail.documents.blocks.DocumentChooserBlock(required=False))])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock()), ('content_list_item', wagtail.core.blocks.StreamBlock([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul', 'bold'])), ('document', books.blocks.CMSDocumentBlock(required=False))])), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('thinglink_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('instruction', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock(required=False)), ('text', wagtail.core.blocks.TextBlock(required=False)), ('document', wagtail.documents.blocks.DocumentChooserBlock(required=False))])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock())]))], blank=True, null=True),
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold'])), ('document', books.blocks.CMSDocumentBlock(required=False))])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock(required=False)), ('text', wagtail.blocks.TextBlock(required=False)), ('document', wagtail.documents.blocks.DocumentChooserBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock()), ('content_list_item', wagtail.blocks.StreamBlock([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold'])), ('document', books.blocks.CMSDocumentBlock(required=False))])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock(required=False)), ('text', wagtail.blocks.TextBlock(required=False)), ('document', wagtail.documents.blocks.DocumentChooserBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock())]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
# Generated by Django 3.2.16 on 2023-02-21 16:04
|
||||
|
||||
import assignments.models
|
||||
import books.blocks
|
||||
from django.db import migrations
|
||||
import surveys.models
|
||||
import wagtail.blocks
|
||||
import wagtail.documents.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
import wagtail.snippets.blocks
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('books', '0040_module_hero_source'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold'])), ('document', books.blocks.CMSDocumentBlock(required=False))])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock(required=False)), ('text', wagtail.blocks.TextBlock(required=False)), ('document', wagtail.documents.blocks.DocumentChooserBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock()), ('content_list_item', wagtail.blocks.StreamBlock([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold'])), ('document', books.blocks.CMSDocumentBlock(required=False))])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock(required=False)), ('text', wagtail.blocks.TextBlock(required=False)), ('document', wagtail.documents.blocks.DocumentChooserBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock())]))], blank=True, null=True, use_json_field=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# Generated by Django 3.2.16 on 2023-04-12 14:01
|
||||
|
||||
import assignments.models
|
||||
import books.blocks
|
||||
from django.db import migrations
|
||||
import surveys.models
|
||||
import wagtail.blocks
|
||||
import wagtail.documents.blocks
|
||||
import wagtail.fields
|
||||
import wagtail.images.blocks
|
||||
import wagtail.snippets.blocks
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('books', '0041_alter_contentblock_contents'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.fields.StreamField([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold', 'subscript', 'superscript']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold', 'subscript', 'superscript'])), ('document', books.blocks.CMSDocumentBlock(required=False))])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock(required=False)), ('text', wagtail.blocks.TextBlock(required=False)), ('document', wagtail.documents.blocks.DocumentChooserBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock()), ('content_list_item', wagtail.blocks.StreamBlock([('text_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold', 'subscript', 'superscript']))])), ('basic_knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.blocks.PageChooserBlock(page_type=['basicknowledge.BasicKnowledge'], required=True))])), ('assignment', wagtail.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('solution', wagtail.blocks.StructBlock([('text', wagtail.blocks.RichTextBlock(features=['ul', 'bold', 'subscript', 'superscript'])), ('document', books.blocks.CMSDocumentBlock(required=False))])), ('video_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('document_block', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock())])), ('infogram_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock()), ('title', wagtail.blocks.TextBlock())])), ('genially_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('thinglink_block', wagtail.blocks.StructBlock([('id', wagtail.blocks.TextBlock())])), ('subtitle', wagtail.blocks.StructBlock([('text', wagtail.blocks.TextBlock())])), ('instruction', wagtail.blocks.StructBlock([('url', wagtail.blocks.URLBlock(required=False)), ('text', wagtail.blocks.TextBlock(required=False)), ('document', wagtail.documents.blocks.DocumentChooserBlock(required=False))])), ('module_room_slug', wagtail.blocks.StructBlock([('title', wagtail.blocks.TextBlock())])), ('cms_document_block', books.blocks.CMSDocumentBlock())]))], blank=True, null=True, use_json_field=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import logging
|
||||
|
||||
from wagtail.admin.edit_handlers import FieldPanel, TabbedInterface, ObjectList
|
||||
from wagtail.admin.panels import FieldPanel, TabbedInterface, ObjectList
|
||||
|
||||
from core.wagtail_utils import StrictHierarchyPage, get_default_settings
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import logging
|
||||
|
||||
from django.db import models
|
||||
from wagtail.admin.edit_handlers import FieldPanel, TabbedInterface, ObjectList
|
||||
from wagtail.admin.panels import FieldPanel, TabbedInterface, ObjectList
|
||||
|
||||
from core.wagtail_utils import StrictHierarchyPage, get_default_settings
|
||||
from users.models import SchoolClass
|
||||
|
|
@ -53,8 +53,7 @@ class Chapter(StrictHierarchyPage, GraphqlNodeMixin):
|
|||
|
||||
def sync_description_visibility(self, school_class_template, school_class_to_sync):
|
||||
if (
|
||||
self.description_hidden_for.filter(
|
||||
id=school_class_template.id).exists()
|
||||
self.description_hidden_for.filter(id=school_class_template.id).exists()
|
||||
and not self.description_hidden_for.filter(
|
||||
id=school_class_to_sync.id
|
||||
).exists()
|
||||
|
|
@ -62,8 +61,7 @@ class Chapter(StrictHierarchyPage, GraphqlNodeMixin):
|
|||
self.description_hidden_for.add(school_class_to_sync)
|
||||
|
||||
if (
|
||||
self.description_hidden_for.filter(
|
||||
id=school_class_to_sync.id).exists()
|
||||
self.description_hidden_for.filter(id=school_class_to_sync.id).exists()
|
||||
and not self.description_hidden_for.filter(
|
||||
id=school_class_template.id
|
||||
).exists()
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
import logging
|
||||
|
||||
from django.db import models
|
||||
from wagtail.admin.edit_handlers import (
|
||||
from wagtail.admin.panels import (
|
||||
FieldPanel,
|
||||
TabbedInterface,
|
||||
ObjectList,
|
||||
StreamFieldPanel,
|
||||
)
|
||||
from wagtail.core.blocks import StreamBlock
|
||||
from wagtail.core.fields import StreamField
|
||||
from wagtail.blocks import StreamBlock
|
||||
from wagtail.fields import StreamField
|
||||
from wagtail.images.blocks import ImageChooserBlock
|
||||
|
||||
from books.managers import ContentBlockManager
|
||||
from core.logger import get_logger
|
||||
from core.wagtail_utils import get_default_settings
|
||||
from books.blocks import (
|
||||
CMSDocumentBlock,
|
||||
|
|
@ -31,14 +29,50 @@ from books.blocks import (
|
|||
ThinglinkBlock,
|
||||
InstructionBlock,
|
||||
)
|
||||
from books.utils import get_type_and_value
|
||||
from core.wagtail_utils import StrictHierarchyPage
|
||||
from notes.models import ContentBlockBookmark
|
||||
from surveys.models import Survey
|
||||
from users.models import SchoolClass, User
|
||||
from core.mixins import GraphqlNodeMixin
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def duplicate_entities_generator(new_module):
|
||||
def duplicate_entities(block):
|
||||
content_type = block.block_type
|
||||
value = block.value
|
||||
# logger.debug(block)
|
||||
if content_type == "assignment":
|
||||
assignment = value.get("assignment_id")
|
||||
if assignment is None:
|
||||
return None
|
||||
# copy the assignment
|
||||
assignment.pk = None
|
||||
assignment.title = f"{assignment.title} (Kopie)"
|
||||
assignment.module = new_module
|
||||
# logger.debug(f"setting new module {new_module}, {assignment.module}")
|
||||
assignment.save()
|
||||
data = {"assignment_id": assignment}
|
||||
new_block = ("assignment", data)
|
||||
return new_block
|
||||
if content_type == "survey":
|
||||
# logger.debug(value)
|
||||
survey = value.get("survey_id")
|
||||
if survey is None:
|
||||
return None
|
||||
# copy the survey
|
||||
survey.pk = None
|
||||
survey.title = f"{survey.title} (Kopie)"
|
||||
survey.module = new_module
|
||||
# logger.debug(f"setting new module {new_module}, {survey.module}")
|
||||
survey.save()
|
||||
data = {"survey_id": survey}
|
||||
new_block = ("survey", data)
|
||||
# logger.debug(new_block)
|
||||
return new_block
|
||||
return block
|
||||
|
||||
return duplicate_entities
|
||||
|
||||
|
||||
class ContentBlock(StrictHierarchyPage, GraphqlNodeMixin):
|
||||
|
|
@ -100,15 +134,15 @@ class ContentBlock(StrictHierarchyPage, GraphqlNodeMixin):
|
|||
content_blocks + [("content_list_item", content_list_item)],
|
||||
null=True,
|
||||
blank=True,
|
||||
use_json_field=True,
|
||||
)
|
||||
|
||||
type = models.CharField(
|
||||
max_length=100, choices=TYPE_CHOICES, default=NORMAL)
|
||||
type = models.CharField(max_length=100, choices=TYPE_CHOICES, default=NORMAL)
|
||||
|
||||
content_panels = [
|
||||
FieldPanel("title", classname="full title"),
|
||||
FieldPanel("type"),
|
||||
StreamFieldPanel("contents"),
|
||||
FieldPanel("contents"),
|
||||
]
|
||||
|
||||
#
|
||||
|
|
@ -127,6 +161,23 @@ class ContentBlock(StrictHierarchyPage, GraphqlNodeMixin):
|
|||
def module(self):
|
||||
return self.get_parent().get_parent().specific
|
||||
|
||||
# duplicate all attached Surveys and Assignments
|
||||
def duplicate_attached_entities(self):
|
||||
duplicate_entities_func = duplicate_entities_generator(self.module)
|
||||
new_contents = [duplicate_entities_func(content) for content in self.contents]
|
||||
cleaned_contents = [item for item in new_contents if item is not None]
|
||||
# we can't just insert a list here, we need a StreamValue data type
|
||||
# so we need to clear the list, then add each element in turn
|
||||
self.contents.clear()
|
||||
# like this, the internal methods of the SteamValue data type can work on the single elements
|
||||
for content in cleaned_contents:
|
||||
self.contents.append(content)
|
||||
|
||||
# as an illustration
|
||||
# data = {'text': 'This is me'}
|
||||
# self.contents.append(('solution', data))
|
||||
self.save()
|
||||
|
||||
def is_hidden_for_class(self, school_class):
|
||||
return (
|
||||
not self.user_created
|
||||
|
|
@ -136,19 +187,38 @@ class ContentBlock(StrictHierarchyPage, GraphqlNodeMixin):
|
|||
and not self.visible_for.filter(id=school_class.id).exists()
|
||||
)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
for data in self.contents.raw_data:
|
||||
block_type, value = get_type_and_value(data)
|
||||
|
||||
if block_type == "survey":
|
||||
module = self.module
|
||||
survey = value["survey_id"]
|
||||
if isinstance(survey, int):
|
||||
survey = Survey.objects.get(pk=survey)
|
||||
def reassign_entities(self):
|
||||
module = self.module
|
||||
logger.debug("reassigning entities")
|
||||
for content in self.contents:
|
||||
if content.block_type == "assignment":
|
||||
assignment = content.value.get("assignment_id")
|
||||
logger.debug(assignment.module)
|
||||
if assignment.module != module:
|
||||
assignment.module = module
|
||||
assignment.save()
|
||||
if content.block_type == "survey":
|
||||
survey = content.value.get("survey_id")
|
||||
logger.debug(survey.module)
|
||||
if survey.module != module:
|
||||
survey.module = module
|
||||
survey.save()
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
# def save(self, *args, **kwargs):
|
||||
# todo: move this to the after_create_page and after_edit_page hooks, and remove from here.
|
||||
# for data in self.contents.raw_data:
|
||||
# block_type, value = get_type_and_value(data)
|
||||
|
||||
# todo: also do the same for assignments
|
||||
# if block_type == "survey":
|
||||
# module = self.module
|
||||
# survey = value["survey_id"]
|
||||
# if isinstance(survey, int):
|
||||
# survey = Survey.objects.get(pk=survey)
|
||||
# if survey.module != module:
|
||||
# survey.module = module
|
||||
# survey.save()
|
||||
# super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class ContentBlockSnapshot(ContentBlock):
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from wagtail.admin.edit_handlers import FieldPanel, TabbedInterface, ObjectList
|
||||
from wagtail.core.fields import RichTextField
|
||||
from wagtail.images.edit_handlers import ImageChooserPanel
|
||||
from wagtail.admin.panels import FieldPanel, InlinePanel, TabbedInterface, ObjectList
|
||||
from wagtail.fields import RichTextField
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from core.constants import DEFAULT_RICH_TEXT_FEATURES
|
||||
from core.wagtail_utils import StrictHierarchyPage, get_default_settings
|
||||
|
|
@ -14,8 +14,7 @@ class Module(StrictHierarchyPage):
|
|||
verbose_name = "Modul"
|
||||
verbose_name_plural = "Module"
|
||||
|
||||
meta_title = models.CharField(
|
||||
max_length=255, help_text="e.g. 'Intro' or 'Modul 1'")
|
||||
meta_title = models.CharField(max_length=255, help_text="e.g. 'Intro' or 'Modul 1'")
|
||||
hero_image = models.ForeignKey(
|
||||
"wagtailimages.Image",
|
||||
null=True,
|
||||
|
|
@ -35,10 +34,30 @@ class Module(StrictHierarchyPage):
|
|||
content_panels = [
|
||||
FieldPanel("title", classname="full title"),
|
||||
FieldPanel("meta_title", classname="full title"),
|
||||
ImageChooserPanel("hero_image"),
|
||||
FieldPanel("hero_image"),
|
||||
FieldPanel("hero_source"),
|
||||
FieldPanel("teaser"),
|
||||
FieldPanel("intro"),
|
||||
InlinePanel(
|
||||
"assignments",
|
||||
label=_("Assignment"),
|
||||
classname="collapsed",
|
||||
heading=_("linked assignments"),
|
||||
help_text=_(
|
||||
"These %s are automatically linked, they are shown here only to provide an overview. Please don't change anything here."
|
||||
)
|
||||
% _("assignments"),
|
||||
),
|
||||
InlinePanel(
|
||||
"surveys",
|
||||
heading=_("linked surveys"),
|
||||
label=_("Survey"),
|
||||
classname="collapsed",
|
||||
help_text=_(
|
||||
"These %s are automatically linked, they are shown here only to provide an overview. Please don't change anything here."
|
||||
)
|
||||
% _("surveys"),
|
||||
),
|
||||
]
|
||||
|
||||
edit_handler = TabbedInterface(
|
||||
|
|
@ -93,8 +112,7 @@ class Module(StrictHierarchyPage):
|
|||
content_block.visible_for.add(school_class_to_sync)
|
||||
|
||||
for chapter in chapters:
|
||||
chapter.sync_title_visibility(
|
||||
school_class_template, school_class_to_sync)
|
||||
chapter.sync_title_visibility(school_class_template, school_class_to_sync)
|
||||
chapter.sync_description_visibility(
|
||||
school_class_template, school_class_to_sync
|
||||
)
|
||||
|
|
@ -102,8 +120,7 @@ class Module(StrictHierarchyPage):
|
|||
objective_groups = self.objective_groups.all()
|
||||
|
||||
for objective_group in objective_groups:
|
||||
objective_group.sync_visibility(
|
||||
school_class_template, school_class_to_sync)
|
||||
objective_group.sync_visibility(school_class_template, school_class_to_sync)
|
||||
|
||||
def get_admin_display_title(self):
|
||||
return f"{self.meta_title} - {self.title}"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import logging
|
||||
|
||||
from django.db import models
|
||||
from wagtail.admin.edit_handlers import FieldPanel, TabbedInterface, ObjectList
|
||||
from wagtail.core.fields import RichTextField
|
||||
from wagtail.admin.panels import FieldPanel, TabbedInterface, ObjectList
|
||||
from wagtail.fields import RichTextField
|
||||
|
||||
from core.constants import DEFAULT_RICH_TEXT_FEATURES
|
||||
from core.wagtail_utils import StrictHierarchyPage, get_default_settings
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import re
|
|||
|
||||
from typing import List, Union
|
||||
|
||||
from wagtail.core.blocks import StreamValue
|
||||
from wagtail.blocks import StreamValue
|
||||
|
||||
from api.utils import get_object
|
||||
from assignments.models import Assignment
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from graphql_relay import to_global_id
|
||||
from wagtail.core.fields import StreamField
|
||||
from wagtail.tests.utils.form_data import streamfield, nested_form_data, rich_text
|
||||
from wagtail.fields import StreamField
|
||||
from wagtail.test.utils.form_data import streamfield, nested_form_data, rich_text
|
||||
|
||||
from books.factories import ContentBlockFactory, ModuleFactory, ChapterFactory
|
||||
from books.models import ContentBlock
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
from django.test import TestCase
|
||||
from assignments.models import Assignment
|
||||
|
||||
from books.factories import BookFactory, ContentBlockFactory
|
||||
from books.models.contentblock import ContentBlock
|
||||
from core.logger import get_logger
|
||||
from surveys.models import Survey
|
||||
from users.services import create_users
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class DuplicateContentsTestCase(TestCase):
|
||||
def setUp(self) -> None:
|
||||
create_users()
|
||||
_, _, self.module, chapter, _ = BookFactory.create_default_structure()
|
||||
text = {"type": "text_block", "value": {"text": "Hallo"}}
|
||||
assignment = {
|
||||
"type": "assignment",
|
||||
"value": {"title": "Hello", "assignment": "Assignment"},
|
||||
}
|
||||
survey = {"type": "survey", "value": {"title": "Survey Title", "data": "null"}}
|
||||
self.content_block = ContentBlockFactory.create(
|
||||
parent=chapter,
|
||||
module=self.module,
|
||||
title="Another content block",
|
||||
type="task",
|
||||
contents=[text, assignment, survey],
|
||||
)
|
||||
self.assignment = Assignment.objects.first()
|
||||
|
||||
def test_duplicate_entities(self):
|
||||
self.assertEqual(
|
||||
self.content_block.contents[1].value["assignment_id"], self.assignment
|
||||
)
|
||||
self.assertEqual(
|
||||
self.content_block.contents[1].value["assignment_id"].title, "Hello"
|
||||
)
|
||||
self.assertEqual(Assignment.objects.count(), 1)
|
||||
self.assertEqual(Survey.objects.count(), 1)
|
||||
self.content_block.duplicate_attached_entities()
|
||||
self.assertEqual(Assignment.objects.count(), 2)
|
||||
self.assertEqual(Survey.objects.count(), 2)
|
||||
new_assignment = Assignment.objects.latest("id")
|
||||
new_survey = Survey.objects.latest("id")
|
||||
content_block = ContentBlock.objects.get(id=self.content_block.id)
|
||||
self.assertEqual(len(content_block.contents), 3)
|
||||
self.assertEqual(
|
||||
content_block.contents[1].value["assignment_id"], new_assignment
|
||||
)
|
||||
self.assertEqual(content_block.contents[2].value["survey_id"], new_survey)
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
DEFAULT_RICH_TEXT_FEATURES = ['ul', 'bold']
|
||||
INSTRUMENTS_RICH_TEXT_FEATURES = ['bold', 'ul', 'brand', 'secondary']
|
||||
DEFAULT_RICH_TEXT_FEATURES = ["ul", "bold", "subscript", "superscript"]
|
||||
INSTRUMENTS_RICH_TEXT_FEATURES = DEFAULT_RICH_TEXT_FEATURES + ["brand", "secondary"]
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from django.conf import settings
|
|||
from django.core import management
|
||||
from django.core.management import BaseCommand
|
||||
from django.db import connection
|
||||
from wagtail.core.models import Page
|
||||
from wagtail.models import Page
|
||||
|
||||
from books.factories import BookFactory, TopicFactory, ModuleFactory, ChapterFactory, ContentBlockFactory
|
||||
from core.factories import UserFactory
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ from django.conf import settings
|
|||
from django.http import Http404, HttpResponsePermanentRedirect
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
from graphene import ResolveInfo
|
||||
from sentry_sdk import capture_exception
|
||||
|
||||
|
||||
try:
|
||||
|
|
@ -15,25 +17,25 @@ _thread_locals = local()
|
|||
|
||||
|
||||
def get_current_request():
|
||||
""" returns the request object for this thread """
|
||||
"""returns the request object for this thread"""
|
||||
return getattr(_thread_locals, "request", None)
|
||||
|
||||
|
||||
def get_current_user():
|
||||
""" returns the current user, if exist, otherwise returns None """
|
||||
"""returns the current user, if exist, otherwise returns None"""
|
||||
request = get_current_request()
|
||||
if request:
|
||||
return getattr(request, "user", None)
|
||||
|
||||
|
||||
class ThreadLocalMiddleware(MiddlewareMixin):
|
||||
""" Simple middleware that adds the request object in thread local storage."""
|
||||
"""Simple middleware that adds the request object in thread local storage."""
|
||||
|
||||
def process_request(self, request):
|
||||
_thread_locals.request = request
|
||||
|
||||
def process_response(self, request, response):
|
||||
if hasattr(_thread_locals, 'request'):
|
||||
if hasattr(_thread_locals, "request"):
|
||||
del _thread_locals.request
|
||||
return response
|
||||
|
||||
|
|
@ -42,9 +44,14 @@ class CommonRedirectMiddleware(MiddlewareMixin):
|
|||
"""
|
||||
redirects common bad requests or missing images
|
||||
"""
|
||||
|
||||
DEFAULT_REDIRECTS = [
|
||||
(re.compile("(?i)(.+\.php|.+wp-admin.+|.+\.htm|\/wordpress\/|\/wp\/|\/mm5\/|\/wp-content\/)"),
|
||||
'http://example.org/'),
|
||||
(
|
||||
re.compile(
|
||||
"(?i)(.+\.php|.+wp-admin.+|.+\.htm|\/wordpress\/|\/wp\/|\/mm5\/|\/wp-content\/)"
|
||||
),
|
||||
"http://example.org/",
|
||||
),
|
||||
]
|
||||
|
||||
def process_exception(self, request, exception):
|
||||
|
|
@ -72,10 +79,17 @@ class CommonRedirectMiddleware(MiddlewareMixin):
|
|||
# some static image is missing show a placeholder (use full for local dev)
|
||||
m = re.match(r".*(max|fill)-(?P<dimensions>\d+x\d+)\.(jpg|png|svg)", path)
|
||||
if m:
|
||||
return 'https://picsum.photos/{}'.format(m.group('dimensions').replace('x', '/'))
|
||||
return "https://picsum.photos/{}".format(
|
||||
m.group("dimensions").replace("x", "/")
|
||||
)
|
||||
# or dummy image: return 'http://via.placeholder.com/{}'.format(m.group('dimensions'))
|
||||
if '.png' in path or '.jpg' in path or '.svg' in path or 'not-found' in path:
|
||||
return 'https://picsum.photos/400/400'
|
||||
if (
|
||||
".png" in path
|
||||
or ".jpg" in path
|
||||
or ".svg" in path
|
||||
or "not-found" in path
|
||||
):
|
||||
return "https://picsum.photos/400/400"
|
||||
|
||||
|
||||
# https://stackoverflow.com/questions/4898408/how-to-set-a-login-cookie-in-django
|
||||
|
|
@ -86,14 +100,24 @@ class UserLoggedInCookieMiddleWare(MiddlewareMixin):
|
|||
If the user is not authenticated and the cookie remains, delete it
|
||||
"""
|
||||
|
||||
cookie_name = 'loginStatus'
|
||||
cookie_name = "loginStatus"
|
||||
|
||||
def process_response(self, request, response):
|
||||
#if user and no cookie, set cookie
|
||||
# if user and no cookie, set cookie
|
||||
if request.user.is_authenticated and not request.COOKIES.get(self.cookie_name):
|
||||
response.set_cookie(self.cookie_name, 'true')
|
||||
elif not request.user.is_authenticated and request.COOKIES.get(self.cookie_name):
|
||||
#else if if no user and cookie remove user cookie, logout
|
||||
response.set_cookie(self.cookie_name, "true")
|
||||
elif not request.user.is_authenticated and request.COOKIES.get(
|
||||
self.cookie_name
|
||||
):
|
||||
# else if if no user and cookie remove user cookie, logout
|
||||
response.delete_cookie(self.cookie_name)
|
||||
return response
|
||||
|
||||
|
||||
class SentryMiddleware(object):
|
||||
def on_error(self, error):
|
||||
capture_exception(error)
|
||||
raise error
|
||||
|
||||
def resolve(self, next, root, info: ResolveInfo, **args):
|
||||
return next(root, info, **args).catch(self.on_error)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
# Generated by Django 3.2.16 on 2023-03-09 17:14
|
||||
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
from django.db import migrations
|
||||
|
||||
"""
|
||||
CMS-Editors:
|
||||
Wagtail: Alle Rechte
|
||||
Django: Bereich «Lernziele»
|
||||
|
||||
Support:
|
||||
Django: Bereich «User»
|
||||
|
||||
News:
|
||||
Django: Bereich «News»
|
||||
|
||||
"""
|
||||
|
||||
news = ["news"]
|
||||
support = ["users", "auth"]
|
||||
cms_editors = [
|
||||
"objectives",
|
||||
"books",
|
||||
"assignments",
|
||||
"basicknowledge",
|
||||
"surveys",
|
||||
"wagtailadmin",
|
||||
"wagtailcore",
|
||||
"wagtailimages",
|
||||
"wagtailembeds",
|
||||
"wagtailredirects",
|
||||
"wagtailsearch",
|
||||
"wagtailusers",
|
||||
"wagtaildocs",
|
||||
]
|
||||
|
||||
groups = [("News", news), ("CMS-Editors", cms_editors), ("Support", support)]
|
||||
|
||||
|
||||
def add_permissions(apps, schema_editor):
|
||||
for name, app_labels in groups:
|
||||
group, _ = Group.objects.get_or_create(name=name)
|
||||
for app_label in app_labels:
|
||||
for permission in Permission.objects.filter(
|
||||
content_type__app_label=app_label
|
||||
):
|
||||
group.permissions.add(permission)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("core", "0002_delete_admindata"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(add_permissions, migrations.RunPython.noop),
|
||||
]
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 3.2.16 on 2023-03-13 15:19
|
||||
|
||||
from django.db import migrations
|
||||
from django.contrib.auth.models import Group
|
||||
|
||||
|
||||
def delete_old_group(apps, schema_editor):
|
||||
try:
|
||||
group = Group.objects.get(name="Altes CMS")
|
||||
group.delete()
|
||||
except Group.DoesNotExist:
|
||||
pass
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("core", "0003_auto_20230309_1714"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(delete_old_group, migrations.RunPython.noop),
|
||||
]
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# Generated by Django 3.2.16 on 2023-03-16 10:28
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
from core.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def add_group_page_permissions(apps, schema_editor):
|
||||
try:
|
||||
types = ["lock", "bulk_delete", "edit", "publish", "unlock", "add"]
|
||||
Group = apps.get_model("auth", "Group")
|
||||
Site = apps.get_model("wagtailcore", "Site")
|
||||
GroupPagePermission = apps.get_model("wagtailcore", "GroupPagePermission")
|
||||
group = Group.objects.get(name="CMS-Editors")
|
||||
site = Site.objects.get(is_default_site=True)
|
||||
page = site.root_page
|
||||
for tp in types:
|
||||
GroupPagePermission.objects.get_or_create(
|
||||
group=group, page=page, permission_type=tp
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("core", "0004_auto_20230313_1519"),
|
||||
("wagtailcore", "0083_workflowcontenttype"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(add_group_page_permissions, migrations.RunPython.noop)
|
||||
]
|
||||
|
|
@ -16,142 +16,138 @@ load_dotenv(find_dotenv())
|
|||
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = os.environ.get('SECRET_KEY')
|
||||
SIGNING_SECRET = os.environ.get('SIGNING_SECRET')
|
||||
SECRET_KEY = os.environ.get("SECRET_KEY")
|
||||
SIGNING_SECRET = os.environ.get("SIGNING_SECRET")
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = bool_value(os.environ.get('DEBUG', ''))
|
||||
TEST = 'test' in sys.argv
|
||||
ENABLE_SILKY = bool_value(os.environ.get('ENABLE_SILKY', ''))
|
||||
SERVE_VIA_WEBPACK = bool_value(os.environ.get('SERVE_VIA_WEBPACK', DEBUG))
|
||||
ENABLE_SENTRY = not DEBUG or bool_value(os.environ.get('ENABLE_SENTRY_DEBUG', ''))
|
||||
DEBUG = bool_value(os.environ.get("DEBUG", ""))
|
||||
TEST = "test" in sys.argv
|
||||
ENABLE_SILKY = bool_value(os.environ.get("ENABLE_SILKY", ""))
|
||||
SERVE_VIA_WEBPACK = bool_value(os.environ.get("SERVE_VIA_WEBPACK", DEBUG))
|
||||
ENABLE_SENTRY = not DEBUG or bool_value(os.environ.get("ENABLE_SENTRY_DEBUG", ""))
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
|
||||
if not DEBUG:
|
||||
SECURE_SSL_REDIRECT = True
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||
|
||||
# Application definition
|
||||
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'core',
|
||||
'api',
|
||||
'users',
|
||||
'books',
|
||||
'objectives',
|
||||
'rooms',
|
||||
'assignments',
|
||||
'basicknowledge',
|
||||
'portfolio',
|
||||
'statistics',
|
||||
'surveys',
|
||||
'notes',
|
||||
'news',
|
||||
'oauth',
|
||||
|
||||
'wagtail.contrib.redirects',
|
||||
'wagtail.contrib.modeladmin',
|
||||
'wagtail.embeds',
|
||||
'wagtail.sites',
|
||||
'wagtail.users',
|
||||
'wagtail.snippets',
|
||||
'wagtail.documents',
|
||||
'wagtail.images',
|
||||
'wagtail.search',
|
||||
'wagtail.admin',
|
||||
'wagtail.core',
|
||||
'wagtail.api.v2',
|
||||
'wagtailautocomplete',
|
||||
|
||||
'taggit',
|
||||
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
"core",
|
||||
"api",
|
||||
"users",
|
||||
"books",
|
||||
"objectives",
|
||||
"rooms",
|
||||
"assignments",
|
||||
"basicknowledge",
|
||||
"portfolio",
|
||||
"statistics",
|
||||
"surveys",
|
||||
"notes",
|
||||
"news",
|
||||
"oauth",
|
||||
"wagtail.contrib.redirects",
|
||||
"wagtail.contrib.modeladmin",
|
||||
"wagtail.embeds",
|
||||
"wagtail.sites",
|
||||
"wagtail.users",
|
||||
"wagtail.snippets",
|
||||
"wagtail.documents",
|
||||
"wagtail.images",
|
||||
"wagtail.search",
|
||||
"wagtail.admin",
|
||||
"wagtail",
|
||||
"wagtail.api.v2",
|
||||
"wagtailautocomplete",
|
||||
"taggit",
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
# 'raven.contrib.django.raven_compat',
|
||||
'whitenoise.runserver_nostatic',
|
||||
'django.contrib.staticfiles',
|
||||
'django_filters',
|
||||
'graphene_django',
|
||||
'django_extensions',
|
||||
'compressor',
|
||||
"whitenoise.runserver_nostatic",
|
||||
"django.contrib.staticfiles",
|
||||
"django_filters",
|
||||
"graphene_django",
|
||||
"django_extensions",
|
||||
"compressor",
|
||||
]
|
||||
|
||||
if DEBUG:
|
||||
INSTALLED_APPS += ['wagtail.contrib.styleguide']
|
||||
INSTALLED_APPS += ["wagtail.contrib.styleguide"]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||
'django.middleware.gzip.GZipMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware'
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||
"django.middleware.gzip.GZipMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.locale.LocaleMiddleware",
|
||||
]
|
||||
|
||||
# Enable CORS for local development
|
||||
if DEBUG:
|
||||
INSTALLED_APPS += ['corsheaders']
|
||||
MIDDLEWARE += ['corsheaders.middleware.CorsMiddleware']
|
||||
CORS_ORIGIN_WHITELIST = (
|
||||
'http://localhost:8080',
|
||||
)
|
||||
INSTALLED_APPS += ["corsheaders"]
|
||||
MIDDLEWARE += ["corsheaders.middleware.CorsMiddleware"]
|
||||
CORS_ORIGIN_WHITELIST = ("http://localhost:8080",)
|
||||
CORS_ALLOW_CREDENTIALS = True
|
||||
|
||||
# enable silk for performance measuring
|
||||
if ENABLE_SILKY:
|
||||
INSTALLED_APPS += ['silk']
|
||||
MIDDLEWARE += ['silk.middleware.SilkyMiddleware', ]
|
||||
INSTALLED_APPS += ["silk"]
|
||||
MIDDLEWARE += [
|
||||
"silk.middleware.SilkyMiddleware",
|
||||
]
|
||||
|
||||
MIDDLEWARE += [
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
|
||||
'wagtail.contrib.redirects.middleware.RedirectMiddleware',
|
||||
|
||||
'core.middleware.ThreadLocalMiddleware',
|
||||
'core.middleware.CommonRedirectMiddleware',
|
||||
'core.middleware.UserLoggedInCookieMiddleWare',
|
||||
'oauth.middleware.user_has_license_middleware',
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
"wagtail.contrib.redirects.middleware.RedirectMiddleware",
|
||||
"core.middleware.ThreadLocalMiddleware",
|
||||
"core.middleware.CommonRedirectMiddleware",
|
||||
"core.middleware.UserLoggedInCookieMiddleWare",
|
||||
"oauth.middleware.user_has_license_middleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'core.urls'
|
||||
ROOT_URLCONF = "core.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [os.path.join(BASE_DIR, '..', 'client/dist'), os.path.join(BASE_DIR, 'templates')],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'core.context_processors.settings_context',
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [
|
||||
os.path.join(BASE_DIR, "..", "client/dist"),
|
||||
os.path.join(BASE_DIR, "templates"),
|
||||
],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
"core.context_processors.settings_context",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'core.wsgi.application'
|
||||
WSGI_APPLICATION = "core.wsgi.application"
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
|
||||
|
||||
# Database
|
||||
DATABASES = {
|
||||
'default': dj_database_url.config(conn_max_age=600)
|
||||
}
|
||||
DATABASES = {"default": dj_database_url.config(conn_max_age=600)}
|
||||
|
||||
# Django custom user
|
||||
AUTH_USER_MODEL = 'users.User'
|
||||
AUTH_USER_MODEL = "users.User"
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
|
||||
|
|
@ -162,30 +158,30 @@ if WEAK_PASSWORDS:
|
|||
else:
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
|
||||
LOGOUT_REDIRECT_URL = '/login'
|
||||
LOGIN_REDIRECT_URL = '/login'
|
||||
LOGOUT_REDIRECT_URL = "/login"
|
||||
LOGIN_REDIRECT_URL = "/login"
|
||||
|
||||
LOGIN_URL = LOGIN_REDIRECT_URL
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.11/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'de'
|
||||
LANGUAGE_CODE = "de"
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
TIME_ZONE = "UTC"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
|
|
@ -194,167 +190,161 @@ USE_L10N = True
|
|||
USE_TZ = True
|
||||
|
||||
LANGUAGES = [
|
||||
('de', _('German')),
|
||||
('en', _('English')),
|
||||
("de", _("German")),
|
||||
("en", _("English")),
|
||||
]
|
||||
|
||||
LOCALE_PATHS = [
|
||||
os.path.join(BASE_DIR, 'locale')
|
||||
]
|
||||
LOCALE_PATHS = [os.path.join(BASE_DIR, "locale")]
|
||||
|
||||
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.11/howto/static-files/
|
||||
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
||||
STATIC_URL = "/static/"
|
||||
|
||||
STATICFILES_DIRS = (
|
||||
os.path.join(BASE_DIR, '..', 'client/dist/static'),
|
||||
os.path.join(BASE_DIR, '..', 'client/src/assets'),
|
||||
os.path.join(BASE_DIR, "..", "client/dist/static"),
|
||||
os.path.join(BASE_DIR, "..", "client/src/assets"),
|
||||
)
|
||||
|
||||
if not TEST:
|
||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
||||
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
|
||||
|
||||
COMPRESS_CSS_FILTERS = [
|
||||
# 'django_compressor_autoprefixer.AutoprefixerFilter',
|
||||
'compressor.filters.cssmin.CSSMinFilter',
|
||||
"compressor.filters.cssmin.CSSMinFilter",
|
||||
]
|
||||
|
||||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
'compressor.finders.CompressorFinder',
|
||||
"django.contrib.staticfiles.finders.FileSystemFinder",
|
||||
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
||||
"compressor.finders.CompressorFinder",
|
||||
)
|
||||
|
||||
COMPRESS_PRECOMPILERS = (
|
||||
('text/x-scss', 'django_libsass.SassCompiler'),
|
||||
)
|
||||
COMPRESS_PRECOMPILERS = (("text/x-scss", "django_libsass.SassCompiler"),)
|
||||
|
||||
COMPRESS_ENABLED = True
|
||||
|
||||
if not DEBUG:
|
||||
COMPRESS_STORAGE = 'compressor.storage.GzipCompressorFileStorage'
|
||||
COMPRESS_STORAGE = "compressor.storage.GzipCompressorFileStorage"
|
||||
COMPRESS_OFFLINE = True
|
||||
|
||||
# AWS S3
|
||||
# http://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html
|
||||
|
||||
USE_AWS = bool_value(os.environ.get('USE_AWS'))
|
||||
USE_AWS = bool_value(os.environ.get("USE_AWS"))
|
||||
AWS_QUERYSTRING_AUTH = False
|
||||
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
|
||||
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
|
||||
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')
|
||||
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID")
|
||||
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY")
|
||||
AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_STORAGE_BUCKET_NAME")
|
||||
AWS_S3_FILE_OVERWRITE = False
|
||||
|
||||
# use with cloudfront
|
||||
AWS_S3_CUSTOM_DOMAIN = '{}.s3-{}.amazonaws.com'.format(AWS_STORAGE_BUCKET_NAME,
|
||||
os.environ.get('AWS_REGION', 'eu-west-1'))
|
||||
AWS_S3_CUSTOM_DOMAIN = "{}.s3-{}.amazonaws.com".format(
|
||||
AWS_STORAGE_BUCKET_NAME, os.environ.get("AWS_REGION", "eu-west-1")
|
||||
)
|
||||
if USE_AWS:
|
||||
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
|
||||
# use with cloudfront
|
||||
MEDIA_URL = "https://%s/" % AWS_S3_CUSTOM_DOMAIN
|
||||
else:
|
||||
MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = os.environ.get('DJANGO_MEDIAFILES', os.path.join(BASE_DIR, 'media'))
|
||||
MEDIA_URL = "/media/"
|
||||
MEDIA_ROOT = os.environ.get("DJANGO_MEDIAFILES", os.path.join(BASE_DIR, "media"))
|
||||
|
||||
AWS_S3_OBJECT_PARAMETERS = {
|
||||
'CacheControl': 'max-age=86400',
|
||||
"CacheControl": "max-age=86400",
|
||||
}
|
||||
|
||||
# Media Files
|
||||
USE_404_FALLBACK_IMAGE = bool_value(os.environ.get('USE_404_FALLBACK_IMAGE', 'True'))
|
||||
USE_404_FALLBACK_IMAGE = bool_value(os.environ.get("USE_404_FALLBACK_IMAGE", "True"))
|
||||
|
||||
# Logging Conf
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'formatters': {
|
||||
'verbose_format': {
|
||||
'format': '%(levelname)s %(asctime)s %(module)s %(name)s (%(process)d): %(message)s'
|
||||
},
|
||||
'simple_format': {
|
||||
'format': '%(levelname)s %(name)s: %(message)s'
|
||||
"version": 1,
|
||||
"formatters": {
|
||||
"verbose_format": {
|
||||
"format": "%(levelname)s %(asctime)s %(module)s %(name)s (%(process)d): %(message)s"
|
||||
},
|
||||
"simple_format": {"format": "%(levelname)s %(name)s: %(message)s"},
|
||||
},
|
||||
'disable_existing_loggers': not DEBUG,
|
||||
'handlers': {
|
||||
'mail_admins': {
|
||||
'level': 'CRITICAL',
|
||||
'class': 'django.utils.log.AdminEmailHandler'
|
||||
"disable_existing_loggers": not DEBUG,
|
||||
"handlers": {
|
||||
"mail_admins": {
|
||||
"level": "CRITICAL",
|
||||
"class": "django.utils.log.AdminEmailHandler",
|
||||
},
|
||||
'console': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.StreamHandler',
|
||||
'stream': sys.stdout,
|
||||
'formatter': 'simple_format'
|
||||
"console": {
|
||||
"level": "DEBUG",
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": sys.stdout,
|
||||
"formatter": "simple_format",
|
||||
},
|
||||
# for automatic papertrail logging
|
||||
'SysLog': {
|
||||
'level': 'INFO',
|
||||
'class': 'logging.handlers.SysLogHandler',
|
||||
'formatter': 'simple_format',
|
||||
|
||||
"SysLog": {
|
||||
"level": "INFO",
|
||||
"class": "logging.handlers.SysLogHandler",
|
||||
"formatter": "simple_format",
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'': {
|
||||
'handlers': ['console'],
|
||||
'level': 'WARNING'
|
||||
"loggers": {
|
||||
"": {"handlers": ["console"], "level": "WARNING"},
|
||||
"skillbox": {
|
||||
"handlers": ["console", "SysLog"],
|
||||
"level": os.environ.get("DJANGO_LOG_LEVEL", "INFO"),
|
||||
"propagate": False,
|
||||
},
|
||||
'skillbox': {
|
||||
'handlers': ['console', 'SysLog'],
|
||||
'level': os.environ.get('DJANGO_LOG_LEVEL', 'INFO'),
|
||||
'propagate': False
|
||||
"graphql": {"handlers": ["console"], "level": "WARNING", "propagate": False},
|
||||
"django": {
|
||||
"handlers": ["console"],
|
||||
"level": "INFO",
|
||||
"propagate": False,
|
||||
},
|
||||
'graphql': {
|
||||
'handlers': ['console'],
|
||||
'level': 'WARNING',
|
||||
'propagate': False
|
||||
"django.server": {
|
||||
"handlers": ["console"],
|
||||
"level": "WARNING",
|
||||
"propagate": False,
|
||||
},
|
||||
'django': {
|
||||
'handlers': ['console'],
|
||||
'level': 'INFO',
|
||||
'propagate': False,
|
||||
},
|
||||
'django.server': {
|
||||
'handlers': ['console'],
|
||||
'level': 'WARNING',
|
||||
'propagate': False,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
if ENABLE_SENTRY and os.environ.get('SENTRY_DSN'):
|
||||
if ENABLE_SENTRY and os.environ.get("SENTRY_DSN"):
|
||||
import sentry_sdk
|
||||
from sentry_sdk.integrations.django import DjangoIntegration
|
||||
|
||||
from sentry_sdk.integrations.logging import ignore_logger
|
||||
|
||||
def before_send(event, hint):
|
||||
user = event['user']
|
||||
id = user['id']
|
||||
event['user'] = {'id': id}
|
||||
user = event["user"]
|
||||
id = user["id"]
|
||||
event["user"] = {"id": id}
|
||||
return event
|
||||
|
||||
|
||||
environment = os.environ.get('SENTRY_ENV', 'localhost')
|
||||
environment = os.environ.get("SENTRY_ENV", "localhost")
|
||||
sample_rate = os.environ.get("SENTRY_SAMPLE_RATE", 0.01)
|
||||
|
||||
sentry_sdk.init(
|
||||
dsn=os.environ.get('SENTRY_DSN'),
|
||||
dsn=os.environ.get("SENTRY_DSN"),
|
||||
integrations=[DjangoIntegration()],
|
||||
send_default_pii=True,
|
||||
before_send=before_send,
|
||||
environment=environment
|
||||
before_send_transaction=before_send,
|
||||
environment=environment,
|
||||
traces_sample_rate=sample_rate,
|
||||
)
|
||||
|
||||
RAVEN_DSN_JS = os.environ.get('RAVEN_DSN_JS', '')
|
||||
# ignore 'Traceback' error messages, they don't give enough information
|
||||
# from https://jerrynsh.com/how-to-monitor-python-graphql-api-with-sentry/
|
||||
ignore_logger("graphql.execution.utils")
|
||||
|
||||
RAVEN_DSN_JS = os.environ.get("RAVEN_DSN_JS", "")
|
||||
|
||||
GRAPHENE = {
|
||||
'SCHEMA': 'api.schema.schema',
|
||||
'SCHEMA_OUTPUT': 'schema.graphql'
|
||||
"SCHEMA": "api.schema.schema",
|
||||
"SCHEMA_OUTPUT": "schema.graphql",
|
||||
"MIDDLEWARE": ["core.middleware.SentryMiddleware"],
|
||||
}
|
||||
|
||||
# if DEBUG:
|
||||
|
|
@ -363,25 +353,27 @@ GRAPHENE = {
|
|||
# ]
|
||||
|
||||
# http://docs.wagtail.io/en/v2.1/advanced_topics/settings.html?highlight=urls
|
||||
WAGTAIL_SITE_NAME = 'skillbox'
|
||||
WAGTAIL_SITE_NAME = "skillbox"
|
||||
WAGTAILSEARCH_BACKENDS = {
|
||||
'default': {
|
||||
'BACKEND': 'wagtail.search.backends.database',
|
||||
"default": {
|
||||
"BACKEND": "wagtail.search.backends.database",
|
||||
}
|
||||
}
|
||||
WAGTAILDOCS_DOCUMENT_MODEL = 'books.CustomDocument'
|
||||
WAGTAILDOCS_DOCUMENT_MODEL = "books.CustomDocument"
|
||||
|
||||
|
||||
GRAPHQL_QUERIES_DIR = os.path.join(BASE_DIR, '..', 'client', 'src', 'graphql', 'gql', 'queries')
|
||||
GRAPHQL_MUTATIONS_DIR = os.path.join(GRAPHQL_QUERIES_DIR, '../mutations')
|
||||
GRAPHQL_QUERIES_DIR = os.path.join(
|
||||
BASE_DIR, "..", "client", "src", "graphql", "gql", "queries"
|
||||
)
|
||||
GRAPHQL_MUTATIONS_DIR = os.path.join(GRAPHQL_QUERIES_DIR, "../mutations")
|
||||
|
||||
DEFAULT_FROM_EMAIL = 'myskillbox <noreply@myskillbox.ch>'
|
||||
DEFAULT_FROM_EMAIL = "myskillbox <noreply@myskillbox.ch>"
|
||||
|
||||
# Metanet Config
|
||||
if DEBUG:
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'
|
||||
EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend"
|
||||
else:
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||
|
||||
ALLOW_BETA_LOGIN = True
|
||||
|
||||
|
|
@ -390,25 +382,25 @@ HEP_URL = os.environ.get("HEP_URL")
|
|||
|
||||
# HEP Oauth
|
||||
AUTHLIB_OAUTH_CLIENTS = {
|
||||
'hep': {
|
||||
'client_id': os.environ.get("OAUTH_CLIENT_ID"),
|
||||
'client_secret': os.environ.get("OAUTH_CLIENT_SECRET"),
|
||||
'request_token_url': None,
|
||||
'request_token_params': None,
|
||||
'access_token_url': os.environ.get("OAUTH_ACCESS_TOKEN_URL"),
|
||||
'access_token_params': None,
|
||||
'refresh_token_url': None,
|
||||
'authorize_url': os.environ.get("OAUTH_AUTHORIZE_URL"),
|
||||
'api_base_url': os.environ.get("OAUTH_API_BASE_URL"),
|
||||
'client_kwargs': {
|
||||
'scope': 'orders',
|
||||
'token_endpoint_auth_method': 'client_secret_post',
|
||||
'token_placement': 'header',
|
||||
}
|
||||
"hep": {
|
||||
"client_id": os.environ.get("OAUTH_CLIENT_ID"),
|
||||
"client_secret": os.environ.get("OAUTH_CLIENT_SECRET"),
|
||||
"request_token_url": None,
|
||||
"request_token_params": None,
|
||||
"access_token_url": os.environ.get("OAUTH_ACCESS_TOKEN_URL"),
|
||||
"access_token_params": None,
|
||||
"refresh_token_url": None,
|
||||
"authorize_url": os.environ.get("OAUTH_AUTHORIZE_URL"),
|
||||
"api_base_url": os.environ.get("OAUTH_API_BASE_URL"),
|
||||
"client_kwargs": {
|
||||
"scope": "orders",
|
||||
"token_endpoint_auth_method": "client_secret_post",
|
||||
"token_placement": "header",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
PLATFORM = os.environ.get('APP_FLAVOR', 'myskillbox')
|
||||
PLATFORM = os.environ.get("APP_FLAVOR", "myskillbox")
|
||||
|
||||
OAUTH_LOCAL_REDIRECT_URI = os.environ.get("OAUTH_LOCAL_REDIRECT_URI")
|
||||
|
||||
|
|
@ -419,12 +411,12 @@ TASKBASE_SUPERPASSWORD = os.environ.get("TASKBASE_SUPERPASSWORD")
|
|||
TASKBASE_BASEURL = os.environ.get("TASKBASE_BASEURL")
|
||||
ENABLE_SPELLCHECK = True if TASKBASE_BASEURL else False
|
||||
|
||||
TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner'
|
||||
TEST_OUTPUT_DIR = './test-reports/'
|
||||
TEST_RUNNER = "xmlrunner.extra.djangotestrunner.XMLTestRunner"
|
||||
TEST_OUTPUT_DIR = "./test-reports/"
|
||||
TEST_OUTPUT_VERBOSE = 1
|
||||
|
||||
# new default in Django 3.0, making it explicit to facilitate bug hunting
|
||||
X_FRAME_OPTIONS = 'DENY'
|
||||
X_FRAME_OPTIONS = "DENY"
|
||||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||
# Django 3.2 uses BitAutoField by default, we keep things the old way
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,264 @@
|
|||
import json
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from wagtail.models import Page
|
||||
from wagtail.test.utils import WagtailTestUtils
|
||||
from assignments.factories import AssignmentFactory
|
||||
from assignments.models import Assignment
|
||||
from books.blocks import AssignmentBlock, SurveyBlock
|
||||
from books.factories import BookFactory, ChapterFactory, ModuleFactory, TopicFactory
|
||||
from books.models.contentblock import ContentBlock
|
||||
from books.models.module import Module
|
||||
from books.models.topic import Topic
|
||||
|
||||
from core.logger import get_logger
|
||||
from surveys.factories import SurveyFactory
|
||||
from surveys.models import Survey
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_copy_payload(title, slug, parent):
|
||||
return {
|
||||
"new_title": title,
|
||||
"new_slug": slug,
|
||||
"new_parent_page": parent.id,
|
||||
"copy_subpages": True,
|
||||
"publish_copies": False,
|
||||
"alias": False,
|
||||
}
|
||||
|
||||
|
||||
def get_copy_url(page):
|
||||
return reverse("wagtailadmin_pages:copy", args=(page.id,))
|
||||
|
||||
|
||||
class CoreHooksTestCase(WagtailTestUtils, TestCase):
|
||||
def setUp(self) -> None:
|
||||
(
|
||||
self.book,
|
||||
self.topic,
|
||||
self.module,
|
||||
self.chapter,
|
||||
self.content_block,
|
||||
) = BookFactory.create_default_structure()
|
||||
self.user = self.login()
|
||||
|
||||
# create content blocks
|
||||
assignment = AssignmentFactory()
|
||||
self.assignment_id = assignment.id
|
||||
assignment_block = AssignmentBlock()
|
||||
assignment_value = assignment_block.to_python({"assignment_id": assignment.id})
|
||||
cleaned_assignment_value = assignment_block.clean(assignment_value)
|
||||
assignment_content = ("assignment", cleaned_assignment_value)
|
||||
|
||||
survey = SurveyFactory()
|
||||
survey_block = SurveyBlock()
|
||||
survey_value = survey_block.to_python({"survey_id": survey.id})
|
||||
cleaned_survey_value = survey_block.clean(survey_value)
|
||||
survey_content = ("survey", cleaned_survey_value)
|
||||
|
||||
self.content_block.contents.append(assignment_content)
|
||||
self.content_block.contents.append(survey_content)
|
||||
self.content_block.save()
|
||||
|
||||
self.assertEqual(
|
||||
self.content_block.contents[0].value["assignment_id"], assignment
|
||||
)
|
||||
self.assertEqual(self.content_block.contents[1].value["survey_id"], survey)
|
||||
self.assertEqual(Assignment.objects.count(), 1)
|
||||
self.assertEqual(Survey.objects.count(), 1)
|
||||
# logger.debug(f"assignment: {assignment.id}")
|
||||
|
||||
self.new_topic = TopicFactory.create(
|
||||
parent=self.book, title="A second Topic", order=2
|
||||
)
|
||||
|
||||
self.new_module = ModuleFactory.create(
|
||||
parent=self.new_topic,
|
||||
title="A second module",
|
||||
meta_title="Modul 1",
|
||||
teaser="Whatever",
|
||||
intro="<p>Hello</p>",
|
||||
)
|
||||
self.new_chapter = ChapterFactory.create(
|
||||
parent=self.new_module, title="A second chapter"
|
||||
)
|
||||
|
||||
def test_after_create_hook(self):
|
||||
# description = rich_text('<p>hello</p>')
|
||||
self.assertEqual(Topic.objects.count(), 2)
|
||||
description = {
|
||||
"blocks": [
|
||||
{
|
||||
"key": "thfb4",
|
||||
"text": "asd",
|
||||
"type": "unstyled",
|
||||
"depth": 0,
|
||||
"inlineStyleRanges": [],
|
||||
"entityRanges": [],
|
||||
"data": {},
|
||||
}
|
||||
],
|
||||
"entityMap": {},
|
||||
}
|
||||
post_data = {
|
||||
"title": "New Page",
|
||||
"order": 1,
|
||||
"teaser": "Tease",
|
||||
"description": json.dumps(description),
|
||||
"slug": "hello-world",
|
||||
}
|
||||
url = reverse(
|
||||
"wagtailadmin_pages:add",
|
||||
args=("books", "topic", self.book.id),
|
||||
)
|
||||
# logger.debug(url)
|
||||
self.client.post(
|
||||
url,
|
||||
post_data,
|
||||
)
|
||||
self.assertEqual(Topic.objects.count(), 3)
|
||||
|
||||
def _check_copied_content_block(self, module=None):
|
||||
if module is None:
|
||||
module = self.new_module
|
||||
|
||||
self.assertEqual(ContentBlock.objects.count(), 2)
|
||||
self.assertEqual(Assignment.objects.count(), 2)
|
||||
self.assertEqual(Survey.objects.count(), 2)
|
||||
new_content_block = ContentBlock.objects.latest("-latest_revision_created_at")
|
||||
new_assignment = Assignment.objects.latest("pk")
|
||||
new_survey = Survey.objects.latest("pk")
|
||||
self.assertEqual(
|
||||
new_content_block.contents[0].value["assignment_id"], new_assignment
|
||||
)
|
||||
self.assertEqual(new_assignment.module, module)
|
||||
self.assertEqual(new_content_block.contents[1].value["survey_id"], new_survey)
|
||||
self.assertEqual(new_survey.module, module)
|
||||
|
||||
def test_content_block_after_copy_hook(self):
|
||||
"""
|
||||
should copy the content block, and set all entities' module to the new parent's parent module
|
||||
"""
|
||||
# inspired by wagtail.admin.tests.pages.test_copy_page
|
||||
|
||||
url = get_copy_url(self.content_block)
|
||||
post_data = get_copy_payload(
|
||||
"Neuer Titel (Kopie)", "new-slug", self.new_chapter
|
||||
)
|
||||
self.client.post(url, post_data)
|
||||
self._check_copied_content_block()
|
||||
|
||||
def test_chapter_after_copy_hook(self):
|
||||
"""
|
||||
should copy the chapter, and set all entities' module to the new parent module
|
||||
"""
|
||||
url = get_copy_url(self.chapter)
|
||||
post_data = get_copy_payload("Neuer Titel (Kopie)", "new-slug", self.new_module)
|
||||
self.client.post(url, post_data)
|
||||
self._check_copied_content_block()
|
||||
|
||||
def test_module_after_copy_hook(self):
|
||||
"""
|
||||
should copy the module, and set all entities' module to the newly created module
|
||||
"""
|
||||
url = get_copy_url(self.module)
|
||||
post_data = get_copy_payload("Neuer Titel (Kopie)", "new-slug", self.new_topic)
|
||||
self.client.post(url, post_data)
|
||||
module = Module.objects.latest("-latest_revision_created_at")
|
||||
self._check_copied_content_block(module)
|
||||
|
||||
def test_topic_after_copy_hook(self):
|
||||
"""
|
||||
should copy the whole topic, and set all entities to the newly created child module
|
||||
"""
|
||||
url = get_copy_url(self.topic)
|
||||
post_data = get_copy_payload("Neuer Titel (Kopie)", "new-slug", self.book)
|
||||
self.client.post(url, post_data)
|
||||
topic = Topic.objects.latest("-latest_revision_created_at")
|
||||
module = topic.get_children().first().specific
|
||||
self._check_copied_content_block(module)
|
||||
|
||||
# def test_chapter_after_move_hook(self):
|
||||
# """
|
||||
# should move the chapter, and set all entities' module to the new parent's parent module
|
||||
# """
|
||||
#
|
||||
# assignment = self.content_block.contents[0].value["assignment_id"]
|
||||
# survey = self.content_block.contents[1].value["survey_id"]
|
||||
# self.assertEqual(self.chapter.pk, self.content_block.get_parent().pk)
|
||||
#
|
||||
# logger.debug("content blocks")
|
||||
# logger.debug(self.chapter.get_content_blocks())
|
||||
#
|
||||
# url = reverse(
|
||||
# "wagtailadmin_pages:move_confirm",
|
||||
# args=(self.chapter.id, self.new_module.id),
|
||||
# )
|
||||
# logger.debug(url)
|
||||
# response = self.client.post(url)
|
||||
# logger.debug(response)
|
||||
# chapter = Page.objects.get(id=self.chapter.id)
|
||||
# logger.debug("new content blocks")
|
||||
# logger.debug(chapter.specific.get_content_blocks())
|
||||
# self.assertEqual(chapter.get_parent().id, self.new_module.id)
|
||||
# # reload the assignment from the DB
|
||||
# assignment = Assignment.objects.get(id=assignment.id)
|
||||
# self.assertEqual(assignment.module, self.new_module)
|
||||
# survey = Survey.objects.get(id=survey.id)
|
||||
# self.assertEqual(survey.module, self.new_module)
|
||||
|
||||
# def test_content_block_after_move_hook(self):
|
||||
# """
|
||||
# should move the content block, and set all entities' module to the new parent's parent module
|
||||
# """
|
||||
#
|
||||
# url = reverse(
|
||||
# "wagtailadmin_pages:move_confirm",
|
||||
# args=(self.content_block.id, self.new_chapter.id),
|
||||
# )
|
||||
# self.client.post(url)
|
||||
# assignment = self.content_block.contents[0].value["assignment_id"]
|
||||
# self.assertEqual(assignment.module, self.new_module)
|
||||
|
||||
def test_content_block_after_create_hook(self):
|
||||
"""
|
||||
should save the content block and set all new entites' module to the correct module
|
||||
"""
|
||||
assignment = AssignmentFactory(module=self.module)
|
||||
survey = SurveyFactory(module=None)
|
||||
self.assertEqual(assignment.module, assignment.module)
|
||||
self.assertIsNone(survey.module)
|
||||
self.assertEqual(ContentBlock.objects.count(), 1)
|
||||
url = reverse(
|
||||
"wagtailadmin_pages:add",
|
||||
args=("books", "contentblock", self.new_chapter.id),
|
||||
)
|
||||
post_data = {
|
||||
"title": "New Content Block",
|
||||
"order": 1,
|
||||
"slug": "hello-world",
|
||||
"contents-count": 2,
|
||||
"contents-0-deleted": "",
|
||||
"contents-0-order": "0",
|
||||
"contents-0-type": "assignment",
|
||||
"contents-0-id": "",
|
||||
"contents-0-value-assignment_id": f"{assignment.id}",
|
||||
"contents-1-deleted": "",
|
||||
"contents-1-order": "1",
|
||||
"contents-1-type": "survey",
|
||||
"contents-1-id": "",
|
||||
"contents-1-value-survey_id": f"{survey.id}",
|
||||
"type": "normal",
|
||||
}
|
||||
response = self.client.post(
|
||||
url,
|
||||
post_data,
|
||||
)
|
||||
self.assertEqual(ContentBlock.objects.count(), 2)
|
||||
# reload assignment
|
||||
assignment = Assignment.objects.get(id=assignment.id)
|
||||
self.assertEqual(assignment.module, self.new_module)
|
||||
survey = Survey.objects.get(id=survey.id)
|
||||
self.assertEqual(survey.module, self.new_module)
|
||||
|
|
@ -5,7 +5,7 @@ from django.contrib import admin
|
|||
from django.urls import re_path
|
||||
from django.views.generic import RedirectView
|
||||
from wagtail.admin import urls as wagtailadmin_urls
|
||||
from wagtail.core import urls as wagtail_urls
|
||||
from wagtail import urls as wagtail_urls
|
||||
from wagtail.documents import urls as wagtaildocs_urls
|
||||
|
||||
from wagtailautocomplete.urls.admin import urlpatterns as autocomplete_admin_urls
|
||||
|
|
@ -15,21 +15,20 @@ from core.views import override_wagtailadmin_explore_default_ordering
|
|||
|
||||
urlpatterns = [
|
||||
# django admin
|
||||
url(r'^guru/', admin.site.urls),
|
||||
url(r'^statistics/', include('statistics.urls', namespace='statistics')),
|
||||
|
||||
url(r"^guru/", admin.site.urls),
|
||||
url(r"^statistics/", include("statistics.urls", namespace="statistics")),
|
||||
# wagtail
|
||||
url(r'^admin/autocomplete/', include(autocomplete_admin_urls)),
|
||||
re_path(r'^cms/pages/(\d+)/$', override_wagtailadmin_explore_default_ordering),
|
||||
url(r'^cms/', include(wagtailadmin_urls)),
|
||||
url(r'^documents/', include(wagtaildocs_urls)),
|
||||
|
||||
url(r"^cms/autocomplete/", include(autocomplete_admin_urls)),
|
||||
re_path(r"^cms/pages/(\d+)/$", override_wagtailadmin_explore_default_ordering),
|
||||
url(r"^cms/", include(wagtailadmin_urls)),
|
||||
url(r"^documents/", include(wagtaildocs_urls)),
|
||||
# graphql backend
|
||||
url(r'^api/', include('api.urls', namespace="api")),
|
||||
|
||||
#favicon
|
||||
url(r'^favicon\.ico$', RedirectView.as_view(url='/static/favicon@2x.png', permanent=True)),
|
||||
|
||||
url(r"^api/", include("api.urls", namespace="api")),
|
||||
# favicon
|
||||
url(
|
||||
r"^favicon\.ico$",
|
||||
RedirectView.as_view(url="/static/favicon@2x.png", permanent=True),
|
||||
),
|
||||
]
|
||||
|
||||
if settings.DEBUG and not settings.USE_AWS:
|
||||
|
|
@ -39,11 +38,13 @@ if settings.DEBUG:
|
|||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
|
||||
if settings.ENABLE_SILKY:
|
||||
urlpatterns += [url(r'^silk/', include('silk.urls', namespace='silk'))]
|
||||
urlpatterns += [url(r"^silk/", include("silk.urls", namespace="silk"))]
|
||||
|
||||
# actually we use the cms in headless mode but need the url pattern to get the wagtail_serve function
|
||||
urlpatterns += [url(r'pages/', include(wagtail_urls)), ]
|
||||
urlpatterns += [
|
||||
url(r"pages/", include(wagtail_urls)),
|
||||
]
|
||||
|
||||
urlpatterns += [re_path(r'^.*$', views.home, name='home')]
|
||||
urlpatterns += [re_path(r"^.*$", views.home, name="home")]
|
||||
|
||||
admin.site.site_header = 'Myskillbox Admin'
|
||||
admin.site.site_header = "Myskillbox Admin"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
from django.http.request import HttpRequest
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
|
|
@ -5,10 +6,34 @@ from django.http.response import HttpResponse, HttpResponseRedirect
|
|||
from django.shortcuts import render
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from graphene_django.views import GraphQLView
|
||||
from sentry_sdk.api import start_transaction
|
||||
from wagtail.admin.views.pages.listing import index as wagtailadmin_explore
|
||||
|
||||
|
||||
class PrivateGraphQLView(LoginRequiredMixin, GraphQLView):
|
||||
# For sentry perfomance monitoring
|
||||
# taken from https://jerrynsh.com/how-to-monitor-python-graphql-api-with-sentry/
|
||||
class SentryGraphQLView(GraphQLView):
|
||||
def execute_graphql_request(
|
||||
self,
|
||||
request: HttpRequest,
|
||||
data,
|
||||
query,
|
||||
variables,
|
||||
operation_name,
|
||||
show_graphiql,
|
||||
):
|
||||
operation_type = (
|
||||
self.get_backend(request)
|
||||
.document_from_string(self.schema, query)
|
||||
.get_operation_type(operation_name)
|
||||
)
|
||||
with start_transaction(op=operation_type, name=operation_name):
|
||||
return super().execute_graphql_request(
|
||||
request, data, query, variables, operation_name, show_graphiql
|
||||
)
|
||||
|
||||
|
||||
class PrivateGraphQLView(LoginRequiredMixin, SentryGraphQLView):
|
||||
pass
|
||||
|
||||
|
||||
|
|
@ -16,22 +41,24 @@ class PrivateGraphQLView(LoginRequiredMixin, GraphQLView):
|
|||
def home(request):
|
||||
if settings.SERVE_VIA_WEBPACK:
|
||||
try:
|
||||
res = requests.get('http://localhost:8080{}'.format(request.get_full_path()))
|
||||
res = requests.get(
|
||||
"http://localhost:8080{}".format(request.get_full_path())
|
||||
)
|
||||
headers = res.headers
|
||||
content_type = headers.get('content-type', 'text/html')
|
||||
content_type = headers.get("content-type", "text/html")
|
||||
return HttpResponse(res.text, content_type=content_type)
|
||||
except Exception as e:
|
||||
print('Can not connect to dev server at http://localhost:8080:', e)
|
||||
print("Can not connect to dev server at http://localhost:8080:", e)
|
||||
|
||||
return render(request, 'index.html', {})
|
||||
return render(request, "index.html", {})
|
||||
|
||||
|
||||
def override_wagtailadmin_explore_default_ordering(request, parent_page_id):
|
||||
"""
|
||||
Wrap Wagtail's explore view to change the default ordering
|
||||
"""
|
||||
if request.method == 'GET' and 'ordering' not in request.GET:
|
||||
if request.method == "GET" and "ordering" not in request.GET:
|
||||
# Display reordering handles by default for children of all Page types.
|
||||
return HttpResponseRedirect(request.path_info + '?ordering=ord')
|
||||
return HttpResponseRedirect(request.path_info + "?ordering=ord")
|
||||
|
||||
return wagtailadmin_explore(request, parent_page_id=parent_page_id)
|
||||
|
|
|
|||
|
|
@ -1,90 +1,200 @@
|
|||
from django.db.models import ProtectedError
|
||||
from django.shortcuts import redirect
|
||||
from wagtail.admin import messages
|
||||
import wagtail.admin.rich_text.editors.draftail.features as draftail_features
|
||||
from wagtail.admin.rich_text.converters.html_to_contentstate import InlineStyleElementHandler
|
||||
from wagtail.core import hooks
|
||||
from wagtail.admin.rich_text.converters.html_to_contentstate import (
|
||||
InlineStyleElementHandler,
|
||||
)
|
||||
from wagtail import hooks
|
||||
from wagtail.admin.utils import get_valid_next_url_from_request
|
||||
|
||||
from basicknowledge.models import BasicKnowledge
|
||||
from books.models import ContentBlockSnapshot
|
||||
from books.models.chapter import Chapter
|
||||
from books.models.contentblock import ContentBlock
|
||||
from core.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
# 1. Use the register_rich_text_features hook.
|
||||
@hooks.register('register_rich_text_features')
|
||||
@hooks.register("register_rich_text_features")
|
||||
def register_brand_feature(features):
|
||||
"""
|
||||
Registering the feature, which uses the `BRAND` Draft.js inline style type,
|
||||
and is stored as HTML with a `<span class="brand">` tag.
|
||||
"""
|
||||
feature_name = 'brand'
|
||||
type_ = 'BRAND'
|
||||
feature_name = "brand"
|
||||
type_ = "BRAND"
|
||||
|
||||
# 2. Configure how Draftail handles the feature in its toolbar.
|
||||
control = {
|
||||
'type': type_,
|
||||
'label': 'Grün',
|
||||
'description': 'Grün',
|
||||
'style': {
|
||||
'color': '#17A887',
|
||||
'font-weight': '600'
|
||||
},
|
||||
"type": type_,
|
||||
"label": "Grün",
|
||||
"description": "Grün",
|
||||
"style": {"color": "#17A887", "font-weight": "600"},
|
||||
}
|
||||
|
||||
# 3. Call register_editor_plugin to register the configuration for Draftail.
|
||||
features.register_editor_plugin(
|
||||
'draftail', feature_name, draftail_features.InlineStyleFeature(control)
|
||||
"draftail", feature_name, draftail_features.InlineStyleFeature(control)
|
||||
)
|
||||
|
||||
# 4.configure the content transform from the DB to the editor and back.
|
||||
db_conversion = {
|
||||
'from_database_format': {'span[class="brand"]': InlineStyleElementHandler(type_)},
|
||||
'to_database_format': {'style_map': {type_: 'span class="brand""'}},
|
||||
"from_database_format": {
|
||||
'span[class="brand"]': InlineStyleElementHandler(type_)
|
||||
},
|
||||
"to_database_format": {"style_map": {type_: 'span class="brand""'}},
|
||||
}
|
||||
|
||||
# 5. Call register_converter_rule to register the content transformation conversion.
|
||||
features.register_converter_rule('contentstate', feature_name, db_conversion)
|
||||
features.register_converter_rule("contentstate", feature_name, db_conversion)
|
||||
|
||||
# 6. (optional) Add the feature to the default features list to make it available
|
||||
# on rich text fields that do not specify an explicit 'features' list
|
||||
features.default_features.append(feature_name)
|
||||
|
||||
|
||||
@hooks.register('register_rich_text_features')
|
||||
@hooks.register("register_rich_text_features")
|
||||
def register_secondary_feature(features):
|
||||
"""
|
||||
Registering the feature, which uses the `SECONDARY` Draft.js inline style type,
|
||||
and is stored as HTML with a `<span class="secondary">` tag.
|
||||
"""
|
||||
feature_name = 'secondary'
|
||||
type_ = 'SECONDARY'
|
||||
feature_name = "secondary"
|
||||
type_ = "SECONDARY"
|
||||
|
||||
# 2. Configure how Draftail handles the feature in its toolbar.
|
||||
control = {
|
||||
'type': type_,
|
||||
'label': 'Blau',
|
||||
'description': 'Blau',
|
||||
'style': {
|
||||
'color': '#078CC6',
|
||||
'font-weight': '600'
|
||||
},
|
||||
"type": type_,
|
||||
"label": "Blau",
|
||||
"description": "Blau",
|
||||
"style": {"color": "#078CC6", "font-weight": "600"},
|
||||
}
|
||||
|
||||
# 3. Call register_editor_plugin to register the configuration for Draftail.
|
||||
features.register_editor_plugin(
|
||||
'draftail', feature_name, draftail_features.InlineStyleFeature(control)
|
||||
"draftail", feature_name, draftail_features.InlineStyleFeature(control)
|
||||
)
|
||||
|
||||
# 4.configure the content transform from the DB to the editor and back.
|
||||
db_conversion = {
|
||||
'from_database_format': {'span[class="secondary"]': InlineStyleElementHandler(type_)},
|
||||
'to_database_format': {'style_map': {type_: 'span class="secondary"'}},
|
||||
"from_database_format": {
|
||||
'span[class="secondary"]': InlineStyleElementHandler(type_)
|
||||
},
|
||||
"to_database_format": {"style_map": {type_: 'span class="secondary"'}},
|
||||
}
|
||||
|
||||
# 5. Call register_converter_rule to register the content transformation conversion.
|
||||
features.register_converter_rule('contentstate', feature_name, db_conversion)
|
||||
features.register_converter_rule("contentstate", feature_name, db_conversion)
|
||||
|
||||
# 6. (optional) Add the feature to the default features list to make it available
|
||||
# on rich text fields that do not specify an explicit 'features' list
|
||||
features.default_features.append(feature_name)
|
||||
|
||||
|
||||
@hooks.register('construct_explorer_page_queryset')
|
||||
@hooks.register("construct_explorer_page_queryset")
|
||||
def remove_page_types_from_menu(parent_page, pages, request):
|
||||
return pages.not_type(ContentBlockSnapshot).not_type(BasicKnowledge).exclude(contentblock__user_created=True)
|
||||
return (
|
||||
pages.not_type(ContentBlockSnapshot)
|
||||
.not_type(BasicKnowledge)
|
||||
.exclude(contentblock__user_created=True)
|
||||
)
|
||||
|
||||
|
||||
@hooks.register("after_copy_page")
|
||||
def after_copy_hook(request, page, new_page):
|
||||
# todo: find every ContentBlock further down in the tree, see if there are any Surveys or Assignments and copy them and reassign them
|
||||
if type(page.specific) == ContentBlock:
|
||||
# logger.debug("It's a content block")
|
||||
content_block: ContentBlock = new_page.specific
|
||||
# logger.debug(f"duplicatin {content_block.title, content_block.pk}")
|
||||
content_block.duplicate_attached_entities()
|
||||
|
||||
else:
|
||||
# logger.debug(f"It's something else {type(page.specific)}, {ContentBlock}")
|
||||
content_blocks = new_page.specific.get_content_blocks()
|
||||
for content_block in content_blocks:
|
||||
content_block.duplicate_attached_entities()
|
||||
|
||||
|
||||
@hooks.register("after_move_page")
|
||||
def after_move_hook(request, page):
|
||||
logger.debug(f"after moving the page {page.title}")
|
||||
if type(page.specific) == ContentBlock:
|
||||
logger.debug("it's a content block")
|
||||
page.specific.reassign_entities()
|
||||
if type(page.specific) == Chapter:
|
||||
logger.debug("it's a chapter")
|
||||
content_blocks = page.specific.get_content_blocks()
|
||||
logger.debug(page.id)
|
||||
logger.debug(page.specific.get_content_blocks())
|
||||
logger.debug(page.get_children())
|
||||
for content_block in content_blocks:
|
||||
content_block.reassign_entities()
|
||||
|
||||
|
||||
@hooks.register("after_edit_page")
|
||||
def after_edit_hook(request, page):
|
||||
logger.debug(f"After edit page {page.title}, {type(page).__name__}")
|
||||
|
||||
|
||||
@hooks.register("after_create_page")
|
||||
def after_create_hook(request, page):
|
||||
# reassign assignment and survey module
|
||||
if type(page.specific) == ContentBlock:
|
||||
content_block = page.specific
|
||||
content_block.reassign_entities()
|
||||
|
||||
|
||||
@hooks.register("before_delete_page")
|
||||
def on_page_delete(request, page):
|
||||
if request.method != "POST":
|
||||
return
|
||||
|
||||
try:
|
||||
next_url = get_valid_next_url_from_request(request)
|
||||
parent_id = page.get_parent().id
|
||||
page.delete()
|
||||
|
||||
messages.success(
|
||||
request, ("Page '{0}' deleted.").format(page.get_admin_display_title())
|
||||
)
|
||||
|
||||
for fn in hooks.get_hooks("after_delete_page"):
|
||||
result = fn(request, page)
|
||||
if hasattr(result, "status_code"):
|
||||
return result
|
||||
|
||||
if next_url:
|
||||
return redirect(next_url)
|
||||
return redirect("wagtailadmin_explore", parent_id)
|
||||
|
||||
except ProtectedError as exc:
|
||||
protected_objects = {}
|
||||
for obj in exc.protected_objects:
|
||||
model_name = obj._meta.verbose_name_plural
|
||||
if model_name in protected_objects:
|
||||
protected_objects[model_name].append(str(obj))
|
||||
else:
|
||||
protected_objects[model_name] = [str(obj)]
|
||||
|
||||
dependency_summary = []
|
||||
for model_name, items in protected_objects.items():
|
||||
if len(items) == 1:
|
||||
items_summary = ("{0} ({1})").format(model_name, items[0])
|
||||
else:
|
||||
items_summary = ("{0} ({1} and {2} more...)").format(
|
||||
model_name, items[0], len(items) - 1
|
||||
)
|
||||
|
||||
dependency_summary.append(items_summary)
|
||||
|
||||
messages.error(
|
||||
request,
|
||||
("Page '{0}' cannot be deleted while it's used by {1}").format(
|
||||
page.get_admin_display_title(), ", ".join(dependency_summary)
|
||||
),
|
||||
)
|
||||
return redirect("wagtailadmin_pages:delete", page.id)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from django.contrib import admin
|
||||
from wagtail.admin.edit_handlers import CommentPanel
|
||||
from wagtail.admin.edit_handlers import FieldPanel, ObjectList
|
||||
from wagtail.core.models import Page
|
||||
from wagtail.admin.panels import CommentPanel
|
||||
from wagtail.admin.panels import FieldPanel, ObjectList
|
||||
from wagtail.models import Page
|
||||
|
||||
|
||||
class StrictHierarchyPage(Page):
|
||||
|
|
@ -9,20 +9,27 @@ class StrictHierarchyPage(Page):
|
|||
abstract = True
|
||||
|
||||
def get_child_ids(self):
|
||||
return self.get_children().values_list('id', flat=True)
|
||||
return self.get_children().values_list("id", flat=True)
|
||||
|
||||
@classmethod
|
||||
def get_by_parent(cls, parent):
|
||||
return cls.objects.filter(id__in=parent.get_child_ids()).live()
|
||||
|
||||
def get_content_blocks(self):
|
||||
from books.models.contentblock import ContentBlock
|
||||
|
||||
return ContentBlock.objects.all().descendant_of(self)
|
||||
|
||||
|
||||
def wagtail_parent_filter(parent_cls, child_cls):
|
||||
class ParentValueFilter(admin.SimpleListFilter):
|
||||
title = 'parent'
|
||||
parameter_name = 'parent'
|
||||
title = "parent"
|
||||
parameter_name = "parent"
|
||||
|
||||
def lookups(self, request, model_admin):
|
||||
return list((parent.slug, parent.title) for parent in parent_cls.objects.all())
|
||||
return list(
|
||||
(parent.slug, parent.title) for parent in parent_cls.objects.all()
|
||||
)
|
||||
|
||||
def queryset(self, request, queryset):
|
||||
filter_value = self.value()
|
||||
|
|
@ -34,7 +41,4 @@ def wagtail_parent_filter(parent_cls, child_cls):
|
|||
|
||||
|
||||
def get_default_settings():
|
||||
return ObjectList([
|
||||
FieldPanel('slug'),
|
||||
CommentPanel()
|
||||
], heading='Settings')
|
||||
return ObjectList([FieldPanel("slug"), CommentPanel()], heading="Settings")
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue