Refactor completion api

This commit is contained in:
Daniel Egger 2022-06-22 17:47:30 +02:00
parent 12322638dc
commit 3686924cfe
16 changed files with 176 additions and 210 deletions

View File

@ -11,12 +11,12 @@ const props = defineProps<{
const circleStore = useCircleStore(); const circleStore = useCircleStore();
function toggleCompleted(learningContent: LearningContent) { function toggleCompleted(learningContent: LearningContent) {
circleStore.toggleCompleted(learningContent, !learningContent.completed); circleStore.markCompletion(learningContent, !learningContent.completed);
} }
const someFinished = computed(() => { const someFinished = computed(() => {
if (props.learningSequence) { if (props.learningSequence) {
return circleStore.flatLearningContents.filter((lc) => { return circleStore.flatChildren.filter((lc) => {
return lc.completed && lc.parentLearningSequence?.translation_key === props.learningSequence.translation_key; return lc.completed && lc.parentLearningSequence?.translation_key === props.learningSequence.translation_key;
}).length > 0; }).length > 0;
} }
@ -68,11 +68,30 @@ const someFinished = computed(() => {
<div <div
v-if="learningUnit.id" v-if="learningUnit.id"
class="flex items-center gap-4 pb-3 hover:cursor-pointer" class="hover:cursor-pointer"
@click="circleStore.openSelfEvaluation(learningUnit)" @click="circleStore.openSelfEvaluation(learningUnit)"
> >
<it-icon-smiley-neutral/> <div
<span>Selbsteinschätzung</span> v-if="circleStore.calcSelfEvaluationStatus(learningUnit)"
class="flex items-center gap-4 pb-3"
>
<it-icon-smiley-happy/>
<span>Selbsteinschätzung: Ich kann das.</span>
</div>
<div
v-else-if="circleStore.calcSelfEvaluationStatus(learningUnit) === false"
class="flex items-center gap-4 pb-3"
>
<it-icon-smiley-thinking/>
<span>Selbsteinschätzung: Muss ich nochmals anschauen</span>
</div>
<div
v-else
class="flex items-center gap-4 pb-3"
>
<it-icon-smiley-neutral/>
<span>Selbsteinschätzung</span>
</div>
</div> </div>
<hr class="-mx-4 text-gray-500"> <hr class="-mx-4 text-gray-500">

View File

@ -57,13 +57,29 @@ const currentQuestion = computed(() => questions.value[questionIndex]);
<h2 class="heading-2">{{ currentQuestion.title }}</h2> <h2 class="heading-2">{{ currentQuestion.title }}</h2>
<div class="mt-12 flex justify-between gap-6"> <div class="mt-12 flex justify-between gap-6">
<button class="flex-1 inline-flex items-center text-left p-4 border border-gray-500"> <button
@click="circleStore.markCompletion(currentQuestion, true)"
class="flex-1 inline-flex items-center text-left p-4 border"
:class="{
'border-green-500': currentQuestion.completed,
'border-2': currentQuestion.completed,
'border-gray-500': !currentQuestion.completed,
}"
>
<it-icon-smiley-happy class="w-16 h-16 mr-4"></it-icon-smiley-happy> <it-icon-smiley-happy class="w-16 h-16 mr-4"></it-icon-smiley-happy>
<span class="font-bold text-xl"> <span class="font-bold text-xl">
Ja, ich kann das. Ja, ich kann das.
</span> </span>
</button> </button>
<button class="flex-1 inline-flex items-center text-left p-4 border border-gray-500"> <button
@click="circleStore.markCompletion(currentQuestion, false)"
class="flex-1 inline-flex items-center text-left p-4 border"
:class="{
'border-orange-500': currentQuestion.completed === false,
'border-2': currentQuestion.completed === false,
'border-gray-500': currentQuestion.completed === true || currentQuestion.completed === undefined,
}"
>
<it-icon-smiley-thinking class="w-16 h-16 mr-4"></it-icon-smiley-thinking> <it-icon-smiley-thinking class="w-16 h-16 mr-4"></it-icon-smiley-thinking>
<span class="font-bold text-xl"> <span class="font-bold text-xl">
Das muss ich nochmals anschauen. Das muss ich nochmals anschauen.

View File

@ -8,7 +8,6 @@ function createEmptyLearningUnit(parentLearningSequence: LearningSequence): Lear
slug: '', slug: '',
translation_key: '', translation_key: '',
type: 'learnpath.LearningUnit', type: 'learnpath.LearningUnit',
questions: [],
learningContents: [], learningContents: [],
minutes: 0, minutes: 0,
parentLearningSequence: parentLearningSequence, parentLearningSequence: parentLearningSequence,
@ -49,6 +48,7 @@ export function parseLearningSequences (children: CircleChild[]): LearningSequen
parentLearningSequence: learningSequence, parentLearningSequence: learningSequence,
children: child.children.map((c) => { children: child.children.map((c) => {
c.parentLearningUnit = learningUnit; c.parentLearningUnit = learningUnit;
c.parentLearningSequence = learningSequence;
return c; return c;
}) })
}); });

View File

@ -2,13 +2,13 @@ import * as log from 'loglevel';
import {defineStore} from 'pinia' import {defineStore} from 'pinia'
import type {Circle, LearningContent, LearningUnit} from '@/types' import type {Circle, CircleChild, CircleCompletion, LearningContent, LearningUnit, LearningUnitQuestion} from '@/types'
import {itGet, itPost} from '@/fetchHelpers'; import {itGet, itPost} from '@/fetchHelpers';
import {parseLearningSequences} from '@/services/circle'; import {parseLearningSequences} from '@/services/circle';
export type CircleStoreState = { export type CircleStoreState = {
circleData: Circle; circleData: Circle;
completionData: any; completionData: CircleCompletion[];
currentLearningContent: LearningContent | undefined; currentLearningContent: LearningContent | undefined;
currentSelfEvaluation: LearningUnit | undefined; currentSelfEvaluation: LearningUnit | undefined;
page: 'INDEX' | 'OVERVIEW' | 'LEARNING_CONTENT' | 'SELF_EVALUATION'; page: 'INDEX' | 'OVERVIEW' | 'LEARNING_CONTENT' | 'SELF_EVALUATION';
@ -26,10 +26,13 @@ export const useCircleStore = defineStore({
} as CircleStoreState; } as CircleStoreState;
}, },
getters: { getters: {
flatLearningContents: (state) => { flatChildren: (state) => {
const result:LearningContent[] = []; const result:CircleChild[] = [];
state.circleData.learningSequences.forEach((learningSequence) => { state.circleData.learningSequences.forEach((learningSequence) => {
learningSequence.learningUnits.forEach((learningUnit) => { learningSequence.learningUnits.forEach((learningUnit) => {
learningUnit.children.forEach((learningUnitQuestion) => {
result.push(learningUnitQuestion);
})
learningUnit.learningContents.forEach((learningContent) => { learningUnit.learningContents.forEach((learningContent) => {
result.push(learningContent); result.push(learningContent);
}); });
@ -42,7 +45,6 @@ export const useCircleStore = defineStore({
async loadCircle(slug: string) { async loadCircle(slug: string) {
try { try {
this.circleData = await itGet(`/learnpath/api/circle/${slug}/`); this.circleData = await itGet(`/learnpath/api/circle/${slug}/`);
console.log(this.circleData);
this.circleData.learningSequences = parseLearningSequences(this.circleData.children); this.circleData.learningSequences = parseLearningSequences(this.circleData.children);
this.completionData = await itGet(`/api/completion/circle/${this.circleData.translation_key}/`); this.completionData = await itGet(`/api/completion/circle/${this.circleData.translation_key}/`);
this.parseCompletionData(); this.parseCompletionData();
@ -51,12 +53,12 @@ export const useCircleStore = defineStore({
return error return error
} }
}, },
async toggleCompleted(learningContent: LearningContent, flag = true) { async markCompletion(page: LearningContent | LearningUnitQuestion, flag = true) {
try { try {
learningContent.completed = flag; page.completed = flag;
this.completionData = await itPost('/api/completion/complete_learning_content/', { this.completionData = await itPost('/api/completion/circle/mark/', {
learning_content_key: learningContent.translation_key, page_key: page.translation_key,
completed: learningContent.completed, completed: page.completed,
}); });
this.parseCompletionData(); this.parseCompletionData();
} catch (error) { } catch (error) {
@ -65,10 +67,15 @@ export const useCircleStore = defineStore({
} }
}, },
parseCompletionData() { parseCompletionData() {
this.flatLearningContents.forEach((learningContent) => { this.flatChildren.forEach((page) => {
learningContent.completed = this.completionData.completed_learning_contents.findIndex((e) => { const pageIndex = this.completionData.findIndex((e) => {
return e.learning_content_key === learningContent.translation_key && e.completed; return e.page_key === page.translation_key;
}) >= 0; });
if (pageIndex >= 0) {
page.completed = this.completionData[pageIndex].completed;
} else {
page.completed = undefined;
}
}); });
}, },
openLearningContent(learningContent: LearningContent) { openLearningContent(learningContent: LearningContent) {
@ -87,9 +94,21 @@ export const useCircleStore = defineStore({
this.page = 'INDEX'; this.page = 'INDEX';
this.currentSelfEvaluation = undefined; this.currentSelfEvaluation = undefined;
}, },
calcSelfEvaluationStatus(learningUnit: LearningUnit) {
if (learningUnit.children.length > 0) {
if (learningUnit.children.every((q) => q.completed)) {
return true;
}
if (learningUnit.children.some((q) => q.completed !== undefined)) {
return false;
}
}
return undefined;
}
,
continueToNextLearningContent() { continueToNextLearningContent() {
if (this.currentLearningContent) { if (this.currentLearningContent) {
this.toggleCompleted(this.currentLearningContent, true); this.markCompletion(this.currentLearningContent, true);
if (this.currentLearningContent.nextLearningContent) { if (this.currentLearningContent.nextLearningContent) {
this.openLearningContent(this.currentLearningContent.nextLearningContent); this.openLearningContent(this.currentLearningContent.nextLearningContent);
} }

View File

@ -50,13 +50,13 @@ export interface LearningWagtailPage {
title: string; title: string;
slug: string; slug: string;
translation_key: string; translation_key: string;
completed?: boolean;
} }
export interface LearningContent extends LearningWagtailPage { export interface LearningContent extends LearningWagtailPage {
type: 'learnpath.LearningContent'; type: 'learnpath.LearningContent';
minutes: number; minutes: number;
contents: (LearningContentBlock | VideoBlock | PodcastBlock | DocumentBlock)[]; contents: (LearningContentBlock | VideoBlock | PodcastBlock | DocumentBlock)[];
completed?: boolean;
parentLearningSequence?: LearningSequence; parentLearningSequence?: LearningSequence;
parentLearningUnit?: LearningUnit; parentLearningUnit?: LearningUnit;
nextLearningContent?: LearningContent; nextLearningContent?: LearningContent;
@ -65,6 +65,7 @@ export interface LearningContent extends LearningWagtailPage {
export interface LearningUnitQuestion extends LearningWagtailPage { export interface LearningUnitQuestion extends LearningWagtailPage {
type: 'learnpath.LearningUnitQuestion'; type: 'learnpath.LearningUnitQuestion';
parentLearningSequence?: LearningSequence;
parentLearningUnit?: LearningUnit; parentLearningUnit?: LearningUnit;
} }
@ -83,7 +84,7 @@ export interface LearningSequence extends LearningWagtailPage {
minutes: number; minutes: number;
} }
export type CircleChild = LearningContent | LearningUnit | LearningSequence; export type CircleChild = LearningContent | LearningUnit | LearningSequence | LearningUnitQuestion;
export interface WagtailCircle extends LearningWagtailPage { export interface WagtailCircle extends LearningWagtailPage {
type: 'learnpath.Circle'; type: 'learnpath.Circle';
@ -91,6 +92,18 @@ export interface WagtailCircle extends LearningWagtailPage {
description: string; description: string;
} }
export interface CircleCompletion {
id: number;
created_at: string;
updated_at: string;
user: number;
page_key: string;
page_type: string;
circle_key: string;
completed: boolean;
json_data: any;
}
export interface Circle extends LearningWagtailPage { export interface Circle extends LearningWagtailPage {
type: 'learnpath.Circle'; type: 'learnpath.Circle';
children: CircleChild[]; children: CircleChild[];

View File

@ -1,4 +1,4 @@
# Generated by Django 3.2.13 on 2022-06-08 13:52 # Generated by Django 3.2.13 on 2022-06-22 16:53
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
@ -15,52 +15,21 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='UserCircleCompletion', name='CircleCompletion',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)), ('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)), ('updated_at', models.DateTimeField(auto_now=True)),
('page_key', models.UUIDField()),
('page_type', models.CharField(blank=True, default='', max_length=255)),
('circle_key', models.UUIDField()), ('circle_key', models.UUIDField()),
('json_data', models.JSONField(blank=True, default=dict)), ('completed', models.BooleanField(default=False)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='LearningUnitQuestionCompletion',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('question_key', models.UUIDField()),
('circle_key', models.UUIDField()),
('completed', models.BooleanField(default=True)),
('json_data', models.JSONField(blank=True, default=dict)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='LearningContentCompletion',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('learning_content_key', models.UUIDField()),
('circle_key', models.UUIDField()),
('completed', models.BooleanField(default=True)),
('json_data', models.JSONField(blank=True, default=dict)), ('json_data', models.JSONField(blank=True, default=dict)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
], ],
), ),
migrations.AddConstraint( migrations.AddConstraint(
model_name='usercirclecompletion', model_name='circlecompletion',
constraint=models.UniqueConstraint(fields=('user', 'circle_key'), name='unique_user_circle_completion'), constraint=models.UniqueConstraint(fields=('user', 'page_key'), name='unique_user_page_key'),
),
migrations.AddConstraint(
model_name='learningunitquestioncompletion',
constraint=models.UniqueConstraint(fields=('user', 'question_key'), name='unique_user_question_key'),
),
migrations.AddConstraint(
model_name='learningcontentcompletion',
constraint=models.UniqueConstraint(fields=('user', 'learning_content_key'), name='unique_user_learning_content_key'),
), ),
] ]

View File

@ -4,56 +4,25 @@ from django.db.models import UniqueConstraint
from vbv_lernwelt.core.models import User from vbv_lernwelt.core.models import User
class LearningContentCompletion(models.Model): class CircleCompletion(models.Model):
# Page can either be a LearningContent or a LearningUnitQuestion for now
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE)
learning_content_key = models.UUIDField()
# Page can either be a LearningContent or a LearningUnitQuestion for now
page_key = models.UUIDField()
page_type = models.CharField(max_length=255, default='', blank=True)
circle_key = models.UUIDField() circle_key = models.UUIDField()
completed = models.BooleanField(default=True) completed = models.BooleanField(default=False)
json_data = models.JSONField(default=dict, blank=True) json_data = models.JSONField(default=dict, blank=True)
class Meta: class Meta:
constraints = [ constraints = [
UniqueConstraint( UniqueConstraint(
fields=['user', 'learning_content_key', ], fields=['user', 'page_key', ],
name='unique_user_learning_content_key' name='unique_user_page_key'
) )
] ]
class LearningUnitQuestionCompletion(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
question_key = models.UUIDField()
circle_key = models.UUIDField()
completed = models.BooleanField(default=True)
json_data = models.JSONField(default=dict, blank=True)
class Meta:
constraints = [
UniqueConstraint(
fields=['user', 'question_key', ],
name='unique_user_question_key'
)
]
class UserCircleCompletion(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
circle_key = models.UUIDField()
json_data = models.JSONField(default=dict, blank=True)
class Meta:
constraints = [
UniqueConstraint(fields=['user', 'circle_key'], name='unique_user_circle_completion')
]

View File

@ -1,18 +1,13 @@
from rest_framework import serializers from rest_framework import serializers
from vbv_lernwelt.completion.models import UserCircleCompletion, LearningContentCompletion from vbv_lernwelt.completion.models import CircleCompletion
class UserCircleCompletionSerializer(serializers.ModelSerializer): class CircleCompletionSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = UserCircleCompletion model = CircleCompletion
fields = ['id', 'created_at', 'updated_at', 'user', 'circle_key', 'json_data']
class LearningContentCompletionSerializer(serializers.ModelSerializer):
class Meta:
model = LearningContentCompletion
fields = [ fields = [
'id', 'created_at', 'updated_at', 'user', 'learning_content_key', 'circle_key', 'id', 'created_at', 'updated_at', 'user', 'page_key', 'page_type', 'circle_key',
'completed', 'json_data', 'completed', 'json_data',
] ]

View File

@ -26,30 +26,28 @@ class CompletionApiTestCase(APITestCase):
learning_content_key = str(learning_content.translation_key) learning_content_key = str(learning_content.translation_key)
circle_key = str(learning_content.get_parent().translation_key) circle_key = str(learning_content.get_parent().translation_key)
response = self.client.post(f'/api/completion/complete_learning_content/', { mark_url = f'/api/completion/circle/mark/'
'learning_content_key': learning_content_key print(mark_url)
response = self.client.post(mark_url, {
'page_key': learning_content_key,
}) })
response_json = response.json() response_json = response.json()
print(json.dumps(response.json(), indent=2)) print(json.dumps(response.json(), indent=2))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response_json['circle_key'], circle_key) self.assertEqual(len(response_json), 1)
self.assertEqual( self.assertEqual(response_json[0]['page_key'], learning_content_key)
response_json['completed_learning_contents'][learning_content_key]['learning_content_key'], self.assertEqual(response_json[0]['circle_key'], circle_key)
learning_content_key self.assertTrue(response_json[0]['completed'])
)
# test getting the circle data # test getting the circle data
response = self.client.get(f'/api/completion/user_circle_completion/{circle_key}/') response = self.client.get(f'/api/completion/circle/{circle_key}/')
response_json = response.json() response_json = response.json()
print(json.dumps(response.json(), indent=2)) print(json.dumps(response.json(), indent=2))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response_json['circle_key'], circle_key) self.assertEqual(len(response_json), 1)
self.assertEqual( self.assertEqual(response_json[0]['page_key'], learning_content_key)
response_json['completed_learning_contents'][learning_content_key]['learning_content_key'], self.assertEqual(response_json[0]['circle_key'], circle_key)
learning_content_key self.assertTrue(response_json[0]['completed'])
)

View File

@ -1,8 +1,8 @@
from django.urls import path from django.urls import path
from vbv_lernwelt.completion.views import complete_learning_content, request_user_circle_completion from vbv_lernwelt.completion.views import request_circle_completion, mark_circle_completion
urlpatterns = [ urlpatterns = [
path(r"circle/<uuid:circle_key>/", request_user_circle_completion, name="request_user_circle_completion"), path(r"circle/<uuid:circle_key>/", request_circle_completion, name="request_circle_completion"),
path(r"complete_learning_content/", complete_learning_content, name="complete_learning_content"), path(r"circle/mark/", mark_circle_completion, name="mark_circle_completion"),
] ]

View File

@ -1,65 +1,57 @@
import structlog import structlog
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
from rest_framework.response import Response from rest_framework.response import Response
from wagtail.models import Page
from vbv_lernwelt.completion.models import LearningContentCompletion, UserCircleCompletion from vbv_lernwelt.completion.models import CircleCompletion
from vbv_lernwelt.completion.serializers import UserCircleCompletionSerializer, LearningContentCompletionSerializer from vbv_lernwelt.completion.serializers import CircleCompletionSerializer
from vbv_lernwelt.learnpath.models import LearningContent from vbv_lernwelt.learnpath.models import Circle
from vbv_lernwelt.learnpath.utils import get_wagtail_type
logger = structlog.get_logger(__name__) logger = structlog.get_logger(__name__)
@api_view(['GET']) @api_view(['GET'])
def request_user_circle_completion(request, circle_key): def request_circle_completion(request, circle_key):
ucc = UserCircleCompletion.objects.filter( response_data = CircleCompletionSerializer(
user=request.user, CircleCompletion.objects.filter(user=request.user, circle_key=circle_key),
circle_key=circle_key, many=True,
)
response_data = {}
if ucc.count() > 0:
response_data = UserCircleCompletionSerializer(ucc.first()).data
response_data['completed_learning_contents'] = LearningContentCompletionSerializer(
LearningContentCompletion.objects.filter(circle_key=circle_key, user=request.user),
many=True
).data ).data
return Response(status=200, data=response_data) return Response(status=200, data=response_data)
@api_view(['POST']) @api_view(['POST'])
def complete_learning_content(request): def mark_circle_completion(request):
learning_content_key = request.data.get('learning_content_key') page_key = request.data.get('page_key')
completed = request.data.get('completed', True) completed = request.data.get('completed', True)
learning_content = LearningContent.objects.get(translation_key=learning_content_key)
circle_key = learning_content.get_parent().translation_key page = Page.objects.get(translation_key=page_key)
page_type = get_wagtail_type(page.specific)
circle = Circle.objects.ancestor_of(page).first()
lcc, created = LearningContentCompletion.objects.get_or_create( cc, created = CircleCompletion.objects.get_or_create(
user=request.user, user=request.user,
learning_content_key=learning_content_key, page_key=page_key,
circle_key=circle_key, circle_key=circle.translation_key,
) )
lcc.completed = completed cc.page_type = page_type
lcc.save() cc.completed = completed
cc.save()
ucc, created = UserCircleCompletion.objects.get_or_create( response_data = CircleCompletionSerializer(
user=request.user, CircleCompletion.objects.filter(user=request.user, circle_key=circle.translation_key),
circle_key=circle_key, many=True,
)
response_data = UserCircleCompletionSerializer(ucc).data
response_data['completed_learning_contents'] = LearningContentCompletionSerializer(
LearningContentCompletion.objects.filter(circle_key=circle_key, user=request.user),
many=True
).data ).data
logger.debug( logger.debug(
'learning content completed', 'page completed',
label='completion_api', label='completion_api',
circle_key=circle_key, circle_key=circle.translation_key,
learning_content_key=learning_content_key, circle_title=circle.title,
page_key=page_key,
page_type=page_type,
page_title=page.title,
user_id=request.user.id, user_id=request.user.id,
) )

View File

@ -1,4 +1,4 @@
# Generated by Django 3.2.13 on 2022-06-14 08:51 # Generated by Django 3.2.13 on 2022-06-22 15:48
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@ -61,7 +61,7 @@ class Migration(migrations.Migration):
('contents', wagtail.fields.StreamField([('video', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('web_based_training', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('podcast', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('competence', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock())])), ('exercise', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock())])), ('document', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock())])), ('knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock())]))], use_json_field=None)), ('contents', wagtail.fields.StreamField([('video', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('web_based_training', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('podcast', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock()), ('url', wagtail.blocks.URLBlock())])), ('competence', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock())])), ('exercise', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock())])), ('document', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock())])), ('knowledge', wagtail.blocks.StructBlock([('description', wagtail.blocks.TextBlock())]))], use_json_field=None)),
], ],
options={ options={
'verbose_name': 'Learning Unit', 'verbose_name': 'Learning Content',
}, },
bases=('wagtailcore.page',), bases=('wagtailcore.page',),
), ),
@ -90,13 +90,22 @@ class Migration(migrations.Migration):
name='LearningUnit', name='LearningUnit',
fields=[ 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')), ('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')),
('questions', wagtail.fields.StreamField([('question', wagtail.blocks.CharBlock())], use_json_field=True)),
], ],
options={ options={
'verbose_name': 'Learning Unit', 'verbose_name': 'Learning Unit',
}, },
bases=('wagtailcore.page',), bases=('wagtailcore.page',),
), ),
migrations.CreateModel(
name='LearningUnitQuestion',
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')),
],
options={
'verbose_name': 'Learning Unit Question',
},
bases=('wagtailcore.page',),
),
migrations.CreateModel( migrations.CreateModel(
name='Topic', name='Topic',
fields=[ fields=[

View File

@ -1,33 +0,0 @@
# Generated by Django 3.2.13 on 2022-06-22 14:04
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wagtailcore', '0069_log_entry_jsonfield'),
('learnpath', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='LearningUnitQuestion',
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')),
],
options={
'verbose_name': 'Learning Unit Question',
},
bases=('wagtailcore.page',),
),
migrations.AlterModelOptions(
name='learningcontent',
options={'verbose_name': 'Learning Content'},
),
migrations.RemoveField(
model_name='learningunit',
name='questions',
),
]

View File

@ -1,6 +1,8 @@
import wagtail.api.v2.serializers as wagtail_serializers import wagtail.api.v2.serializers as wagtail_serializers
from rest_framework.fields import SerializerMethodField from rest_framework.fields import SerializerMethodField
from vbv_lernwelt.learnpath.utils import get_wagtail_type
def get_it_serializer_class(model, field_names): def get_it_serializer_class(model, field_names):
return wagtail_serializers.get_serializer_class(model, field_names=field_names, meta_fields=[], base=ItBaseSerializer) return wagtail_serializers.get_serializer_class(model, field_names=field_names, meta_fields=[], base=ItBaseSerializer)
@ -8,7 +10,7 @@ def get_it_serializer_class(model, field_names):
class ItTypeField(wagtail_serializers.TypeField): class ItTypeField(wagtail_serializers.TypeField):
def to_representation(self, obj): def to_representation(self, obj):
name = type(obj)._meta.app_label + '.' + type(obj).__name__ name = get_wagtail_type(obj)
return name return name

View File

@ -114,10 +114,6 @@ Fachspezialisten bei.
title="Ich bin in der Lage, mit geeigneten Fragestellungen die Deckung von Versicherungen zu erfassen.", title="Ich bin in der Lage, mit geeigneten Fragestellungen die Deckung von Versicherungen zu erfassen.",
parent=lu parent=lu
) )
LearningUnitQuestionFactory(
title="Ich weiss was meine Kunden wollen",
parent=lu
)
LearningContentFactory( LearningContentFactory(
title='Ermittlung des Kundenbedarfs', title='Ermittlung des Kundenbedarfs',
parent=circe_analyse, parent=circe_analyse,

View File

@ -0,0 +1,2 @@
def get_wagtail_type(obj):
return obj._meta.app_label + '.' + type(obj).__name__