Merge branch 'develop'
This commit is contained in:
commit
8bcb76709c
15
README.md
15
README.md
|
|
@ -128,21 +128,8 @@ Change DATABASE URL (e.g after a rollback)
|
||||||
|
|
||||||
### Backup
|
### Backup
|
||||||
|
|
||||||
Create a backup
|
See [Docs](./docs/heroku-backup.md)
|
||||||
|
|
||||||
`heroku pg:backups:capture --app <appname>`
|
|
||||||
|
|
||||||
The following command will provide a URL to where the backup can be downloaded (expires after 60 minutes)
|
|
||||||
|
|
||||||
`heroku pg:backups:url b001 --app <appname>`
|
|
||||||
|
|
||||||
To restore a backup, use
|
|
||||||
|
|
||||||
`heroku pg:backups:restore b001 DATABASE_URL --app <appname>`
|
|
||||||
|
|
||||||
To see the backup schedule
|
|
||||||
|
|
||||||
`heroku pg:backus:schedules --app <appname>`
|
|
||||||
|
|
||||||
## AWS
|
## AWS
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
|
|
||||||
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
const {VueLoaderPlugin} = require('vue-loader');
|
||||||
|
|
||||||
const {isDev, styleRule, assetsPath} = require('./utils');
|
const {isDev, styleRule, assetsPath} = require('./utils');
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ module.exports = {
|
||||||
alias: {
|
alias: {
|
||||||
'@': resolve('src'),
|
'@': resolve('src'),
|
||||||
styles: resolve('src/styles'),
|
styles: resolve('src/styles'),
|
||||||
gql: resolve('src/graphql/gql')
|
gql: resolve('src/graphql/gql'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
|
|
@ -64,9 +64,9 @@ module.exports = {
|
||||||
test: /\.tsx?$/,
|
test: /\.tsx?$/,
|
||||||
loader: 'ts-loader',
|
loader: 'ts-loader',
|
||||||
options: {
|
options: {
|
||||||
appendTsSuffixTo: [/\.vue$/]
|
appendTsSuffixTo: [/\.vue$/],
|
||||||
},
|
},
|
||||||
exclude: /node_modules/
|
exclude: /node_modules/,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
|
|
@ -79,7 +79,7 @@ module.exports = {
|
||||||
{
|
{
|
||||||
test: /\.(gql|graphql)$/,
|
test: /\.(gql|graphql)$/,
|
||||||
loader: 'graphql-tag/loader',
|
loader: 'graphql-tag/loader',
|
||||||
exclude: /node_modules/
|
exclude: /node_modules/,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,13 @@ const classMemberIdIterator = idGenerator('ClassMemberNode');
|
||||||
const chapterIdIterator = idGenerator('ChapterNode');
|
const chapterIdIterator = idGenerator('ChapterNode');
|
||||||
const moduleIdIterator = idGenerator('ModuleNode');
|
const moduleIdIterator = idGenerator('ModuleNode');
|
||||||
const contentBlockIdIterator = idGenerator('ContentBlockNode');
|
const contentBlockIdIterator = idGenerator('ContentBlockNode');
|
||||||
|
const instrumentIdGenerator = idGenerator('InstrumentNode');
|
||||||
|
|
||||||
const getClassMemberId = () => classMemberIdIterator.next().value;
|
const getClassMemberId = () => classMemberIdIterator.next().value;
|
||||||
const getChapterId = () => chapterIdIterator.next().value;
|
const getChapterId = () => chapterIdIterator.next().value;
|
||||||
const getModuleId = () => moduleIdIterator.next().value;
|
const getModuleId = () => moduleIdIterator.next().value;
|
||||||
const getContentBlockId = () => contentBlockIdIterator.next().value;
|
const getContentBlockId = () => contentBlockIdIterator.next().value;
|
||||||
|
const getInstrumentId = () => instrumentIdGenerator.next().value;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
UUID: () => '123-456-789',
|
UUID: () => '123-456-789',
|
||||||
|
|
@ -108,5 +110,11 @@ export default {
|
||||||
RoomEntryNode: () => ({
|
RoomEntryNode: () => ({
|
||||||
title: 'A Room Entry',
|
title: 'A Room Entry',
|
||||||
contents: [],
|
contents: [],
|
||||||
|
}),
|
||||||
|
InstrumentNode: () => ({
|
||||||
|
contents: [],
|
||||||
|
title: 'instrument-title',
|
||||||
|
slug: 'instrument-slug',
|
||||||
|
id: getInstrumentId(),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
describe('Instruments Page', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.setup();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('opens the instruments page', () => {
|
||||||
|
const analyse = {
|
||||||
|
name: 'Analyse',
|
||||||
|
category: 'LANGUAGE_COMMUNICATION',
|
||||||
|
type: 'analyse',
|
||||||
|
};
|
||||||
|
|
||||||
|
const argumentation = {
|
||||||
|
name: 'Argumentation',
|
||||||
|
category: 'LANGUAGE_COMMUNICATION',
|
||||||
|
type: 'argumentation',
|
||||||
|
};
|
||||||
|
|
||||||
|
const ethik = {
|
||||||
|
name: 'Ethik',
|
||||||
|
category: 'SOCIETY',
|
||||||
|
type: 'ethik',
|
||||||
|
};
|
||||||
|
|
||||||
|
cy.mockGraphqlOps({
|
||||||
|
operations: {
|
||||||
|
MeQuery: {},
|
||||||
|
InstrumentsQuery: {
|
||||||
|
instruments: [
|
||||||
|
{
|
||||||
|
type: analyse,
|
||||||
|
title: 'Instrument: Analyse',
|
||||||
|
slug: 'analyse',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: argumentation,
|
||||||
|
title: 'Instrument: Argumentation',
|
||||||
|
slug: 'argumentation',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: ethik,
|
||||||
|
title: 'Instrument: Ethik',
|
||||||
|
slug: 'ethik',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
InstrumentTypesQuery: {
|
||||||
|
instrumentTypes: [
|
||||||
|
analyse,
|
||||||
|
argumentation,
|
||||||
|
{
|
||||||
|
name: 'Beschreibung',
|
||||||
|
category: 'LANGUAGE_COMMUNICATION',
|
||||||
|
type: 'beschreibung',
|
||||||
|
},
|
||||||
|
ethik,
|
||||||
|
{
|
||||||
|
name: 'Identität und Sozialisation',
|
||||||
|
category: 'SOCIETY',
|
||||||
|
type: 'identitt-und-sozialisation',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
cy.visit('instruments/');
|
||||||
|
|
||||||
|
cy.getByDataCy('instrument').should('have.length', 3);
|
||||||
|
|
||||||
|
cy.getByDataCy('filter-language-communication').click();
|
||||||
|
cy.getByDataCy('instrument').should('have.length', 2);
|
||||||
|
|
||||||
|
cy.getByDataCy('filter-society').click();
|
||||||
|
cy.getByDataCy('instrument').should('have.length', 1);
|
||||||
|
|
||||||
|
cy.getByDataCy('filter-interdisciplinary').click();
|
||||||
|
cy.getByDataCy('instrument').should('have.length', 0);
|
||||||
|
|
||||||
|
cy.getByDataCy('filter-analyse').click();
|
||||||
|
cy.getByDataCy('instrument').should('have.length', 1);
|
||||||
|
|
||||||
|
cy.getByDataCy('filter-ethik').click();
|
||||||
|
cy.getByDataCy('instrument').should('have.length', 1);
|
||||||
|
|
||||||
|
cy.getByDataCy('filter-all-instruments').click();
|
||||||
|
cy.getByDataCy('instrument').should('have.length', 3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -6,21 +6,34 @@ describe('Sidebar', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should open sidebar and stay open', () => {
|
it('should open sidebar and stay open', () => {
|
||||||
|
const {me} = getMinimalMe({});
|
||||||
const operations = {
|
const operations = {
|
||||||
MeQuery: getMinimalMe({}),
|
MeQuery: {
|
||||||
|
me: {
|
||||||
|
...me,
|
||||||
|
schoolClasses: {
|
||||||
|
edges: [
|
||||||
|
...me.schoolClasses.edges,
|
||||||
|
{node: {}},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
ProjectsQuery: {
|
ProjectsQuery: {
|
||||||
projects: []
|
projects: [],
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
cy.mockGraphqlOps({
|
cy.mockGraphqlOps({
|
||||||
operations
|
operations,
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.visit('/portfolio');
|
cy.visit('/portfolio');
|
||||||
cy.getByDataCy('sidebar').should('not.exist');
|
cy.getByDataCy('sidebar').should('not.exist');
|
||||||
cy.getByDataCy('user-widget-avatar').click();
|
cy.getByDataCy('user-widget-avatar').click();
|
||||||
cy.getByDataCy('sidebar').should('exist');
|
cy.getByDataCy('sidebar').should('exist');
|
||||||
|
cy.getByDataCy('class-selection').click();
|
||||||
|
cy.getByDataCy('class-selection-entry').should('have.length', 2);
|
||||||
cy.getByDataCy('close-profile-sidebar-link').click();
|
cy.getByDataCy('close-profile-sidebar-link').click();
|
||||||
cy.getByDataCy('sidebar').should('not.exist');
|
cy.getByDataCy('sidebar').should('not.exist');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -43746,6 +43746,13 @@
|
||||||
"integrity": "sha512-q8GgAIPU7xHCsUhB1PUgR//8GoI0bUdMRUKd69jw2UcKy7pGuu0NbJsOGqdSpdpvhO4LY/dgqohPEkE1TrBwKQ==",
|
"integrity": "sha512-q8GgAIPU7xHCsUhB1PUgR//8GoI0bUdMRUKd69jw2UcKy7pGuu0NbJsOGqdSpdpvhO4LY/dgqohPEkE1TrBwKQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"vue": "^2.1.10"
|
"vue": "^2.1.10"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vue": {
|
||||||
|
"version": "2.6.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz",
|
||||||
|
"integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"svgo": {
|
"svgo": {
|
||||||
|
|
@ -45176,6 +45183,13 @@
|
||||||
"babel-preset-env": "^1.6.0",
|
"babel-preset-env": "^1.6.0",
|
||||||
"rollup-plugin-babel": "^3.0.2",
|
"rollup-plugin-babel": "^3.0.2",
|
||||||
"vue": "^2.4.4"
|
"vue": "^2.4.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vue": {
|
||||||
|
"version": "2.6.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz",
|
||||||
|
"integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"vuejs-logger": {
|
"vuejs-logger": {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,152 @@
|
||||||
|
<template>
|
||||||
|
<a
|
||||||
|
:class="typeClass"
|
||||||
|
class="filter-entry">
|
||||||
|
<span class="filter-entry__text">{{ text }}</span>
|
||||||
|
<span class="filter-entry__icon-wrapper">
|
||||||
|
<chevron-right class="filter-entry__icon"/>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ChevronRight from '@/components/icons/ChevronRight';
|
||||||
|
import {INTERDISCIPLINARY, LANGUAGE_COMMUNICATION, SOCIETY} from '@/consts/instrument.consts';
|
||||||
|
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFiler.gql';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
isCategory: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
category: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
ChevronRight,
|
||||||
|
},
|
||||||
|
|
||||||
|
apollo: {
|
||||||
|
instrumentFilter: {
|
||||||
|
query: INSTRUMENT_FILTER_QUERY
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
instrumentFilter: {
|
||||||
|
currentFilter: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isActive() {
|
||||||
|
if (!this.instrumentFilter.currentFilter) {
|
||||||
|
return this.type === '';
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line
|
||||||
|
const [_, identifier] = this.instrumentFilter.currentFilter.split(':');
|
||||||
|
console.log(identifier, this.type);
|
||||||
|
return this.type === identifier;
|
||||||
|
},
|
||||||
|
typeClass() {
|
||||||
|
return {
|
||||||
|
'filter-entry--language-communication': this.category === LANGUAGE_COMMUNICATION,
|
||||||
|
'filter-entry--society': this.category === SOCIETY,
|
||||||
|
'filter-entry--interdisciplinary': this.category === INTERDISCIPLINARY,
|
||||||
|
'filter-entry--active': this.isActive,
|
||||||
|
'filter-entry--category': this.isCategory,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '~styles/helpers';
|
||||||
|
|
||||||
|
.filter-entry {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
@include sub-heading;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
$root: &;
|
||||||
|
|
||||||
|
@mixin filter-block($color) {
|
||||||
|
&#{$root}--category {
|
||||||
|
color: $color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&#{$root}--active {
|
||||||
|
#{$root}__icon-wrapper {
|
||||||
|
background-color: $color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#{$root}__icon {
|
||||||
|
fill: $color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--language-communication {
|
||||||
|
@include filter-block($color-accent-2-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--society {
|
||||||
|
@include filter-block($color-accent-1-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--interdisciplinary {
|
||||||
|
@include filter-block($color-accent-4-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--active {
|
||||||
|
#{$root}__text {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
#{$root}__icon-wrapper {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#{$root}__icon {
|
||||||
|
fill: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
<template>
|
||||||
|
<div class="filter-group">
|
||||||
|
<filter-entry
|
||||||
|
:text="title"
|
||||||
|
v-bind="$attrs"
|
||||||
|
:type="category"
|
||||||
|
:category="category"
|
||||||
|
:is-category="true"
|
||||||
|
@click.native="setCategoryFilter(category)"/>
|
||||||
|
<div class="filter-group__children">
|
||||||
|
<filter-entry
|
||||||
|
:key="type.id"
|
||||||
|
:data-cy="`filter-${type.type}`"
|
||||||
|
:category="type.category"
|
||||||
|
:text="type.name"
|
||||||
|
:type="type.type"
|
||||||
|
v-for="type in types"
|
||||||
|
@click.native="setFilter(`type:${type.type}`)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ChevronRight from '@/components/icons/ChevronRight';
|
||||||
|
import FilterEntry from '@/components/instruments/FilterEntry';
|
||||||
|
|
||||||
|
import SET_FILTER_MUTATION from 'gql/local/mutations/setInstrumentFilter.gql';
|
||||||
|
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFiler.gql';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
types: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
category: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
FilterEntry,
|
||||||
|
ChevronRight,
|
||||||
|
},
|
||||||
|
|
||||||
|
apollo: {
|
||||||
|
instrumentFilter: {
|
||||||
|
query: INSTRUMENT_FILTER_QUERY
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
instrumentFilter: {
|
||||||
|
currentFilter: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
inheritAttrs: false,
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
setCategoryFilter(category) {
|
||||||
|
if (category) {
|
||||||
|
this.setFilter(`category:${category}`);
|
||||||
|
} else {
|
||||||
|
this.setFilter(``);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setFilter(filter) {
|
||||||
|
this.$apollo.mutate({
|
||||||
|
mutation: SET_FILTER_MUTATION,
|
||||||
|
variables: {
|
||||||
|
filter
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '~styles/helpers';
|
||||||
|
|
||||||
|
.filter-group {
|
||||||
|
border-bottom: 1px solid $color-silver;
|
||||||
|
padding: $medium-spacing 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&__children {
|
||||||
|
padding-left: $medium-spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:class="typeClass"
|
||||||
|
class="instrument-entry">
|
||||||
|
<h4 class="instrument-entry__category">{{ categoryName }}</h4>
|
||||||
|
<h3 class="instrument-entry__title">{{ instrument.title }}</h3>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {INTERDISCIPLINARY, LANGUAGE_COMMUNICATION, SOCIETY} from '@/consts/instrument.consts';
|
||||||
|
import instrumentType from '@/helpers/instrumentType';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
instrument: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
typeClass() {
|
||||||
|
return {
|
||||||
|
'instrument-entry__language-communication': this.instrument.type.category === LANGUAGE_COMMUNICATION,
|
||||||
|
'instrument-entry__society': this.instrument.type.category === SOCIETY,
|
||||||
|
'instrument-entry__interdisciplinary': this.instrument.type.category === INTERDISCIPLINARY,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
categoryName() {
|
||||||
|
return instrumentType(this.instrument);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '~styles/helpers';
|
||||||
|
|
||||||
|
.instrument-entry {
|
||||||
|
padding: $medium-spacing;
|
||||||
|
margin-bottom: $medium-spacing;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
@include heading-3;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__category {
|
||||||
|
@include sub-heading;
|
||||||
|
margin-bottom: $small-spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
$root: &;
|
||||||
|
|
||||||
|
&__language-communication {
|
||||||
|
background-color: $color-accent-2-light;
|
||||||
|
|
||||||
|
#{$root}__category {
|
||||||
|
color: $color-accent-2-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__society {
|
||||||
|
background-color: $color-accent-1-light;
|
||||||
|
|
||||||
|
#{$root}__category {
|
||||||
|
color: $color-accent-1-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__interdisciplinary {
|
||||||
|
background-color: $color-accent-4-light;
|
||||||
|
|
||||||
|
#{$root}__category {
|
||||||
|
color: $color-accent-4-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -1,97 +1,90 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="instrument-filter">
|
<div class="instrument-filter">
|
||||||
<checkbox
|
<filter-group
|
||||||
:checked="type.enabled"
|
title="Alle Instrumente"
|
||||||
:class="`instrument-filter__checkbox--${type.cls}`"
|
data-cy="filter-all-instruments"
|
||||||
:label="type.label"
|
|
||||||
:key="i"
|
|
||||||
class="instrument-filter__checkbox"
|
|
||||||
v-for="(type, i) in types"
|
|
||||||
@input="change($event, i)"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<filter-group
|
||||||
|
:types="languageCommunicationTypes"
|
||||||
|
:category="LANGUAGE_COMMUNICATION"
|
||||||
|
title="Sprache und Kommunikation"
|
||||||
|
data-cy="filter-language-communication"
|
||||||
|
class="instrument-filter__group--language"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<filter-group
|
||||||
|
:types="societyTypes"
|
||||||
|
:category="SOCIETY"
|
||||||
|
title="Gesellschaft"
|
||||||
|
data-cy="filter-society"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<filter-group
|
||||||
|
:category="INTERDISCIPLINARY"
|
||||||
|
title="Überfachliche Instrumente"
|
||||||
|
data-cy="filter-interdisciplinary"
|
||||||
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import {INTERDISCIPLINARY, LANGUAGE_COMMUNICATION, SOCIETY} from '@/consts/instrument.consts';
|
||||||
|
|
||||||
import Checkbox from '@/components/ui/Checkbox';
|
import Checkbox from '@/components/ui/Checkbox';
|
||||||
|
import FilterGroup from '@/components/instruments/FilterGroup';
|
||||||
|
|
||||||
|
import INSTRUMENT_TYPES_QUERY from 'gql/queries/instrumentTypesQuery';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
Checkbox
|
FilterGroup,
|
||||||
|
Checkbox,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
filter: [],
|
filter: '',
|
||||||
types: [
|
LANGUAGE_COMMUNICATION,
|
||||||
{
|
SOCIETY,
|
||||||
label: 'Sprache und Kommunikation',
|
INTERDISCIPLINARY,
|
||||||
enabled: true,
|
instrumentTypes: [],
|
||||||
prop: 'LANGUAGE_COMMUNICATION',
|
|
||||||
cls: 'language'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Gesellschaft',
|
|
||||||
enabled: true,
|
|
||||||
prop: 'SOCIETY',
|
|
||||||
cls: 'society'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Überfachliches Instrument',
|
|
||||||
enabled: true,
|
|
||||||
prop: 'INTERDISCIPLINARY',
|
|
||||||
cls: 'interdisciplinary'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
languageCommunicationTypes() {
|
||||||
|
return this.instrumentTypes.filter(t => t.category === 'LANGUAGE_COMMUNICATION');
|
||||||
|
},
|
||||||
|
societyTypes() {
|
||||||
|
return this.instrumentTypes.filter(t => t.category === 'SOCIETY');
|
||||||
|
},
|
||||||
|
interdisciplinaryTypes() {
|
||||||
|
return this.instrumentTypes.filter(t => t.category === 'INTERDISCIPLINARY');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
change(enabled, index) {
|
setFilter(filter) {
|
||||||
let type = this.types[index];
|
this.filter = filter;
|
||||||
this.types = [
|
this.$emit('filter', filter);
|
||||||
...this.types.slice(0, index),
|
|
||||||
{
|
|
||||||
...type,
|
|
||||||
enabled
|
|
||||||
},
|
|
||||||
...this.types.slice(index + 1),
|
|
||||||
];
|
|
||||||
this.$emit('filter',
|
|
||||||
this.types
|
|
||||||
.filter(t => t.enabled)
|
|
||||||
.map(t => t.prop)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
apollo: {
|
||||||
|
instrumentTypes: {
|
||||||
|
query: INSTRUMENT_TYPES_QUERY,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import "~styles/helpers";
|
||||||
|
|
||||||
.instrument-filter {
|
.instrument-filter {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-content: center;
|
flex-direction: column;
|
||||||
|
|
||||||
&__checkbox {
|
|
||||||
&--language {
|
|
||||||
/deep/ input:checked + .checkbox {
|
|
||||||
background-color: $color-accent-1-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--society {
|
|
||||||
/deep/ input:checked + .checkbox {
|
|
||||||
background-color: $color-accent-2-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--interdisciplinary {
|
|
||||||
/deep/ input:checked + .checkbox {
|
|
||||||
background-color: $color-accent-4-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
import ActivityEntry from '@/components/profile/ActivityEntry';
|
import ActivityEntry from '@/components/profile/ActivityEntry';
|
||||||
|
|
||||||
import SCROLL_TO_MUTATION from '@/graphql/gql/local/mutations/scrollTo.gql';
|
import SCROLL_TO_MUTATION from '@/graphql/gql/local/mutations/scrollTo.gql';
|
||||||
|
import instrumentType from '@/helpers/instrumentType';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['instrument', 'filter'],
|
props: ['instrument', 'filter'],
|
||||||
|
|
@ -52,11 +53,7 @@
|
||||||
return this.applyFilter('bookmarks') ? this.instrument.bookmarks : [];
|
return this.applyFilter('bookmarks') ? this.instrument.bookmarks : [];
|
||||||
},
|
},
|
||||||
type() {
|
type() {
|
||||||
if (this.instrument.type === 'LANGUAGE_COMMUNICATION') {
|
return instrumentType(this.instrument);
|
||||||
return 'Sprache & Kommunikation';
|
|
||||||
} else {
|
|
||||||
return 'Gesellschaft';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
export const LANGUAGE_COMMUNICATION = 'LANGUAGE_COMMUNICATION';
|
||||||
|
export const SOCIETY = 'SOCIETY';
|
||||||
|
export const INTERDISCIPLINARY = 'INTERDISCIPLINARY';
|
||||||
|
|
@ -24,6 +24,10 @@ const writeLocalCache = cache => {
|
||||||
__typename: 'HelloEmail',
|
__typename: 'HelloEmail',
|
||||||
email: '',
|
email: '',
|
||||||
},
|
},
|
||||||
|
instrumentFilter: {
|
||||||
|
__typename: 'InstrumentFilter',
|
||||||
|
currentFilter: 'abc'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
query InstrumentFilter {
|
||||||
|
instrumentFilter @client {
|
||||||
|
currentFilter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
mutation($filter: String!) {
|
||||||
|
setInstrumentFilter(filter: $filter) @client
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
query InstrumentTypesQuery {
|
||||||
|
instrumentTypes {
|
||||||
|
name
|
||||||
|
type
|
||||||
|
category
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
query InstrumentQuery($type: String!){
|
|
||||||
instruments(type: $type) {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
contents
|
|
||||||
slug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
query InstrumentQuery {
|
query InstrumentsQuery {
|
||||||
instruments {
|
instruments {
|
||||||
edges {
|
id
|
||||||
node {
|
title
|
||||||
id
|
contents
|
||||||
title
|
slug
|
||||||
contents
|
type {
|
||||||
slug
|
id
|
||||||
type
|
type
|
||||||
}
|
category
|
||||||
|
name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import SCROLL_POSITION from '@/graphql/gql/local/scrollPosition.gql';
|
import SCROLL_POSITION from '@/graphql/gql/local/scrollPosition.gql';
|
||||||
import HELLO_EMAIL from '@/graphql/gql/local/helloEmail.gql';
|
import HELLO_EMAIL from '@/graphql/gql/local/helloEmail.gql';
|
||||||
import SIDEBAR from '@/graphql/gql/local/sidebar.gql';
|
import SIDEBAR from '@/graphql/gql/local/sidebar.gql';
|
||||||
|
import INSTRUMENT_FILTER from '@/graphql/gql/local/instrumentFiler.gql';
|
||||||
|
|
||||||
export const resolvers = {
|
export const resolvers = {
|
||||||
Mutation: {
|
Mutation: {
|
||||||
|
|
@ -16,6 +17,12 @@ export const resolvers = {
|
||||||
cache.writeQuery({query: HELLO_EMAIL, data});
|
cache.writeQuery({query: HELLO_EMAIL, data});
|
||||||
return data.helloEmail;
|
return data.helloEmail;
|
||||||
},
|
},
|
||||||
|
setInstrumentFilter: (_, {filter}, {cache}) => {
|
||||||
|
const data = cache.readQuery({query: INSTRUMENT_FILTER});
|
||||||
|
data.instrumentFilter.currentFilter = filter;
|
||||||
|
cache.writeQuery({query: INSTRUMENT_FILTER, data});
|
||||||
|
return data.instrumentFilter;
|
||||||
|
},
|
||||||
toggleSidebar: (_, {sidebar: {profile, navigation}}, {cache}) => {
|
toggleSidebar: (_, {sidebar: {profile, navigation}}, {cache}) => {
|
||||||
const data = cache.readQuery({query: SIDEBAR});
|
const data = cache.readQuery({query: SIDEBAR});
|
||||||
if (typeof profile !== 'undefined') {
|
if (typeof profile !== 'undefined') {
|
||||||
|
|
@ -26,6 +33,6 @@ export const resolvers = {
|
||||||
}
|
}
|
||||||
cache.writeQuery({query: SIDEBAR, data});
|
cache.writeQuery({query: SIDEBAR, data});
|
||||||
return data.sidebar;
|
return data.sidebar;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@ export const typeDefs = gql`
|
||||||
profile: Boolean
|
profile: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InstrumentFilter {
|
||||||
|
currentFilter: String!
|
||||||
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
scrollTo(scrollTo: String!): ScrollPosition
|
scrollTo(scrollTo: String!): ScrollPosition
|
||||||
helloEmail(email: String!): HelloEmail
|
helloEmail(email: String!): HelloEmail
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import {LANGUAGE_COMMUNICATION, SOCIETY} from '@/consts/instrument.consts';
|
||||||
|
|
||||||
|
const instrumentType = ({type: {category}}) => {
|
||||||
|
if (category === LANGUAGE_COMMUNICATION) {
|
||||||
|
return 'Sprache & Kommunikation';
|
||||||
|
} else if (category === SOCIETY) {
|
||||||
|
return 'Gesellschaft';
|
||||||
|
} else {
|
||||||
|
return 'Überfachliches Instrument';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default instrumentType;
|
||||||
|
|
@ -1,10 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="instrument-overview">
|
<div class="instrument-overview">
|
||||||
<div class="instrument-overview__heading">
|
|
||||||
<h1 class="instrument-overview__title">
|
|
||||||
Instrumente
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
<instrument-filter
|
<instrument-filter
|
||||||
class="instrument-overview__filter"
|
class="instrument-overview__filter"
|
||||||
@filter="updateFilter"/>
|
@filter="updateFilter"/>
|
||||||
|
|
@ -12,10 +7,10 @@
|
||||||
<router-link
|
<router-link
|
||||||
:to="{name: 'instrument', params: {slug: instrument.slug}}"
|
:to="{name: 'instrument', params: {slug: instrument.slug}}"
|
||||||
:key="instrument.id"
|
:key="instrument.id"
|
||||||
class="instrument-overview__list-item"
|
data-cy="instrument"
|
||||||
tag="div"
|
tag="div"
|
||||||
v-for="instrument in filteredInstruments">
|
v-for="instrument in filteredInstruments">
|
||||||
{{ instrument.title }}
|
<instrument-entry :instrument="instrument"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -23,11 +18,15 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import InstrumentFilter from '@/components/instruments/InstrumentFilter';
|
import InstrumentFilter from '@/components/instruments/InstrumentFilter';
|
||||||
|
import InstrumentEntry from '@/components/instruments/InstrumentEntry';
|
||||||
import INSTRUMENTS_QUERY from '@/graphql/gql/queries/instrumentsQuery.gql';
|
import INSTRUMENTS_QUERY from '@/graphql/gql/queries/instrumentsQuery.gql';
|
||||||
|
|
||||||
|
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFiler.gql';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
InstrumentFilter
|
InstrumentFilter,
|
||||||
|
InstrumentEntry,
|
||||||
},
|
},
|
||||||
|
|
||||||
apollo: {
|
apollo: {
|
||||||
|
|
@ -35,27 +34,43 @@
|
||||||
query: INSTRUMENTS_QUERY,
|
query: INSTRUMENTS_QUERY,
|
||||||
update(data) {
|
update(data) {
|
||||||
return this.$getRidOfEdges(data).instruments;
|
return this.$getRidOfEdges(data).instruments;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
instrumentFilter: {
|
||||||
|
query: INSTRUMENT_FILTER_QUERY,
|
||||||
|
update({instrumentFilter}) {
|
||||||
|
const {currentFilter} = instrumentFilter;
|
||||||
|
if (currentFilter && currentFilter.indexOf(':') > -1) {
|
||||||
|
const [filterType, identifier] = currentFilter.split(':');
|
||||||
|
this.filter = i => i.type[filterType] === identifier;
|
||||||
|
} else {
|
||||||
|
this.filter = i => i; // identity
|
||||||
|
}
|
||||||
|
return instrumentFilter;
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
instruments: [],
|
instruments: [],
|
||||||
filter: []
|
filter: i => i, // identity
|
||||||
|
instrumentFilter: {
|
||||||
|
currentFilter: '',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
filteredInstruments() {
|
filteredInstruments() {
|
||||||
return this.instruments.filter(instrument => this.filter.includes(instrument.type) || !this.filter.length);
|
return this.instruments.filter(i => this.filter(i));
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
updateFilter(filter) {
|
updateFilter(filter) {
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -65,24 +80,14 @@
|
||||||
|
|
||||||
.instrument-overview {
|
.instrument-overview {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: auto auto 1fr;
|
//grid-template-rows: auto auto 1fr;
|
||||||
@include centered(800px);
|
grid-template-columns: 300px auto;
|
||||||
|
grid-column-gap: $small-spacing;
|
||||||
&__heading {
|
//@include centered(800px);
|
||||||
padding: 2*$large-spacing 0;
|
padding: 0 $small-spacing;
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
max-width: $screen-width;
|
|
||||||
line-height: 1.2;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__filter {
|
&__filter {
|
||||||
justify-self: start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__list {
|
&__list {
|
||||||
|
|
@ -91,6 +96,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
justify-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__list-item {
|
&__list-item {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,12 @@
|
||||||
font-size: toRem(18px);
|
font-size: toRem(18px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin sub-heading {
|
||||||
|
font-family: $sans-serif-font-family;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: toRem(16px);
|
||||||
|
}
|
||||||
|
|
||||||
@mixin modal-heading {
|
@mixin modal-heading {
|
||||||
@include heading-2;
|
@include heading-2;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,26 @@
|
||||||
### list backups
|
### List backups
|
||||||
|
|
||||||
```
|
```
|
||||||
heroku login
|
heroku login
|
||||||
heroku pg:backups --app skillbox-prod
|
heroku pg:backups --app skillbox-prod
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Create a backup
|
||||||
|
|
||||||
|
`heroku pg:backups:capture --app <appname>`
|
||||||
|
|
||||||
|
The following command will provide a URL to where the backup can be downloaded (expires after 60 minutes)
|
||||||
|
|
||||||
|
`heroku pg:backups:url b001 --app <appname>`
|
||||||
|
|
||||||
|
To restore a backup, use
|
||||||
|
|
||||||
|
`heroku pg:backups:restore b001 DATABASE_URL --app <appname>`
|
||||||
|
|
||||||
|
To see the backup schedule
|
||||||
|
|
||||||
|
`heroku pg:backus:schedules --app <appname>`
|
||||||
|
|
||||||
|
To download a backup use
|
||||||
|
`heroku pg:backups:download --app <appname>`
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from graphene_django.debug import DjangoDebug
|
||||||
from api import graphene_wagtail # Keep this import exactly here, it's necessary for StreamField conversion
|
from api import graphene_wagtail # Keep this import exactly here, it's necessary for StreamField conversion
|
||||||
from assignments.schema.mutations import AssignmentMutations
|
from assignments.schema.mutations import AssignmentMutations
|
||||||
from assignments.schema.queries import AssignmentsQuery, StudentSubmissionQuery
|
from assignments.schema.queries import AssignmentsQuery, StudentSubmissionQuery
|
||||||
from basicknowledge.queries import BasicKnowledgeQuery
|
from basicknowledge.queries import InstrumentQuery
|
||||||
from books.schema.mutations import BookMutations
|
from books.schema.mutations import BookMutations
|
||||||
from books.schema.queries import BookQuery
|
from books.schema.queries import BookQuery
|
||||||
from news.schema import AllNewsTeasersQuery
|
from news.schema import AllNewsTeasersQuery
|
||||||
|
|
@ -27,7 +27,7 @@ from users.mutations import ProfileMutations
|
||||||
|
|
||||||
|
|
||||||
class CustomQuery(UsersQuery, AllUsersQuery, ModuleRoomsQuery, RoomsQuery, ObjectivesQuery, BookQuery, AssignmentsQuery,
|
class CustomQuery(UsersQuery, AllUsersQuery, ModuleRoomsQuery, RoomsQuery, ObjectivesQuery, BookQuery, AssignmentsQuery,
|
||||||
StudentSubmissionQuery, BasicKnowledgeQuery, PortfolioQuery, SurveysQuery, AllNewsTeasersQuery, graphene.ObjectType):
|
StudentSubmissionQuery, InstrumentQuery, PortfolioQuery, SurveysQuery, AllNewsTeasersQuery, graphene.ObjectType):
|
||||||
node = relay.Node.Field()
|
node = relay.Node.Field()
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ from django.http import HttpResponse
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
|
|
||||||
|
from assignments.helpers import write_assignments_to_csv, write_submissions_to_csv
|
||||||
from assignments.models import Assignment, StudentSubmission, SubmissionFeedback
|
from assignments.models import Assignment, StudentSubmission, SubmissionFeedback
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -38,10 +39,7 @@ class AssignmentAdmin(admin.ModelAdmin):
|
||||||
response['Content-Disposition'] = 'attachment;filename=assignment-export.csv'
|
response['Content-Disposition'] = 'attachment;filename=assignment-export.csv'
|
||||||
|
|
||||||
writer = csv.writer(response)
|
writer = csv.writer(response)
|
||||||
field_names = ['ID', 'Titel', 'Auftragstext', 'Modul']
|
write_assignments_to_csv(writer, queryset)
|
||||||
writer.writerow(field_names)
|
|
||||||
for assignment in queryset.all():
|
|
||||||
writer.writerow([assignment.id, assignment.title, assignment.assignment, assignment.module])
|
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
@ -52,11 +50,7 @@ class AssignmentAdmin(admin.ModelAdmin):
|
||||||
response['Content-Disposition'] = 'attachment;filename=assignment-submission-export.csv'
|
response['Content-Disposition'] = 'attachment;filename=assignment-submission-export.csv'
|
||||||
|
|
||||||
writer = csv.writer(response)
|
writer = csv.writer(response)
|
||||||
field_names = ['Assignment-ID', 'Text', 'Mit Lehrer geteilt',]
|
write_submissions_to_csv(writer, queryset)
|
||||||
writer.writerow(field_names)
|
|
||||||
for assignment in queryset.all():
|
|
||||||
for submission in assignment.submissions.filter(final=True):
|
|
||||||
writer.writerow([submission.assignment.id, submission.text, submission.final])
|
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
|
||||||
|
def write_assignments_to_csv(writer, queryset):
|
||||||
|
field_names = ['ID', 'Titel', 'Auftragstext', 'Modul']
|
||||||
|
writer.writerow(field_names)
|
||||||
|
for assignment in queryset.all():
|
||||||
|
writer.writerow([assignment.id, assignment.title, assignment.assignment, assignment.module])
|
||||||
|
|
||||||
|
def write_submissions_to_csv(writer, queryset):
|
||||||
|
field_names = ['Assignment-ID', 'Text', 'Mit Lehrer geteilt', ]
|
||||||
|
writer.writerow(field_names)
|
||||||
|
for submission in queryset.all():
|
||||||
|
writer.writerow([submission.assignment.id, submission.text, submission.final])
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
import csv
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
from assignments.helpers import write_assignments_to_csv, write_submissions_to_csv
|
||||||
|
from assignments.models import Assignment, StudentSubmission
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = """
|
||||||
|
Export assignments with submissions
|
||||||
|
"""
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
ids = [171, 112, 113, 114, 272, 246, 250, 348, 598]
|
||||||
|
|
||||||
|
assignments = Assignment.objects.filter(id__in=ids)
|
||||||
|
|
||||||
|
with open('./export-assignments.csv', 'w') as f:
|
||||||
|
writer = csv.writer(f)
|
||||||
|
write_assignments_to_csv(writer, assignments)
|
||||||
|
|
||||||
|
submissions = StudentSubmission.objects.filter(assignment__id__in=ids)
|
||||||
|
|
||||||
|
with open('./export-submissions.csv', 'w') as f:
|
||||||
|
writer = csv.writer(f)
|
||||||
|
write_submissions_to_csv(writer, submissions)
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Generated by Django 2.2.24 on 2021-10-20 12:02
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('basicknowledge', '0007_basicknowledge_intro'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='InstrumentType',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255)),
|
||||||
|
('category', models.CharField(choices=[('language_communication', 'Sprache & Kommunikation'), ('society', 'Gesellschaft'), ('interdisciplinary', 'Überfachliches Instrument')], max_length=100)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='basicknowledge',
|
||||||
|
name='new_type',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='basicknowledge.InstrumentType'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
# Generated by Django 2.2.24 on 2021-10-20 12:13
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
from basicknowledge.models import INTERDISCIPLINARY, LANGUAGE_COMMUNICATION, SOCIETY
|
||||||
|
|
||||||
|
|
||||||
|
def create_types(apps, schema_editor):
|
||||||
|
BasicKnowledge = apps.get_model('basicknowledge', 'BasicKnowledge')
|
||||||
|
InstrumentType = apps.get_model('basicknowledge', 'InstrumentType')
|
||||||
|
language_type=InstrumentType.objects.create(
|
||||||
|
name='Sprache & Kommunikation',
|
||||||
|
category=LANGUAGE_COMMUNICATION
|
||||||
|
)
|
||||||
|
society_type=InstrumentType.objects.create(
|
||||||
|
name='Gesellschaft',
|
||||||
|
category=SOCIETY
|
||||||
|
)
|
||||||
|
interdisciplinary_type=InstrumentType.objects.create(
|
||||||
|
name='Überfachliches Instrument',
|
||||||
|
category=INTERDISCIPLINARY
|
||||||
|
)
|
||||||
|
instruments = []
|
||||||
|
for instrument in BasicKnowledge.objects.filter(type=LANGUAGE_COMMUNICATION):
|
||||||
|
instrument.new_type=language_type
|
||||||
|
instruments.append(instrument)
|
||||||
|
for instrument in BasicKnowledge.objects.filter(type=SOCIETY):
|
||||||
|
instrument.new_type=society_type
|
||||||
|
instruments.append(instrument)
|
||||||
|
for instrument in BasicKnowledge.objects.filter(type=INTERDISCIPLINARY):
|
||||||
|
instrument.new_type=interdisciplinary_type
|
||||||
|
instruments.append(instrument)
|
||||||
|
|
||||||
|
BasicKnowledge.objects.bulk_update(instruments, ['new_type'])
|
||||||
|
|
||||||
|
|
||||||
|
def delete_types(apps, schema_editor):
|
||||||
|
BasicKnowledge = apps.get_model('basicknowledge', 'BasicKnowledge')
|
||||||
|
InstrumentType = apps.get_model('basicknowledge', 'InstrumentType')
|
||||||
|
instruments = []
|
||||||
|
for instrument in BasicKnowledge.objects.all():
|
||||||
|
instrument.new_type = None
|
||||||
|
instruments.append(instrument)
|
||||||
|
BasicKnowledge.objects.bulk_update(instruments, ['new_type'])
|
||||||
|
InstrumentType.objects.all().delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('basicknowledge', '0008_auto_20211020_1202'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(create_types, delete_types)
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.24 on 2021-10-30 20:04
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('basicknowledge', '0009_auto_20211020_1213'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='basicknowledge',
|
||||||
|
old_name='type',
|
||||||
|
new_name='old_type',
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.24 on 2021-10-31 11:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('basicknowledge', '0010_auto_20211030_2004'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='instrumenttype',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=255, unique=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Generated by Django 2.2.24 on 2021-11-01 10:08
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
from basicknowledge.models import LANGUAGE_COMMUNICATION, SOCIETY
|
||||||
|
from core.logger import get_logger
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def create_new_types(apps, schema_editor):
|
||||||
|
InstrumentType = apps.get_model('basicknowledge', 'InstrumentType')
|
||||||
|
language_communication_types = [
|
||||||
|
'Analyse', 'Argumentation', 'Beschreibung', 'Grafiken', 'Interview',
|
||||||
|
'Kommunikation', 'Korrespondenz', 'Orthografie', 'Präsentation',
|
||||||
|
'Struktur', 'Umfrage', 'Zusammenfassung', 'Blog'
|
||||||
|
]
|
||||||
|
society_types = [
|
||||||
|
'Ethik', 'Identität und Sozialisation', 'Kultur', 'Ökologie',
|
||||||
|
'Politik', 'Recht', 'Technologie', 'Wirtschaft'
|
||||||
|
]
|
||||||
|
|
||||||
|
for type_name in language_communication_types:
|
||||||
|
obj, created = InstrumentType.objects.get_or_create(name=type_name, category=LANGUAGE_COMMUNICATION)
|
||||||
|
|
||||||
|
for type_name in society_types:
|
||||||
|
obj, created = InstrumentType.objects.get_or_create(name=type_name, category=SOCIETY)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('basicknowledge', '0011_auto_20211031_1144'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(create_new_types, migrations.RunPython.noop)
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 2.2.24 on 2021-11-10 11:40
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('basicknowledge', '0012_auto_20211101_1008'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='basicknowledge',
|
||||||
|
name='new_type',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='instruments', to='basicknowledge.InstrumentType'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -1,13 +1,39 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.text import slugify
|
||||||
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel
|
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel
|
||||||
from wagtail.core.fields import StreamField, RichTextField
|
from wagtail.core.fields import RichTextField, StreamField
|
||||||
from wagtail.images.blocks import ImageChooserBlock
|
from wagtail.images.blocks import ImageChooserBlock
|
||||||
|
|
||||||
from books.blocks import LinkBlock, VideoBlock, DocumentBlock, SectionTitleBlock, InfogramBlock, \
|
from books.blocks import DocumentBlock, GeniallyBlock, InfogramBlock, InstrumentTextBlock, LinkBlock, SectionTitleBlock, \
|
||||||
GeniallyBlock, InstrumentTextBlock, SubtitleBlock, ThinglinkBlock
|
SubtitleBlock, ThinglinkBlock, VideoBlock
|
||||||
from core.constants import DEFAULT_RICH_TEXT_FEATURES
|
from core.constants import DEFAULT_RICH_TEXT_FEATURES
|
||||||
from core.wagtail_utils import StrictHierarchyPage
|
from core.wagtail_utils import StrictHierarchyPage
|
||||||
|
|
||||||
|
LANGUAGE_COMMUNICATION = 'language_communication'
|
||||||
|
SOCIETY = 'society'
|
||||||
|
INTERDISCIPLINARY = 'interdisciplinary'
|
||||||
|
|
||||||
|
|
||||||
|
class InstrumentType(models.Model):
|
||||||
|
CATEGORY_CHOICES = (
|
||||||
|
(LANGUAGE_COMMUNICATION, 'Sprache & Kommunikation'),
|
||||||
|
(SOCIETY, 'Gesellschaft'),
|
||||||
|
(INTERDISCIPLINARY, 'Überfachliches Instrument'),
|
||||||
|
)
|
||||||
|
|
||||||
|
name = models.CharField(max_length=255, unique=True)
|
||||||
|
category = models.CharField(
|
||||||
|
max_length=100,
|
||||||
|
choices=CATEGORY_CHOICES
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
return slugify(self.name.lower())
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.type
|
||||||
|
|
||||||
|
|
||||||
class BasicKnowledge(StrictHierarchyPage):
|
class BasicKnowledge(StrictHierarchyPage):
|
||||||
parent_page_types = ['books.book']
|
parent_page_types = ['books.book']
|
||||||
|
|
@ -27,24 +53,16 @@ class BasicKnowledge(StrictHierarchyPage):
|
||||||
('subtitle', SubtitleBlock()),
|
('subtitle', SubtitleBlock()),
|
||||||
], null=True, blank=True)
|
], null=True, blank=True)
|
||||||
|
|
||||||
LANGUAGE_COMMUNICATION = 'language_communication'
|
new_type = models.ForeignKey(InstrumentType, null=True, on_delete=models.PROTECT, related_name='instruments')
|
||||||
SOCIETY = 'society'
|
|
||||||
INTERDISCIPLINARY = 'interdisciplinary'
|
|
||||||
|
|
||||||
TYPE_CHOICES = (
|
old_type = models.CharField(
|
||||||
(LANGUAGE_COMMUNICATION, 'Sprache & Kommunikation'),
|
|
||||||
(SOCIETY, 'Gesellschaft'),
|
|
||||||
(INTERDISCIPLINARY, 'Überfachliches Instrument'),
|
|
||||||
)
|
|
||||||
|
|
||||||
type = models.CharField(
|
|
||||||
max_length=100,
|
max_length=100,
|
||||||
choices=TYPE_CHOICES
|
choices=InstrumentType.CATEGORY_CHOICES
|
||||||
)
|
)
|
||||||
|
|
||||||
content_panels = [
|
content_panels = [
|
||||||
FieldPanel('title', classname="full title"),
|
FieldPanel('title', classname="full title"),
|
||||||
FieldPanel('type'),
|
FieldPanel('new_type'),
|
||||||
FieldPanel('intro'),
|
FieldPanel('intro'),
|
||||||
StreamFieldPanel('contents')
|
StreamFieldPanel('contents')
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,54 @@
|
||||||
import graphene
|
import graphene
|
||||||
from graphene import relay
|
from graphene import relay
|
||||||
from graphene_django import DjangoObjectType
|
from graphene_django import DjangoObjectType
|
||||||
from graphene_django.filter import DjangoFilterConnectionField
|
|
||||||
|
|
||||||
from api.utils import get_object
|
from api.utils import get_object
|
||||||
from notes.models import InstrumentBookmark
|
from notes.models import InstrumentBookmark
|
||||||
from notes.schema import InstrumentBookmarkNode
|
from notes.schema import InstrumentBookmarkNode
|
||||||
from .models import BasicKnowledge
|
from .models import BasicKnowledge, InstrumentType
|
||||||
|
|
||||||
|
|
||||||
|
class InstrumentTypeNode(DjangoObjectType):
|
||||||
|
type = graphene.String(required=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = InstrumentType
|
||||||
|
only_fields = [
|
||||||
|
'name', 'category', 'type', 'id'
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def resolve_type(root: InstrumentType, info, **kwargs):
|
||||||
|
return root.type
|
||||||
|
|
||||||
|
|
||||||
class InstrumentNode(DjangoObjectType):
|
class InstrumentNode(DjangoObjectType):
|
||||||
bookmarks = graphene.List(InstrumentBookmarkNode)
|
bookmarks = graphene.List(InstrumentBookmarkNode)
|
||||||
|
type = graphene.Field(InstrumentTypeNode)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = BasicKnowledge
|
model = BasicKnowledge
|
||||||
filter_fields = ['slug', 'type']
|
filter_fields = ['slug']
|
||||||
interfaces = (relay.Node,)
|
interfaces = (relay.Node,)
|
||||||
only_fields = [
|
only_fields = [
|
||||||
'slug', 'title', 'intro', 'type', 'contents',
|
'slug', 'title', 'intro', 'contents',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def resolve_type(root: BasicKnowledge, info, **kwargs):
|
||||||
|
return root.new_type
|
||||||
|
|
||||||
def resolve_bookmarks(self, info, **kwargs):
|
def resolve_bookmarks(self, info, **kwargs):
|
||||||
return InstrumentBookmark.objects.filter(
|
return InstrumentBookmark.objects.filter(
|
||||||
user=info.context.user,
|
user=info.context.user,
|
||||||
instrument=self
|
instrument=self
|
||||||
)
|
)
|
||||||
|
|
||||||
class BasicKnowledgeQuery(object):
|
|
||||||
|
class InstrumentQuery(object):
|
||||||
instrument = graphene.Field(InstrumentNode, slug=graphene.String(), id=graphene.ID())
|
instrument = graphene.Field(InstrumentNode, slug=graphene.String(), id=graphene.ID())
|
||||||
instruments = DjangoFilterConnectionField(InstrumentNode)
|
instruments = graphene.List(InstrumentNode)
|
||||||
|
instrument_types = graphene.List(InstrumentTypeNode)
|
||||||
|
|
||||||
def resolve_instrument(self, info, **kwargs):
|
def resolve_instrument(self, info, **kwargs):
|
||||||
slug = kwargs.get('slug')
|
slug = kwargs.get('slug')
|
||||||
|
|
@ -42,3 +62,6 @@ class BasicKnowledgeQuery(object):
|
||||||
|
|
||||||
def resolve_instruments(self, info, **kwargs):
|
def resolve_instruments(self, info, **kwargs):
|
||||||
return BasicKnowledge.objects.all().live()
|
return BasicKnowledge.objects.all().live()
|
||||||
|
|
||||||
|
def resolve_instrument_types(self, info, **kwargs):
|
||||||
|
return InstrumentType.objects.filter(instruments__isnull=False)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
from books.factories import InstrumentFactory, InstrumentTypeFactory
|
||||||
|
from core.tests.base_test import SkillboxTestCase
|
||||||
|
|
||||||
|
INSTRUMENT_TYPES_QUERY = """
|
||||||
|
query InstrumentTypesQuery {
|
||||||
|
instrumentTypes {
|
||||||
|
name
|
||||||
|
type
|
||||||
|
category
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class InstrumentTypesQueryTestCase(SkillboxTestCase):
|
||||||
|
def setUp(self) -> None:
|
||||||
|
self.createDefault()
|
||||||
|
self.type = InstrumentTypeFactory(name='Type O Negative')
|
||||||
|
second_type = InstrumentTypeFactory(name='Typecast')
|
||||||
|
InstrumentTypeFactory(name='Guitar')
|
||||||
|
self.instrument = InstrumentFactory(new_type=self.type)
|
||||||
|
InstrumentFactory(new_type=second_type)
|
||||||
|
|
||||||
|
def test_instrument_types_empty_not_returned(self):
|
||||||
|
result = self.get_client().get_result(INSTRUMENT_TYPES_QUERY)
|
||||||
|
self.assertIsNone(result.errors)
|
||||||
|
self.assertEqual(len(result.data['instrumentTypes']), 2)
|
||||||
|
|
@ -9,10 +9,10 @@ from wagtail.core.models import Page, Site
|
||||||
from wagtail.core.rich_text import RichText
|
from wagtail.core.rich_text import RichText
|
||||||
|
|
||||||
from assignments.models import Assignment
|
from assignments.models import Assignment
|
||||||
from basicknowledge.models import BasicKnowledge
|
from basicknowledge.models import BasicKnowledge, INTERDISCIPLINARY, InstrumentType, LANGUAGE_COMMUNICATION, SOCIETY
|
||||||
from books.blocks import BasicKnowledgeBlock, ImageUrlBlock, LinkBlock, AssignmentBlock, VideoBlock
|
from books.blocks import AssignmentBlock, BasicKnowledgeBlock, ImageUrlBlock, LinkBlock, VideoBlock
|
||||||
from books.models import Book, Topic, Module, Chapter, ContentBlock, TextBlock
|
from books.models import Book, Chapter, ContentBlock, Module, TextBlock, Topic
|
||||||
from core.factories import BasePageFactory, fake, DummyImageFactory, fake_paragraph, fake_title
|
from core.factories import BasePageFactory, DummyImageFactory, fake, fake_paragraph, fake_title
|
||||||
|
|
||||||
|
|
||||||
class BookFactory(BasePageFactory):
|
class BookFactory(BasePageFactory):
|
||||||
|
|
@ -70,9 +70,18 @@ class TextBlockFactory(wagtail_factories.StructBlockFactory):
|
||||||
model = TextBlock
|
model = TextBlock
|
||||||
|
|
||||||
|
|
||||||
|
class InstrumentTypeFactory(factory.DjangoModelFactory):
|
||||||
|
class Meta:
|
||||||
|
model = InstrumentType
|
||||||
|
|
||||||
|
category = factory.Iterator([LANGUAGE_COMMUNICATION, SOCIETY, INTERDISCIPLINARY])
|
||||||
|
name = factory.LazyAttribute(lambda x: fake.text(max_nb_chars=20))
|
||||||
|
|
||||||
|
|
||||||
class InstrumentFactory(BasePageFactory):
|
class InstrumentFactory(BasePageFactory):
|
||||||
title = factory.LazyAttribute(fake_title)
|
title = factory.LazyAttribute(fake_title)
|
||||||
type = factory.Iterator([BasicKnowledge.LANGUAGE_COMMUNICATION, BasicKnowledge.SOCIETY, BasicKnowledge.INTERDISCIPLINARY])
|
old_type = factory.Iterator([LANGUAGE_COMMUNICATION, SOCIETY, INTERDISCIPLINARY])
|
||||||
|
new_type = factory.SubFactory(InstrumentTypeFactory)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = BasicKnowledge
|
model = BasicKnowledge
|
||||||
|
|
@ -83,7 +92,6 @@ class InstrumentFactory(BasePageFactory):
|
||||||
return super()._create(model_class, *args, **kwargs)
|
return super()._create(model_class, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BasicKnowledgeBlockFactory(wagtail_factories.StructBlockFactory):
|
class BasicKnowledgeBlockFactory(wagtail_factories.StructBlockFactory):
|
||||||
description = factory.LazyAttribute(fake_paragraph)
|
description = factory.LazyAttribute(fake_paragraph)
|
||||||
basic_knowledge = factory.SubFactory(InstrumentFactory)
|
basic_knowledge = factory.SubFactory(InstrumentFactory)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ class SkillboxTestCase(TestCase):
|
||||||
|
|
||||||
self.school_class = SchoolClass.objects.get(name='skillbox')
|
self.school_class = SchoolClass.objects.get(name='skillbox')
|
||||||
|
|
||||||
def get_client(self, user=None) -> Client:
|
def get_client(self, user=None) -> GQLClient:
|
||||||
request = RequestFactory().get('/')
|
request = RequestFactory().get('/')
|
||||||
if user is None:
|
if user is None:
|
||||||
user = self.teacher
|
user = self.teacher
|
||||||
|
|
|
||||||
|
|
@ -206,12 +206,6 @@ type AssignmentNodeEdge {
|
||||||
cursor: String!
|
cursor: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
enum BasicKnowledgeType {
|
|
||||||
LANGUAGE_COMMUNICATION
|
|
||||||
SOCIETY
|
|
||||||
INTERDISCIPLINARY
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapterBookmarkNode implements Node {
|
type ChapterBookmarkNode implements Node {
|
||||||
user: PrivateUserNode!
|
user: PrivateUserNode!
|
||||||
note: NoteNode
|
note: NoteNode
|
||||||
|
|
@ -461,7 +455,8 @@ type CustomQuery {
|
||||||
project(id: ID, slug: String): ProjectNode
|
project(id: ID, slug: String): ProjectNode
|
||||||
projects: [ProjectNode]
|
projects: [ProjectNode]
|
||||||
instrument(slug: String, id: ID): InstrumentNode
|
instrument(slug: String, id: ID): InstrumentNode
|
||||||
instruments(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, type: String): InstrumentNodeConnection
|
instruments: [InstrumentNode]
|
||||||
|
instrumentTypes: [InstrumentTypeNode]
|
||||||
studentSubmission(id: ID!): StudentSubmissionNode
|
studentSubmission(id: ID!): StudentSubmissionNode
|
||||||
assignment(id: ID!): AssignmentNode
|
assignment(id: ID!): AssignmentNode
|
||||||
assignments(offset: Int, before: String, after: String, first: Int, last: Int): AssignmentNodeConnection
|
assignments(offset: Int, before: String, after: String, first: Int, last: Int): AssignmentNodeConnection
|
||||||
|
|
@ -484,7 +479,7 @@ type CustomQuery {
|
||||||
me: PrivateUserNode
|
me: PrivateUserNode
|
||||||
allUsers(offset: Int, before: String, after: String, first: Int, last: Int, username: String, email: String): PrivateUserNodeConnection
|
allUsers(offset: Int, before: String, after: String, first: Int, last: Int, username: String, email: String): PrivateUserNodeConnection
|
||||||
myActivity(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, slug_In: [String], title: String, title_Icontains: String, title_In: [String]): ModuleNodeConnection
|
myActivity(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, slug_In: [String], title: String, title_Icontains: String, title_In: [String]): ModuleNodeConnection
|
||||||
myInstrumentActivity(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, type: String): InstrumentNodeConnection
|
myInstrumentActivity(offset: Int, before: String, after: String, first: Int, last: Int, slug: String): InstrumentNodeConnection
|
||||||
_debug: DjangoDebug
|
_debug: DjangoDebug
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -609,9 +604,9 @@ type InstrumentNode implements Node {
|
||||||
slug: String!
|
slug: String!
|
||||||
intro: String!
|
intro: String!
|
||||||
contents: GenericStreamFieldType
|
contents: GenericStreamFieldType
|
||||||
type: BasicKnowledgeType!
|
|
||||||
id: ID!
|
id: ID!
|
||||||
bookmarks: [InstrumentBookmarkNode]
|
bookmarks: [InstrumentBookmarkNode]
|
||||||
|
type: InstrumentTypeNode
|
||||||
}
|
}
|
||||||
|
|
||||||
type InstrumentNodeConnection {
|
type InstrumentNodeConnection {
|
||||||
|
|
@ -624,6 +619,19 @@ type InstrumentNodeEdge {
|
||||||
cursor: String!
|
cursor: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum InstrumentTypeCategory {
|
||||||
|
LANGUAGE_COMMUNICATION
|
||||||
|
SOCIETY
|
||||||
|
INTERDISCIPLINARY
|
||||||
|
}
|
||||||
|
|
||||||
|
type InstrumentTypeNode {
|
||||||
|
id: ID!
|
||||||
|
name: String!
|
||||||
|
category: InstrumentTypeCategory!
|
||||||
|
type: String!
|
||||||
|
}
|
||||||
|
|
||||||
scalar JSONString
|
scalar JSONString
|
||||||
|
|
||||||
input JoinClassInput {
|
input JoinClassInput {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue