Compare commits

..

No commits in common. 'master' and 'feature/fix_accout_not_found' have entirely different histories.

  1. 5
      .gitignore
  2. 23
      Envoy.blade.php
  3. 42
      access/management/commands/set_tokens.py
  4. 7
      access/models/other.py
  5. 40
      access/serializers.py
  6. 8
      access/urls.py
  7. 30
      access/views.py
  8. 31
      config_app/management/commands/for_test.py
  9. 5
      config_app/settings/prod.env
  10. 5
      config_app/settings/prod.env.skeleton
  11. 23
      courses/migrations/0006_auto_20180323_1743.py
  12. 34
      courses/models.py
  13. 19
      courses/serializers.py
  14. 13
      courses/tasks.py
  15. 6
      courses/urls.py
  16. 240
      courses/views.py
  17. 10
      finance/admin.py
  18. 56
      finance/loggers.py
  19. 0
      finance/management/__init__.py
  20. 14
      finance/management/commands/yandex_repeat_payment.py
  21. 20
      finance/migrations/0003_auto_20180315_1358.py
  22. 22
      finance/migrations/0004_bill_date.py
  23. 35
      finance/migrations/0005_auto_20180329_1346.py
  24. 37
      finance/migrations/0006_auto_20180330_1121.py
  25. 23
      finance/migrations/0007_auto_20180330_1452.py
  26. 28
      finance/migrations/0008_invoicerebilling.py
  27. 21
      finance/migrations/0009_invoicerebilling_pay_count.py
  28. 40
      finance/migrations/0010_auto_20180412_1628.py
  29. 128
      finance/models.py
  30. 6
      finance/serializers.py
  31. 21
      finance/signals.py
  32. 81
      finance/tasks.py
  33. 8
      finance/urls.py
  34. 441
      finance/views.py
  35. 14
      lms/celery.py
  36. 60
      lms/settings.py
  37. 6
      lms/urls.py
  38. 520
      logs/celery.log
  39. 623
      logs/flower.log
  40. 121
      logs/schedule.log
  41. 20
      progress/migrations/0009_progress_is_freeze.py
  42. 20
      progress/migrations/0010_progress_exp_date.py
  43. 2
      progress/models.py
  44. 40
      progress/serializers.py
  45. 5
      progress/urls.py
  46. 243
      progress/views.py
  47. 22
      storage/views.py
  48. 6
      templates/mail/sales/back_set_bill.html
  49. 7
      templates/mail/sales/pay_access.html
  50. 57
      templates/yandex/test_pay.html

5
.gitignore vendored

@ -3,7 +3,6 @@
# use glob syntax.
syntax: glob
logs/
docs/_build
.idea
.DS_Store
@ -37,5 +36,5 @@ coverage.xml
# Celery
celerybeat-schedule
/config_app/settings/local.env
/config_app/settings/dev.env
/config_app/settings/test.env

@ -29,16 +29,11 @@ echo '{{ $new_release_dir }}'
@task('create_symlinks', ['on' => 'localhost'])
echo '>> Создание симлинков'
ln -s {{ $app_dir }}/configs/master/ssl {{ $new_release_dir }}/ssl
@if ($branch == 'master')
ln -nfs {{ $app_dir }}/configs/master/prod.env {{ $new_release_dir }}/config_app/settings/local.env
ln -nfs {{ $app_dir }}/media/master {{ $new_release_dir }}/media
@endif
@if ($branch == 'dev')
ln -nfs {{ $app_dir }}/configs/dev/dev.env {{ $new_release_dir }}/config_app/settings/local.env
@if ($branch)
ln -nfs {{ $app_dir }}/configs/master/prod.env {{ $new_release_dir }}/config_app/settings/prod.env
ln -nfs {{ $app_dir }}/configs/dev/dev.env {{ $new_release_dir }}/config_app/settings/dev.env
ln -nfs {{ $app_dir }}/media/master {{ $new_release_dir }}/media
@endif
ln -nfs {{ $app_dir }}/logs/{{ $branch }} {{ $new_release_dir }}/logs
@endtask
@task('install_req', ['on' => 'localhost'])
@ -50,18 +45,10 @@ echo '>> Подтягиваем зависимости'
@endtask
@task('run_tests', ['on' => 'localhost'])
echo '>> Запускаем тесты'
@if ($branch)
cd {{ $new_release_dir }}
source /env/bin/activate && python manage.py test
@endif
@endtask
@task('run_migrate', ['on' => 'localhost'])
echo '>> Запускаем миграции'
echo '>> Запускаем миграции тесты'
@if ($branch)
cd {{ $new_release_dir }}
source /env/bin/activate && python manage.py migrate
source /env/bin/activate && python manage.py migrate && python manage.py test
@endif
@endtask

@ -1,42 +0,0 @@
import csv
import jwt
from django.conf import settings
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = 'Добавляет 1 или нескольких юзеров в указанные группы'
def add_arguments(self, parser):
parser.add_argument(
'--from',
type=str,
dest='from',
help='Файл подгрузки данных'
)
parser.add_argument(
'--to',
type=str,
dest='to',
help='Файл выгрузки'
)
def handle(self, *args, **options):
from_path = options['from']
to_path = options['to']
with open(from_path) as f:
with open(to_path, 'w') as out_f:
fw = csv.writer(out_f)
fr = csv.reader(f, delimiter=';')
for row in fr:
email = row[0]
course_token = row[1]
period = row[2]
payload = {
'period': period,
'course_token': course_token,
'email': email.lower(),
}
token = jwt.encode(payload, settings.COURSE_PROGRESS_SECRET_KEY, algorithm='HS256').decode("utf-8")
url = "https://go.skillbox.ru/api/v1/progress/progress_token/?token=%s" % str(token)
fw.writerow([email.lower(), url])

@ -53,13 +53,6 @@ class Account(models.Model):
def __str__(self):
return self.owner.email
def get_phone(self):
try:
return '' if self.phone is None else ('' if self.phone.national_number else \
(self.phone.national_number if self.phone.country_code is None else str(self.phone)))
except AttributeError:
return self.phone
class Meta:
verbose_name = 'Дополнительная информация о пользователе'
verbose_name_plural = 'Дополнительная информация о пользователе'

@ -1,14 +1,14 @@
from django.contrib.auth import get_user_model
from rest_framework import serializers
from rest_framework.generics import get_object_or_404
from access.models.other import Account
from achievements.serialers import DiplomaSerializer, AchievementsSerializer
from progress.serializers import SecureProgressSerializer, SupportProgressSerializer
from django.utils import timezone
from progress.serializers import ProgressSerializer
class AccountSerializer(serializers.ModelSerializer):
gender = serializers.SerializerMethodField()
phone = serializers.SerializerMethodField()
class Meta:
model = Account
@ -18,21 +18,17 @@ class AccountSerializer(serializers.ModelSerializer):
def get_gender(self):
return self.get_gender_display()
@staticmethod
def get_phone(self):
return self.get_phone()
class UserSelfSerializer(serializers.ModelSerializer):
account = serializers.SerializerMethodField()
groups = serializers.SerializerMethodField()
progresses = serializers.SerializerMethodField()
progress = serializers.SerializerMethodField()
diplomas = serializers.SerializerMethodField()
achievements = serializers.SerializerMethodField()
class Meta:
model = get_user_model()
fields = ('out_key', 'email', 'first_name', 'last_name', 'progresses', 'achievements',
fields = ('out_key', 'email', 'first_name', 'last_name', 'progress', 'achievements',
'account', 'groups', 'is_staff', 'is_superuser', 'diplomas', 'is_active')
@staticmethod
@ -52,9 +48,8 @@ class UserSelfSerializer(serializers.ModelSerializer):
return [group.name for group in self.groups.all()]
@staticmethod
def get_progresses(self):
return [SecureProgressSerializer(i).data for i in
self.progress_set.filter(is_freeze=False).exclude(exp_date__lt=timezone.now())]
def get_progress(self):
return [ProgressSerializer(i).data for i in self.progress_set.all()]
class UserProfileSerializer(serializers.ModelSerializer):
@ -90,7 +85,7 @@ class UserSearchSerializer(serializers.ModelSerializer):
@staticmethod
def get_phone(self):
return self.account.get_phone()
return None if self.account.phone is None else self.account.phone.raw_input
@staticmethod
def get_pay(self):
@ -107,22 +102,3 @@ class UserSearchSerializer(serializers.ModelSerializer):
@staticmethod
def get_last_request(self):
return self.useractivity.last_request
class UserProgressSearchSerializer(serializers.ModelSerializer):
phone = serializers.SerializerMethodField()
progresses = serializers.SerializerMethodField()
class Meta:
model = get_user_model()
fields = ('out_key', 'email', 'first_name',
'last_name', 'phone', 'progresses')
@staticmethod
def get_phone(self):
return self.account.get_phone()
@staticmethod
def get_progresses(self):
return [SupportProgressSerializer(i).data for i in self.progress_set.all()]

@ -5,10 +5,12 @@ from access import views
urlpatterns = [
url(r'progress_detail/(?P<token>[0-9A-Fa-f-]+)/$', progress.views.CourseProgressUserView.as_view()),
url(r'progress_dynamic/(?P<token>[0-9A-Fa-f-]+)/$', progress.views.CourseProgressDynamicView.as_view()),
url(r'teachers/$', views.TeacherListView.as_view()),
url(r'detail/(?P<out_key>[0-9A-Fa-f-]+)/$', views.DetailUserView.as_view()),
url(r'detail/$', views.DetailUserView.as_view()),
url(r'info/(?P<out_key>[0-9A-Fa-f-]+)/$', views.MinUserView.as_view()),
url(r'guard/(?P<pk>[0-9]{1,99})/(?P<page>.+)/$', progress.views.UserGuardView.as_view()),
url(r'find/$', views.FindUserView.as_view()),
url(r'registration/$', views.RegistrationView.as_view()),
url(r'change_password/$', views.ChangePasswordView.as_view()),
@ -16,6 +18,10 @@ urlpatterns = [
url(r'logout/$', views.LogoutView.as_view()),
url(r'reset/$', views.ResetPasswordView.as_view()),
url(r'progress_detail/upload/(?P<token>[0-9A-Fa-f-]+)/$', progress.views.UploadCourseProgressUserView.as_view()),
url(r'management/password/$', views.ManagementPassword.as_view(), name='management-password')
url(
r'management/password/$',
views.ManagementPassword.as_view(),
name='management-password'
)
]

@ -28,10 +28,7 @@ class TeacherListView(APIView):
status_code = 200
def get(self, request):
return Response([{
'email': i.email,
'token': i.out_key,
} for i in get_user_model().objects.filter(groups__name='teachers')], self.status_code)
return Response([i.email for i in get_user_model().objects.filter(groups__name='teachers')], self.status_code)
class ResetPasswordView(APIView):
@ -128,7 +125,6 @@ class FindUserView(APIView):
class DetailUserView(APIView):
renderer_classes = (JSONRenderer,)
permission_classes = (permissions.IsAuthenticated,)
@staticmethod
def post(request, out_key=None):
@ -238,7 +234,7 @@ class ChangePasswordView(APIView):
@staticmethod
def post(request):
if request.user.is_authenticated() and not request.user.check_password(request.JSON['old_password']):
if request.user.is_authenticated() or not request.user.check_password(request.JSON['old_password']):
return Response("Неверный пароль", status=400)
request.user.set_password(request.JSON['new_password'])
request.user.save()
@ -252,15 +248,21 @@ class LoginView(APIView):
def post(request):
password = request.JSON.get('password')
email = request.JSON.get('email').lower()
try:
user = get_user_model().objects.get(email=email)
except get_user_model().DoesNotExist:
return Response("Аккаунт не найден", status=404)
user = None
if not request.user.is_authenticated():
if not password == settings.MASTER_PASSWORD and not auth.authenticate(email=email, password=password):
return Response("Неверный пароль", status=403)
if not password == settings.MASTER_PASSWORD:
try:
get_user_model().objects.get(email=email)
user = auth.authenticate(email=email, password=request.JSON.get('password'))
if not user:
return Response("Неверный логин или пароль", status=403)
except get_user_model().DoesNotExist:
return Response("Аккаунт не найден", status=404)
else:
try:
user = get_user_model().objects.get(email=email)
except get_user_model().DoesNotExist:
return Response("Аккаунт не найден", status=404)
try:
auth.login(request, user)

@ -1,31 +0,0 @@
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = 'Команда для тестов'
def handle(self, *args, **options):
from xml.dom import minidom
xx = """<?xml version="1.0" encoding="UTF-8"?>
<repeatCardPaymentResponse status="3" error="112" processedDT="2018-04-23T19:37:04.544+03:00" techMessage="Неверное значение параметра invoiceId" clientOrderId="unknown"/>"""
dom = minidom.parseString(xx)
dom.normalize()
node1 = dom.getElementsByTagName("repeatCardPaymentResponse")[0]
print(node1)
print(node1.getAttribute('error'))
print(node1.getAttribute('processedDT'))
print(node1.getAttribute('techMessage'))
# def handle(self, *args, **options):
# from finance.loggers import FinanceLogger
# logger = FinanceLogger()
# try:
# 10 / 0
# except Exception as exc:
# logger.exception('FinanceLogger test log record', extra={'asdf': 3246523},
# invoice_id=42, some_param={'a': 1, 'b': 3, 'привет': 'медвед'}
# )
#

@ -0,0 +1,5 @@
DEBUG=False
SECRET_KEY='!eiquy7_+2#vn3z%zfp51$m-=tmvtcv*cj*@x$!v(_9btq0w=$'
DATABASE_URL='psql://team:nu5Xefise@127.0.0.1:5432/new_lms'
EMAIL_URL='smtp+tls://robo@skillbox.ru:nu5Xefise@smtp.gmail.com:587'
CACHE_URL=rediscache://127.0.0.1:6379/1?client_class=django_redis.client.DefaultClient

@ -1,5 +0,0 @@
DEBUG=False
SECRET_KEY='....'
DATABASE_URL='psql://<name>:<password>@127.0.0.1:5432/<db_name>'
EMAIL_URL='smtp+tls://<name>:<password>@smtp.gmail.com:587'
CACHE_URL=rediscache://127.0.0.1:6379/<db>?client_class=django_redis.client.DefaultClient

@ -1,23 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-03-23 17:43
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('courses', '0005_auto_20180222_1911'),
]
operations = [
migrations.RemoveField(
model_name='topic',
name='description',
),
migrations.RemoveField(
model_name='topic',
name='icon',
),
]

@ -58,6 +58,8 @@ class Lesson(models.Model):
class Topic(models.Model):
course = models.ForeignKey(to="Course", verbose_name='курс')
title = models.CharField(verbose_name='Название', max_length=255)
description = models.TextField(verbose_name='Описание', blank=True, null=True)
icon = models.ImageField(verbose_name='Иконка темы', null=True, blank=True)
sort = models.SmallIntegerField(verbose_name='Поле сортировки')
def __str__(self):
@ -72,13 +74,13 @@ class Topic(models.Model):
class CourseManager(models.Manager):
def update_or_create_course(self, image=None, big_image=None, statistic=None, old_slug=None,
big_mobile_image=None, slug=None, teacher_tokens=None,
def update_or_create_course(self, image=None, big_image=None, statistic=None,
big_mobile_image=None, slug=None, teachers=None,
level=None, direction=None, **kwargs):
slug = slug if slug else slugify(unidecode.unidecode(kwargs['title']))
kwargs['teacher_tokens'] = teacher_tokens
kwargs['teacher_tokens'] = teachers
if image:
path = 'course/image%s.png' % slug
@ -99,14 +101,13 @@ class CourseManager(models.Manager):
kwargs['level'] = get_real_name(COURSE_LEVEL, level)
if direction:
kwargs['direction'] = get_real_name(COURSE_DIRECTION, direction[0])
kwargs['direction'] = get_real_name(COURSE_DIRECTION, direction)
try:
course = self.get(slug=old_slug)
course = self.get(slug=slug)
for i in kwargs:
if kwargs[i]:
setattr(course, i, kwargs[i])
course.slug = slug
course.save()
except ObjectDoesNotExist:
@ -153,26 +154,19 @@ class Course(models.Model):
lesson_list += list(topic.lesson_set.all())
return lesson_list
def get_next(self, lesson: Lesson, f=None) -> Lesson:
def get_next(self, lesson: Lesson) -> Lesson:
lessons = self.get_lesson_list()
try:
n = lessons[lessons.index(lesson)+1]
if f is None or f(n):
return n
else:
return self.get_next(n, f)
return lessons[lessons.index(lesson)]
except IndexError:
pass
def get_previous(self, lesson: Lesson, f=None):
def get_previous(self, lesson: Lesson):
lessons = self.get_lesson_list()
idx = lessons.index(lesson) - 1
if idx > -1:
prev = lessons[idx]
if f is None or f(prev):
return prev
else:
return self.get_previous(prev, f)
try:
return lessons[lessons.index(lesson) - 2]
except IndexError:
pass
def get_first_lesson(self) -> Lesson:
lessons = self.get_lesson_list()

@ -1,8 +1,6 @@
from rest_framework import serializers
from django.conf import settings
from courses.models import Course, Lesson, Topic
import os
class TopicSerializer(serializers.ModelSerializer):
@ -21,30 +19,15 @@ class MiniLessonSerializer(serializers.ModelSerializer):
class Meta:
model = Lesson
fields = ('title', 'free', 'token', 'is_hm', 'sort')
fields = ('title', 'free', 'token', 'is_hm')
class LessonSerializer(MiniLessonSerializer):
course_slug = serializers.SerializerMethodField()
materials = serializers.SerializerMethodField()
class Meta:
model = Lesson
exclude = ('id', 'topic', 'key')
@staticmethod
def get_course_slug(self):
return self.topic.course.slug
@staticmethod
def get_materials(self):
try:
prefix = 'materials/%s/%s/%s' % (self.topic.course.token, self.topic.id, self.token)
name_list = os.listdir('%s/%s/' % (settings.MEDIA_ROOT, prefix))
return ["%s%s/%s" % (settings.MEDIA_URL, prefix, i) for i in name_list]
except FileNotFoundError:
return []
class TeacherLessonSerializer(MiniLessonSerializer):
topic_sort = serializers.SerializerMethodField()

@ -1,13 +0,0 @@
from progress.models import ProgressLesson, Progress
from django.contrib.auth import get_user_model
def add_lesson(user_out_key: str, course_token: str, lesson_token: str, teacher_key: str, is_hm: bool):
p = Progress.objects.get(course_token=course_token, user__out_key=user_out_key)
ProgressLesson.objects.get_or_create(
progress=p,
lesson_token=lesson_token,
checker=get_user_model().objects.get(out_key=(teacher_key if is_hm else user_out_key)),
)

@ -3,13 +3,9 @@ from django.conf.urls import url
from courses import views as views
urlpatterns = [
url(r'lesson/update/$', views.UpdateLessonView.as_view()),
url(r'lesson/delete/(?P<lesson_token>.+)/$', views.DeleteLessonView.as_view()),
url(r'vertex/(?P<token>.+)/$', views.LessonDetail.as_view()),
url(r'lesson/teacher/(?P<token>.+)/$', views.LessonInfoView.as_view()),
url(r'lesson/(?P<token>.+)/$', views.LessonDetail.as_view()),
url(r'tree/(?P<slug>.+)/$', views.TreeView.as_view()),
url(r'detail/(?P<slug>.+)/$', views.CourseDetailView.as_view()),
url(r'topic/update/$', views.UpdateTopicView.as_view()),
url(r'topic/delete/(?P<topic_id>[0-9]{1,99})/$', views.DeleteTopicView.as_view()),
url(r'^$', views.CourseListView.as_view()),
]

@ -1,15 +1,11 @@
from jwt import DecodeError
from courses.models import Course, Lesson, Topic
from courses.models import Course, Lesson
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from django.contrib.auth import get_user_model
from courses.serializers import CourseDetailSerializer, CourseTreeSerializer, LessonSerializer, TeacherLessonSerializer
import jwt
from courses.tasks import add_lesson
from lms import settings
from progress.models import ProgressLesson
class TreeView(APIView):
@ -30,6 +26,27 @@ class CourseListView(APIView):
status_code = 200
def post(self, request):
"""
This API endpoint create/update course.
---
parameters:
- name: level
type: string
required: true
location: form
- name: direction
type: string
required: true
location: form
- name: statistic
type: string
required: true
location: form
...
"""
# TODO: Костыль
teachers_emails = request.JSON.get('teachers', [])
request.JSON['teachers'] = [get_user_model().objects.get(email=i).out_key for i in teachers_emails]
course = Course.objects.update_or_create_course(**request.JSON.dict())
return Response(CourseDetailSerializer(course).data, status=self.status_code)
@ -58,141 +75,6 @@ class CourseDetailView(APIView):
return Response(CourseDetailSerializer(Course.objects.get(slug=slug)).data, self.status_code)
class DeleteTopicView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def delete(request, topic_id):
if request.user and request.user.is_staff:
try:
t = Topic.objects.get(id=topic_id)
except Topic.DoesNotExist:
return Response("Темы не существует", status=404)
t.delete()
return Response(CourseTreeSerializer(t.course).data, status=200)
class DeleteLessonView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def delete(request, lesson_token):
if request.user and request.user.is_staff:
try:
l = Lesson.objects.get(token=lesson_token)
except Lesson.DoesNotExist:
return Response("Темы не существует", status=404)
l.delete()
return Response(CourseTreeSerializer(l.topic.course).data, status=200)
class UpdateLessonView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def post(request):
lesson_token = request.JSON.get('token', None)
sort = request.JSON.get('sort', None)
topic_id = request.JSON.get('topic', None)
title = request.JSON.get('title', None)
description = request.JSON.get('description', None)
video = request.JSON.get('video', None)
free = request.JSON.get('free', None)
is_hm = request.JSON.get('is_hm', None)
if topic_id is None:
return Response("topic не передан", status=400)
if sort is None:
return Response("sort не передан", status=400)
try:
topic = Topic.objects.get(id=topic_id)
except Topic.DoesNotExist:
return Response("Тема не найдена", status=404)
if lesson_token is None:
if title is None:
return Response("Название урока не переданно", status=400)
for lesson in reversed(topic.lesson_set.filter(sort__gte=sort)):
lesson.sort = lesson.sort + 1
lesson.save()
l = Lesson.objects.create(
title=title,
topic=topic,
sort=sort,
)
else:
try:
l = Lesson.objects.get(token=lesson_token)
except Lesson.DoesNotExist:
return Response("Урок не найден", status=404)
l.title = l.title if title is None else title
l.video = l.video if video is None else video
l.free = l.free if free is None else free
l.is_hm = l.is_hm if is_hm is None else is_hm
l.description = l.description if description is None else description
if not l.sort == sort:
for lesson in reversed(topic.lesson_set.filter(sort__gte=sort)):
lesson.sort = lesson.sort + 1
lesson.save()
l.sort = sort
l.save()
return Response(CourseTreeSerializer(topic.course).data, status=200)
class UpdateTopicView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def post(request):
topic_id = request.JSON.get('id', None)
sort = request.JSON.get('sort', None)
course_token = request.JSON.get('course_token', None)
title = request.JSON.get('title', None)
if course_token is None:
return Response("Не передан course_token", status=400)
if sort is None:
return Response("Не передан sort", status=400)
try:
course = Course.objects.get(token=course_token)
except Course.DoesNotExist:
return Response("Курс не найден", status=404)
try:
if topic_id:
t = Topic.objects.get(id=topic_id)
if not t.sort == sort:
for topic in reversed(course.topic_set.filter(sort__gte=sort)):
topic.sort = topic.sort + 1
topic.save()
t.sort = sort
t.title = t.title if title is None else title
t.save()
else:
raise Topic.DoesNotExist()
except Topic.DoesNotExist:
if title is None:
return Response("Не передан title", status=400)
for topic in reversed(course.topic_set.filter(sort__gte=sort)):
topic.sort = topic.sort + 1
topic.save()
Topic.objects.create(
course=course,
title=title,
sort=sort,
)
return Response(CourseTreeSerializer(course).data, status=200)
class LessonInfoView(APIView):
renderer_classes = (JSONRenderer,)
status_code = 200
@ -202,7 +84,7 @@ class LessonInfoView(APIView):
lesson = Lesson.objects.get(token=token)
except Lesson.DoesNotExist:
return Response('Урок не найден', status=404)
if request.user.is_authenticated:
if request.user.is_authenticated and request.user.out_key in lesson.topic.course.teacher_tokens:
return Response(TeacherLessonSerializer(lesson).data, self.status_code)
return Response("Пользователь не является преподователем по курсу", status=403)
@ -211,53 +93,33 @@ class LessonDetail(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def post(request, token):
jwt_token = request.JSON.get('jwt_token', None)
def get(request, token):
try:
lesson = Lesson.objects.get(token=token)
except Lesson.DoesNotExist:
return Response("Урока не существует", status=404)
l = LessonSerializer(lesson).data
try:
payload = None if jwt_token is None \
else jwt.decode(jwt_token, settings.COURSE_PROGRESS_SECRET_KEY, algorithms=['HS256'])
except DecodeError:
payload = None
course = lesson.topic.course
if payload is None:
if not (lesson.free or request.user.is_authenticated and request.user.is_staff):
return Response("Bad token", status=400)
else:
return Response(l, status=200)
prev_lesson = course.get_previous(lesson, (lambda x: not x.is_hm) if payload['only_watch'] else None)
next_lesson = course.get_next(lesson, (lambda x: not x.is_hm) if payload['only_watch'] else None)
if not prev_lesson is None:
l['prev_token'] = prev_lesson.token
if not next_lesson is None:
l['next_token'] = next_lesson.token
new_lesson = False
for payload_lesson in payload['lessons']:
if payload_lesson['lesson_token'] == str(lesson.token):
return Response(l, status=200)
if not prev_lesson is None and str(prev_lesson.token) == payload_lesson['lesson_token']:
new_lesson = True if prev_lesson is None else \
(payload_lesson['status'] == "done" or payload_lesson['status'] == "wait")
if not new_lesson:
return Response("Permission denied", status=403)
# TODO Задача для селери
add_lesson(request.user.out_key, course.token, lesson.token, course.get_teacher(), lesson.is_hm)
return Response(l, status=200)
return Response("Lesson doesn't exist", status=404)
if not lesson.free and not ProgressLesson.objects.filter(lesson_token=lesson.token).exists():
previous_lesson = lesson.topic.course.get_previous(lesson)
if not previous_lesson is None or not ProgressLesson.objects.filter(
lesson_token=previous_lesson.token, status=ProgressLesson.STATUSES.done).exists():
return Response("Lesson doesn't access", status=403)
# TODO: Доделать систему прав на курс
res = LessonSerializer(lesson).data
# progress = vertex.course.progress_set.filter(user=request.user)
# try:
# if progress.exists():
# next_vertex = vertex.get_next(progress[0].get_template())
# if next_vertex:
# res['next'] = MiniVertexSerializer(next_vertex).data
# res['is_in_progress'] = vertex in progress[0].get_objects_in_progress()
# else:
# res['next'] = MiniVertexSerializer(vertex.get_next(vertex.course.route)).data
# except Thread.DoesNotExist or Vertex.DoesNotExist:
# res['next'] = MiniVertexSerializer(vertex.get_next(vertex.course.route)).data
return Response(res, status=200)

@ -1,13 +1,7 @@
# coding=utf-8
from django.contrib import admin
from finance.models import Bill, Invoice, InvoiceRebilling
class InvoiceAdmin(admin.ModelAdmin):
list_display = ('__str__', 'rebilling_on',)
from finance.models import Bill, Invoice
admin.site.register(Bill)
admin.site.register(Invoice)
admin.site.register(InvoiceRebilling, InvoiceAdmin)
admin.site.register(Invoice)

@ -1,56 +0,0 @@
# -*- coding: utf-8 -*-
import logging
_logger = logging.getLogger('finance_data')
class FinanceLogger:
"""
Все kwargs попадют в %(finance_data)s и логируются
'format': '%(asctime)s - %(levelname)s - %(message)s - %(finance_data)s'
"""
def __init__(self, prefix=None):
self.prefix = prefix
def log(self, level, msg, *args, **kwargs):
_logger.log(level=level, msg=self._get_msg(msg), *args, **self._make_kwargs(kwargs))
def _get_msg(self, msg):
if self.prefix:
msg = '{}: {}'.format(self.prefix, msg)
return msg
def _make_kwargs(self, kwargs):
new_kwargs = {}
for inspected_kwarg in ('exc_info', 'stack_info', 'extra'):
try:
new_kwargs[inspected_kwarg] = kwargs.pop(inspected_kwarg)
except KeyError:
pass
if 'extra' in new_kwargs:
new_kwargs['extra']['finance_data'] = kwargs
else:
new_kwargs['extra'] = dict(finance_data=kwargs)
return new_kwargs
def debug(self, msg, *args, **kwargs):
self.log(level=logging.DEBUG, msg=msg, *args, **kwargs)
def info(self, msg, *args, **kwargs):
self.log(level=logging.INFO, msg=msg, *args, **kwargs)
def warning(self, msg, *args, **kwargs):
self.log(level=logging.WARNING, msg=msg, *args, **kwargs)
# TODO отделить логирование ошибок в другой лог
def error(self, msg, *args, **kwargs):
self.log(level=logging.ERROR, msg=msg, *args, **kwargs)
def critical(self, msg, *args, **kwargs):
self.log(level=logging.CRITICAL, msg=msg, *args, **kwargs)
def exception(self, msg, *args, **kwargs):
kwargs['stack_info'] = True
_logger.exception(self._get_msg(msg), *args, **self._make_kwargs(kwargs))

@ -1,14 +0,0 @@
from django.core.management.base import BaseCommand
from finance.loggers import FinanceLogger
from finance.tasks import periodic_billing
finance_logger = FinanceLogger() # prefix='YandexMoney'
class Command(BaseCommand):
def handle(self, *args, **options):
finance_logger.info("start console repeat payment command")
print('Started')
periodic_billing()

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-03-15 13:58
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('finance', '0002_auto_20180202_1301'),
]
operations = [
migrations.AlterField(
model_name='invoice',
name='real_price',
field=models.FloatField(blank=True, editable=False, help_text='Сумма, минус комиссия', null=True, verbose_name='Полученная сумма'),
),
]

@ -1,22 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-03-23 17:43
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('finance', '0003_auto_20180315_1358'),
]
operations = [
migrations.AddField(
model_name='bill',
name='date',
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='Дата выставления'),
preserve_default=False,
),
]

@ -1,35 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-03-29 13:46
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('finance', '0004_bill_date'),
]
operations = [
migrations.CreateModel(
name='InstallmentPlan',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
('invoice_amount', models.IntegerField(verbose_name='Количество платежей')),
('price', models.IntegerField(verbose_name='Цена одного платежа')),
('bill', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='finance.Bill', verbose_name='Связный счёт')),
],
options={
'verbose_name': 'Рассрочка',
'verbose_name_plural': 'Рассрочки',
},
),
migrations.AlterField(
model_name='invoice',
name='date',
field=models.DateTimeField(auto_now_add=True, verbose_name='Дата создания'),
),
]

@ -1,37 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-03-30 11:21
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('finance', '0005_auto_20180329_1346'),
]
operations = [
migrations.RemoveField(
model_name='installmentplan',
name='bill',
),
migrations.AddField(
model_name='invoice',
name='rebilling',
field=models.BooleanField(default=False, editable=False, verbose_name='Повторный платеж'),
),
migrations.AddField(
model_name='invoice',
name='rebilling_on',
field=models.BooleanField(default=False, editable=False, verbose_name='Повторять платеж'),
),
migrations.AlterField(
model_name='invoice',
name='date',
field=models.DateTimeField(auto_now_add=True),
),
migrations.DeleteModel(
name='InstallmentPlan',
),
]

@ -1,23 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-03-30 14:52
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('finance', '0006_auto_20180330_1121'),
]
operations = [
migrations.RemoveField(
model_name='invoice',
name='rebilling',
),
migrations.RemoveField(
model_name='invoice',
name='rebilling_on',
),
]

@ -1,28 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-03-30 14:52
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('finance', '0007_auto_20180330_1452'),
]
operations = [
migrations.CreateModel(
name='InvoiceRebilling',
fields=[
('invoice_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='finance.Invoice')),
('rebilling_on', models.BooleanField(default=False, editable=False, verbose_name='Повторять платеж')),
],
options={
'verbose_name': 'Повторный платёж',
'verbose_name_plural': 'Повторные платежи',
},
bases=('finance.invoice',),
),
]

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-03-30 15:03
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('finance', '0008_invoicerebilling'),
]
operations = [
migrations.AddField(
model_name='invoicerebilling',
name='pay_count',
field=models.SmallIntegerField(default=2, editable=False, verbose_name='Всего платежей'),
preserve_default=False,
),
]

@ -1,40 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-04-12 16:28
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('finance', '0009_invoicerebilling_pay_count'),
]
operations = [
migrations.RemoveField(
model_name='invoicerebilling',
name='pay_count',
),
migrations.AddField(
model_name='bill',
name='freeze',
field=models.BooleanField(default=False, verbose_name='Отказ от платежей'),
),
migrations.AddField(
model_name='invoice',
name='date_of_payment',
field=models.DateTimeField(blank=True, null=True, verbose_name='Дата фактической оплаты'),
),
migrations.AddField(
model_name='invoice',
name='expected_date',
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='Ожидаемая дата платежа'),
),
migrations.AlterField(
model_name='invoice',
name='date',
field=models.DateTimeField(auto_now_add=True, verbose_name='Дата создания платежа'),
),
]

@ -1,17 +1,9 @@
# coding=utf-8
from dateutil.relativedelta import relativedelta
from django.conf import settings
from django.core.mail import EmailMessage
from django.db import models
from django.utils import timezone
from yandex_money.models import Payment
import logging
from progress.models import Progress
logger_business_rules = logging.getLogger('business_rules')
from courses.models import Course, Lesson
class Bill(models.Model):
@ -21,85 +13,13 @@ class Bill(models.Model):
comment = models.TextField(verbose_name='Комментарий продавца', help_text='Будет показано пользователю',
blank=True, editable=False)
description = models.TextField(verbose_name='Внутренняя заметка', blank=True)
date = models.DateTimeField(verbose_name="Дата выставления", auto_now_add=True)
freeze = models.BooleanField(verbose_name='Отказ от платежей', default=False)
def __str__(self):
return '%s: %s' % (self.id, self.user)
def freeze_course(self):
if self.invoice_set.exclude(status='F').exists():
log = False
try:
p = Progress.objects.get(user=self.user, course_token=str(self.course_token))
p.is_freeze = True
p.save()
except Progress.DoesNotExist:
log = True
if log:
logger_business_rules.info('Отказ от платежей прошёл успешно', exc_info=True, extra={
'description': 'The privileges were not taken away, as they were not granted',
'user': self.user,
})
msg = EmailMessage(
'Вы откозались от оплаты по счёту',
"""Вы откозались от оплаты по счёту.
Вы сможете продолжить оплату в личном кабинете""",
to=[self.user.email],
bcc=[self.opener.email],
reply_to=[self.opener.email],
)
msg.send()
self.freeze = True
self.save()
else:
logger_business_rules.warning('Попытка нарушения правила отказа от платежей', exc_info=True, extra={
'description': 'All payments already paid',
'user': self.user,
})
def unfreeze_course(self, force=False):
if force or self.invoice_set.exclude(status='F')\
.filter(expected_date__lt=timezone.now() + relativedelta(days=1)).exists():
if self.invoice_set.filter(status='F').exclude(expected_date__lt=timezone.now()).exists():
try:
p = Progress.objects.get(user=self.user, course_token=str(self.course_token))
p.is_freeze = False
p.save()
except Progress.DoesNotExist:
pass
msg = EmailMessage(
'Вы возобновили оплату по счёту',
"""Вы возобновили оплату по счёту.""",
to=[self.user.email],
bcc=[self.opener.email],
reply_to=[self.opener.email],
)
msg.send()
self.freeze = False
self.save()
else:
logger_business_rules.warning('Попытка нарушения правила возобновления платежей', exc_info=True, extra={
'description': 'Excepted date more than one day',
'user': self.user,
})
def get_full_price(self):
return sum([i.price for i in self.invoice_set.all() if not i.price is None])
def check_validate(self, invoice_id):
return self.invoice_set.filter(is_open=True).exclude(id=invoice_id).count() == 1
def check_pay(self):
return self.invoice_set.filter(status="F").exists()
class Meta:
verbose_name = 'Счет'
verbose_name_plural = 'Счета'
@ -123,8 +43,8 @@ class Invoice(models.Model):
('C', 'Отклонен'),
)
status = models.CharField(verbose_name='Статус', max_length=1, default='W', choices=BILL_STATUSES)
price = models.IntegerField(verbose_name='Сумма', editable=False, null=True, blank=True) #Todo На самом деле тут не далжно быть значений null
real_price = models.FloatField(verbose_name='Полученная сумма', null=True, blank=True,
price = models.IntegerField(verbose_name='Сумма', editable=False, null=True, blank=True)
real_price = models.IntegerField(verbose_name='Полученная сумма', null=True, blank=True,
help_text='Сумма, минус комиссия', editable=False)
method = models.CharField(verbose_name='Способ оплаты', max_length=2, default='Y', choices=BILL_METHOD)
key = models.CharField(verbose_name='Ключ платежа', max_length=255, editable=False, blank=True)
@ -133,24 +53,7 @@ class Invoice(models.Model):
blank=True, editable=False)
bill = models.ForeignKey(to=Bill, verbose_name="Связный счёт")
is_open = models.BooleanField(default=True, verbose_name="Открывает ли платёж курс")
date = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания платежа")
expected_date = models.DateTimeField(default=timezone.now, verbose_name="Ожидаемая дата платежа")
date_of_payment = models.DateTimeField(verbose_name="Дата фактической оплаты", blank=True, null=True)
def get_comment(self):
return '''Вам выставлен счёт,''' if \
self.comment == "" else self.comment
def send_link(self):
msg = EmailMessage(
'Вам выставлен новый счёт',
"""%s для оплаты перейдите по ссылке
%s/api/v1/finance/payment/%s/""" % (self.get_comment(), settings.DOMAIN, self.yandex_pay.id),
to=[self.yandex_pay.cps_email],
bcc=[self.bill.opener.email],
reply_to=[self.bill.opener.email],
)
msg.send()
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s:%s %s' % (self.id, self.get_status_display(), self.bill.user)
@ -158,26 +61,3 @@ class Invoice(models.Model):
class Meta:
verbose_name = 'Платёж'
verbose_name_plural = 'Платежи'
class InvoiceRebilling(Invoice):
rebilling_on = models.BooleanField(verbose_name='Повторять платеж', default=False, editable=False)
def create_child_pays(self, count):
# TODO Заменить expected_date
for idx in range(1, int(count)):
InvoiceRebilling.objects.create(
bill=self.bill,
comment=self.comment,
method=self.method,
status='W',
is_open=self.is_open,
price=self.price,
rebilling_on=False,
key=self.key,
expected_date=(timezone.now() + relativedelta(months=idx)),
)
class Meta:
verbose_name = 'Повторный платёж'
verbose_name_plural = 'Повторные платежи'

@ -28,18 +28,18 @@ class BillSerializer(serializers.ModelSerializer):
class InvoiceSerializer(serializers.ModelSerializer):
status = serializers.SerializerMethodField()
method = serializers.SerializerMethodField()
yandex_pay = serializers.SerializerMethodField()
yandex_pay_id = serializers.SerializerMethodField()
class Meta:
model = Invoice
fields = '__all__'
exclude = ('bill',)
@staticmethod
def get_status(self):
return self.get_status_display()
@staticmethod
def get_yandex_pay(self):
def get_yandex_pay_id(self):
return None if self.yandex_pay is None else self.yandex_pay.id
@staticmethod

@ -16,6 +16,18 @@ def invoice_signal(instance, **kwargs):
course = Course.objects.get(token=instance.bill.course_token)
if instance.yandex_pay and instance.method == 'Y' and instance.status == 'P':
msg = EmailMessage(
'Вам выставлен новый счёт',
'''Вам выставлен счёт, для оплаты перейдите по ссылке
%s/api/v1/finance/payment/%s/''' % (settings.DOMAIN, instance.yandex_pay.id,),
'robo@skillbox.ru',
[instance.yandex_pay.cps_email],
[instance.bill.opener.email],
reply_to=[instance.bill.opener.email],
)
msg.send()
if instance.status == 'F':
if instance.is_open:
try:
@ -24,7 +36,7 @@ def invoice_signal(instance, **kwargs):
user=instance.bill.user,
)
except Progress.DoesNotExist:
p = Progress.objects.create(
p=Progress.objects.create(
course_token=instance.bill.course_token,
user=instance.bill.user,
teacher=get_user_model().objects.get(out_key=course.get_teacher())
@ -40,8 +52,9 @@ def invoice_signal(instance, **kwargs):
'''Вам открыт доступ к курсу "%s", вы можете перейти по ссылке и
ознакомиться с материалами %s/course/%s'''
% (course.title, settings.DOMAIN, course.slug),
to=[instance.bill.user.email],
bcc=[instance.bill.opener.email],
'robo@skillbox.ru',
[instance.bill.user.email],
cc=[instance.bill.opener.email],
reply_to=[instance.bill.opener.email],
)
else:
@ -50,7 +63,7 @@ def invoice_signal(instance, **kwargs):
'''Курс "%s" был забронирован''' % course.title,
'robo@skillbox.ru',
[instance.bill.user.email],
bcc=[instance.bill.opener.email],
cc=[instance.bill.opener.email],
reply_to=[instance.bill.opener.email],
)
msg.send()

@ -1,81 +0,0 @@
import logging
import os
import requests
from django.conf import settings
from django.db import transaction
from django.utils import timezone
from yandex_money.models import Payment
from finance.loggers import FinanceLogger
from finance.models import InvoiceRebilling, Invoice
from lms import celery_app
finance_logger = FinanceLogger()
@celery_app.task
def periodic_billing():
finance_logger.info("start periodic billing task")
# TODO заюзать Invoice.BILL_STATUSES
invoices = InvoiceRebilling.objects.filter(method='Y', status='W')
# TODO тут был exclude('F') то есть все неоплаченные... но это не верно!
for invoice in invoices.filter(expected_date__lt=timezone.now()):
# выбираем все необработанные из прошлого
with transaction.atomic():
try:
_yandex_repeat_card_payment(invoice)
except Exception as exc:
finance_logger.exception('Yandex Money repeatCardPayment Exception', invoice_id=invoice.id)
invoice.comment += 'Yandex Money: Ошибка при попытке повторного платежа, свяжитесь с клиентской службой'
invoice.save()
def _yandex_repeat_card_payment(invoice):
user = invoice.bill.user
yandex_pay = Payment.objects.create(
order_amount=invoice.price,
customer_number=user.id,
user=user,
cps_email=user.email,
shop_id=settings.YANDEX_MONEY_REBILLING_SHOP_ID,
scid=settings.YANDEX_MONEY_REBILLING_SCID
)
invoice.yandex_pay = yandex_pay
finance_logger.info('YandexMoney repeatCardPayment start', invoice_id=invoice.id)
resp = requests.post(
url=settings.YANDEX_MONEY_MWS_URL + 'repeatCardPayment',
data={
'clientOrderId': invoice.id, # уникальное возрастающее целое число
'invoiceId': invoice.key,
'amount': invoice.price,
'orderNumber': invoice.yandex_pay.order_number
},
cert=(
os.path.join(settings.SSL_ROOT, 'skillbox.cer'),
os.path.join(settings.SSL_ROOT, 'skillbox.key')
),
verify=os.path.join(settings.SSL_ROOT, 'yamoney_chain.cer')
)
resp_text = resp.text
finance_logger.info('YandexMoney repeatCardPayment response',
invoice_id=invoice.id, response=resp_text, code=resp.status_code, )
try:
_check_yandex_response_status(invoice, resp_text)
except Exception as exc:
finance_logger.exception("Can't parse yandex response", invoice_id=invoice.id, response=resp_text)
def _check_yandex_response_status(invoice, resp_text):
from xml.dom import minidom
dom = minidom.parseString(resp_text)
dom.normalize()
resp_node = dom.getElementsByTagName("repeatCardPaymentResponse")[0]
status = resp_node.getAttribute('status')
if status != '0':
error = resp_node.getAttribute('error')
processed_dt = resp_node.getAttribute('processedDT')
tech_message = resp_node.getAttribute('techMessage')
invoice.status = Invoice.BILL_STATUSES[-1][0]
invoice.comment += 'Yandex Money: ошибка № {}, сообщение {} от {}'.format(error, tech_message, processed_dt)

@ -2,14 +2,10 @@ from django.conf.urls import url
from finance import views
urlpatterns = [
url(r'payment/([0-9]{1,99})/$', views.YandexPay.as_view()),
url(r'bill/([0-9]{1,99})/freeze/$', views.FreezeView.as_view()),
url(r'bill/([0-9]{1,99})/unfreeze/$', views.UnFreezeView.as_view()),
url(r'bills/$', views.BillListView.as_view()),
url(r'bills/([0-9]{1,99})/$', views.BillDetailView.as_view()),
url(r'payment/([0-9]{1,99})/$', views.YandexPay.as_view()),
url(r'bills_find/$', views.FindBillView.as_view()),
url(r'bills/$', views.BillListView.as_view()),
url(r'yandex/fail/$', views.YandexFailView.as_view()),
url(r'invoice/([0-9]{1,99})/$', views.InvoiceDetailView.as_view()),
url(r'invoices/$', views.get_invoices),
url(r'test/pay/$', views.test_pay),
]

@ -1,73 +1,26 @@
import csv
import uuid
import logging
import datetime
import dicttoxml
import requests
from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.mail import EmailMessage
from django.core.mail import EmailMultiAlternatives
from django.db import IntegrityError
from django.db.models import Q
from django.http import HttpResponse, HttpResponseForbidden
from django.shortcuts import redirect, render_to_response
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.html import strip_tags
from django.shortcuts import redirect
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from yandex_money.models import Payment
from django.conf import settings
from courses.api import CourseParamsApi
from courses.models import Course
from finance.loggers import FinanceLogger
from finance.models import Bill, Invoice, InvoiceRebilling
from finance.models import Bill, Invoice
from finance.serializers import BillSerializer, InvoiceSerializer
from lms.global_decorators import transaction_decorator
from lms.tools import get_real_name
finance_logger = FinanceLogger() # prefix='YandexMoney'
def test_pay(request):
return render_to_response('yandex/test_pay.html', context={
'shop_id': settings.YANDEX_MONEY_SHOP_ID,
'sc_id': settings.YANDEX_MONEY_TEST_SCID,
'order_number': str(uuid.uuid4())[:12],
'user_email': request.user.email if request.user.is_authenticated else 'user@domain.com'
})
class FreezeView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def post(request, pk):
try:
bill = Bill.objects.get(id=pk)
except Bill.DoesNotExist:
return Response("Счёт не найден", status=404)
if request.user.is_authenticated and request.user.email == bill.user.email:
bill.freeze_course()
return Response(status=204)
return Response("Permission denied", status=403)
class UnFreezeView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def post(request, pk):
try:
bill = Bill.objects.get(id=pk)
except Bill.DoesNotExist:
return Response("Счёт не найден", status=404)
if request.user.is_authenticated and request.user.email == bill.user.email:
bill.unfreeze_course()
return Response(status=204)
return Response("Permission denied", status=403)
logger_yandex = logging.getLogger('yandex_money')
class BillListView(APIView):
@ -86,164 +39,52 @@ class BillListView(APIView):
def post(self, request):
if request.user.is_authenticated and (request.user.groups.filter(name__in=['managers','lead_managers']).exists()
or request.user.is_superuser):
user = get_user_model().objects.get(email=request.JSON.get('user'))
opener = get_user_model().objects.get(email=request.JSON.get('opener'))
description = request.JSON.get('description', None)
comment = request.JSON.get('comment', None)
course_token = request.JSON.get('course_token', None)
if course_token is None:
return Response("Идентификатор курса не передан", status=400)
try:
bill_obj = Bill.objects.get(user=user, course_token=course_token)
except Bill.DoesNotExist:
try:
bill_obj = Bill.objects.create(user=user, course_token=course_token)
except IntegrityError:
return Response("У пользователя уже есть счёт на этот курс", status=400)
bill_obj.opener = bill_obj.opener if opener is None else opener
bill_obj.description = bill_obj.description if description is None else description
bill_obj.comment = bill_obj.comment if comment is None else comment
bill_obj.save()
return Response(bill_obj.id, status=200)
return Response("Ошибка доступа, возможно вы разлогинились из другой вкладки браузера", status=403)
class InvoiceDetailView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def delete(request, invoice_id):
try:
i = Invoice.objects.get(id=invoice_id)
if not i.status == "F" and not (i.bill.check_pay() and i.is_open):
i.delete()
except Invoice.DoesNotExist:
pass
return Response(status=204)
@staticmethod
def post(request, invoice_id):
if request.user.is_authenticated and (request.user.groups.filter(name__in=['managers','lead_managers']).exists()
or request.user.is_superuser):
invoice_id = int(invoice_id)
bill_id = request.JSON.get('bill', None)
is_open = request.JSON.get('is_open', None)
method = request.JSON.get('method', None)
status = request.JSON.get('status', None)
price = request.JSON.get('price', None)
comment = request.JSON.get('comment', None)
real_price = request.JSON.get('real_price', None)
pay_count = int(request.JSON.get('pay_count', '1'))
if bill_id is None:
return Response("Не передан id счёта", status=400)
if is_open is None or method is None or status is None or price is None:
return Response("Не передан один из пораметров is_open, method, status, price", status=400)
try:
bill = Bill.objects.get(id=bill_id)
except Bill.DoesNotExist:
return Response('Не найден счёт с id=%s' % bill_id, status=404)
method = get_real_name(elem=method[0], array=Invoice.BILL_METHOD)
status = get_real_name(elem=status[0], array=Invoice.BILL_STATUSES)
if bill.check_validate(invoice_id) and is_open:
return Response("Уже есть платёж открывающий курс", status=400)
if pay_count > 1:
invoice = InvoiceRebilling.objects.create(
bill=bill,
method=method,
status=status,
is_open=is_open,
rebilling_on=True,
)
else:
try:
invoice = Invoice.objects.get(id=invoice_id)
except Invoice.DoesNotExist:
if not invoice_id == 0:
return Response("Платёж не найден", status=404)
if bill.check_pay():
return Response(
"Нельзя добавить новый платёж, так как один из платежей по счёту уже оплачен", status=400)
invoice = Invoice.objects.create(
bill=bill,
method=method,
status=status,
is_open=is_open,
)
if invoice.status == "F":
return Response(InvoiceSerializer(invoice).data, status=200)
invoice.real_price = None
invoice.method = method
invoice.status = status
if invoice.status == "F":
# TODO это никогда не выполнится
invoice.real_price = invoice.real_price if real_price is None else real_price
if bill.check_pay() and (invoice.price < price):
return Response("""Нельзя менять стоимость по счёту в большую сторону,
когда один из платежей оплачен""", status=400)
invoice.price = price
invoice.is_open = is_open
invoice.comment = comment
if pay_count > 1:
invoice.create_child_pays(pay_count)
if invoice.method == 'Y' and invoice.yandex_pay is None:
yandex_pay = Payment(
order_amount=invoice.price,
shop_amount=0,
customer_number=bill.user.id,
user=bill.user,
cps_email=bill.user.email,
)
if pay_count > 1:
yandex_pay.shop_id = settings.YANDEX_MONEY_REBILLING_SHOP_ID
yandex_pay.scid = settings.YANDEX_MONEY_REBILLING_SCID
yandex_pay.save()
invoice.yandex_pay = yandex_pay
invoice.send_link()
context = {
'user_email': invoice.bill.user.email,
'opener_full_name': invoice.bill.opener.get_full_name(),
'course_title': Course.objects.get(token=invoice.bill.course_token).title,
'date': str(invoice.date),
'price': invoice.price,
bill = request.JSON.get('bill')
children = request.JSON.get('children', [])
bill_kwarg = dict()
if bill:
bill_kwarg['user'] = get_user_model().objects.get(email=bill['user'])
bill_kwarg['opener'] = get_user_model().objects.get(email=bill['opener'])
bill_kwarg['description'] = bill['description']
bill_kwarg['comment'] = bill['comment']
bill_kwarg['course_token'] = bill['course_token']
bill_obj, is_create = Bill.objects.update_or_create(**bill_kwarg)
invoices = bill_obj.invoice_set.all()
for i in children:
i['method'] = get_real_name(elem=i['method'], array=Invoice.BILL_METHOD)
i['status'] = get_real_name(elem=i['status'], array=Invoice.BILL_STATUSES)
i['bill'] = bill_obj
i['yandex_pay'] = None
invoice, _is_create = Invoice.objects.update_or_create(**i)
if i['method'] == 'Y':
yandex_pay, _is_create = Payment.objects.get_or_create(
order_amount=i['price'],
order_number=invoice.id,
shop_amount=0,
customer_number=bill_obj.user.id,
user=bill_obj.user,
cps_email=bill_obj.user.email,
)
invoice.yandex_pay = yandex_pay
invoice.save()
invoices = [j for j in invoices if not j.id == invoice.id]
[i.delete() for i in invoices]
res = {
"bill": BillSerializer(bill_obj).data,
"children": [InvoiceSerializer(i).data for i in bill_obj.invoice_set.all()],
}
subject, to = 'Выставлен новый счёт', invoice.bill.opener.email
html_content = render_to_string('mail/sales/back_set_bill.html', context)
text_content = strip_tags(html_content)
return Response(res, status=200)
msg = EmailMultiAlternatives(subject, text_content, to=[to], bcc=['dmitry.dolya@skillbox.ru'])
msg.attach_alternative(html_content, "text/html")
msg.send()
return Response("Bill not set", status=400)
invoice.save()
return Response(InvoiceSerializer(invoice).data, status=200)
return Response("Invoice detail access only for manager users", status=403)
return Response("Course detail access only for manager users", status=403)
class BillDetailView(APIView):
@ -284,9 +125,7 @@ class FindBillView(APIView):
if key:
res = Bill.objects.filter(
Q(opener__email__contains=key.lower())
| Q(user__email__contains=key.lower())
| Q(id__contains=key)
Q(opener__email__contains=key.lower()) | Q(user__email__contains=key.lower())
)
else:
@ -309,10 +148,6 @@ class YandexPay(APIView):
def get(request, pk):
try:
pay = Payment.objects.get(id=pk)
try:
inv = InvoiceRebilling.objects.get(yandex_pay=pay)
except InvoiceRebilling.DoesNotExist:
inv = None
r = requests.post('https://money.yandex.ru/eshop.xml', data={
'shopId': pay.shop_id,
'scid': pay.scid,
@ -320,24 +155,11 @@ class YandexPay(APIView):
'customerNumber': pay.customer_number,
'orderNumber': pay.order_number,
'cps_email': pay.cps_email,
'rebillingOn': False if inv is None else inv.rebilling_on,
'shopSuccessURL': settings.YANDEX_MONEY_SUCCESS_URL,
'shopFailURL': settings.YANDEX_MONEY_FAIL_URL,
})
try:
msg = EmailMessage(
'Пользователь перешёл на страницу оплаты.',
'''Пользователь "%s" перешёл на страницу оплаты курса "%s".'''
% (pay.invoice.bill.user.email, Course.objects.get(token=pay.invoice.bill.course_token).title),
'robo@skillbox.ru',
[pay.invoice.bill.opener.email],
bcc=['dmitry.dolya@skillbox.ru'],
)
msg.send()
except Exception as exc:
finance_logger.exception('YandexPay: Email not sended')
logger_yandex.info(r)
return redirect(r.url)
@ -357,8 +179,8 @@ def get_invoices(request):
file_name = file_name + "__to_%s" % date_to if date_to else file_name
invoices = Invoice.objects.filter(method="Y", status="F")
invoices = invoices.filter(yandex_pay__performed_datetime__lt=date_to) if date_to else invoices
invoices = invoices.filter(yandex_pay__performed_datetime__gte=date_from) if date_from else invoices
invoices = invoices.filter(date__lt=date_to) if date_to else invoices
invoices = invoices.filter(date__gte=date_from) if date_from else invoices
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="%s.csv"' % file_name
@ -369,8 +191,8 @@ def get_invoices(request):
for i in invoices.order_by('-date'):
course_api = CourseParamsApi(i.bill.course_token)
writer.writerow([
i.yandex_pay.performed_datetime.date(),
i.yandex_pay.performed_datetime.time(),
i.date.date(),
i.date.time(),
i.bill.user.email,
i.bill.user.get_full_name(),
course_api.get_slug_and_title()['title'],
@ -388,53 +210,48 @@ class YandexCheckView(APIView):
@staticmethod
def post(request):
data = dict()
# TODO заюзать url.parse https://goo.gl/s8Ygos
for i in request.body.decode('utf-8').split('&'):
key = i.split('=')[0]
val = i.split('=')[1]
data[key] = val
finance_logger.info('Проверка платежа запрос', request=data)
order_number = data['orderNumber']
logger_yandex.info(data)
try:
pay = Payment.objects.get(order_number=order_number)
pay = Payment.objects.get(order_number=data['orderNumber'])
except Payment.DoesNotExist:
finance_logger.error('Ошибка проверки платежа', exc_info=True,
request="Payment with id=%s not found" % order_number)
logger_yandex.error("Payment with id=%s not found" % data['orderNumber'])
return Response(status=204)
if not pay.status == Payment.STATUS.PROCESSED:
finance_logger.error('Ошибка проверки платежа',
order_number=order_number,
request="Payment with id=%s have status %s" % (order_number, pay.status))
logger_yandex.error("Payment with id=%s have status %s" % (data['orderNumber'], pay.status))
return Response(status=204)
if not pay.shop_id == int(data['shopId']):
finance_logger.error('Ошибка проверки платежа',
request="ShopId=%s not match" % (data['shopId'],))
logger_yandex.error("ShopId=%s not match" % (data['shopId'],))
return Response(status=204)
if not pay.scid == int(data['scid']):
finance_logger.error('Ошибка проверки платежа',
request="scid=%s not match" % (data['scid'],))
logger_yandex.error("scid=%s not match" % (data['scid'],))
return Response(status=204)
if not pay.order_amount == float(data['orderSumAmount']):
finance_logger.error('Ошибка проверки платежа',
request="Expected amount is %s received amount is %s" % (pay.order_amount, data['orderSumAmount']))
logger_yandex.error("Expected amount is %s received amount is %s"
% (pay.order_amount, data['orderSumAmount']))
return Response(status=204)
now = timezone.now()
pay.performed_datetime = now.isoformat()
pay.save()
xml_res = """<checkOrderResponse performedDatetime="%s" code="0" invoiceId="%s" shopId="%s"/>
""" % (pay.performed_datetime, str(data['invoiceId']), str(pay.shop_id))
# TODO Нужно решение
# pay.invoice_id = int(data['invoiceId'])
# pay.save()
xml_res = dicttoxml.dicttoxml({
'code': 0,
'shopId': int(pay.shop_id),
'invoiceId': int(data['invoiceId']),
'orderSumAmount': pay.order_amount,
'performedDatetime': datetime.datetime.now(),
})
logger_yandex.info(xml_res)
finance_logger.info('Проверка платежа ответ', response=xml_res)
return HttpResponse(xml_res, content_type='application/xml')
return Response(xml_res, content_type='application/xml')
class YandexAvisoView(APIView):
@ -448,45 +265,26 @@ class YandexAvisoView(APIView):
val = i.split('=')[1]
data[key] = val
finance_logger.info('Подтверждение платежа запрос', request=data)
order_number = data['orderNumber']
try:
pay = Payment.objects.get(order_number=order_number)
pay = Payment.objects.get(order_number=data['orderNumber'])
except Payment.DoesNotExist:
finance_logger.error('Ошибка подтверждения платежа', exc_info=True,
request="Payment with invoice_id=%s not found" % order_number)
logger_yandex.error("Payment with invoice_id=%s not found" % data['orderNumber'])
return Response(status=204)
logger_yandex.info('Get success pay with invoice_id(yandex) %s' % pay.invoice_id)
pay.shop_amount = data['shopSumAmount']
pay.status = Payment.STATUS.SUCCESS
now = timezone.now()
pay.performed_datetime = now.isoformat()
pay.save()
InvoiceRebilling.objects.filter(bill=pay.invoice.bill).update(key=data['invoiceId'])
xml_res = """<paymentAvisoResponse performedDatetime="%s" code="0" invoiceId="%s" shopId="%s"/>
""" % (pay.performed_datetime, str(data['invoiceId']), str(pay.shop_id))
finance_logger.info('Подтверждение платежа ответ', response=xml_res)
context = {
'user_email': pay.invoice.bill.user.email,
'opener_full_name': pay.invoice.bill.opener.get_full_name(),
'course_title': Course.objects.get(token=pay.invoice.bill.course_token).title,
'date': str(pay.invoice.date),
'price': pay.invoice.price,
'finish_date': pay.performed_datetime,
}
subject, to = 'Счёт оплачен', pay.invoice.bill.opener.email
html_content = render_to_string('mail/sales/pay_access.html', context)
text_content = strip_tags(html_content)
msg = EmailMultiAlternatives(
subject, text_content, to=[to], bcc=['dmitry.dolya@skillbox.ru', 'vera.procenko@skillbox.ru'])
msg.attach_alternative(html_content, "text/html")
msg.send()
xml_res = dicttoxml.dicttoxml({
'code': 0,
'shopId':int(pay.shop_id),
'invoiceId': int(data['invoiceId']),
'orderSumAmount': pay.order_amount,
'performedDatetime': datetime.datetime.now(),
})
logger_yandex.info(xml_res)
return HttpResponse(xml_res, content_type='application/xml')
@ -494,73 +292,14 @@ class YandexAvisoView(APIView):
class YandexFailView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def get(request):
data = dict()
for i in request.body.decode('utf-8').split('&'):
key = i.split('=')[0]
val = i.split('=')[1]
data[key] = val
finance_logger.error('YandexFailView', data=data)
return redirect(to=settings.DOMAIN)
class DemoYandexCheckView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def post(request):
# Деалем допущение, что customerNumber=abc1111111 иначе всё плохо
data = dict()
try:
for i in request.body.decode('utf-8').split('&'):
key = i.split('=')[0]
val = i.split('=')[1]
data[key] = val
finance_logger.info('Проверка демо платежа запрос', request=data)
except IndexError:
finance_logger.exception("Непредвиденная ошибка проверки тестогого платежа")
return Response(status=204)
now = timezone.now()
try:
if data['customerNumber'] == "abc000":
xml_res = """<checkOrderResponse performedDatetime="%s" code="0" invoiceId="%s" shopId="%s"/>
""" % (now.isoformat(), str(data['invoiceId']), str(data['shopId']))
else:
xml_res = """<checkOrderResponse performedDatetime="%s" code="100" invoiceId="%s" shopId="%s"
message="Неверный номер ордера"/>""" % (now.isoformat(), str(data['invoiceId']), str(data['shopId']))
finance_logger.warning("Ошибка проверки тестового платежа", response=xml_res)
return HttpResponse(xml_res, content_type='application/xml')
except KeyError:
finance_logger.exception('Ошибка в данных checkYandex')
return Response(status=204)
class DemoYandexAvisoView(APIView):
@staticmethod
def post(request):
finance_logger.info('Начало тестирования avisoYandex')
data = dict()
for i in request.body.decode('utf-8').split('&'):
key = i.split('=')[0]
val = i.split('=')[1]
data[key] = val
now = timezone.now()
if float(data['orderSumAmount']) < 1001:
xml_res = """<paymentAvisoResponse performedDatetime="%s" code="0" invoiceId="%s" shopId="%s"/>
""" % (now.isoformat(), str(data['invoiceId']), str(data['shopId']))
finance_logger.info('Подтверждение демо платежа ответ', response=xml_res)
else:
xml_res = """<paymentAvisoResponse performedDatetime="%s" code="100" invoiceId="%s" shopId="%s"
message="Нам не позволяет совесть принять от вас более 1000 рублей"/
>""" % (now.isoformat(), str(data['invoiceId']), str(data['shopId']))
finance_logger.warning("Ошибка подтверждения тестогого платежа", response=xml_res)
return HttpResponse(xml_res, content_type='application/xml')
logger_yandex.error(data)
return redirect(to=settings.DOMAIN)

@ -3,8 +3,6 @@ import os
from celery import Celery
from raven import Client
from raven.contrib.celery import register_signal, register_logger_signal
from celery.schedules import crontab
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lms.settings')
@ -15,19 +13,11 @@ app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
client = Client('http://caaea487274f4e23a9107862484c79f3:3d463ad4717942508536f7a659921950@sentry.skillbox.ru/7')
client = Client('http://caaea487274f4e23a9107862484c79f3:3d463ad4717942508536f7a659921950@sentry.skillbox.ru/3')
register_logger_signal(client)
register_signal(client)
app.conf.beat_schedule = {
'periodic_billing': {
# 'schedule': crontab(day_of_month='1', hour='1', minute='1'), # заглушка на время отладки
'schedule': crontab(minute='0', hour='*/3',),
'task': 'finance.tasks.periodic_billing'
}
}
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
print('Request: {0!r}'.format(self.request))

@ -5,15 +5,26 @@ import raven
import environ
import socket
root = environ.Path(__file__) - 2
env = environ.Env()
environ.Env.read_env(str(root) + '/config_app/settings/local.env')
MOD = os.environ.get('MOD', 'Prod')
DEBUG = os.environ.get('DEBUG', 'False')
MASTER_PASSWORD = os.environ.get('MASTER_PASSWORD', '@J*1')
if MOD == 'Test':
environ.Env.read_env(str(root) + '/config_app/settings/test.env')
elif MOD == 'Dev':
environ.Env.read_env(str(root) + '/config_app/settings/dev.env')
elif MOD == 'Prod':
environ.Env.read_env(str(root) + '/config_app/settings/prod.env')
else:
raise ImportError('no such environ ' + MOD)
EMAIL_CONFIG = env.email_url('EMAIL_URL',)
vars().update(EMAIL_CONFIG)
@ -44,17 +55,10 @@ DOMAIN = 'https://go.skillbox.ru'
YANDEX_MONEY_DEBUG = False
YANDEX_MONEY_SCID = '149639'
YANDEX_MONEY_TEST_SCID = '558146'
YANDEX_MONEY_SHOP_ID = '157133'
#Todo костыль на рассрочку
YANDEX_MONEY_REBILLING_SCID = '723030'
YANDEX_MONEY_REBILLING_SHOP_ID = '199287'
YANDEX_MONEY_SHOP_PASSWORD = 'nu5Xefise'
YANDEX_MONEY_FAIL_URL = '%s/api/v1/finance/yandex/fail/' % DOMAIN
YANDEX_MONEY_SUCCESS_URL = '%s/' % DOMAIN
YANDEX_MONEY_MWS_URL = 'https://penelope.yamoney.ru/webservice/mws/api/'
# информировать о случаях, когда модуль вернул Яндекс.Кассе ошибку
YANDEX_MONEY_MAIL_ADMINS_ON_PAYMENT_ERROR = True
# Application definition
@ -66,8 +70,6 @@ DATABASES = {
'default': env.db(),
}
COURSE_PROGRESS_SECRET_KEY = "!gf?s3@4Hr5#J#&%Kfr@56s"
SESSION_ENGINE = 'redis_sessions.session'
CELERY_EMAIL_CHUNK_SIZE = 1
@ -188,8 +190,6 @@ STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
SSL_ROOT = os.path.join(BASE_DIR, 'ssl')
RAVEN_CONFIG = {
'dsn': 'http://1a09557dbd144e52af4b14bea569c114:fbb5dfaa39e64f02a1b4cc7ac665d7d7@sentry.skillbox.ru/7'
}
@ -206,51 +206,31 @@ LOGGING = {
'format': '%(levelname)s %(asctime)s %(module)s '
'%(process)d %(thread)d %(message)s'
},
'finance_data_formatter': {
'format': '%(asctime)s - %(levelname)s - %(message)s - %(finance_data)s'
},
},
'handlers': {
'sentry': {
'level': 'WARNING', # To capture more than ERROR, change to WARNING, INFO, etc.
'level': 'WARNING', # To capture more than ERROR, change to WARNING, INFO, etc.
'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler',
'tags': {'custom-tag': 'x'},
},
'finance_data': {
'level': 'DEBUG',
'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler',
'tags': {'custom-tag': 'yandex'}, # TODO переделать на finance_data
},
'finance_data_file': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(BASE_DIR, 'logs', 'finance_data.log'),
'maxBytes': 1024 * 1024 * 10,
'formatter': 'finance_data_formatter'
},
'business_rules': {
'yandex_money': {
'level': 'DEBUG',
'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler',
'tags': {'custom-tag': 'business_rules'},
'tags': {'custom-tag': 'yandex'},
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose'
},
}
},
'loggers': {
'': {
'level': 'WARNING',
'handlers': ['sentry'],
},
'finance_data': {
'handlers': ['finance_data', 'finance_data_file', ],
'level': 'DEBUG',
'propagate': False
},
'business_rules': {
'handlers': ['business_rules'],
'yandex_money': {
'handlers': ['yandex_money'],
'level': 'DEBUG',
'propagate': False
},

@ -1,7 +1,7 @@
from django.conf.urls import url, include
from django.contrib import admin
from django.views.static import serve
from finance.views import YandexCheckView, YandexAvisoView, DemoYandexCheckView, DemoYandexAvisoView
from finance.views import YandexCheckView, YandexAvisoView
from django.conf import settings
@ -12,7 +12,5 @@ urlpatterns = [
url(r'^static/(?P<path>.*)/$', serve, {'document_root': settings.STATIC_ROOT}),
url(r'^wallet/pay/check/$', YandexCheckView.as_view(), name='yandex_money_check'),
url(r'^wallet/pay/result/$', YandexAvisoView.as_view(), name='yandex_money_notice'),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^yandex-money/check/$', DemoYandexCheckView.as_view()),
url(r'^yandex-money/aviso/$', DemoYandexAvisoView.as_view())
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

@ -0,0 +1,520 @@
[2017-10-20 13:12:58,041: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2017-10-20 13:12:58,049: INFO/MainProcess] mingle: searching for neighbors
[2017-10-20 13:12:59,065: INFO/MainProcess] mingle: all alone
[2017-10-20 13:12:59,110: WARNING/MainProcess] /home/andrey/skillbox/lib/python3.6/site-packages/celery/fixups/django.py:202: UserWarning: Using settings.DEBUG leads to a memory leak, never use this setting in production environments!
warnings.warn('Using settings.DEBUG leads to a memory leak, never '
[2017-10-20 13:12:59,113: INFO/MainProcess] celery@andrey-desktop ready.
[2017-10-20 13:13:02,946: INFO/MainProcess] Events of group {task} enabled by remote.
[2017-10-20 13:17:23,104: INFO/MainProcess] Received task: lms.celery.debug_task[e7d9bdc2-a3a8-44b2-b3c6-935acfa092d7]
[2017-10-20 13:17:23,106: WARNING/ForkPoolWorker-2] Request: <Context: {'lang': 'py', 'task': 'lms.celery.debug_task', 'id': 'e7d9bdc2-a3a8-44b2-b3c6-935acfa092d7', 'eta': None, 'expires': None, 'group': None, 'retries': 0, 'timelimit': [None, None], 'root_id': 'e7d9bdc2-a3a8-44b2-b3c6-935acfa092d7', 'parent_id': None, 'argsrepr': '()', 'kwargsrepr': '{}', 'origin': 'gen13641@andrey-desktop', 'reply_to': 'b8c6ce7f-8ee0-35c7-ad70-026ad2f36d4a', 'correlation_id': 'e7d9bdc2-a3a8-44b2-b3c6-935acfa092d7', 'delivery_info': {'exchange': '', 'routing_key': 'celery', 'priority': 0, 'redelivered': False}, 'args': [], 'kwargs': {}, 'hostname': 'celery@andrey-desktop', 'is_eager': False, 'callbacks': None, 'errbacks': None, 'chain': None, 'chord': None, 'called_directly': False, '_protected': 1}>
[2017-10-20 13:17:23,124: INFO/ForkPoolWorker-2] Task lms.celery.debug_task[e7d9bdc2-a3a8-44b2-b3c6-935acfa092d7] succeeded in 0.018874458000027516s: None
[2017-10-20 13:17:29,057: INFO/MainProcess] Received task: lms.celery.debug_task[88f178fc-7222-4de0-b671-57e7472a9be1]
[2017-10-20 13:17:29,059: WARNING/ForkPoolWorker-1] Request: <Context: {'lang': 'py', 'task': 'lms.celery.debug_task', 'id': '88f178fc-7222-4de0-b671-57e7472a9be1', 'eta': None, 'expires': None, 'group': None, 'retries': 0, 'timelimit': [None, None], 'root_id': '88f178fc-7222-4de0-b671-57e7472a9be1', 'parent_id': None, 'argsrepr': '()', 'kwargsrepr': '{}', 'origin': 'gen13641@andrey-desktop', 'reply_to': 'b8c6ce7f-8ee0-35c7-ad70-026ad2f36d4a', 'correlation_id': '88f178fc-7222-4de0-b671-57e7472a9be1', 'delivery_info': {'exchange': '', 'routing_key': 'celery', 'priority': 0, 'redelivered': False}, 'args': [], 'kwargs': {}, 'hostname': 'celery@andrey-desktop', 'is_eager': False, 'callbacks': None, 'errbacks': None, 'chain': None, 'chord': None, 'called_directly': False, '_protected': 1}>
[2017-10-20 13:17:29,081: INFO/ForkPoolWorker-1] Task lms.celery.debug_task[88f178fc-7222-4de0-b671-57e7472a9be1] succeeded in 0.022606980999626103s: None
worker: Warm shutdown (MainProcess)
-------------- celery@andrey-desktop v4.1.0 (latentcall)
---- **** -----
--- * *** * -- Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial 2017-10-20 13:12:57
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: lms:0x7f47cb927be0
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results:
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. djcelery_email_send_multiple
. lms.celery.debug_task
[2017-10-20 13:32:32,128: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2017-10-20 13:32:32,135: INFO/MainProcess] mingle: searching for neighbors
[2017-10-20 13:32:33,150: INFO/MainProcess] mingle: all alone
[2017-10-20 13:32:33,201: WARNING/MainProcess] /home/andrey/skillbox/lib/python3.6/site-packages/celery/fixups/django.py:202: UserWarning: Using settings.DEBUG leads to a memory leak, never use this setting in production environments!
warnings.warn('Using settings.DEBUG leads to a memory leak, never '
[2017-10-20 13:32:33,202: INFO/MainProcess] celery@andrey-desktop ready.
[2017-10-20 13:32:36,911: INFO/MainProcess] Events of group {task} enabled by remote.
worker: Warm shutdown (MainProcess)
-------------- celery@andrey-desktop v4.1.0 (latentcall)
---- **** -----
--- * *** * -- Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial 2017-10-20 13:32:32
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: lms:0x7f34afe2fbe0
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results:
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. djcelery_email_send_multiple
. lms.celery.debug_task
[2017-10-20 13:38:00,333: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2017-10-20 13:38:00,341: INFO/MainProcess] mingle: searching for neighbors
[2017-10-20 13:38:01,361: INFO/MainProcess] mingle: all alone
[2017-10-20 13:38:01,408: WARNING/MainProcess] /home/andrey/skillbox/lib/python3.6/site-packages/celery/fixups/django.py:202: UserWarning: Using settings.DEBUG leads to a memory leak, never use this setting in production environments!
warnings.warn('Using settings.DEBUG leads to a memory leak, never '
[2017-10-20 13:38:01,409: INFO/MainProcess] celery@andrey-desktop ready.
[2017-10-20 13:38:05,171: INFO/MainProcess] Events of group {task} enabled by remote.
worker: Warm shutdown (MainProcess)
-------------- celery@andrey-desktop v4.1.0 (latentcall)
---- **** -----
--- * *** * -- Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial 2017-10-20 13:38:00
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: lms:0x7fd8781acbe0
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results:
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. djcelery_email_send_multiple
. lms.celery.debug_task
[2017-10-20 13:47:50,974: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2017-10-20 13:47:50,985: INFO/MainProcess] mingle: searching for neighbors
[2017-10-20 13:47:52,012: INFO/MainProcess] mingle: all alone
[2017-10-20 13:47:52,069: WARNING/MainProcess] /home/andrey/skillbox/lib/python3.6/site-packages/celery/fixups/django.py:202: UserWarning: Using settings.DEBUG leads to a memory leak, never use this setting in production environments!
warnings.warn('Using settings.DEBUG leads to a memory leak, never '
[2017-10-20 13:47:52,069: INFO/MainProcess] celery@andrey-desktop ready.
[2017-10-20 13:47:56,047: INFO/MainProcess] Events of group {task} enabled by remote.
worker: Warm shutdown (MainProcess)
-------------- celery@andrey-desktop v4.1.0 (latentcall)
---- **** -----
--- * *** * -- Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial 2017-10-20 13:47:50
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: lms:0x7fc6511c1b70
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results:
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. djcelery_email_send_multiple
. lms.celery.debug_task
[2017-10-20 14:42:47,658: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2017-10-20 14:42:47,664: INFO/MainProcess] mingle: searching for neighbors
[2017-10-20 14:42:48,682: INFO/MainProcess] mingle: all alone
[2017-10-20 14:42:48,727: INFO/MainProcess] celery@andrey-desktop ready.
[2017-10-20 14:42:52,394: INFO/MainProcess] Events of group {task} enabled by remote.
[2017-10-20 14:47:53,063: INFO/MainProcess] Tasks flagged as revoked: ff8246ff-1904-47da-ac57-1a844272c826
worker: Warm shutdown (MainProcess)
-------------- celery@andrey-desktop v4.1.0 (latentcall)
---- **** -----
--- * *** * -- Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial 2017-10-20 14:42:47
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: lms:0x7f89a2228be0
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results:
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. djcelery_email_send_multiple
. lms.celery.debug_task
[2017-10-20 14:56:43,024: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2017-10-20 14:56:43,031: INFO/MainProcess] mingle: searching for neighbors
[2017-10-20 14:56:44,048: INFO/MainProcess] mingle: all alone
[2017-10-20 14:56:44,112: INFO/MainProcess] celery@andrey-desktop ready.
[2017-10-20 14:56:47,869: INFO/MainProcess] Events of group {task} enabled by remote.
worker: Warm shutdown (MainProcess)
-------------- celery@andrey-desktop v4.1.0 (latentcall)
---- **** -----
--- * *** * -- Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial 2017-10-20 14:56:42
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: lms:0x7f4f0c601be0
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results:
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. djcelery_email_send_multiple
. lms.celery.debug_task
[2017-10-20 15:14:13,071: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2017-10-20 15:14:13,086: INFO/MainProcess] mingle: searching for neighbors
[2017-10-20 15:14:14,109: INFO/MainProcess] mingle: all alone
[2017-10-20 15:14:14,123: INFO/MainProcess] celery@andrey-desktop ready.
[2017-10-20 15:14:18,076: INFO/MainProcess] Events of group {task} enabled by remote.
worker: Warm shutdown (MainProcess)
-------------- celery@andrey-desktop v4.1.0 (latentcall)
---- **** -----
--- * *** * -- Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial 2017-10-20 15:14:12
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: lms:0x7fd94e575b70
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results:
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. djcelery_email_send_multiple
. lms.celery.debug_task
[2017-10-20 15:18:26,330: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2017-10-20 15:18:26,337: INFO/MainProcess] mingle: searching for neighbors
[2017-10-20 15:18:27,355: INFO/MainProcess] mingle: all alone
[2017-10-20 15:18:27,417: INFO/MainProcess] celery@andrey-desktop ready.
[2017-10-20 15:18:31,190: INFO/MainProcess] Events of group {task} enabled by remote.
worker: Warm shutdown (MainProcess)
-------------- celery@andrey-desktop v4.1.0 (latentcall)
---- **** -----
--- * *** * -- Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial 2017-10-20 15:18:26
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: lms:0x7f4b2ac05be0
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results:
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. djcelery_email_send_multiple
. lms.celery.debug_task
[2017-10-20 15:31:17,246: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2017-10-20 15:31:17,253: INFO/MainProcess] mingle: searching for neighbors
[2017-10-20 15:31:18,269: INFO/MainProcess] mingle: all alone
[2017-10-20 15:31:18,311: INFO/MainProcess] celery@andrey-desktop ready.
[2017-10-20 15:31:22,075: INFO/MainProcess] Events of group {task} enabled by remote.
worker: Warm shutdown (MainProcess)
-------------- celery@andrey-desktop v4.1.0 (latentcall)
---- **** -----
--- * *** * -- Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial 2017-10-20 15:31:17
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: lms:0x7f2e6cc96be0
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results:
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. djcelery_email_send_multiple
. lms.celery.debug_task
[2017-10-20 16:52:27,050: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2017-10-20 16:52:27,057: INFO/MainProcess] mingle: searching for neighbors
[2017-10-20 16:52:28,074: INFO/MainProcess] mingle: all alone
[2017-10-20 16:52:28,128: INFO/MainProcess] celery@andrey-desktop ready.
[2017-10-20 16:52:31,818: INFO/MainProcess] Events of group {task} enabled by remote.
[2017-10-20 17:00:17,556: INFO/MainProcess] Received task: djcelery_email_send[8735440e-9760-43c7-b84c-c6efdac4e64d]
[2017-10-20 17:00:19,202: INFO/ForkPoolWorker-2] Task djcelery_email_send[8735440e-9760-43c7-b84c-c6efdac4e64d] succeeded in 1.4465199199985364s: 1
[2017-10-20 17:39:12,619: INFO/MainProcess] Received task: djcelery_email_send[243eb7a2-b4e0-4221-8ab2-c83c94d8f241]
[2017-10-20 17:39:14,523: INFO/ForkPoolWorker-1] Task djcelery_email_send[243eb7a2-b4e0-4221-8ab2-c83c94d8f241] succeeded in 1.4357735300000058s: 1
[2017-10-20 17:40:33,125: INFO/MainProcess] Received task: djcelery_email_send[863adc65-6bf5-4a1d-a2b9-91ebb9737520]
[2017-10-20 17:40:34,548: INFO/ForkPoolWorker-2] Task djcelery_email_send[863adc65-6bf5-4a1d-a2b9-91ebb9737520] succeeded in 1.3558088320023671s: 1
[2017-10-20 17:42:16,950: INFO/MainProcess] Received task: djcelery_email_send[a60b5727-8d77-49f8-8008-82ae064ed682]
[2017-10-20 17:42:18,493: INFO/ForkPoolWorker-1] Task djcelery_email_send[a60b5727-8d77-49f8-8008-82ae064ed682] succeeded in 1.1552653329999885s: 1
[2017-10-20 17:57:36,541: INFO/MainProcess] Received task: djcelery_email_send[8184ca5f-b2e2-42ee-a096-b3c2ecf152e2]
[2017-10-20 17:57:37,905: INFO/ForkPoolWorker-2] Task djcelery_email_send[8184ca5f-b2e2-42ee-a096-b3c2ecf152e2] succeeded in 1.251813505001337s: 1
[2017-10-20 19:20:51,999: WARNING/MainProcess] consumer: Connection to broker lost. Trying to re-establish the connection...
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/worker/consumer/consumer.py", line 320, in start
blueprint.start(self)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/bootsteps.py", line 119, in start
step.start(parent)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/worker/consumer/consumer.py", line 596, in start
c.loop(*c.loop_args())
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/worker/loops.py", line 88, in asynloop
next(loop)
File "/home/andrey/skillbox/lib/python3.6/site-packages/kombu/async/hub.py", line 354, in create_loop
cb(*cbargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/kombu/transport/base.py", line 236, in on_readable
reader(loop)
File "/home/andrey/skillbox/lib/python3.6/site-packages/kombu/transport/base.py", line 218, in _read
drain_events(timeout=0)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 471, in drain_events
while not self.blocking_read(timeout):
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 477, in blocking_read
return self.on_inbound_frame(frame)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/method_framing.py", line 55, in on_frame
callback(channel, method_sig, buf, None)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 481, in on_inbound_method
method_sig, payload, content,
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/abstract_channel.py", line 128, in dispatch_method
listener(*args)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 603, in _on_close
(class_id, method_id), ConnectionError)
amqp.exceptions.ConnectionForced: (0, 0): (320) CONNECTION_FORCED - broker forced connection closure with reason 'shutdown'
[2017-10-20 19:20:52,012: ERROR/MainProcess] consumer: Cannot connect to amqp://guest:**@127.0.0.1:5672//: [Errno 111] Connection refused.
Trying again in 2.00 seconds...
worker: Warm shutdown (MainProcess)
-------------- celery@andrey-desktop v4.1.0 (latentcall)
---- **** -----
--- * *** * -- Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial 2017-10-20 16:52:26
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: lms:0x7fe25f735be0
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results:
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. djcelery_email_send
. lms.celery.debug_task
[2017-10-23 08:32:22,988: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2017-10-23 08:32:22,998: INFO/MainProcess] mingle: searching for neighbors
[2017-10-23 08:32:24,013: INFO/MainProcess] mingle: all alone
[2017-10-23 08:32:24,021: INFO/MainProcess] celery@andrey-desktop ready.
[2017-10-23 08:32:27,769: INFO/MainProcess] Events of group {task} enabled by remote.
[2017-10-23 11:42:09,222: INFO/MainProcess] Received task: djcelery_email_send[54f16e2a-a437-4000-850f-0bf29ff758b8]
[2017-10-23 11:42:10,844: INFO/ForkPoolWorker-2] Task djcelery_email_send[54f16e2a-a437-4000-850f-0bf29ff758b8] succeeded in 1.4740454479997425s: 1
[2017-10-23 11:44:36,901: INFO/MainProcess] Received task: djcelery_email_send[2ef60ead-2523-4bf8-b117-366bb120359d]
[2017-10-23 11:44:39,194: INFO/ForkPoolWorker-1] Task djcelery_email_send[2ef60ead-2523-4bf8-b117-366bb120359d] succeeded in 1.4229817790001107s: 1
[2017-10-23 11:45:49,202: INFO/MainProcess] Received task: djcelery_email_send[3e60e35a-c846-4f37-bd88-1d92afc9dcac]
[2017-10-23 11:45:50,624: INFO/ForkPoolWorker-2] Task djcelery_email_send[3e60e35a-c846-4f37-bd88-1d92afc9dcac] succeeded in 1.1725643370009493s: 1
[2017-10-23 11:47:18,371: INFO/MainProcess] Received task: djcelery_email_send[4530e853-0db4-499d-8a65-7128121ee5bc]
[2017-10-23 11:47:20,136: INFO/ForkPoolWorker-1] Task djcelery_email_send[4530e853-0db4-499d-8a65-7128121ee5bc] succeeded in 1.3828427380012727s: 1
[2017-10-23 11:56:05,834: INFO/MainProcess] Received task: djcelery_email_send[9fc201ce-f3ec-40af-9dd1-bf998f34a57d]
[2017-10-23 11:56:08,831: INFO/ForkPoolWorker-2] Task djcelery_email_send[9fc201ce-f3ec-40af-9dd1-bf998f34a57d] succeeded in 1.293271452001136s: 1
[2017-10-23 11:59:57,509: INFO/MainProcess] Received task: djcelery_email_send[7945e9d6-ef7c-4e19-9c59-422100ac9f73]
[2017-10-23 11:59:58,959: INFO/ForkPoolWorker-1] Task djcelery_email_send[7945e9d6-ef7c-4e19-9c59-422100ac9f73] succeeded in 1.1895115009992878s: 1
[2017-10-23 12:08:24,457: INFO/MainProcess] Received task: djcelery_email_send[f0968ae1-8fbd-4d2c-905a-2ecf445aa10e]
[2017-10-23 12:08:25,890: INFO/ForkPoolWorker-2] Task djcelery_email_send[f0968ae1-8fbd-4d2c-905a-2ecf445aa10e] succeeded in 1.3443215190000046s: 1
[2017-10-23 12:20:29,414: INFO/MainProcess] Received task: djcelery_email_send[4438a0d4-228c-40a9-b91d-612f82ea791b]
[2017-10-23 12:20:31,027: INFO/ForkPoolWorker-1] Task djcelery_email_send[4438a0d4-228c-40a9-b91d-612f82ea791b] succeeded in 1.452125650999733s: 1
[2017-10-23 12:21:31,101: INFO/MainProcess] Received task: djcelery_email_send[c3793dcb-e5f9-42bd-83b2-dd94f166c741]
[2017-10-23 12:21:32,804: INFO/ForkPoolWorker-2] Task djcelery_email_send[c3793dcb-e5f9-42bd-83b2-dd94f166c741] succeeded in 1.1413313480006764s: 1
[2017-10-23 12:38:27,027: INFO/MainProcess] Received task: djcelery_email_send[ea55b25a-8e6d-4e88-8b18-52d561bd7c95]
[2017-10-23 12:38:28,225: INFO/ForkPoolWorker-1] Task djcelery_email_send[ea55b25a-8e6d-4e88-8b18-52d561bd7c95] succeeded in 1.150906519000273s: 1
[2017-10-23 13:47:05,338: INFO/MainProcess] Received task: djcelery_email_send[b05bd9eb-848d-49b6-9725-d190e256527e]
[2017-10-23 13:47:08,582: INFO/ForkPoolWorker-2] Task djcelery_email_send[b05bd9eb-848d-49b6-9725-d190e256527e] succeeded in 1.5058496720012045s: 1
[2017-10-23 13:48:09,314: INFO/MainProcess] Received task: djcelery_email_send[fe0bd44a-f23e-476b-a447-c03d8b5bb266]
[2017-10-23 13:48:12,620: INFO/ForkPoolWorker-1] Task djcelery_email_send[fe0bd44a-f23e-476b-a447-c03d8b5bb266] succeeded in 1.340003754998179s: 1
[2017-10-23 14:36:33,382: INFO/MainProcess] Received task: djcelery_email_send[33418ad8-1f87-4a6f-ba11-a2fc0f52374a]
[2017-10-23 14:36:35,323: INFO/ForkPoolWorker-2] Task djcelery_email_send[33418ad8-1f87-4a6f-ba11-a2fc0f52374a] succeeded in 1.3137642000001506s: 1
[2017-10-23 14:36:49,212: INFO/MainProcess] Received task: djcelery_email_send[5f3beb45-7d03-447a-be90-41506efb897b]
[2017-10-23 14:36:51,271: INFO/ForkPoolWorker-1] Task djcelery_email_send[5f3beb45-7d03-447a-be90-41506efb897b] succeeded in 1.23961846200109s: 1
[2017-10-23 14:46:42,199: INFO/MainProcess] Received task: djcelery_email_send[69d6f018-e571-4d65-93a4-151fa78361ae]
[2017-10-23 14:46:44,060: INFO/ForkPoolWorker-2] Task djcelery_email_send[69d6f018-e571-4d65-93a4-151fa78361ae] succeeded in 1.2866839900016203s: 1
[2017-10-23 14:55:56,121: WARNING/MainProcess] consumer: Connection to broker lost. Trying to re-establish the connection...
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/worker/consumer/consumer.py", line 320, in start
blueprint.start(self)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/bootsteps.py", line 119, in start
step.start(parent)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/worker/consumer/consumer.py", line 596, in start
c.loop(*c.loop_args())
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/worker/loops.py", line 88, in asynloop
next(loop)
File "/home/andrey/skillbox/lib/python3.6/site-packages/kombu/async/hub.py", line 354, in create_loop
cb(*cbargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/kombu/transport/base.py", line 236, in on_readable
reader(loop)
File "/home/andrey/skillbox/lib/python3.6/site-packages/kombu/transport/base.py", line 218, in _read
drain_events(timeout=0)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 471, in drain_events
while not self.blocking_read(timeout):
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 477, in blocking_read
return self.on_inbound_frame(frame)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/method_framing.py", line 55, in on_frame
callback(channel, method_sig, buf, None)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 481, in on_inbound_method
method_sig, payload, content,
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/abstract_channel.py", line 128, in dispatch_method
listener(*args)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 601, in _on_close
self._x_close_ok()
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 616, in _x_close_ok
self.send_method(spec.Connection.CloseOk, callback=self._on_close_ok)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/abstract_channel.py", line 50, in send_method
conn.frame_writer(1, self.channel_id, sig, args, content)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/method_framing.py", line 166, in write_frame
write(view[:offset])
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/transport.py", line 258, in write
self._write(s)
ConnectionResetError: [Errno 104] Connection reset by peer
[2017-10-23 14:55:56,137: ERROR/MainProcess] consumer: Cannot connect to amqp://guest:**@127.0.0.1:5672//: [Errno 111] Connection refused.
Trying again in 2.00 seconds...
[2017-10-23 14:55:58,150: ERROR/MainProcess] consumer: Cannot connect to amqp://guest:**@127.0.0.1:5672//: [Errno 111] Connection refused.
Trying again in 4.00 seconds...
[2017-10-23 14:56:02,176: ERROR/MainProcess] consumer: Cannot connect to amqp://guest:**@127.0.0.1:5672//: [Errno 111] Connection refused.
Trying again in 6.00 seconds...
[2017-10-23 14:56:08,193: ERROR/MainProcess] consumer: Cannot connect to amqp://guest:**@127.0.0.1:5672//: [Errno 111] Connection refused.
Trying again in 8.00 seconds...
[2017-10-23 14:56:16,210: ERROR/MainProcess] consumer: Cannot connect to amqp://guest:**@127.0.0.1:5672//: [Errno 111] Connection refused.
Trying again in 10.00 seconds...
[2017-10-23 14:56:26,228: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2017-10-23 14:56:26,237: INFO/MainProcess] mingle: searching for neighbors
[2017-10-23 14:56:26,241: WARNING/MainProcess] consumer: Connection to broker lost. Trying to re-establish the connection...
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/worker/consumer/consumer.py", line 320, in start
blueprint.start(self)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/bootsteps.py", line 119, in start
step.start(parent)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/worker/consumer/mingle.py", line 38, in start
self.sync(c)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/worker/consumer/mingle.py", line 42, in sync
replies = self.send_hello(c)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/worker/consumer/mingle.py", line 55, in send_hello
replies = inspect.hello(c.hostname, our_revoked._data) or {}
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/control.py", line 129, in hello
return self._request('hello', from_node=from_node, revoked=revoked)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/control.py", line 81, in _request
timeout=self.timeout, reply=True,
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/control.py", line 436, in broadcast
limit, callback, channel=channel,
File "/home/andrey/skillbox/lib/python3.6/site-packages/kombu/pidbox.py", line 315, in _broadcast
serializer=serializer)
File "/home/andrey/skillbox/lib/python3.6/site-packages/kombu/pidbox.py", line 290, in _publish
serializer=serializer,
File "/home/andrey/skillbox/lib/python3.6/site-packages/kombu/messaging.py", line 181, in publish
exchange_name, declare,
File "/home/andrey/skillbox/lib/python3.6/site-packages/kombu/messaging.py", line 203, in _publish
mandatory=mandatory, immediate=immediate,
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/channel.py", line 1734, in _basic_publish
(0, exchange, routing_key, mandatory, immediate), msg
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/abstract_channel.py", line 50, in send_method
conn.frame_writer(1, self.channel_id, sig, args, content)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/method_framing.py", line 166, in write_frame
write(view[:offset])
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/transport.py", line 258, in write
self._write(s)
ConnectionResetError: [Errno 104] Connection reset by peer
[2017-10-23 14:56:26,250: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2017-10-23 14:56:26,256: INFO/MainProcess] mingle: searching for neighbors
[2017-10-23 14:56:27,273: INFO/MainProcess] mingle: all alone
[2017-10-23 14:56:27,310: INFO/MainProcess] Received task: djcelery_email_send[455cf8cb-b29f-4159-a81b-b33e5dbee1f3]
[2017-10-23 14:56:28,959: INFO/ForkPoolWorker-2] Task djcelery_email_send[455cf8cb-b29f-4159-a81b-b33e5dbee1f3] succeeded in 1.1903551169998536s: 1
[2017-10-23 18:52:13,477: INFO/MainProcess] Received task: djcelery_email_send[0fb5c171-4123-47fa-8089-823904fde5fd]
[2017-10-23 18:52:16,661: INFO/ForkPoolWorker-1] Task djcelery_email_send[0fb5c171-4123-47fa-8089-823904fde5fd] succeeded in 1.222238110996841s: 1
[2017-10-23 19:05:28,619: WARNING/MainProcess] consumer: Connection to broker lost. Trying to re-establish the connection...
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/worker/consumer/consumer.py", line 320, in start
blueprint.start(self)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/bootsteps.py", line 119, in start
step.start(parent)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/worker/consumer/consumer.py", line 596, in start
c.loop(*c.loop_args())
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/worker/loops.py", line 88, in asynloop
next(loop)
File "/home/andrey/skillbox/lib/python3.6/site-packages/kombu/async/hub.py", line 354, in create_loop
cb(*cbargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/kombu/transport/base.py", line 236, in on_readable
reader(loop)
File "/home/andrey/skillbox/lib/python3.6/site-packages/kombu/transport/base.py", line 218, in _read
drain_events(timeout=0)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 471, in drain_events
while not self.blocking_read(timeout):
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 477, in blocking_read
return self.on_inbound_frame(frame)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/method_framing.py", line 55, in on_frame
callback(channel, method_sig, buf, None)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 481, in on_inbound_method
method_sig, payload, content,
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/abstract_channel.py", line 128, in dispatch_method
listener(*args)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 601, in _on_close
self._x_close_ok()
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/connection.py", line 616, in _x_close_ok
self.send_method(spec.Connection.CloseOk, callback=self._on_close_ok)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/abstract_channel.py", line 50, in send_method
conn.frame_writer(1, self.channel_id, sig, args, content)
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/method_framing.py", line 166, in write_frame
write(view[:offset])
File "/home/andrey/skillbox/lib/python3.6/site-packages/amqp/transport.py", line 258, in write
self._write(s)
ConnectionResetError: [Errno 104] Connection reset by peer
[2017-10-23 19:05:28,624: ERROR/MainProcess] consumer: Cannot connect to amqp://guest:**@127.0.0.1:5672//: [Errno 111] Connection refused.
Trying again in 2.00 seconds...
worker: Warm shutdown (MainProcess)
-------------- celery@andrey-desktop v4.1.0 (latentcall)
---- **** -----
--- * *** * -- Linux-4.10.0-37-generic-x86_64-with-Ubuntu-16.04-xenial 2017-10-23 08:32:22
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: lms:0x7f574ff21ba8
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results:
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. djcelery_email_send
. lms.celery.debug_task

@ -0,0 +1,623 @@
[E 171020 13:12:57 signal:232] Signal handler <promise@0x7f84e8f79678 --> <bound method Celery._autodiscover_tasks of <Celery lms at 0x7f84e711bbe0>>> raised: ImportError("cannot import name 'TrafSource'",)
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/utils/dispatch/signal.py", line 227, in send
response = receiver(signal=self, sender=sender, **named)
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 143, in __call__
return self.throw()
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 140, in __call__
retval = fun(*final_args, **final_kwargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 671, in _autodiscover_tasks
return self._autodiscover_tasks_from_fixups(related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 684, in _autodiscover_tasks_from_fixups
], related_name=related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 676, in _autodiscover_tasks_from_names
packages() if callable(packages) else packages, related_name,
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 223, in autodiscover_tasks
related_name) if mod)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in autodiscover_tasks
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in <listcomp>
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 274, in find_related_module
return importlib.import_module('{0}.{1}'.format(package, related_name))
File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/andrey/skillbox/go.skillbox.ru/access/tasks.py", line 4, in <module>
from access.models import User, TrafSource, TrafTokenHistory
ImportError: cannot import name 'TrafSource'
[I 171020 13:12:57 command:139] Visit me at http://localhost:5555
[I 171020 13:12:57 command:144] Broker: amqp://guest:**@localhost:5672//
[I 171020 13:12:57 command:147] Registered tasks:
['celery.accumulate',
'celery.backend_cleanup',
'celery.chain',
'celery.chord',
'celery.chord_unlock',
'celery.chunks',
'celery.group',
'celery.map',
'celery.starmap',
'djcelery_email_send_multiple',
'lms.celery.debug_task']
[I 171020 13:12:57 mixins:224] Connected to amqp://guest:**@127.0.0.1:5672//
[W 171020 13:13:00 control:44] 'stats' inspect method failed
[W 171020 13:13:00 control:44] 'active_queues' inspect method failed
[W 171020 13:13:00 control:44] 'registered' inspect method failed
[W 171020 13:13:00 control:44] 'scheduled' inspect method failed
[W 171020 13:13:00 control:44] 'active' inspect method failed
[W 171020 13:13:00 control:44] 'reserved' inspect method failed
[W 171020 13:13:00 control:44] 'revoked' inspect method failed
[W 171020 13:13:00 control:44] 'conf' inspect method failed
[I 171020 13:32:28 command:47] SIGTERM detected, shutting down
[E 171020 13:32:31 signal:232] Signal handler <promise@0x7f72af4b2678 --> <bound method Celery._autodiscover_tasks of <Celery lms at 0x7f72ad655b70>>> raised: ImportError("cannot import name 'TrafSource'",)
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/utils/dispatch/signal.py", line 227, in send
response = receiver(signal=self, sender=sender, **named)
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 143, in __call__
return self.throw()
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 140, in __call__
retval = fun(*final_args, **final_kwargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 671, in _autodiscover_tasks
return self._autodiscover_tasks_from_fixups(related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 684, in _autodiscover_tasks_from_fixups
], related_name=related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 676, in _autodiscover_tasks_from_names
packages() if callable(packages) else packages, related_name,
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 223, in autodiscover_tasks
related_name) if mod)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in autodiscover_tasks
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in <listcomp>
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 274, in find_related_module
return importlib.import_module('{0}.{1}'.format(package, related_name))
File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/andrey/skillbox/go.skillbox.ru/access/tasks.py", line 4, in <module>
from access.models import User, TrafSource, TrafTokenHistory
ImportError: cannot import name 'TrafSource'
[I 171020 13:32:31 command:139] Visit me at http://localhost:5555
[I 171020 13:32:31 command:144] Broker: amqp://guest:**@localhost:5672//
[I 171020 13:32:31 command:147] Registered tasks:
['celery.accumulate',
'celery.backend_cleanup',
'celery.chain',
'celery.chord',
'celery.chord_unlock',
'celery.chunks',
'celery.group',
'celery.map',
'celery.starmap',
'djcelery_email_send_multiple',
'lms.celery.debug_task']
[I 171020 13:32:31 mixins:224] Connected to amqp://guest:**@127.0.0.1:5672//
[W 171020 13:32:34 control:44] 'stats' inspect method failed
[W 171020 13:32:34 control:44] 'active_queues' inspect method failed
[W 171020 13:32:34 control:44] 'registered' inspect method failed
[W 171020 13:32:34 control:44] 'scheduled' inspect method failed
[W 171020 13:32:34 control:44] 'active' inspect method failed
[W 171020 13:32:34 control:44] 'reserved' inspect method failed
[W 171020 13:32:34 control:44] 'revoked' inspect method failed
[W 171020 13:32:34 control:44] 'conf' inspect method failed
[I 171020 13:37:56 command:47] SIGTERM detected, shutting down
[E 171020 13:38:00 signal:232] Signal handler <promise@0x7f00bb71c678 --> <bound method Celery._autodiscover_tasks of <Celery lms at 0x7f00b98bebe0>>> raised: ImportError("cannot import name 'TrafSource'",)
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/utils/dispatch/signal.py", line 227, in send
response = receiver(signal=self, sender=sender, **named)
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 143, in __call__
return self.throw()
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 140, in __call__
retval = fun(*final_args, **final_kwargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 671, in _autodiscover_tasks
return self._autodiscover_tasks_from_fixups(related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 684, in _autodiscover_tasks_from_fixups
], related_name=related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 676, in _autodiscover_tasks_from_names
packages() if callable(packages) else packages, related_name,
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 223, in autodiscover_tasks
related_name) if mod)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in autodiscover_tasks
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in <listcomp>
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 274, in find_related_module
return importlib.import_module('{0}.{1}'.format(package, related_name))
File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/andrey/skillbox/go.skillbox.ru/access/tasks.py", line 4, in <module>
from access.models import User, TrafSource, TrafTokenHistory
ImportError: cannot import name 'TrafSource'
[I 171020 13:38:00 command:139] Visit me at http://localhost:5555
[I 171020 13:38:00 command:144] Broker: amqp://guest:**@localhost:5672//
[I 171020 13:38:00 command:147] Registered tasks:
['celery.accumulate',
'celery.backend_cleanup',
'celery.chain',
'celery.chord',
'celery.chord_unlock',
'celery.chunks',
'celery.group',
'celery.map',
'celery.starmap',
'djcelery_email_send_multiple',
'lms.celery.debug_task']
[I 171020 13:38:00 mixins:224] Connected to amqp://guest:**@127.0.0.1:5672//
[W 171020 13:38:02 control:44] 'stats' inspect method failed
[W 171020 13:38:02 control:44] 'active_queues' inspect method failed
[W 171020 13:38:02 control:44] 'registered' inspect method failed
[W 171020 13:38:02 control:44] 'scheduled' inspect method failed
[W 171020 13:38:02 control:44] 'active' inspect method failed
[W 171020 13:38:02 control:44] 'reserved' inspect method failed
[W 171020 13:38:02 control:44] 'revoked' inspect method failed
[W 171020 13:38:02 control:44] 'conf' inspect method failed
[I 171020 13:47:47 command:47] SIGTERM detected, shutting down
[E 171020 13:47:51 signal:232] Signal handler <promise@0x7f7efbb18678 --> <bound method Celery._autodiscover_tasks of <Celery lms at 0x7f7ef9cbabe0>>> raised: ImportError("cannot import name 'TrafSource'",)
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/utils/dispatch/signal.py", line 227, in send
response = receiver(signal=self, sender=sender, **named)
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 143, in __call__
return self.throw()
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 140, in __call__
retval = fun(*final_args, **final_kwargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 671, in _autodiscover_tasks
return self._autodiscover_tasks_from_fixups(related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 684, in _autodiscover_tasks_from_fixups
], related_name=related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 676, in _autodiscover_tasks_from_names
packages() if callable(packages) else packages, related_name,
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 223, in autodiscover_tasks
related_name) if mod)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in autodiscover_tasks
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in <listcomp>
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 274, in find_related_module
return importlib.import_module('{0}.{1}'.format(package, related_name))
File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/andrey/skillbox/go.skillbox.ru/access/tasks.py", line 4, in <module>
from access.models import User, TrafSource, TrafTokenHistory
ImportError: cannot import name 'TrafSource'
[I 171020 13:47:51 command:139] Visit me at http://localhost:5555
[I 171020 13:47:51 command:144] Broker: amqp://guest:**@localhost:5672//
[I 171020 13:47:51 command:147] Registered tasks:
['celery.accumulate',
'celery.backend_cleanup',
'celery.chain',
'celery.chord',
'celery.chord_unlock',
'celery.chunks',
'celery.group',
'celery.map',
'celery.starmap',
'djcelery_email_send_multiple',
'lms.celery.debug_task']
[I 171020 13:47:51 mixins:224] Connected to amqp://guest:**@127.0.0.1:5672//
[W 171020 13:47:53 control:44] 'stats' inspect method failed
[W 171020 13:47:53 control:44] 'active_queues' inspect method failed
[W 171020 13:47:53 control:44] 'registered' inspect method failed
[W 171020 13:47:53 control:44] 'scheduled' inspect method failed
[I 171020 14:42:44 command:47] SIGTERM detected, shutting down
[E 171020 14:42:47 signal:232] Signal handler <promise@0x7f9b93353678 --> <bound method Celery._autodiscover_tasks of <Celery lms at 0x7f9b914f5be0>>> raised: ImportError("cannot import name 'TrafSource'",)
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/utils/dispatch/signal.py", line 227, in send
response = receiver(signal=self, sender=sender, **named)
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 143, in __call__
return self.throw()
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 140, in __call__
retval = fun(*final_args, **final_kwargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 671, in _autodiscover_tasks
return self._autodiscover_tasks_from_fixups(related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 684, in _autodiscover_tasks_from_fixups
], related_name=related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 676, in _autodiscover_tasks_from_names
packages() if callable(packages) else packages, related_name,
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 223, in autodiscover_tasks
related_name) if mod)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in autodiscover_tasks
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in <listcomp>
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 274, in find_related_module
return importlib.import_module('{0}.{1}'.format(package, related_name))
File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/andrey/skillbox/go.skillbox.ru/access/tasks.py", line 4, in <module>
from access.models import User, TrafSource, TrafTokenHistory
ImportError: cannot import name 'TrafSource'
[I 171020 14:42:47 command:139] Visit me at http://localhost:5555
[I 171020 14:42:47 command:144] Broker: amqp://guest:**@localhost:5672//
[I 171020 14:42:47 command:147] Registered tasks:
['celery.accumulate',
'celery.backend_cleanup',
'celery.chain',
'celery.chord',
'celery.chord_unlock',
'celery.chunks',
'celery.group',
'celery.map',
'celery.starmap',
'djcelery_email_send_multiple',
'lms.celery.debug_task']
[I 171020 14:42:47 mixins:224] Connected to amqp://guest:**@127.0.0.1:5672//
[W 171020 14:42:49 control:44] 'stats' inspect method failed
[W 171020 14:42:49 control:44] 'active_queues' inspect method failed
[W 171020 14:42:49 control:44] 'registered' inspect method failed
[W 171020 14:42:49 control:44] 'scheduled' inspect method failed
[W 171020 14:42:49 control:44] 'active' inspect method failed
[W 171020 14:42:49 control:44] 'reserved' inspect method failed
[W 171020 14:42:49 control:44] 'revoked' inspect method failed
[W 171020 14:42:49 control:44] 'conf' inspect method failed
[I 171020 14:56:39 command:47] SIGTERM detected, shutting down
[E 171020 14:56:42 signal:232] Signal handler <promise@0x7f15cad6f678 --> <bound method Celery._autodiscover_tasks of <Celery lms at 0x7f15c8f11be0>>> raised: ImportError("cannot import name 'TrafSource'",)
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/utils/dispatch/signal.py", line 227, in send
response = receiver(signal=self, sender=sender, **named)
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 143, in __call__
return self.throw()
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 140, in __call__
retval = fun(*final_args, **final_kwargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 671, in _autodiscover_tasks
return self._autodiscover_tasks_from_fixups(related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 684, in _autodiscover_tasks_from_fixups
], related_name=related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 676, in _autodiscover_tasks_from_names
packages() if callable(packages) else packages, related_name,
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 223, in autodiscover_tasks
related_name) if mod)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in autodiscover_tasks
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in <listcomp>
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 274, in find_related_module
return importlib.import_module('{0}.{1}'.format(package, related_name))
File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/andrey/skillbox/go.skillbox.ru/access/tasks.py", line 4, in <module>
from access.models import User, TrafSource, TrafTokenHistory
ImportError: cannot import name 'TrafSource'
[I 171020 14:56:42 command:139] Visit me at http://localhost:5555
[I 171020 14:56:42 command:144] Broker: amqp://guest:**@localhost:5672//
[I 171020 14:56:42 command:147] Registered tasks:
['celery.accumulate',
'celery.backend_cleanup',
'celery.chain',
'celery.chord',
'celery.chord_unlock',
'celery.chunks',
'celery.group',
'celery.map',
'celery.starmap',
'djcelery_email_send_multiple',
'lms.celery.debug_task']
[I 171020 14:56:42 mixins:224] Connected to amqp://guest:**@127.0.0.1:5672//
[W 171020 14:56:45 control:44] 'stats' inspect method failed
[W 171020 14:56:45 control:44] 'active_queues' inspect method failed
[W 171020 14:56:45 control:44] 'registered' inspect method failed
[W 171020 14:56:45 control:44] 'scheduled' inspect method failed
[W 171020 14:56:45 control:44] 'active' inspect method failed
[W 171020 14:56:45 control:44] 'reserved' inspect method failed
[W 171020 14:56:45 control:44] 'revoked' inspect method failed
[W 171020 14:56:45 control:44] 'conf' inspect method failed
[I 171020 15:14:09 command:47] SIGTERM detected, shutting down
[E 171020 15:14:13 signal:232] Signal handler <promise@0x7f60e14ab678 --> <bound method Celery._autodiscover_tasks of <Celery lms at 0x7f60df64dbe0>>> raised: ImportError("cannot import name 'TrafSource'",)
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/utils/dispatch/signal.py", line 227, in send
response = receiver(signal=self, sender=sender, **named)
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 143, in __call__
return self.throw()
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 140, in __call__
retval = fun(*final_args, **final_kwargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 671, in _autodiscover_tasks
return self._autodiscover_tasks_from_fixups(related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 684, in _autodiscover_tasks_from_fixups
], related_name=related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 676, in _autodiscover_tasks_from_names
packages() if callable(packages) else packages, related_name,
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 223, in autodiscover_tasks
related_name) if mod)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in autodiscover_tasks
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in <listcomp>
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 274, in find_related_module
return importlib.import_module('{0}.{1}'.format(package, related_name))
File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/andrey/skillbox/go.skillbox.ru/access/tasks.py", line 4, in <module>
from access.models import User, TrafSource, TrafTokenHistory
ImportError: cannot import name 'TrafSource'
[I 171020 15:14:13 command:139] Visit me at http://localhost:5555
[I 171020 15:14:13 command:144] Broker: amqp://guest:**@localhost:5672//
[I 171020 15:14:13 command:147] Registered tasks:
['celery.accumulate',
'celery.backend_cleanup',
'celery.chain',
'celery.chord',
'celery.chord_unlock',
'celery.chunks',
'celery.group',
'celery.map',
'celery.starmap',
'djcelery_email_send_multiple',
'lms.celery.debug_task']
[I 171020 15:14:13 mixins:224] Connected to amqp://guest:**@127.0.0.1:5672//
[W 171020 15:14:15 control:44] 'stats' inspect method failed
[W 171020 15:14:15 control:44] 'active_queues' inspect method failed
[W 171020 15:14:15 control:44] 'registered' inspect method failed
[W 171020 15:14:15 control:44] 'scheduled' inspect method failed
[I 171020 15:18:22 command:47] SIGTERM detected, shutting down
[E 171020 15:18:26 signal:232] Signal handler <promise@0x7ff7eb19f678 --> <bound method Celery._autodiscover_tasks of <Celery lms at 0x7ff7e9341b70>>> raised: ImportError("cannot import name 'TrafSource'",)
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/utils/dispatch/signal.py", line 227, in send
response = receiver(signal=self, sender=sender, **named)
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 143, in __call__
return self.throw()
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 140, in __call__
retval = fun(*final_args, **final_kwargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 671, in _autodiscover_tasks
return self._autodiscover_tasks_from_fixups(related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 684, in _autodiscover_tasks_from_fixups
], related_name=related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 676, in _autodiscover_tasks_from_names
packages() if callable(packages) else packages, related_name,
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 223, in autodiscover_tasks
related_name) if mod)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in autodiscover_tasks
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in <listcomp>
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 274, in find_related_module
return importlib.import_module('{0}.{1}'.format(package, related_name))
File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/andrey/skillbox/go.skillbox.ru/access/tasks.py", line 4, in <module>
from access.models import User, TrafSource, TrafTokenHistory
ImportError: cannot import name 'TrafSource'
[I 171020 15:18:26 command:139] Visit me at http://localhost:5555
[I 171020 15:18:26 command:144] Broker: amqp://guest:**@localhost:5672//
[I 171020 15:18:26 command:147] Registered tasks:
['celery.accumulate',
'celery.backend_cleanup',
'celery.chain',
'celery.chord',
'celery.chord_unlock',
'celery.chunks',
'celery.group',
'celery.map',
'celery.starmap',
'djcelery_email_send_multiple',
'lms.celery.debug_task']
[I 171020 15:18:26 mixins:224] Connected to amqp://guest:**@127.0.0.1:5672//
[W 171020 15:18:28 control:44] 'stats' inspect method failed
[W 171020 15:18:28 control:44] 'active_queues' inspect method failed
[W 171020 15:18:28 control:44] 'registered' inspect method failed
[W 171020 15:18:28 control:44] 'scheduled' inspect method failed
[W 171020 15:18:28 control:44] 'active' inspect method failed
[W 171020 15:18:28 control:44] 'reserved' inspect method failed
[W 171020 15:18:28 control:44] 'revoked' inspect method failed
[W 171020 15:18:28 control:44] 'conf' inspect method failed
[I 171020 15:31:13 command:47] SIGTERM detected, shutting down
[E 171020 15:31:17 signal:232] Signal handler <promise@0x7fcacf94e678 --> <bound method Celery._autodiscover_tasks of <Celery lms at 0x7fcacdaf0be0>>> raised: ImportError("cannot import name 'TrafSource'",)
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/utils/dispatch/signal.py", line 227, in send
response = receiver(signal=self, sender=sender, **named)
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 143, in __call__
return self.throw()
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 140, in __call__
retval = fun(*final_args, **final_kwargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 671, in _autodiscover_tasks
return self._autodiscover_tasks_from_fixups(related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 684, in _autodiscover_tasks_from_fixups
], related_name=related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 676, in _autodiscover_tasks_from_names
packages() if callable(packages) else packages, related_name,
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 223, in autodiscover_tasks
related_name) if mod)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in autodiscover_tasks
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in <listcomp>
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 274, in find_related_module
return importlib.import_module('{0}.{1}'.format(package, related_name))
File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/andrey/skillbox/go.skillbox.ru/access/tasks.py", line 4, in <module>
from access.models import User, TrafSource, TrafTokenHistory
ImportError: cannot import name 'TrafSource'
[I 171020 15:31:17 command:139] Visit me at http://localhost:5555
[I 171020 15:31:17 command:144] Broker: amqp://guest:**@localhost:5672//
[I 171020 15:31:17 command:147] Registered tasks:
['celery.accumulate',
'celery.backend_cleanup',
'celery.chain',
'celery.chord',
'celery.chord_unlock',
'celery.chunks',
'celery.group',
'celery.map',
'celery.starmap',
'djcelery_email_send_multiple',
'lms.celery.debug_task']
[I 171020 15:31:17 mixins:224] Connected to amqp://guest:**@127.0.0.1:5672//
[W 171020 15:31:19 control:44] 'stats' inspect method failed
[W 171020 15:31:19 control:44] 'active_queues' inspect method failed
[W 171020 15:31:19 control:44] 'registered' inspect method failed
[W 171020 15:31:19 control:44] 'scheduled' inspect method failed
[W 171020 15:31:19 control:44] 'active' inspect method failed
[W 171020 15:31:19 control:44] 'reserved' inspect method failed
[W 171020 15:31:19 control:44] 'revoked' inspect method failed
[W 171020 15:31:19 control:44] 'conf' inspect method failed
[I 171020 16:52:23 command:47] SIGTERM detected, shutting down
[E 171020 16:52:26 signal:232] Signal handler <promise@0x7fb7bea9a678 --> <bound method Celery._autodiscover_tasks of <Celery lms at 0x7fb7bcc3cb70>>> raised: ImportError("cannot import name 'TrafSource'",)
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/utils/dispatch/signal.py", line 227, in send
response = receiver(signal=self, sender=sender, **named)
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 143, in __call__
return self.throw()
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 140, in __call__
retval = fun(*final_args, **final_kwargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 671, in _autodiscover_tasks
return self._autodiscover_tasks_from_fixups(related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 684, in _autodiscover_tasks_from_fixups
], related_name=related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 676, in _autodiscover_tasks_from_names
packages() if callable(packages) else packages, related_name,
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 223, in autodiscover_tasks
related_name) if mod)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in autodiscover_tasks
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in <listcomp>
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 274, in find_related_module
return importlib.import_module('{0}.{1}'.format(package, related_name))
File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/andrey/skillbox/go.skillbox.ru/access/tasks.py", line 4, in <module>
from access.models import User, TrafSource, TrafTokenHistory
ImportError: cannot import name 'TrafSource'
[I 171020 16:52:26 command:139] Visit me at http://localhost:5555
[I 171020 16:52:26 command:144] Broker: amqp://guest:**@localhost:5672//
[I 171020 16:52:26 command:147] Registered tasks:
['celery.accumulate',
'celery.backend_cleanup',
'celery.chain',
'celery.chord',
'celery.chord_unlock',
'celery.chunks',
'celery.group',
'celery.map',
'celery.starmap',
'djcelery_email_send',
'lms.celery.debug_task']
[I 171020 16:52:26 mixins:224] Connected to amqp://guest:**@127.0.0.1:5672//
[W 171020 16:52:28 control:44] 'stats' inspect method failed
[W 171020 16:52:28 control:44] 'active_queues' inspect method failed
[W 171020 16:52:28 control:44] 'registered' inspect method failed
[W 171020 16:52:28 control:44] 'scheduled' inspect method failed
[W 171020 16:52:28 control:44] 'active' inspect method failed
[W 171020 16:52:28 control:44] 'reserved' inspect method failed
[W 171020 16:52:28 control:44] 'revoked' inspect method failed
[W 171020 16:52:28 control:44] 'conf' inspect method failed
[I 171020 19:20:51 command:47] SIGTERM detected, shutting down
[E 171023 08:32:22 signal:232] Signal handler <promise@0x7f249b502678 --> <bound method Celery._autodiscover_tasks of <Celery lms at 0x7f24996a4be0>>> raised: ImportError("cannot import name 'TrafSource'",)
Traceback (most recent call last):
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/utils/dispatch/signal.py", line 227, in send
response = receiver(signal=self, sender=sender, **named)
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 143, in __call__
return self.throw()
File "/home/andrey/skillbox/lib/python3.6/site-packages/vine/promises.py", line 140, in __call__
retval = fun(*final_args, **final_kwargs)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 671, in _autodiscover_tasks
return self._autodiscover_tasks_from_fixups(related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 684, in _autodiscover_tasks_from_fixups
], related_name=related_name)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/app/base.py", line 676, in _autodiscover_tasks_from_names
packages() if callable(packages) else packages, related_name,
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 223, in autodiscover_tasks
related_name) if mod)
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in autodiscover_tasks
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 248, in <listcomp>
return [find_related_module(pkg, related_name) for pkg in packages]
File "/home/andrey/skillbox/lib/python3.6/site-packages/celery/loaders/base.py", line 274, in find_related_module
return importlib.import_module('{0}.{1}'.format(package, related_name))
File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/andrey/skillbox/go.skillbox.ru/access/tasks.py", line 4, in <module>
from access.models import User, TrafSource, TrafTokenHistory
ImportError: cannot import name 'TrafSource'
[I 171023 08:32:22 command:139] Visit me at http://localhost:5555
[I 171023 08:32:22 command:144] Broker: amqp://guest:**@localhost:5672//
[I 171023 08:32:22 command:147] Registered tasks:
['celery.accumulate',
'celery.backend_cleanup',
'celery.chain',
'celery.chord',
'celery.chord_unlock',
'celery.chunks',
'celery.group',
'celery.map',
'celery.starmap',
'djcelery_email_send',
'lms.celery.debug_task']
[I 171023 08:32:22 mixins:224] Connected to amqp://guest:**@127.0.0.1:5672//
[W 171023 08:32:24 control:44] 'stats' inspect method failed
[W 171023 08:32:24 control:44] 'active_queues' inspect method failed
[W 171023 08:32:24 control:44] 'registered' inspect method failed
[W 171023 08:32:24 control:44] 'scheduled' inspect method failed
[W 171023 08:32:24 control:44] 'active' inspect method failed
[W 171023 08:32:24 control:44] 'reserved' inspect method failed
[W 171023 08:32:24 control:44] 'revoked' inspect method failed
[W 171023 08:32:24 control:44] 'conf' inspect method failed
[E 171023 14:55:56 events:123] Failed to capture events: '[Errno 104] Connection reset by peer', trying again in 1 seconds.
[I 171023 14:56:17 mixins:224] Connected to amqp://guest:**@127.0.0.1:5672//
[E 171023 14:56:17 events:123] Failed to capture events: '[Errno 104] Connection reset by peer', trying again in 1 seconds.
[I 171023 14:56:18 mixins:224] Connected to amqp://guest:**@127.0.0.1:5672//
[I 171023 19:05:28 command:47] SIGTERM detected, shutting down

@ -0,0 +1,121 @@
[2017-10-20 13:12:57,958: INFO/MainProcess] beat: Starting...
celery beat v4.1.0 (latentcall) is starting.
__ - ... __ - _
LocalTime -> 2017-10-20 13:12:57
Configuration ->
. broker -> amqp://guest:**@localhost:5672//
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 minutes (300s)
[2017-10-20 13:32:31,865: INFO/MainProcess] beat: Starting...
celery beat v4.1.0 (latentcall) is starting.
__ - ... __ - _
LocalTime -> 2017-10-20 13:32:31
Configuration ->
. broker -> amqp://guest:**@localhost:5672//
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 minutes (300s)
[2017-10-20 13:38:00,107: INFO/MainProcess] beat: Starting...
celery beat v4.1.0 (latentcall) is starting.
__ - ... __ - _
LocalTime -> 2017-10-20 13:38:00
Configuration ->
. broker -> amqp://guest:**@localhost:5672//
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 minutes (300s)
[2017-10-20 13:47:51,058: INFO/MainProcess] beat: Starting...
celery beat v4.1.0 (latentcall) is starting.
__ - ... __ - _
LocalTime -> 2017-10-20 13:47:51
Configuration ->
. broker -> amqp://guest:**@localhost:5672//
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 minutes (300s)
[2017-10-20 14:42:47,578: INFO/MainProcess] beat: Starting...
celery beat v4.1.0 (latentcall) is starting.
__ - ... __ - _
LocalTime -> 2017-10-20 14:42:47
Configuration ->
. broker -> amqp://guest:**@localhost:5672//
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 minutes (300s)
[2017-10-20 14:56:42,777: INFO/MainProcess] beat: Starting...
celery beat v4.1.0 (latentcall) is starting.
__ - ... __ - _
LocalTime -> 2017-10-20 14:56:42
Configuration ->
. broker -> amqp://guest:**@localhost:5672//
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 minutes (300s)
[2017-10-20 15:14:13,137: INFO/MainProcess] beat: Starting...
celery beat v4.1.0 (latentcall) is starting.
__ - ... __ - _
LocalTime -> 2017-10-20 15:14:13
Configuration ->
. broker -> amqp://guest:**@localhost:5672//
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 minutes (300s)
[2017-10-20 15:18:26,051: INFO/MainProcess] beat: Starting...
celery beat v4.1.0 (latentcall) is starting.
__ - ... __ - _
LocalTime -> 2017-10-20 15:18:26
Configuration ->
. broker -> amqp://guest:**@localhost:5672//
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 minutes (300s)
[2017-10-20 15:31:17,073: INFO/MainProcess] beat: Starting...
celery beat v4.1.0 (latentcall) is starting.
__ - ... __ - _
LocalTime -> 2017-10-20 15:31:17
Configuration ->
. broker -> amqp://guest:**@localhost:5672//
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 minutes (300s)
[2017-10-20 16:52:26,958: INFO/MainProcess] beat: Starting...
celery beat v4.1.0 (latentcall) is starting.
__ - ... __ - _
LocalTime -> 2017-10-20 16:52:26
Configuration ->
. broker -> amqp://guest:**@localhost:5672//
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 minutes (300s)
[2017-10-23 08:32:22,755: INFO/MainProcess] beat: Starting...
celery beat v4.1.0 (latentcall) is starting.
__ - ... __ - _
LocalTime -> 2017-10-23 08:32:22
Configuration ->
. broker -> amqp://guest:**@localhost:5672//
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 minutes (300s)

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-03-27 13:29
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('progress', '0008_auto_20180227_1803'),
]
operations = [
migrations.AddField(
model_name='progress',
name='is_freeze',
field=models.BooleanField(default=False, verbose_name='Прохождение было преостановленно'),
),
]

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-04-16 18:50
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('progress', '0009_progress_is_freeze'),
]
operations = [
migrations.AddField(
model_name='progress',
name='exp_date',
field=models.DateTimeField(blank=True, null=True, verbose_name='Дата сгорания'),
),
]

@ -12,9 +12,7 @@ class Progress(models.Model):
user = models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name='Студент')
course_token = models.UUIDField(verbose_name="Токен курса", editable=False)
is_finish = models.BooleanField(verbose_name="Окончен ли курс", default=False)
is_freeze = models.BooleanField(verbose_name="Прохождение было преостановленно", default=False)
only_watch = models.BooleanField(verbose_name="Только просмотр", default=False)
exp_date = models.DateTimeField(verbose_name='Дата сгорания', blank=True, null=True)
def progress_status(self, sorted_token_list):
"""

@ -1,8 +1,6 @@
from rest_framework import serializers
from progress.models import Progress, ProgressLesson
import jwt
from django.conf import settings
class ProgressSerializer(serializers.ModelSerializer):
@ -17,40 +15,6 @@ class ProgressSerializer(serializers.ModelSerializer):
return [ProgressLessonSerializer(i).data for i in self.progresslesson_set.all()]
class SupportProgressSerializer(serializers.ModelSerializer):
teacher_email = serializers.SerializerMethodField()
mod = serializers.SerializerMethodField()
class Meta:
model = Progress
fields = ('id', 'course_token', 'mod', 'teacher_email', "is_freeze")
@staticmethod
def get_teacher_email(self):
return self.teacher.email
@staticmethod
def get_mod(self):
return "Без дз" if self.only_watch else "Стандарт"
class SecureProgressSerializer(serializers.ModelSerializer):
jwt_token = serializers.SerializerMethodField()
class Meta:
model = Progress
fields = ('jwt_token', )
@staticmethod
def get_jwt_token(self):
payload = {
'lessons': [ProgressLessonSerializer(i).data for i in self.progresslesson_set.all()],
'course_token': str(self.course_token),
'only_watch': self.only_watch,
}
return jwt.encode(payload, settings.COURSE_PROGRESS_SECRET_KEY, algorithm='HS256')
class ProgressAnalyticSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField()
email = serializers.SerializerMethodField()
@ -83,8 +47,8 @@ class ProgressLessonSerializer(serializers.ModelSerializer):
@staticmethod
def get_student(self):
return {'name': self.progress.user.get_full_name(), "out_key": str(self.progress.user.out_key)}
return {'name': self.progress.user.get_full_name(), "out_key": self.progress.user.out_key}
@staticmethod
def get_course_token(self):
return str(self.progress.course_token)
return self.progress.course_token

@ -3,14 +3,9 @@ from django.conf.urls import url
from progress import views
urlpatterns = [
url(r'progress_dynamic/$', views.CourseProgressDynamicView.as_view()),
url(r'students/(?P<teacher_token>[0-9A-Fa-f-]+)/$', views.StudentWorkView.as_view()),
url(r'student/$', views.StudentUpdateProgress.as_view()),
url(r'find/$', views.FindProgressView.as_view()),
url(r'freeze/$', views.FreezeProgressView.as_view()),
url(r'change_teacher/$', views.ChangeTeacherView.as_view()),
url(r'teacher/$', views.TeacherUpdateProgress.as_view()),
url(r'set-progress/$', views.SetProgress.as_view()),
url(r'get_hw_pay/$', views.get_teachers_pay),
url(r'progress_token/$', views.ProgressToken.as_view()),
]

@ -1,11 +1,6 @@
import csv
import datetime
from django.db import IntegrityError
from django.shortcuts import redirect
from dateutil.relativedelta import relativedelta
from django.contrib import auth
from django.utils import timezone
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.core.mail import EmailMessage
@ -15,15 +10,11 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from django.db.models import Q, Count
import jwt
from django.conf import settings
from django.db.models import Q
from access.serializers import UserProgressSearchSerializer
from courses.models import Course, Lesson
from courses.models import Course
from progress.models import ProgressLesson, Progress
from progress.serializers import ProgressAnalyticSerializer, ProgressLessonSerializer, ProgressSerializer, \
SecureProgressSerializer
from progress.serializers import ProgressAnalyticSerializer, ProgressLessonSerializer, ProgressSerializer
from courses.api import CourseProgressApi, CourseParamsApi
from progress.tasks import add_next_lesson
@ -64,31 +55,19 @@ class CourseProgressDynamicView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def get(request):
course_token = request.GET.get('course_token', None)
from_date = int(request.GET.get('from', '7'))
to_date = int(request.GET.get('to', '0'))
def get(request, token):
if request.user.is_authenticated() and request.user.is_staff:
progresses = ProgressLesson.objects.filter(status='done')
if not course_token is None:
try:
progresses = progresses.filter(progress__course_token=course_token)
except ProgressLesson.DoesNotExist:
return Response('incorrect course token', status=404)
progresses = progresses.filter(finish_date__gt=timezone.now() - relativedelta(days=from_date))
progresses = progresses.filter(finish_date__lt=timezone.now() - relativedelta(days=to_date))
progresses = progresses.order_by('finish_date')
res = {}
progresses = progresses.extra({'finish_date_day': "date(finish_date)"})\
.values('progress__course_token', 'finish_date_day')\
.annotate(total=Count('progress'))
#TODO Доделать
try:
progresses = Progress.objects.filter(course_token=token)
res = {}
for i in progresses:
key = i.progresslesson_set.filter(status="done").count() + 1
res[key] = 1 if not key in res.keys() else res[key] + 1
return Response(res, status=200)
except ValidationError:
return Response("Bad request", status=400)
return Response(res, status=200)
return Response('Доступно только персоналу', status=403)
return Response(status=403)
class CourseProgressUserView(APIView):
@ -112,7 +91,6 @@ class CourseProgressUserView(APIView):
class TeacherUpdateProgress(APIView):
permission_classes = (permissions.IsAuthenticated, )
renderer_classes = (JSONRenderer,)
@staticmethod
@ -133,6 +111,7 @@ class TeacherUpdateProgress(APIView):
student = get_user_model().objects.get(out_key=student_out_key)
p = Progress.objects.get(
user=student,
teacher=request.user,
course_token=course_token,
)
@ -147,7 +126,7 @@ class TeacherUpdateProgress(APIView):
pv.status = ProgressLesson.STATUSES.fail
msg = EmailMessage(
'Ваша работа отправлена на доработку',
'''Преподаватель "%s" отклонил вашу работу''' % request.user.get_full_name(),
'''Преподователь "%s" отклонил вашу работу''' % request.user.get_full_name(),
'robo@skillbox.ru',
[student.email],
)
@ -196,52 +175,47 @@ class StudentUpdateProgress(APIView):
@staticmethod
def post(request):
lesson_token = request.JSON.get('lesson_token', None)
course_token = request.JSON.get('course_token', None)
comment = request.JSON.get('comment', None)
if lesson_token is None:
return Response('Не передан токен урока', status=400)
if lesson_token is None or course_token is None:
return Response('Не передан слаг курса или токен урока', status=400)
try:
student = request.user
student = request.user
p = Progress.objects.get(user=student, course_token=course_token)
try:
pv = ProgressLesson.objects.get(
progress__user=student,
lesson_token=lesson_token,
)
try:
pv = ProgressLesson.objects.get(
progress=p,
lesson_token=lesson_token,
)
if pv.status == ProgressLesson.STATUSES.done:
return Response(SecureProgressSerializer(pv.progress).data, status=200)
if not pv.status == ProgressLesson.STATUSES.wait:
if pv.checker == p.teacher and not comment is None:
pv.status = ProgressLesson.STATUSES.wait
pv.comment_tokens.append(comment)
if not pv.status == ProgressLesson.STATUSES.wait:
if pv.checker == pv.progress.user:
pv.status = ProgressLesson.STATUSES.done
pv.finish_date = datetime.datetime.now()
elif pv.checker == p.user:
pv.status = ProgressLesson.STATUSES.done
pv.finish_date = datetime.datetime.now()
elif not comment is None and\
not pv.progress.progresslesson_set.filter(status=ProgressLesson.STATUSES.wait).exists():
pv.status = ProgressLesson.STATUSES.wait
pv.comment_tokens.append(comment)
msg = EmailMessage(
'Студент оставил комментарий',
'''Студент "%s" оставил вам комментарий.''' % request.user.get_full_name(),
'robo@skillbox.ru',
[pv.checker.email],
)
msg.send()
else:
raise ValueError("Этого никогда не должно происходить, но я уверен, что произойдёт")
elif comment is None:
return Response("Не преложен комментарий", status=400)
pv.save()
else:
return Response("В настоящее время, мы уже проверяем одно из ваших домашних заданий. <br> Как "
"только оно будет успешно сдано - вы сможете продолжить.", status=403)
return Response("Ошибка прав доступа", status=403)
elif not comment is None:
pv.comment_tokens.append(comment)
except ProgressLesson.DoesNotExist:
return Response('Урок не проходится этим пользователем', status=403)
pv.save()
if pv.status == ProgressLesson.STATUSES.done:
# TODO: Ассинхроннаязадача для celery
add_next_lesson(p)
return Response(SecureProgressSerializer(pv.progress).data, status=200)
return Response(ProgressSerializer(p).data, status=200)
except Progress.DoesNotExist:
return Response('Не найден прогресс по заданным параметрам', status=404)
@ -275,74 +249,36 @@ class UploadCourseProgressUserView(APIView):
return Response(status=403)
class FindProgressView(APIView):
class UserGuardView(APIView):
renderer_classes = (JSONRenderer,)
permission_classes = (IsAuthenticated,)
@staticmethod
def get(request):
if not request.user.is_staff:
return Response("Только сотрудники персонала могут запрашивать инфо по прогрессу", status=403)
key = request.GET.get('key', None)
count = int(request.GET.get('count', '10'))
if key:
res = get_user_model().objects.filter(
Q(id__contains=key) | Q(email__contains=key.lower()) | Q(first_name__contains=key) |
Q(last_name__contains=key) | Q(account__phone__contains=key)
)
else:
res = get_user_model().objects.all()
res = res[:(count if len(res) > count else len(res))]
return Response([UserProgressSearchSerializer(i).data for i in res], status=200)
class FreezeProgressView(APIView):
renderer_classes = (JSONRenderer,)
permission_classes = (IsAuthenticated,)
@staticmethod
def post(request):
if not request.user.is_staff:
return Response("Только сотрудники персонала могут вносить изменение в прогресс", status=403)
key = request.JSON.get('id', None)
is_freeze = request.JSON.get('is_freeze', False)
def get(request, pk, page):
try:
p = Progress.objects.get(id=key)
p.is_freeze = is_freeze
p.save()
except Progress.DoesNotExist:
return Response("не найден прогресс по заданному id", status=404)
user = get_user_model().objects.get(out_key=pk)
except get_user_model().DoesNotExist:
return Response("User doesn't exist", status=404)
return Response(status=204)
is_i = request.user == user
res_403 = Response('Permission denied', status=403)
res_204 = Response(status=204)
if is_i and not request.user.groups.filter(name='teachers').exists() and page == 'homeworks':
return res_403
class ChangeTeacherView(APIView):
renderer_classes = (JSONRenderer,)
permission_classes = (IsAuthenticated,)
if is_i and not \
request.user.groups.filter(name__in=['students', 'managers', 'lead_managers']).exists() \
and page == 'payment':
return res_403
@staticmethod
def post(request):
if not request.user.is_staff:
return Response("Только сотрудники персонала могут вносить изменение в прогресс", status=403)
key = request.JSON.get('id', None)
teacher_email = request.JSON.get('teacher_email', False)
if is_i:
return res_204
try:
p = Progress.objects.get(id=key)
try:
teacher = get_user_model().objects.get(email=teacher_email.lower())
except get_user_model().DoesNotExist:
return Response("Нет пользователя c таким email", status=404)
p.teacher = teacher
p.progresslesson_set.filter(status=ProgressLesson.STATUSES.wait).update(checker=teacher)
p.save()
except Progress.DoesNotExist:
return Response("не найден прогресс по заданному id", status=404)
if page == 'profile' and (request.user.is_superuser or request.user.is_staff):
return res_204
return Response(status=204)
return res_403
class SetProgress(APIView):
@ -356,7 +292,6 @@ class SetProgress(APIView):
course_slug = request.JSON.get('course_slug', None)
topic_sort = int(request.JSON.get('topic', 1))
lesson_sort = int(request.JSON.get('lesson', 1))
only_watch = request.JSON.get('only_watch', False)
force = request.JSON.get('force', False)
if course_slug is None:
@ -384,9 +319,6 @@ class SetProgress(APIView):
teacher = get_user_model().objects.get(out_key=course.get_teacher())
progress = Progress.objects.create(course_token=course.token, user=student, teacher=teacher)
progress.only_watch = only_watch
progress.save()
token_list = []
lesson_list = []
for topic_idx, topic in enumerate(course.topic_set.all()):
@ -467,63 +399,16 @@ def get_teachers_pay(request):
response['Content-Disposition'] = 'attachment; filename="%s.csv"' % file_name
writer = csv.writer(response)
writer.writerow(['Почта студента', 'Имя студента', 'Тема', 'Курс', 'Дата', 'Время',])
writer.writerow(['Почта студента', 'Имя студента', 'Курс', 'Дата', 'Время',])
for i in progress_lessons.order_by('-finish_date'):
course_api = CourseParamsApi(i.progress.course_token)
writer.writerow([
i.progress.user.email,
i.progress.user.get_full_name(),
#TODO очередной костыль
Lesson.objects.get(token=i.lesson_token).topic.title,
course_api.get_slug_and_title()['title'],
i.finish_date.date(),
i.finish_date.time(),
])
return response
class ProgressToken(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def get(request):
token = request.GET.get('token', None)
if token is None:
return Response("bad request", 400)
payload = jwt.decode(token, settings.COURSE_PROGRESS_SECRET_KEY, algorithms=['HS256'])
try:
user = get_user_model().objects.get(email=payload['email'].lower())
except get_user_model().DoesNotExist:
user = get_user_model().objects.create_student(email=payload['email'].lower())
user.is_active = True
user.save()
try:
course = Course.objects.get(token=payload['course_token'])
except get_user_model().DoesNotExist:
return Response("Course doesn't exist", status=404)
teacher = get_user_model().objects.get(out_key=course.get_teacher())
try:
p = Progress.objects.create(
user=user,
course_token=payload['course_token'],
teacher=teacher,
exp_date=timezone.now() + relativedelta(days=int(payload['period'])),
)
ProgressLesson.objects.create(
progress=p,
lesson_token=course.get_first_lesson().token,
checker=p.user,
)
except IntegrityError:
pass
auth.login(request, user)
return redirect('/')

@ -1,6 +1,3 @@
import base64
import json
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
@ -47,19 +44,12 @@ class CommentView(APIView):
@staticmethod
def get(request):
base64_tokens = request.GET.get('base64_tokens', None)
token = request.GET.get('token', None)
if not base64_tokens:
if not token:
return Response("Attribute token not set", status=400)
tokens = json.loads(base64.b64decode(base64_tokens).decode('utf-8'))
comments = []
for token in tokens:
try:
comment = Comment.objects.get(token=token)
comments.append(comment)
except Comment.DoesNotExist:
pass
return Response([CommentSerializer(comment).data for comment in comments], status=200)
try:
return Response(CommentSerializer(Comment.objects.get(token=token)).data, status=200)
except Comment.DoesNotExist:
return Response("Comment not found", status=404)

@ -1,6 +0,0 @@
<div> Выставлен новый счет </div>
<div> Пользователь: {{ user_email }} </div>
<div> Продавец: {{ opener_full_name }} </div>
<div> Курс: {{ course_title }} </div>
<div> Дата продажи: {{ date }} </div>
<div> Сумма: {{ price }} руб. </div>

@ -1,7 +0,0 @@
<div> Успешный платёж </div>
<div> Пользователь: {{ user_email }} </div>
<div> Продавец: {{ opener_full_name }} </div>
<div> Курс: {{ course_title }} </div>
<div> Дата продажи: {{ date }} </div>
<div> Дата оплаты: {{ finish_date }} </div>
<div> Сумма: {{ price }} руб. </div>

@ -1,57 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Тестовый платёж</title>
</head>
<body>
<div>
Номер карты: 4444 4444 4444 4448 <br>
Действует до: любой год и месяц в будущем <br>
Код CVV: 000 <br>
Больше инфы
<a href="https://tech.yandex.ru/money/doc/payment-solution/examples/examples-test-data-docpage/" target="_blank">
В доке
</a><br>
Отправление формы срабатывает только раз затем нужно будет заменить orderNumber
</div>
<br><br><br>
<form action="https://demomoney.yandex.ru/eshop.xml" method="post" target="_blank">
<table>
<tr>
<td>shopId</td>
<td><input name="shopId" value="{{ shop_id }}" type="text"></td>
</tr>
<tr>
<td>scid</td>
<td><input name="scid" value="{{ sc_id }}" type="text"></td>
</tr>
<tr>
<td>sum</td>
<td><input name="sum" value="100.50" type="text"></td>
</tr>
<tr>
<td>customerNumber</td>
<td><input name="customerNumber" value="abc000" type="text"/></td>
</tr>
<tr>
<td>orderNumber</td>
<td><input name="orderNumber" value="{{ order_number }}" type="text"/></td>
</tr>
<tr>
<td>cps_phone</td>
<td><input name="cps_phone" value="79110000000" type="text"/></td>
</tr>
<tr>
<td>cps_email</td>
<td><input name="cps_email" value="{{ user_email }}" type="text"/></td>
</tr>
<tr>
<td>rebillingOn</td>
<td><input name="rebillingOn" value="false" type="text"/></td>
</tr>
</table>
<input type="submit" value="Заплатить"/>
</form>
</body>
</html>
Loading…
Cancel
Save