parent
01b6d3b5fe
commit
14ad75259b
29 changed files with 426 additions and 362 deletions
@ -1,65 +0,0 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.11.6 on 2017-11-28 11:50 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.conf import settings |
||||
from django.db import migrations, models |
||||
import django.db.models.deletion |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
initial = True |
||||
|
||||
dependencies = [ |
||||
('auth', '0008_alter_user_username_max_length'), |
||||
('access', '0001_initial'), |
||||
('courses', '0001_initial'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AddField( |
||||
model_name='progress', |
||||
name='course', |
||||
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='courses.Course', verbose_name='Курс'), |
||||
), |
||||
migrations.AddField( |
||||
model_name='progress', |
||||
name='progress_list', |
||||
field=models.ManyToManyField(blank=True, to='courses.Vertex', verbose_name='Лист пройденных объектов'), |
||||
), |
||||
migrations.AddField( |
||||
model_name='progress', |
||||
name='template', |
||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='courses.CourseRoute', verbose_name='Шаблон для прохождения если не указан явно смотри функцию get_template()'), |
||||
), |
||||
migrations.AddField( |
||||
model_name='progress', |
||||
name='user', |
||||
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Студент'), |
||||
), |
||||
migrations.AddField( |
||||
model_name='invite', |
||||
name='owner', |
||||
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), |
||||
), |
||||
migrations.AddField( |
||||
model_name='account', |
||||
name='owner', |
||||
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), |
||||
), |
||||
migrations.AddField( |
||||
model_name='user', |
||||
name='groups', |
||||
field=models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups'), |
||||
), |
||||
migrations.AddField( |
||||
model_name='user', |
||||
name='user_permissions', |
||||
field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions'), |
||||
), |
||||
migrations.AlterUniqueTogether( |
||||
name='progress', |
||||
unique_together=set([('user', 'course')]), |
||||
), |
||||
] |
||||
@ -0,0 +1,9 @@ |
||||
from django.contrib import admin |
||||
|
||||
from achievements.models import Skills, Achievements, SkillJ, DiplomaGen, Diploma |
||||
|
||||
admin.site.register(Skills) |
||||
admin.site.register(Achievements) |
||||
admin.site.register(SkillJ) |
||||
admin.site.register(Diploma) |
||||
admin.site.register(DiplomaGen) |
||||
@ -0,0 +1,5 @@ |
||||
from django.apps import AppConfig |
||||
|
||||
|
||||
class AchievementsConfig(AppConfig): |
||||
name = 'achievements' |
||||
@ -0,0 +1,73 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.11.6 on 2017-11-28 15:18 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
initial = True |
||||
|
||||
dependencies = [ |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.CreateModel( |
||||
name='Achievements', |
||||
fields=[ |
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
('icon', models.ImageField(blank=True, null=True, upload_to='diplomas', verbose_name='Отображение достижения')), |
||||
], |
||||
options={ |
||||
'verbose_name': 'Достижение', |
||||
'verbose_name_plural': 'Достижения', |
||||
}, |
||||
), |
||||
migrations.CreateModel( |
||||
name='Diploma', |
||||
fields=[ |
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
('icon', models.ImageField(upload_to='diplomas', verbose_name='Иконка')), |
||||
], |
||||
options={ |
||||
'verbose_name': 'Диплом', |
||||
'verbose_name_plural': 'Дипломы', |
||||
}, |
||||
), |
||||
migrations.CreateModel( |
||||
name='DiplomaGen', |
||||
fields=[ |
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
('template', models.URLField(verbose_name='Путь до шаблона')), |
||||
], |
||||
options={ |
||||
'verbose_name': 'Генератор дипломов', |
||||
'verbose_name_plural': 'Генераторы дипловов', |
||||
}, |
||||
), |
||||
migrations.CreateModel( |
||||
name='SkillJ', |
||||
fields=[ |
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
], |
||||
options={ |
||||
'verbose_name': 'Размер навыка', |
||||
'verbose_name_plural': 'Размеры навыков', |
||||
}, |
||||
), |
||||
migrations.CreateModel( |
||||
name='Skills', |
||||
fields=[ |
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
('title', models.CharField(max_length=255, verbose_name='Наименование')), |
||||
('color', models.CharField(max_length=255, verbose_name='Цвет')), |
||||
('icon', models.ImageField(help_text='65x65', null=True, upload_to='skills', verbose_name='Большая картинка')), |
||||
('description', models.TextField(blank=True, verbose_name='Описание')), |
||||
], |
||||
options={ |
||||
'verbose_name': 'Навык', |
||||
'verbose_name_plural': 'Навыки', |
||||
}, |
||||
), |
||||
] |
||||
@ -0,0 +1,56 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.11.6 on 2017-11-28 15:18 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.conf import settings |
||||
from django.db import migrations, models |
||||
import django.db.models.deletion |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
initial = True |
||||
|
||||
dependencies = [ |
||||
('achievements', '0001_initial'), |
||||
('courses', '0001_initial'), |
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AddField( |
||||
model_name='skillj', |
||||
name='lesson', |
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Vertex', verbose_name='Урок'), |
||||
), |
||||
migrations.AddField( |
||||
model_name='skillj', |
||||
name='skill', |
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='achievements.Skills', verbose_name='Навык'), |
||||
), |
||||
migrations.AddField( |
||||
model_name='diplomagen', |
||||
name='course', |
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course'), |
||||
), |
||||
migrations.AddField( |
||||
model_name='diploma', |
||||
name='template', |
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='achievements.DiplomaGen', verbose_name='Использовать шаблон'), |
||||
), |
||||
migrations.AddField( |
||||
model_name='diploma', |
||||
name='user', |
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), |
||||
), |
||||
migrations.AddField( |
||||
model_name='achievements', |
||||
name='course', |
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course'), |
||||
), |
||||
migrations.AddField( |
||||
model_name='achievements', |
||||
name='user', |
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), |
||||
), |
||||
] |
||||
@ -0,0 +1,66 @@ |
||||
from django.db import models |
||||
from django.conf import settings |
||||
|
||||
from courses.models import Course, Vertex |
||||
|
||||
|
||||
class Achievements(models.Model): |
||||
course = models.ForeignKey(to=Course) |
||||
icon = models.ImageField(verbose_name='Отображение достижения', upload_to='diplomas', blank=True, null=True) |
||||
user = models.ForeignKey(to=settings.AUTH_USER_MODEL) |
||||
|
||||
def __str__(self): |
||||
return 'Студенту %s за курс %s' % (self.user.username, self.course.title) |
||||
|
||||
class Meta: |
||||
verbose_name = 'Достижение' |
||||
verbose_name_plural = 'Достижения' |
||||
|
||||
|
||||
class Skills(models.Model): |
||||
title = models.CharField(verbose_name='Наименование', max_length=255) |
||||
color = models.CharField(verbose_name='Цвет', max_length=255) |
||||
icon = models.ImageField(verbose_name='Большая картинка', upload_to='skills', null=True, help_text='65x65') |
||||
description = models.TextField(verbose_name='Описание', blank=True) |
||||
|
||||
def __str__(self): return '%s' % self.title |
||||
|
||||
class Meta: |
||||
verbose_name = 'Навык' |
||||
verbose_name_plural = 'Навыки' |
||||
|
||||
|
||||
class SkillJ(models.Model): |
||||
skill = models.ForeignKey(to=Skills, verbose_name='Навык') |
||||
lesson = models.ForeignKey(to=Vertex, verbose_name='Урок') |
||||
|
||||
def __str__(self): return '%s' % self.skill |
||||
|
||||
class Meta: |
||||
verbose_name = 'Размер навыка' |
||||
verbose_name_plural = 'Размеры навыков' |
||||
|
||||
|
||||
class DiplomaGen(models.Model): |
||||
course = models.ForeignKey(to=Course) |
||||
template = models.URLField(verbose_name="Путь до шаблона") |
||||
|
||||
def __str__(self): |
||||
return 'Шаблон можно найти по адресу: %s, диплом выдаётся за курс %s' % (self.template, self.course.title) |
||||
|
||||
class Meta: |
||||
verbose_name = 'Генератор дипломов' |
||||
verbose_name_plural = 'Генераторы дипловов' |
||||
|
||||
|
||||
class Diploma(models.Model): |
||||
icon = models.ImageField(verbose_name='Иконка', upload_to='diplomas') |
||||
template = models.ForeignKey(to=DiplomaGen, verbose_name='Использовать шаблон', blank=True, null=True) |
||||
user = models.ForeignKey(to=settings.AUTH_USER_MODEL) |
||||
|
||||
def __str__(self): |
||||
return 'Студенту %s за курс %s' % (self.user.username, self.template.course.title) |
||||
|
||||
class Meta: |
||||
verbose_name = 'Диплом' |
||||
verbose_name_plural = 'Дипломы' |
||||
@ -0,0 +1,3 @@ |
||||
from django.test import TestCase |
||||
|
||||
# Create your tests here. |
||||
@ -0,0 +1,3 @@ |
||||
from django.shortcuts import render |
||||
|
||||
# Create your views here. |
||||
@ -1,16 +1,9 @@ |
||||
from django.contrib import admin |
||||
|
||||
from courses.models import Course, Skills, Achievements, SkillJ,\ |
||||
CourseMap, Topic, Task, Vertex, Diploma, Tutorial, DiplomaGen |
||||
from courses.models import Course, Tutorial, Topic, Task, Vertex |
||||
|
||||
admin.site.register(CourseMap) |
||||
admin.site.register(Topic) |
||||
admin.site.register(Task) |
||||
admin.site.register(Vertex) |
||||
admin.site.register(Tutorial) |
||||
admin.site.register(Course) |
||||
admin.site.register(Skills) |
||||
admin.site.register(Achievements) |
||||
admin.site.register(SkillJ) |
||||
admin.site.register(Diploma) |
||||
admin.site.register(DiplomaGen) |
||||
@ -0,0 +1,6 @@ |
||||
from django.contrib import admin |
||||
|
||||
from maps.models import CourseMap, CourseRoute |
||||
|
||||
admin.site.register(CourseMap) |
||||
admin.site.register(CourseRoute) |
||||
@ -0,0 +1,5 @@ |
||||
from django.apps import AppConfig |
||||
|
||||
|
||||
class MapsConfig(AppConfig): |
||||
name = 'maps' |
||||
@ -0,0 +1,77 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.11.6 on 2017-11-28 15:18 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.db import migrations, models |
||||
import django.db.models.deletion |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
initial = True |
||||
|
||||
dependencies = [ |
||||
('courses', '0001_initial'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.CreateModel( |
||||
name='CourseMap', |
||||
fields=[ |
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course', verbose_name='К какому курсу привязан')), |
||||
], |
||||
options={ |
||||
'verbose_name': 'Карта линейного прохождения курсов', |
||||
'verbose_name_plural': 'Карты линейного прохождения курсов', |
||||
}, |
||||
), |
||||
migrations.CreateModel( |
||||
name='CourseRoute', |
||||
fields=[ |
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
('name', models.CharField(blank=True, max_length=255, null=True, unique=True, verbose_name='Имя шаблона')), |
||||
('is_template', models.BooleanField(default=True, verbose_name='Может ли быть использован как шаблон')), |
||||
], |
||||
options={ |
||||
'verbose_name': 'Маршрут прохождения', |
||||
'verbose_name_plural': 'Маршруты прохождения', |
||||
}, |
||||
), |
||||
migrations.CreateModel( |
||||
name='PivotCourseMap', |
||||
fields=[ |
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
('sort', models.SmallIntegerField(unique=True, verbose_name='Порядок сортировки')), |
||||
('map_course', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='maps.CourseMap', verbose_name='К какой сортеровке имеетотношение')), |
||||
('route', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='maps.CourseRoute', verbose_name='К какому узлу')), |
||||
], |
||||
options={ |
||||
'verbose_name': 'Порядок сортировки узла', |
||||
'verbose_name_plural': 'Порядки сортировок узла', |
||||
'ordering': ('sort',), |
||||
}, |
||||
), |
||||
migrations.CreateModel( |
||||
name='PivotVertex', |
||||
fields=[ |
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
('sort', models.SmallIntegerField(unique=True, verbose_name='Порядок сортировки')), |
||||
('map_course', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='maps.CourseMap', verbose_name='К какой сортеровке имеетотношение')), |
||||
('vertex', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Vertex', verbose_name='К какому узлу')), |
||||
], |
||||
options={ |
||||
'verbose_name': 'Порядок сортировки узла', |
||||
'verbose_name_plural': 'Порядки сортировок узла', |
||||
'ordering': ('sort',), |
||||
}, |
||||
), |
||||
migrations.AlterUniqueTogether( |
||||
name='pivotvertex', |
||||
unique_together=set([('map_course', 'vertex')]), |
||||
), |
||||
migrations.AlterUniqueTogether( |
||||
name='pivotcoursemap', |
||||
unique_together=set([('map_course', 'route')]), |
||||
), |
||||
] |
||||
@ -0,0 +1,86 @@ |
||||
from django.db import models |
||||
|
||||
from lms.global_decorators import transaction_decorator |
||||
|
||||
|
||||
class CourseRoute(models.Model): |
||||
""" |
||||
Объединение нескольких мап курса, одназначно |
||||
определяет способ прохождения по курсу. |
||||
""" |
||||
name = models.CharField(max_length=255, verbose_name='Имя шаблона', blank=True, null=True, unique=True) |
||||
is_template = models.BooleanField(default=True, verbose_name='Может ли быть использован как шаблон') |
||||
|
||||
def is_finish(self, user): |
||||
return bool(sum([int(i.map_course.is_finish(user)) for i in self.pivotcoursemap_set.all()])) |
||||
|
||||
def get_active_objects(self, user): |
||||
return (i.map_course.getactive_object(user) for i in self.pivotcoursemap_set.all()) |
||||
|
||||
def get_view(self): |
||||
return (i.map_course for i in self.pivotcoursemap_set.all()) |
||||
|
||||
class Meta: |
||||
verbose_name = 'Маршрут прохождения' |
||||
verbose_name_plural = 'Маршруты прохождения' |
||||
|
||||
|
||||
class CourseMap(models.Model): |
||||
""" |
||||
Способы отображения курса. Упорядочены в порядке возрастания приоретета. |
||||
""" |
||||
course = models.ForeignKey(to='courses.Course', verbose_name='К какому курсу привязан') |
||||
|
||||
@transaction_decorator |
||||
def add_vertex(self, vertex, sort): |
||||
if sort > self.pivotvertex_set.count()+1: |
||||
raise ValueError("list index out of range") |
||||
for i in self.pivotvertex_set.filter(sort__gte=sort): |
||||
i.sort += 1 |
||||
i.save() |
||||
|
||||
pivot = PivotVertex.objects.create(vertex=vertex, sort=sort, map_course=self) |
||||
pivot.save() |
||||
return pivot |
||||
|
||||
def merge(self, another): |
||||
return # TODO: Доделать!!! |
||||
|
||||
def get_difference(self, user) -> list: |
||||
return list(set( |
||||
[i.vertex for i in self.pivotvertex_set.all()]).difference(set(user.progress.progress_list.all()) |
||||
)) |
||||
|
||||
def is_finish(self, user) -> bool: |
||||
return self.get_difference(user) == [] |
||||
|
||||
def get_active_object(self, user): |
||||
return self.pivotvertex_set.exclude(vertex__in=self.get_difference(user))[0] |
||||
|
||||
class Meta: |
||||
verbose_name = 'Карта линейного прохождения курсов' |
||||
verbose_name_plural = 'Карты линейного прохождения курсов' |
||||
|
||||
|
||||
class PivotCourseMap(models.Model): |
||||
route = models.ForeignKey(to=CourseRoute, verbose_name="К какому узлу") |
||||
sort = models.SmallIntegerField(verbose_name='Порядок сортировки', unique=True) |
||||
map_course = models.ForeignKey(to=CourseMap, verbose_name='К какой сортеровке имеетотношение', blank=True, null=True) |
||||
|
||||
class Meta: |
||||
verbose_name = 'Порядок сортировки узла' |
||||
verbose_name_plural = 'Порядки сортировок узла' |
||||
unique_together = (('map_course', 'route'),) |
||||
ordering = ('sort', ) |
||||
|
||||
|
||||
class PivotVertex(models.Model): |
||||
vertex = models.ForeignKey(to='courses.Vertex', verbose_name="К какому узлу") |
||||
sort = models.SmallIntegerField(verbose_name='Порядок сортировки', unique=True) |
||||
map_course = models.ForeignKey(to=CourseMap, verbose_name='К какой сортеровке имеетотношение', blank=True, null=True) |
||||
|
||||
class Meta: |
||||
verbose_name = 'Порядок сортировки узла' |
||||
verbose_name_plural = 'Порядки сортировок узла' |
||||
unique_together = (('map_course', 'vertex'),) |
||||
ordering = ('sort', ) |
||||
@ -0,0 +1,3 @@ |
||||
from django.test import TestCase |
||||
|
||||
# Create your tests here. |
||||
@ -0,0 +1,3 @@ |
||||
from django.shortcuts import render |
||||
|
||||
# Create your views here. |
||||
Loading…
Reference in new issue