diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7e858c2..3664577 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,8 +1,8 @@ # This file is a template, and might need editing before it works on your project. # Official docker image. -#image: docker:latest -#services: -# - docker:dind +image: docker:latest +services: + - docker:dind variables: CHANNEL: "skillbox" SERVER_URL: "lms.test.spicycms.com" diff --git a/courses/migrations/0046_auto_20170711_1704.py b/courses/migrations/0046_auto_20170711_1704.py new file mode 100644 index 0000000..7ad4302 --- /dev/null +++ b/courses/migrations/0046_auto_20170711_1704.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.3 on 2017-07-11 17:04 +from __future__ import unicode_literals + +import datetime +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('courses', '0045_merge'), + ] + + operations = [ + migrations.CreateModel( + name='Flow', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255, verbose_name='Название')), + ('description', models.TextField(blank=True, default='', null=True, verbose_name='Описание')), + ('start_flow', models.DateTimeField(default=datetime.datetime.now, verbose_name='Дата начала потока')), + ('created', models.DateTimeField(default=datetime.datetime.now, editable=False, verbose_name='Создан')), + ('modified', models.DateTimeField(auto_now=True, verbose_name='Изменен')), + ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course', verbose_name='Курс')), + ], + options={ + 'ordering': ['-modified'], + 'verbose_name_plural': 'Потоки', + 'verbose_name': 'Поток', + }, + ), + migrations.RemoveField( + model_name='coursetheme', + name='empty_old', + ), + ] diff --git a/courses/migrations/0047_remove_course_public_old.py b/courses/migrations/0047_remove_course_public_old.py new file mode 100644 index 0000000..ae4455c --- /dev/null +++ b/courses/migrations/0047_remove_course_public_old.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.3 on 2017-07-11 17:09 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('courses', '0046_auto_20170711_1704'), + ] + + operations = [ + migrations.RemoveField( + model_name='course', + name='public_old', + ), + ] diff --git a/courses/models.py b/courses/models.py index aac726d..fd25d8c 100755 --- a/courses/models.py +++ b/courses/models.py @@ -77,7 +77,6 @@ class Course(models.Model): direction = models.ForeignKey(MaterialDirection, verbose_name=u'Направление', null=True) mentors = models.ManyToManyField(User, verbose_name=u'Кураторы', null=True, blank=True, related_name='course_mentors') public = models.BooleanField(verbose_name=u'Опубликовать', default=False) - public_old = models.BooleanField(verbose_name=u'Старый статус', default=False) title = models.CharField(verbose_name=u"Заголовок", max_length=255) description = RedactorField(verbose_name=u'Описание', blank=True) image = models.ImageField(verbose_name=u'Изображение', upload_to='course', blank=True) @@ -206,12 +205,6 @@ class Course(models.Model): return '/courses/%s' % self.slug def save(self, *args, **kwargs): - # Костыль для поиска ошибки галочки - if self.public != self.public_old: - log = logging.getLogger('Course_public_change') - log.error('status change') - self.public_old = self.public - # if not self.slug: self.slug = '{0}'.format(translit(self.title)) super(Course, self).save(*args, **kwargs) @@ -234,7 +227,6 @@ class CourseTheme(models.Model): empty = models.BooleanField(verbose_name=u'Ты не пройдешь!', help_text=u'Заблокировать дальнейшее прохождение курса. Из-за того, ' u'что курс не заполнен или что-то вроде того.', default=False) - empty_old = models.BooleanField(verbose_name=u'Для проверки галочки', default=False) def __unicode__(self): return u'%s:%s/%s' % (self.sort, self.course, self.title if self.title else self.get__type_display()) @@ -322,13 +314,6 @@ class CourseTheme(models.Model): return Homework.objects.filter(theme=self).count() def save(self, *args, **kwargs): - # Костыль для поиска ошибки смены галочки - if self.empty != self.empty_old: - log = logging.getLogger('Themes_status_change') - log.error('status change') - self.public_old = self.public - # Костыль конец - if CourseTheme.objects.filter(course=self.course, sort=self.sort).exclude(id=self.id).exists(): # Переформировать порядок test_in = self.sort + 1 @@ -684,14 +669,6 @@ class CourseMap(models.Model): return _next._type, _next.get_obj() - def get_lesson_before(self): - try: - _before = CourseMap.objects.get(course=self.course, sort=self.sort - 2) - except CourseMap.DoesNotExist: - _before = CourseMap.objects.get(course=self.course, sort=0) - - return _before._type, _before.get_obj() - def get_before(self): try: _next = CourseMap.objects.get(course=self.course, sort=self.sort - 1) diff --git a/courses/views.py b/courses/views.py index d89d44e..54023b3 100755 --- a/courses/views.py +++ b/courses/views.py @@ -45,9 +45,12 @@ def course(request, slug): if created: check_journal(journal) _map = CourseMap.objects.filter(course=course).order_by('sort').first() - #_j = _map.get_obj() - #j = HomeworkJ.objects.get(material=_j, student=request.user) - #j.open_material() + _j = _map.get_obj() + if _map._type == 'H': + j = HomeworkJ.objects.get(material=_j, student=request.user) + if _map._type == 'L': + j = LessonJ.objects.get(material=_j, student=request.user) + j.open_material() else: journal, created = TeacherJ.objects.get_or_create(course=course, student=user_fabric(request.user)) @@ -59,11 +62,12 @@ def course(request, slug): start_flow = None if request.user.is_authenticated() and not request.user.is_admin: try: - bill = Bill.objects.get( + bills = Bill.objects.filter( service__course=course, user=request.user, status='F') - if bill.flow: - flow = bill.flow.get_status() - start_flow = bill.flow.start_flow + for bill in bills: + if bill.flow: + flow = bill.flow.get_status() + start_flow = bill.flow.start_flow except Bill.DoesNotExist: pass diff --git a/journals/models.py b/journals/models.py index 5666f53..d37b418 100755 --- a/journals/models.py +++ b/journals/models.py @@ -414,15 +414,6 @@ class CourseThemeJ(models.Model): p.save() return p - def check_lessons(self): - """ Проверка уроков темы на статус. Если сдано - сдана тема""" - for lessonj in LessonJ.objects.filter(parent=self, student=self.student): - if lessonj.success == False: - return False - - return True - - def save(self, *args, **kwargs): if not self.parent: self.parent = self.get_parent() @@ -437,8 +428,11 @@ class CourseThemeJ(models.Model): elif actual_lesson != self.actual_lesson.id: self.actual_lesson = Lesson.objects.get(id=self.make_actual_lesson()) - if self.check_lessons(): - self.success = True + if LessonJ.objects.filter(parent=self, student=self.student).exists(): + if LessonJ.objects.filter(parent=self, student=self.student, success=False).exists(): + self.success = False + else: + self.success = True if self.set_open: if Lesson.objects.filter(theme=self.material).order_by('sort').exists(): @@ -591,9 +585,7 @@ class LessonJ(models.Model): if _type == 'L': obj = LessonJ elif _type == 'H': - _before = CourseMap.objects.get(token=_before.token) - _type, _before = _before.get_lesson_before() - obj = LessonJ + obj = HomeworkJ elif _type == 'E': obj = ExamJ diff --git a/lms/settings.py b/lms/settings.py index e360867..4e062db 100644 --- a/lms/settings.py +++ b/lms/settings.py @@ -65,6 +65,10 @@ YANDEX_SHOP_ID = '84348' YANDEX_scid = '78309' # Application definition +# место куда сохраняем пользовательские файлы +PERSONAL_FILES = '/personal_files/' + + INSTALLED_APPS = [ #'jet.dashboard', #'jet', diff --git a/lms/urls.py b/lms/urls.py index 85f4d58..a1ad487 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -6,8 +6,10 @@ from lms import views from lms import settings from access.views import profile_view + urlpatterns = [ url(r'^$', views.index), + url(r'^oferta/', views.show_oferta), url(r'^test/$', views.test), url(r'^all_comments/$', views.all_comments), url(r'^reports/$', views.new_reports), diff --git a/lms/views.py b/lms/views.py index d7dff34..41f3d5b 100644 --- a/lms/views.py +++ b/lms/views.py @@ -10,7 +10,7 @@ from finance.models import Bill from courses.templates import comment_fabric from library.models import Article from management.reports import get_now_success_hw, get_second_success_hw - +from django.http import HttpResponse def sortByTimeStamp(inputStr): return inputStr['sort'] @@ -154,3 +154,9 @@ def new_reports(request): @response_decor(template='contacts.html', without_auth=True) def contacts(request): return {} + +def show_oferta(request): + with open('oferta.pdf', 'rb') as pdf: + response = HttpResponse(pdf.read(), content_type='application/pdf') + response['Content-Disposition'] = 'filename=oferta.pdf' + return response \ No newline at end of file diff --git a/management/api.py b/management/api.py index 9045c27..f656f13 100755 --- a/management/api.py +++ b/management/api.py @@ -7,7 +7,8 @@ from lms.tools import out_date_format, condition_factory, user_fabric from finance.models import Price, Bill, ServiceRequest from management.letters import sent_new_bill, sent_clean_letter, send_burning_course_letter from management.models import News, Feedback, Comment - +from courses.models import Course, CourseTheme +from journals.models import TeacherJ, CourseThemeJ, LessonJ, HomeworkJ @api_decor(without_auth=False, need_keys=['title', 'content', 'to'], method='POST', check_request=True) def self_sent_letter(request, context): @@ -172,3 +173,115 @@ def burning_course(request): send_burning_course_letter(user, course) + +""" + Все функции снизу используются в подобии кабинета для отдела по работе с персоналом. + Если хочешь переписать - перепиши. +""" +@api_decor(without_auth=False) +def find_user(request, context): + try: + user = User.objects.get(id=request.GET['user']) + data = "%s | %s %s" % (user.id, user.name, user.fname) + except User.DoesNotExist: + data = '0' + except ValueError: + data = '0' + + return data + +@api_decor(without_auth=False) +def find_course(request, context): + try: + course = Course.objects.get(id=request.GET['course']) + data = course.title + except Course.DoesNotExist: + data = '0' + except ValueError: + data = '0' + + return data + +@api_decor(without_auth=False) +def open_lessons(request, context): + try: + user = User.objects.get(id=request.GET['user']) + course = Course.objects.get(id=request.GET['course']) + checkbox = True if request.GET.get('homes') == 'on' else False + themes = request.GET['themes'].split(' ') + if '' in themes: + themes.remove('') + for t in themes: + t = int(t) + + except Exception: + return '0' + + try: + teachj, status = TeacherJ.objects.get_or_create(student=user, course=course) + if themes: + course_themes = CourseTheme.objects.filter(course=course, sort__in=themes) + else: + course_themes = CourseTheme.objects.filter(course=course) + for t in course_themes: + for l in LessonJ.objects.filter(student=user, parent__material=t): + l.success = True + l.save() + if open_homes: + if HomeworkJ.objects.filter(student=user, parent__material=t).exists(): + homej = HomeworkJ.objects.get(student=user, parent__material=t) + homej.success = True + homej.save() + themej, status = CourseThemeJ.objects.get_or_create(student=user, material=t) + themej.success = True + themej.save() + teachj.reload_progress() + except Exception: + return '1' + + return '2' + +@api_decor(without_auth=False) +def open_homes(request, context): + try: + user = User.objects.get(id=request.GET['user']) + course = Course.objects.get(id=request.GET['course']) + themes = request.GET['themes'].split(' ') + if '' in themes: + themes.remove('') + for t in themes: + t = int(t) + + except Exception: + return'0' + + try: + if themes: + course_themes = CourseTheme.objects.filter(course=course, sort__in=themes) + else: + course_themes = CourseTheme.objects.filter(course=course) + for t in course_themes: + if HomeworkJ.objects.filter(student=user, parent__material=t).exists(): + homej = HomeworkJ.objects.get(student=user, parent__material=t) + homej.success = True + homej.save() + except Exception: + return '1' + + return '2' + +@api_decor(without_auth=False) +def change_pass(request, context): + try: + user = User.objects.get(id=request.GET['user']) + password = request.GET.get('pass') + except Exception: + return '0' + + try: + user.set_password(password) + user.save() + except Exception: + return '1' + + return '2' diff --git a/management/forms.py b/management/forms.py new file mode 100644 index 0000000..2556a04 --- /dev/null +++ b/management/forms.py @@ -0,0 +1,5 @@ +from django import forms + +class UploadFileForm(forms.Form): + service_id = forms.CharField(max_length=50, label=u'id услуги') + file = forms.FileField() \ No newline at end of file diff --git a/management/urls.py b/management/urls.py index dcf5331..c6b6a89 100755 --- a/management/urls.py +++ b/management/urls.py @@ -36,5 +36,12 @@ urlpatterns = [ url(r'reports_api/get_process_report/$', reports.get_process_report), url(r'reports_api/now_success_hw/$', reports.now_success_hw), url(r'reports_api/now_second_hw/$', reports.now_second_hw), - url(r'self_sent_letter/$', api.self_sent_letter) + url(r'self_sent_letter/$', api.self_sent_letter), + url(r'workcabinet/$', views.render_management_cabinet), + url(r'diplomscabinet/$', views.render_diplom_cabinet), + url(r'find_user/$', api.find_user), + url(r'find_course/$', api.find_course), + url(r'open_lessons/$', api.open_lessons), + url(r'open_homes/$', api.open_homes), + url(r'change_pass/$', api.change_pass), ] diff --git a/management/views.py b/management/views.py index 809b658..dee6ed0 100755 --- a/management/views.py +++ b/management/views.py @@ -9,7 +9,9 @@ from finance.models import Bill, ServiceRequest, Price from management.models import News, Faq, FaqTitle from courses.models import Course, CourseTheme from management.reports import get_now_success_hw, get_second_success_hw - +from access.models import User +from finance.models import Bill, Price +from .forms import UploadFileForm @response_decor(template='super_bill.html') def super_bill(request): @@ -129,3 +131,46 @@ def progress_report(request): 'journals': []} map.append(c) return {'map': map, 'get_now_success_hw': get_now_success_hw(), 'get_second_success_hw': get_second_success_hw()} + + +@response_decor(template='cabinet.html') +def render_management_cabinet(request): + if request.user.in_role != 'A': + raise Http404 + else: + courses = Course.objects.filter(hidden=False).order_by('id') + return {'courses': courses} + + + + +@response_decor(template='diplomscab.html') +def render_diplom_cabinet(request): + context = {} + if request.method == 'POST': + + form = UploadFileForm(request.POST, request.FILES) + for l in request.FILES['file'].readlines(): + try: + user = User.objects.get(email=l.rstrip().lower()) + except User.DoesNotExist: + context['error'] = 'Плохая почта %s' % l + + try: + data = form.cleaned_data + id_ = int(data['service_id']) + service = Price.objects.get(id=id_) + bill = Bill.objects.create(user=user, status='F', service=service) + bill.save() + except Exception: + context['error'] = 'Не получилось создать счет для %s' % l + + + context['form'] = form + return context + else: + form = UploadFileForm() + + context['form'] = form + return context + diff --git a/oferta.pdf b/oferta.pdf new file mode 100644 index 0000000..0f10852 Binary files /dev/null and b/oferta.pdf differ diff --git a/static/js/apis/access.js b/static/js/apis/access.js index bbafc7d..f511241 100755 --- a/static/js/apis/access.js +++ b/static/js/apis/access.js @@ -95,9 +95,17 @@ function forgot(){ }) } function registry_go(){ + if ($('#checkBox').prop('checked') != true){ + console.log('NOT PASS') + $('#error_registration').html('Перед регистрацией ознакомтесь с договором-оферты'); + $('#error_registration').fadeIn('fast'); + + } else { + console.log('PASS') $('#error_registration').html(''); $('#error_registration').fadeIn('fast'); var theForm = $(document.forms['registration_form']).serialize(); + console.log(theForm) $.ajax({ type: 'POST', url: '/access/registration/', @@ -120,6 +128,7 @@ function registry_go(){ console.log('Возникла ошибка registry_go(): ' + str); } }); + } } function registry_go2(){ diff --git a/static/js/apis/activation.js b/static/js/apis/activation.js index 6edb105..cafe099 100755 --- a/static/js/apis/activation.js +++ b/static/js/apis/activation.js @@ -28,20 +28,27 @@ function sent_step(step){ return result; } function check_step(step){ - // Проверка данных этапа - > Отправка данных - var result = sent_step(step); - if (result[0]){ - if (step==3){ - final_button() - } - close_step(step); - enable_step(step+1); + if ($('#checkBox').prop('checked') != true){ + console.log('NOT PASS') + $('[name="error"]').html('Перед регистрацией ознакомтесь с договором-оферты'); + $('#error_registration').fadeIn('fast'); + } else { - visible_error(step, result[1]['inputs'], result[1]['message']) + // Проверка данных этапа - > Отправка данных + var result = sent_step(step); + if (result[0]){ + if (step==3){ + final_button() + } + close_step(step); + enable_step(step+1); + } else { + visible_error(step, result[1]['inputs'], result[1]['message']) + } + // Если все верно - > Переход на новый уровень + // Если нет - > Подсвечивание полей + //console.log('Получил запрос этапа '+step) } - // Если все верно - > Переход на новый уровень - // Если нет - > Подсвечивание полей - //console.log('Получил запрос этапа '+step) } function enable_step(step){ // Активация этапа diff --git a/storage/files_api.py b/storage/files_api.py index ce520a1..a7accea 100755 --- a/storage/files_api.py +++ b/storage/files_api.py @@ -8,7 +8,7 @@ from lms.decors import api_decor from lms.tools import translit from storage.models import Storage, CroppedImage, FormatIndex -IMAGE_TMP = settings.MEDIA_ROOT + 'tmp/' +IMAGE_TMP = settings.MEDIA_ROOT + settings.PERSONAL_FILES def save_gif(pil_img, path): diff --git a/storage/models.py b/storage/models.py index 839a8c4..2685ea6 100755 --- a/storage/models.py +++ b/storage/models.py @@ -137,7 +137,7 @@ class CroppedImage(models.Model): verbose_name_plural = u'Картинки' -IMAGE_TMP = settings.MEDIA_ROOT + 'tmp/' +IMAGE_TMP = settings.MEDIA_ROOT + settings.PERSONAL_FILES def save_resize_image(filename, pil_img, save_field, file_format): diff --git a/templates/activation.html b/templates/activation.html index 9b564ce..b29db2d 100755 --- a/templates/activation.html +++ b/templates/activation.html @@ -301,6 +301,10 @@ +
+ + Регистрируясь, вы соглашаетесь с договором-оферты +

{% now "Y" %} {{ NAME }} diff --git a/templates/cabinet.html b/templates/cabinet.html new file mode 100644 index 0000000..fde991d --- /dev/null +++ b/templates/cabinet.html @@ -0,0 +1,238 @@ +{% extends 'base_index.html' %} +{% block title %}Рабочий кабинет{% endblock %} +{% block content %} + + +

+
+
Открыть уроки
+
+
+ Введите id пользователя + +
+
+
+ Введите id курса + +
+
+
+ Открыть домашки + +
+
+ Отдельные темы + +
+
+ +
+
+
+
Открыть домашки
+
+
+ Введите id пользователя + +
+
+
+ Введите id курса + +
+
+
+ Отдельные темы + +
+
+ +
+
+
+
Поменять пароль
+
+
+ Введите id пользователя + +
+
+
+ Введите новый пароль + +
+
+ +
+
+
+
+ {% for c in courses %} +
{{ c.id }}: {{ c.title }}
+ {% endfor %} +
+ + + +{% endblock %} diff --git a/templates/course.html b/templates/course.html index aaaaed5..7f08e18 100755 --- a/templates/course.html +++ b/templates/course.html @@ -118,7 +118,7 @@
{% if i.head.lessons_length > 0 %} {% if i.head.button %} - + {% else %} {% endif %} @@ -143,10 +143,14 @@ {% if i.head.lessons_length > 0 %} {% if i.head.button %} + {% if flow or flow == None %} + {% else %} + + {% endif %} {% else %} {% endif %} @@ -163,7 +167,7 @@ {{ i.head.title|safe }} - {% if i.head.status.flag != 'N' %} + {% if i.head.status.flag != 'N' and flow or flow == None %} {{ i.head.status.title }} @@ -192,12 +196,17 @@ @@ -280,7 +289,7 @@ {% if i.head.button %}
{% if flow or flow == None %} - + + {% endif %}
{% endif %} @@ -332,6 +348,23 @@ }); $('[data-toggle="tooltip"]').tooltip() + // Проверка доступности уроков(старт потока) + // если поток открыт редирект на урок + $('.flow').on('click', function(e){ + e.preventDefault(); + var path = document.location.pathname; + $.get(path, function(data){ + _flow = $(data).find('.flow').attr('href'); + if (_flow === '#'){ + $('#flowAccess').modal('show'); + } + else { + document.location.href = _flow; + } + //console.log(_flow); + }); + }); + if(flow == 'False'){ $('#flowAccess').modal('show'); } diff --git a/templates/diplomscab.html b/templates/diplomscab.html new file mode 100644 index 0000000..6ac3d33 --- /dev/null +++ b/templates/diplomscab.html @@ -0,0 +1,14 @@ +{% extends 'base_index.html' %} +{% block title %}Рабочий кабинет{% endblock %} +{% block content %} +
Массовое открытие дипломов
+
+ {% csrf_token %} + + {{form.as_table}} +
+
{{ ERROR }}
+ +
+ +{% endblock %} \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 372174e..2f2fe73 100755 --- a/templates/index.html +++ b/templates/index.html @@ -58,7 +58,10 @@ {% for i in courses %}
+ {% comment %} + {% endcomment %} +