diff --git a/access/migrations/0001_initial.py b/access/migrations/0001_initial.py index 71c8c9f..e29a62b 100644 --- a/access/migrations/0001_initial.py +++ b/access/migrations/0001_initial.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.6 on 2017-12-12 16:07 +# Generated by Django 1.11.6 on 2017-12-12 23:07 from __future__ import unicode_literals import access.models.user +import django.contrib.postgres.fields from django.db import migrations, models import django.db.models.deletion @@ -69,7 +70,8 @@ class Migration(migrations.Migration): name='PivotProgressVertex', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('status', models.SmallIntegerField(choices=[(0, 'Выполненно'), (1, 'Ожидание'), (2, 'Не выполненно')], default=0)), + ('status', models.SmallIntegerField(choices=[(2, 'Выполненно'), (1, 'Ожидание'), (0, 'Не выполненно')], default=0)), + ('comment', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=15, verbose_name='Ссылки на комменты'), size=None)), ], ), migrations.CreateModel( diff --git a/access/migrations/0002_auto_20171212_2307.py b/access/migrations/0002_auto_20171212_2307.py new file mode 100644 index 0000000..014ab17 --- /dev/null +++ b/access/migrations/0002_auto_20171212_2307.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.6 on 2017-12-12 23:07 +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 = [ + ('courses', '0002_auto_20171212_2307'), + ('auth', '0008_alter_user_username_max_length'), + ('maps', '0001_initial'), + ('access', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='progress', + name='course', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='courses.Course', verbose_name='Курс'), + ), + migrations.AddField( + model_name='progress', + name='teacher', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teacher_progress', to=settings.AUTH_USER_MODEL, verbose_name='Преподователь по умолчанию'), + ), + migrations.AddField( + model_name='progress', + name='template', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='maps.CourseRoute', verbose_name='Шаблон для прохождения если не указан явно смотри функцию get_template()'), + ), + migrations.AddField( + model_name='progress', + name='user', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Студент'), + ), + migrations.AddField( + model_name='pivotprogressvertex', + name='progress', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='access.Progress'), + ), + migrations.AddField( + model_name='pivotprogressvertex', + name='vertex', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Vertex'), + ), + migrations.AddField( + model_name='invite', + name='owner', + field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Кому приглошение'), + ), + 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')]), + ), + ] diff --git a/access/models/other.py b/access/models/other.py index dd74eb7..380963c 100644 --- a/access/models/other.py +++ b/access/models/other.py @@ -1,4 +1,5 @@ from django.conf import settings +from django.contrib.postgres.fields import ArrayField from django.db import models from courses.models import Course, Vertex @@ -65,6 +66,11 @@ class Progress(models.Model): @transaction_decorator def add_vertex(self, vertex): + PivotProgressVertex.objects.create( + progress=self, + vertex=vertex, + + ) self.progress_list.add(vertex) parent = vertex.vertex_set.first() if vertex.vertex_set.all().exists() else None if parent: @@ -93,11 +99,13 @@ class Progress(models.Model): class PivotProgressVertex(models.Model): VERTEX_STATUS = ( - (0, 'Выполненно'), + (2, 'Выполненно'), (1, 'Ожидание'), - (2, 'Не выполненно'), + (0, 'Не выполненно'), ) progress = models.ForeignKey(to=Progress) vertex = models.ForeignKey(to=Vertex) status = models.SmallIntegerField(choices=VERTEX_STATUS, default=0) - comment = models.ManyToManyField(to=Comment) \ No newline at end of file + comment = ArrayField( + models.CharField(max_length=15, blank=True, verbose_name='Ссылки на комменты'), + ) \ No newline at end of file diff --git a/achievements/migrations/0001_initial.py b/achievements/migrations/0001_initial.py index 17ec3d4..ce12385 100644 --- a/achievements/migrations/0001_initial.py +++ b/achievements/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.6 on 2017-12-12 16:07 +# Generated by Django 1.11.6 on 2017-12-12 23:07 from __future__ import unicode_literals from django.db import migrations, models diff --git a/achievements/migrations/0002_auto_20171212_2307.py b/achievements/migrations/0002_auto_20171212_2307.py new file mode 100644 index 0000000..917b715 --- /dev/null +++ b/achievements/migrations/0002_auto_20171212_2307.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.6 on 2017-12-12 23:07 +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 = [ + ('courses', '0001_initial'), + ('achievements', '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='users', + field=models.ManyToManyField(to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/courses/admin.py b/courses/admin.py index 99b9a23..71dc813 100755 --- a/courses/admin.py +++ b/courses/admin.py @@ -1,9 +1,7 @@ from django.contrib import admin -from courses.models import Course, Tutorial, Topic, Task, Vertex +from courses.models import Course, Topic, Vertex admin.site.register(Topic) -admin.site.register(Task) admin.site.register(Vertex) -admin.site.register(Tutorial) admin.site.register(Course) \ No newline at end of file diff --git a/courses/migrations/0001_initial.py b/courses/migrations/0001_initial.py index c7f13b4..6f88e5b 100644 --- a/courses/migrations/0001_initial.py +++ b/courses/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.6 on 2017-12-12 16:07 +# Generated by Django 1.11.6 on 2017-12-12 23:07 from __future__ import unicode_literals from django.db import migrations, models @@ -11,7 +11,6 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), ('storage', '0001_initial'), ] @@ -37,29 +36,18 @@ class Migration(migrations.Migration): 'verbose_name_plural': 'Курсы', }, ), - migrations.CreateModel( - name='Task', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('is_exam', models.BooleanField(default=False, verbose_name='Экзамен или домашка')), - ('materials', models.ManyToManyField(blank=True, to='storage.Storage', verbose_name='Материалы для домашней работы')), - ], - ), migrations.CreateModel( name='Topic', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255, verbose_name='Название')), ('icon', models.ImageField(blank=True, null=True, upload_to='', verbose_name='Иконка темы')), + ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course')), ], - ), - migrations.CreateModel( - name='Tutorial', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('on_comment', models.BooleanField(default=False, verbose_name='Комментарии')), - ('video', models.TextField(blank=True, default='', verbose_name='Код видео')), - ('materials', models.ManyToManyField(blank=True, to='storage.Storage', verbose_name='Материалы урока')), - ], + options={ + 'verbose_name': 'Тема', + 'verbose_name_plural': 'Темы', + }, ), migrations.CreateModel( name='Vertex', @@ -68,10 +56,14 @@ class Migration(migrations.Migration): ('title', models.CharField(max_length=255, verbose_name='Название')), ('free', models.BooleanField(default=True, verbose_name='Привилегии для узла не будут проверяться')), ('description', models.TextField(blank=True, default='', null=True, verbose_name='Описание')), - ('object_id', models.PositiveIntegerField()), - ('children', models.ManyToManyField(blank=True, to='courses.Vertex')), - ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')), - ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course')), + ('video', models.TextField(blank=True, default='', null=True, verbose_name='Код видео')), + ('valid_type', models.SmallIntegerField(choices=[(3, 'Автаматическая валидация'), (2, 'Полуавтаматическая валидация'), (1, 'Ручная валидация'), (0, 'Без валидации')], default=0)), + ('materials', models.ManyToManyField(blank=True, to='storage.File', verbose_name='Материалы урока')), + ('topic', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Topic')), ], + options={ + 'verbose_name': 'Урок', + 'verbose_name_plural': 'Уроки', + }, ), ] diff --git a/courses/migrations/0002_auto_20171212_2307.py b/courses/migrations/0002_auto_20171212_2307.py new file mode 100644 index 0000000..3eea03f --- /dev/null +++ b/courses/migrations/0002_auto_20171212_2307.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.6 on 2017-12-12 23:07 +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 = [ + ('courses', '0001_initial'), + ('maps', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='course', + name='route', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='maps.CourseRoute', verbose_name='Порядок прохождения по умолчанию'), + ), + migrations.AddField( + model_name='course', + name='teachers', + field=models.ManyToManyField(related_name='course_teachers', to=settings.AUTH_USER_MODEL, verbose_name='Преподаватели'), + ), + ] diff --git a/courses/models.py b/courses/models.py index ac3cdd7..9c3ccd9 100755 --- a/courses/models.py +++ b/courses/models.py @@ -13,7 +13,7 @@ from maps.models import CourseRoute, CourseMap from lms.tools import decode_base64, get_real_name from lms.global_decorators import transaction_decorator from library.models import Tags -from storage.models import Storage +from storage.models import File import random COURSE_LEVEL = ( @@ -163,58 +163,33 @@ class Course(models.Model): verbose_name_plural = "Курсы" -class VertexManager(models.Manager): - # Менеджер вершин графа. - @transaction_decorator - def create_with_dependencies(self, model, course, title, description, extra_data=None, - free=True, materials=None, parents=None, children=None): - - extra_data = json.loads(extra_data) - - content_type = ContentType.objects.get(app_label='courses', model=model) - obj = content_type.model_class().objects.create(**extra_data) - - [obj.materials.add(i) for i in materials] if materials else None - - res = self.create( - content_type=content_type, - object_id=obj.id, - course=course, - title=title, - description=description, - free=free, - ) - - if children: - for child in children: - res.children.add(child) - - if parents: - for parent in parents: - parent.children.add(res) +class Topic(models.Model): + title = models.CharField(verbose_name='Название', max_length=255) + icon = models.ImageField(verbose_name='Иконка темы', null=True, blank=True) + course = models.ForeignKey(to=Course) - return res + class Meta: + verbose_name = "Тема" + verbose_name_plural = "Темы" class Vertex(models.Model): - """ - Основная структурная единица узел графа курса. - Позволяет работать со структурой курса на более высоком уровне абстракции. - """ - - course = models.ForeignKey(to=Course) + VALID_TYPE = ( + (3, 'Автаматическая валидация'), + (2, 'Полуавтаматическая валидация'), + (1, 'Ручная валидация'), + (0, 'Без валидации'), + ) + topic = models.ForeignKey(to=Topic) title = models.CharField(verbose_name='Название', max_length=255) free = models.BooleanField(default=True, verbose_name='Привилегии для узла не будут проверяться') description = models.TextField(verbose_name='Описание', default='', blank=True, null=True) - children = models.ManyToManyField(to='Vertex', blank=True) - content_type = models.ForeignKey(to=ContentType) - object_id = models.PositiveIntegerField() - content_object = GenericForeignKey('content_type', 'object_id') - - objects = VertexManager() + video = models.TextField(verbose_name='Код видео', default='', blank=True, null=True) + materials = models.ManyToManyField(File, verbose_name='Материалы урока', blank=True) + valid_type = models.SmallIntegerField(choices=VALID_TYPE, default=0) def __str__(self): - return self.title + ': ' + str(self.content_type.model) + return self.title def get_next(self, route): return route.get_first().get_next(self) @@ -271,42 +246,6 @@ class Vertex(models.Model): res = None return res - -# Модели нового API со временем всё, что выше будет выпилено -class Tutorial(models.Model): - """ - Модель урока. - Урок может быть открыт для комментирования и закрыт, по дефолту открыт, - вероятно закрывать нужно будет крайне редко. - Видео к уроку фрейм который лежит прямо в базе, конечно же костыль и со временем - мы уйдём от этого, все видео хостятся на двух онлайн сервисах на клиент нужно передовать - id и сервис на котором, это дело хостится, а правило отображения оставить клиенту. - Материалы для урока по сути FileField, нужна только для создания лишней связи в таблице - и дублирования метазаголовков файла - """ - - on_comment = models.BooleanField(verbose_name=u'Комментарии', default=False) - video = models.TextField(verbose_name=u'Код видео', default='', blank=True) - materials = models.ManyToManyField(Storage, verbose_name=u'Материалы урока', blank=True) - - -class Task(models.Model): - """ - Модель таска. - Исторически сложилось, что на сервере хостятся два типа тасков отличающихся лишь наименованием - домашние работы и экзамены, не нужно быть гением, чтобы понять для чего нужно булево значение - is_exam - Материалы для урока по сути FileField, нужна только для создания лишней связи в таблице - и дублирования метазаголовков файла - """ - materials = models.ManyToManyField(Storage, verbose_name='Материалы для домашней работы', blank=True) - is_exam = models.BooleanField(default=False, verbose_name='Экзамен или домашка') - - -class Topic(models.Model): - """ - Модель темы, нужно просто для объединения тасков и уроков. - У некоторых тем есть иконка. - Возможно поле icon перекачует в Vertex, а данная модель отвалится за ненадобностью - """ - icon = models.ImageField(verbose_name='Иконка темы', null=True, blank=True) + class Meta: + verbose_name = "Урок" + verbose_name_plural = "Уроки" diff --git a/courses/serializers.py b/courses/serializers.py index 3a26a4f..9afb06c 100644 --- a/courses/serializers.py +++ b/courses/serializers.py @@ -1,24 +1,6 @@ from rest_framework import serializers -from courses.models import Course, Vertex, Tutorial, Topic, Task - - -class TutorialSerializer(serializers.ModelSerializer): - materials = serializers.SerializerMethodField() - - class Meta: - model = Tutorial - exclude = ['id'] - - @staticmethod - def get_materials(self): - return [i.original.url for i in self.materials.all()] - - -class TaskSerializer(serializers.ModelSerializer): - class Meta: - model = Task - exclude = ['id'] +from courses.models import Course, Vertex, Topic class TopicSerializer(serializers.ModelSerializer): @@ -49,15 +31,7 @@ class MiniVertexSerializer(serializers.ModelSerializer): class VertexSerializer(MiniVertexSerializer): class Meta: model = Vertex - fields = ('id', 'title', 'type', 'object', "description") - - @staticmethod - def get_object(self): - if self.content_type.model == 'tutorial': - return TutorialSerializer(self.content_object).data - if self.content_type.model == 'task': - return TaskSerializer(self.content_object).data - return False + fields = '__all__' class CourseInitSerializer(serializers.ModelSerializer): diff --git a/csv/load_courses.py b/csv/load_courses.py index 9e75d5f..b957be6 100644 --- a/csv/load_courses.py +++ b/csv/load_courses.py @@ -8,7 +8,7 @@ django.setup() from courses.models import Course, Vertex from maps.models import CourseRoute, CourseMap, PivotVertex, PivotCourseMap -from storage.models import Storage +from storage.models import File if __name__ == '__main__': CourseMap.objects.all().delete() @@ -37,7 +37,7 @@ if __name__ == '__main__': storage_reader = csv.DictReader(storage_csv) for row in storage_reader: if row['original']: - Storage.objects.get_or_create(**row) + File.objects.get_or_create(**row) with open('./course/vertex.csv') as vertex_csv: vertex_reader = csv.DictReader(vertex_csv) diff --git a/csv/load_student_teachers_threads.py b/csv/load_student_teachers_threads.py index 6cf2dfb..7ce2dc4 100644 --- a/csv/load_student_teachers_threads.py +++ b/csv/load_student_teachers_threads.py @@ -9,7 +9,7 @@ django.setup() from courses.models import Vertex from django.contrib.contenttypes.models import ContentType from journals.models import Thread, Journal -from storage.models import Storage +from storage.models import File if __name__ == '__main__': csv.field_size_limit(500 * 1024 * 1024) @@ -53,5 +53,5 @@ if __name__ == '__main__': for file_id in row['files'].split("[")[1].split("]")[0].split(", "): if file_id: - journal.files.add(Storage.objects.get(id=file_id)) + journal.files.add(File.objects.get(id=file_id)) diff --git a/finance/migrations/0001_initial.py b/finance/migrations/0001_initial.py index 77b80c9..3e1cb53 100644 --- a/finance/migrations/0001_initial.py +++ b/finance/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.6 on 2017-12-12 16:07 +# Generated by Django 1.11.6 on 2017-12-12 23:07 from __future__ import unicode_literals from django.conf import settings @@ -12,9 +12,9 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('yandex_money', '0002_auto_20171128_1150'), + ('courses', '0002_auto_20171212_2307'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('courses', '0002_auto_20171212_1607'), + ('yandex_money', '0002_auto_20171128_1150'), ] operations = [ diff --git a/library/migrations/0001_initial.py b/library/migrations/0001_initial.py index 72ec65b..e5e02b8 100644 --- a/library/migrations/0001_initial.py +++ b/library/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.6 on 2017-12-12 16:07 +# Generated by Django 1.11.6 on 2017-12-12 23:07 from __future__ import unicode_literals import datetime diff --git a/maps/migrations/0001_initial.py b/maps/migrations/0001_initial.py index 48b5f78..baa45fb 100644 --- a/maps/migrations/0001_initial.py +++ b/maps/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.6 on 2017-12-12 16:07 +# Generated by Django 1.11.6 on 2017-12-12 23:07 from __future__ import unicode_literals from django.db import migrations, models @@ -73,6 +73,6 @@ class Migration(migrations.Migration): ), migrations.AlterUniqueTogether( name='pivotcoursemap', - unique_together=set([('sort', 'route'), ('map_course', 'route')]), + unique_together=set([('map_course', 'route'), ('sort', 'route')]), ), ] diff --git a/storage/admin.py b/storage/admin.py index a2561c2..c506fee 100755 --- a/storage/admin.py +++ b/storage/admin.py @@ -1,4 +1,5 @@ from django.contrib import admin -from storage.models import Storage +from storage.models import File, Comment -admin.site.register(Storage) \ No newline at end of file +admin.site.register(File) +admin.site.register(Comment) \ No newline at end of file diff --git a/storage/migrations/0001_initial.py b/storage/migrations/0001_initial.py index 641d24b..93b6f87 100644 --- a/storage/migrations/0001_initial.py +++ b/storage/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.6 on 2017-12-12 16:07 +# Generated by Django 1.11.6 on 2017-12-12 23:07 from __future__ import unicode_literals from django.db import migrations, models @@ -17,11 +17,17 @@ class Migration(migrations.Migration): name='Comment', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('text', models.TextField(default='')), + ('email', models.CharField(max_length=63, verbose_name='email автора')), + ('text', models.TextField(default='', verbose_name='Текст комментария')), + ('key', models.SlugField(unique=True, verbose_name='Получения комментария по ключу')), ], + options={ + 'verbose_name': 'Коммент', + 'verbose_name_plural': 'Комменты', + }, ), migrations.CreateModel( - name='Storage', + name='File', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('original', models.FileField(max_length=255, upload_to='files', verbose_name='Файл')), @@ -35,6 +41,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='comment', name='files', - field=models.ManyToManyField(blank=True, to='storage.Storage'), + field=models.ManyToManyField(blank=True, to='storage.File', verbose_name='Файлы'), ), ] diff --git a/storage/models.py b/storage/models.py index 6f0a01b..140ed99 100755 --- a/storage/models.py +++ b/storage/models.py @@ -2,7 +2,7 @@ from django.db import models -class Storage(models.Model): +class File(models.Model): original = models.FileField(max_length=255, verbose_name='Файл', upload_to="files") name = models.CharField(max_length=255, null=True, blank=True, verbose_name='Видимое имя файла') @@ -15,5 +15,14 @@ class Storage(models.Model): class Comment(models.Model): - text = models.TextField(default="") - files = models.ManyToManyField(to=Storage, blank=True) \ No newline at end of file + email = models.CharField(verbose_name="email автора", max_length=63) + text = models.TextField(default="", verbose_name="Текст комментария") + files = models.ManyToManyField(to=File, blank=True, verbose_name='Файлы') + key = models.SlugField(unique=True, verbose_name="Получения комментария по ключу") + + def __str__(self): + return '%s' % self.key + + class Meta: + verbose_name = 'Коммент' + verbose_name_plural = 'Комменты' diff --git a/storage/serializers.py b/storage/serializers.py index 736f44f..5510683 100644 --- a/storage/serializers.py +++ b/storage/serializers.py @@ -1,10 +1,10 @@ from rest_framework import serializers -from storage.models import Storage +from storage.models import File class StorageSerializer(serializers.ModelSerializer): class Meta: - model = Storage + model = File exclude = ('id',) diff --git a/storage/tests.py b/storage/tests.py new file mode 100644 index 0000000..5883796 --- /dev/null +++ b/storage/tests.py @@ -0,0 +1,28 @@ +from django.test import TestCase +from storage.views import add_comment, delete_comment, update_comment, get_comment +from django.core.files.uploadedfile import SimpleUploadedFile + + +class CommentTestCase(TestCase): + def setUp(self): + self.first_comment = add_comment("first comment", "vasia@rambler.ru") + self.second_comment = add_comment(text="Привет, отличная работа", email="artem4000@gmail.com") + + def test_comment_get(self): + self.assertEqual(self.first_comment, get_comment(self.first_comment.key)) + + def test_comment_update(self): + new_text = "Новый текст для коммента" + update_comment(key=self.first_comment.key, text=new_text) + self.assertEqual(get_comment(self.first_comment.key).text, new_text) + + def test_comment_create(self): + token = 'fskjfskj' + comment1 = add_comment(text=token, email="artem4000@gmail.com") + self.assertEqual(comment1.text, token) + file_for_upload = SimpleUploadedFile('1.txt', 'Я файл!'.encode('utf-8')) + file_name = 'Клёвый файл' + object_for_upload = {'original': file_for_upload, 'name': file_name} + comment2 = add_comment(text=token, email="artem4000@gmail.com", files=[object_for_upload]) + self.assertEqual(comment2.files.count(), 1) + self.assertEqual(comment2.files.all()[0].name, file_name) diff --git a/storage/views.py b/storage/views.py new file mode 100644 index 0000000..027fe46 --- /dev/null +++ b/storage/views.py @@ -0,0 +1,47 @@ +import random +import string + +from storage.models import Comment, File + + +def add_comment(text: str, email: str, files=None) -> Comment: + """ + :param text: sting + :param email: string + :param files: {name?: string, file?: File, base64?: string}[] одно из двух последних свойств должно быть указано + :return: Comment + """ + key = ''.join(random.choice(string.ascii_letters) for _x in range(15)) + comment = Comment.objects.create( + text=text, + email=email, + key=key, + ) + + if files: + for file in files: + new_file = File.objects.create(original=file['original']) + if 'name' in file.keys(): + new_file.name = file['name'] + new_file.save() + + comment.files.add(new_file) + + return comment + + +def get_comment(key): + comment = Comment.objects.get(key=key) + return comment + + +def update_comment(key, **kwargs): + comment = Comment.objects.get(key=key) + comment.__dict__.update(kwargs) + comment.save() + return comment + + +def delete_comment(key): + comment = Comment.objects.get(key=key).delete() + return comment