From eabc1745d14cde3ad14ca02d38bb78818f79e387 Mon Sep 17 00:00:00 2001 From: Dmitriy Shesterkin Date: Tue, 6 Mar 2018 16:10:19 +0300 Subject: [PATCH 01/26] change test for new code --- access/views.py | 2 +- config_app/settings/test.env | 1 - tests/test_user.py | 6 +++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/access/views.py b/access/views.py index 5915943..09930b2 100644 --- a/access/views.py +++ b/access/views.py @@ -13,7 +13,7 @@ from django.shortcuts import redirect from rest_framework.renderers import JSONRenderer from rest_framework.response import Response from rest_framework.views import APIView -from rest_framework import permissions, generics, status +from rest_framework import permissions, generics from access.models.other import Invite, ResetPassword, Account from access.serializers import (UserSelfSerializer, UserSearchSerializer) diff --git a/config_app/settings/test.env b/config_app/settings/test.env index 5b922cf..ad176a0 100644 --- a/config_app/settings/test.env +++ b/config_app/settings/test.env @@ -1,4 +1,3 @@ -DEBUG=True SECRET_KEY='!eiquy7_+2#vn3z%zfp51$m-=tmvtcv*cj*@x$!v(_9btq0w=$' DATABASE_URL='psql://postgres@127.0.0.1:5432/test_lms' EMAIL_URL='smtp+tls://9ae31a1a770138:a7d79ee373a14c@smtp.mailtrap.io:2525' diff --git a/tests/test_user.py b/tests/test_user.py index b85b636..f755ca2 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -9,7 +9,7 @@ from rest_framework.generics import get_object_or_404 @pytest.mark.django_db -@mock.patch('django.core.mail.send_mail') +@mock.patch('django.core.mail.EmailMessage.send') def test_generate_password_by_manager(mocked_send_mail, staff_client, student_client, user_student): """ @@ -53,7 +53,7 @@ def test_generate_password_by_manager(mocked_send_mail, staff_client, assert staff_client.post( reverse('users:management-password'), data=wrong_email, - status=status.HTTP_400_BAD_REQUEST + status=status.HTTP_404_NOT_FOUND ) @@ -70,5 +70,5 @@ def test_generate_password_by_manager_for_not_active_student(staff_client, assert staff_client.post( reverse('users:management-password'), data=data, - status=status.HTTP_400_BAD_REQUEST + status=status.HTTP_201_CREATED ) From 80cc25a92aebe65a16df3de9ed6249b61845d6e7 Mon Sep 17 00:00:00 2001 From: Dmitriy Shesterkin Date: Tue, 6 Mar 2018 16:15:35 +0300 Subject: [PATCH 02/26] del test env --- .gitignore | 1 + config_app/settings/test.env | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 config_app/settings/test.env diff --git a/.gitignore b/.gitignore index f55a249..a385b2b 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ coverage.xml # Celery celerybeat-schedule /config_app/settings/dev.env +/config_app/settings/test.env diff --git a/config_app/settings/test.env b/config_app/settings/test.env deleted file mode 100644 index ad176a0..0000000 --- a/config_app/settings/test.env +++ /dev/null @@ -1,4 +0,0 @@ -SECRET_KEY='!eiquy7_+2#vn3z%zfp51$m-=tmvtcv*cj*@x$!v(_9btq0w=$' -DATABASE_URL='psql://postgres@127.0.0.1:5432/test_lms' -EMAIL_URL='smtp+tls://9ae31a1a770138:a7d79ee373a14c@smtp.mailtrap.io:2525' -CACHE_URL=rediscache://127.0.0.1:6379/1?client_class=django_redis.client.DefaultClient \ No newline at end of file From 3679d31293a9617a22110491c7611fc1188eb7a7 Mon Sep 17 00:00:00 2001 From: Dmitriy Shesterkin Date: Tue, 6 Mar 2018 22:37:52 +0300 Subject: [PATCH 03/26] add some test for login user, set master password in envirement var, some fixes for task when user not found --- access/urls.py | 2 +- access/views.py | 14 ++++++--- factories/users.py | 19 ++++++++++++ lms/settings.py | 4 +++ tests/fixtures/images/simple.jpg | Bin 0 -> 17751 bytes tests/fixtures/users.py | 5 +++- tests/test_user.py | 50 +++++++++++++++++++++++++++++++ 7 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 tests/fixtures/images/simple.jpg diff --git a/access/urls.py b/access/urls.py index 579905d..416cf7b 100644 --- a/access/urls.py +++ b/access/urls.py @@ -14,7 +14,7 @@ urlpatterns = [ url(r'find/$', views.FindUserView.as_view()), url(r'registration/$', views.RegistrationView.as_view()), url(r'change_password/$', views.ChangePasswordView.as_view()), - url(r'login/$', views.LoginView.as_view()), + url(r'login/$', views.LoginView.as_view(), name='login'), url(r'logout/$', views.LogoutView.as_view()), url(r'reset/$', views.ResetPasswordView.as_view()), url(r'progress_detail/upload/(?P[0-9A-Fa-f-]+)/$', progress.views.UploadCourseProgressUserView.as_view()), diff --git a/access/views.py b/access/views.py index 09930b2..146364c 100644 --- a/access/views.py +++ b/access/views.py @@ -250,18 +250,24 @@ class LoginView(APIView): email = request.JSON.get('email').lower() user = None if not request.user.is_authenticated(): - if not password == "@J*1": - user = auth.authenticate(email=email, password=request.JSON.get('password')) + 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("User doesn't exist", status=404) + return Response("Аккаунт не найден", status=404) try: auth.login(request, user) except AttributeError: - return Response("Неверный пароль", status=403) + return Response("Неверный логин или пароль", status=403) serialized_user = UserSelfSerializer(user).data serialized_user['is_i'] = True diff --git a/factories/users.py b/factories/users.py index a3c859f..e89a055 100644 --- a/factories/users.py +++ b/factories/users.py @@ -1,3 +1,4 @@ +import os import pytz import factory @@ -6,9 +7,11 @@ import factory.fuzzy from functools import partial from django.contrib.auth import get_user_model +from django.conf import settings USER_PASSWORD = 'test' +AVATAR_SAMPLE_IMAGE = os.path.join(settings.IMAGE_SAMPLES_DIR, 'simple.jpg') Faker = partial(factory.Faker, locale='ru_RU') @@ -28,3 +31,19 @@ class UserFactory(factory.django.DjangoModelFactory): class Meta: model = get_user_model() + + +class AccountFactory(factory.django.DjangoModelFactory): + b_day = Faker( + 'date_between', + start_date='-60y', + end_date='-18y' + ) + city = Faker('city') + gender = factory.fuzzy.FuzzyChoice(range(1, 2)) + owner = factory.SubFactory(UserFactory) + photo = factory.django.ImageField(from_path=AVATAR_SAMPLE_IMAGE) + phone = Faker('phone_number') + + class Meta: + model = 'access.Account' diff --git a/lms/settings.py b/lms/settings.py index ff764b8..4040ad5 100644 --- a/lms/settings.py +++ b/lms/settings.py @@ -11,6 +11,8 @@ env = environ.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') @@ -253,3 +255,5 @@ SWAGGER_SETTINGS = { 'JSON_EDITOR': True, 'DOC_EXPANSION': 'list' } + +IMAGE_SAMPLES_DIR = os.path.join(BASE_DIR, 'tests', 'fixtures', 'images') diff --git a/tests/fixtures/images/simple.jpg b/tests/fixtures/images/simple.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5dfea4cd05a9f299ae37fdb2374f82fe1cb724cf GIT binary patch literal 17751 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 B{Z;?~ literal 0 HcmV?d00001 diff --git a/tests/fixtures/users.py b/tests/fixtures/users.py index 8116bd7..7c95a99 100644 --- a/tests/fixtures/users.py +++ b/tests/fixtures/users.py @@ -1,6 +1,6 @@ import pytest -from factories.users import UserFactory +from factories.users import UserFactory, AccountFactory @pytest.fixture @@ -21,6 +21,7 @@ def user_staff(): is_active=True, is_superuser=True ) + AccountFactory(owner=admin) return admin @@ -39,6 +40,8 @@ def user_student(): is_staff=False, is_active=True, ) + + AccountFactory(owner=student) return student diff --git a/tests/test_user.py b/tests/test_user.py index f755ca2..5afc79d 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -7,6 +7,8 @@ from django.urls import reverse from rest_framework import status from rest_framework.generics import get_object_or_404 +from factories.users import USER_PASSWORD + @pytest.mark.django_db @mock.patch('django.core.mail.EmailMessage.send') @@ -72,3 +74,51 @@ def test_generate_password_by_manager_for_not_active_student(staff_client, data=data, status=status.HTTP_201_CREATED ) + + +@pytest.mark.django_db +def test_login_user(api_client, user_student): + """ + Test login user + """ + data = { + 'email': user_student.email, + 'password': USER_PASSWORD + } + assert api_client.post( + reverse('users:login'), + data=data, + status=status.HTTP_200_OK + ) + + +@pytest.mark.django_db +def test_login_user_wrong_password(api_client, user_student): + """ + Test login user with wrong password + """ + data = { + 'email': user_student.email, + 'password': USER_PASSWORD + '1' + } + assert api_client.post( + reverse('users:login'), + data=data, + status=status.HTTP_403_FORBIDDEN + ) + + +@pytest.mark.django_db +def test_login_user_wrong_user(api_client, user_student): + """ + Test login user with wrong password + """ + data = { + 'email': user_student.email + '1', + 'password': USER_PASSWORD + } + assert api_client.post( + reverse('users:login'), + data=data, + status=status.HTTP_404_NOT_FOUND + ) From c708310e432c772c46af20bc2053c91d0e7de9c5 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 15 Mar 2018 13:56:08 +0300 Subject: [PATCH 04/26] storage update --- finance/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/finance/models.py b/finance/models.py index 9516873..ae56954 100755 --- a/finance/models.py +++ b/finance/models.py @@ -44,7 +44,7 @@ class Invoice(models.Model): ) status = models.CharField(verbose_name='Статус', max_length=1, default='W', choices=BILL_STATUSES) price = models.IntegerField(verbose_name='Сумма', editable=False, null=True, blank=True) - real_price = models.IntegerField(verbose_name='Полученная сумма', null=True, blank=True, + real_price = models.FloatField(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) From 6de90bb28629c33f87aaa7963903c679b2e998b6 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 15 Mar 2018 14:00:00 +0300 Subject: [PATCH 05/26] pay --- finance/migrations/0003_auto_20180315_1358.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 finance/migrations/0003_auto_20180315_1358.py diff --git a/finance/migrations/0003_auto_20180315_1358.py b/finance/migrations/0003_auto_20180315_1358.py new file mode 100644 index 0000000..67c8bd1 --- /dev/null +++ b/finance/migrations/0003_auto_20180315_1358.py @@ -0,0 +1,20 @@ +# -*- 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='Полученная сумма'), + ), + ] From 084d8661724876220dadc8e2226fcfad431aa894 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 15 Mar 2018 14:46:24 +0300 Subject: [PATCH 06/26] pay --- progress/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress/views.py b/progress/views.py index 842a3ec..50d2b61 100644 --- a/progress/views.py +++ b/progress/views.py @@ -190,7 +190,7 @@ class StudentUpdateProgress(APIView): ) if pv.status == ProgressLesson.STATUSES.done: - Response(SecureProgressSerializer(pv.progress).data, status=200) + return Response(SecureProgressSerializer(pv.progress).data, status=200) if not pv.status == ProgressLesson.STATUSES.wait: if pv.checker == pv.progress.user: From fad1ac9b0419988a0125705457326653e5463bcb Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 15 Mar 2018 16:30:40 +0300 Subject: [PATCH 07/26] pay --- finance/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/finance/views.py b/finance/views.py index c97513f..c6bdf3c 100644 --- a/finance/views.py +++ b/finance/views.py @@ -269,7 +269,7 @@ class YandexAvisoView(APIView): 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) + logger_yandex.info('Get success pay with invoice_id(yandex) %s' % str(data['invoiceId'])) pay.shop_amount = data['shopSumAmount'] pay.status = Payment.STATUS.SUCCESS From 35c0f4c5916ef4c5cb7b0c4e0d796ed3e520c52f Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 15 Mar 2018 17:30:59 +0300 Subject: [PATCH 08/26] pay --- finance/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/finance/views.py b/finance/views.py index c6bdf3c..e83f7d5 100644 --- a/finance/views.py +++ b/finance/views.py @@ -273,6 +273,8 @@ class YandexAvisoView(APIView): pay.shop_amount = data['shopSumAmount'] pay.status = Payment.STATUS.SUCCESS + now = timezone.now() + pay.performed_datetime = now.isoformat() pay.save() xml_res = """ """ % (pay.performed_datetime, str(data['invoiceId']), str(pay.shop_id)) From 0adfde03b42d5caf3968271d176976d2c3a6fe90 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 15 Mar 2018 18:38:01 +0300 Subject: [PATCH 09/26] pay --- finance/signals.py | 5 +++-- finance/views.py | 29 ++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/finance/signals.py b/finance/signals.py index 110a4f5..bd8d330 100644 --- a/finance/signals.py +++ b/finance/signals.py @@ -36,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()) @@ -54,6 +54,7 @@ def invoice_signal(instance, **kwargs): % (course.title, settings.DOMAIN, course.slug), 'robo@skillbox.ru', [instance.bill.user.email], + bcc=[instance.bill.opener.email], reply_to=[instance.bill.opener.email], ) else: @@ -62,7 +63,7 @@ def invoice_signal(instance, **kwargs): '''Курс "%s" был забронирован''' % course.title, 'robo@skillbox.ru', [instance.bill.user.email], - cc=[instance.bill.opener.email], + bcc=[instance.bill.opener.email], reply_to=[instance.bill.opener.email], ) msg.send() diff --git a/finance/views.py b/finance/views.py index e83f7d5..8ae4166 100644 --- a/finance/views.py +++ b/finance/views.py @@ -1,10 +1,9 @@ import csv import logging -import datetime -import dicttoxml import requests from django.contrib.auth import get_user_model +from django.core.mail import EmailMessage from django.db.models import Q from django.http import HttpResponse, HttpResponseForbidden from django.shortcuts import redirect @@ -14,6 +13,7 @@ from rest_framework.views import APIView from yandex_money.models import Payment from django.conf import settings +from courses.models import Course from courses.api import CourseParamsApi from finance.models import Bill, Invoice from finance.serializers import BillSerializer, InvoiceSerializer @@ -237,9 +237,6 @@ class YandexCheckView(APIView): % (pay.order_amount, data['orderSumAmount'])) return Response(status=204) - # TODO Нужно решение - # pay.invoice_id = int(data['invoiceId']) - # pay.save() now = timezone.now() pay.performed_datetime = now.isoformat() pay.save() @@ -249,6 +246,17 @@ class YandexCheckView(APIView): logger_yandex.info(xml_res) + msg = EmailMessage( + 'Списание средств с карты пользователя.', + '''Пользователь "%s", переволит %s рублей. Номер платежа в яндекс кассе %s''' + % (pay.invoice.bill.user.email, str(pay.invoice.real_price), str(data['invoiceId'])), + 'robo@skillbox.ru', + [pay.invoice.bill.opener.email], + bcc='dmitry.dolya@skillbox.ru', + ) + + msg.send() + return HttpResponse(xml_res, content_type='application/xml') @@ -281,6 +289,17 @@ class YandexAvisoView(APIView): logger_yandex.info(xml_res) + msg = EmailMessage( + 'Успешная оплата.', + '''Пользователь "%s", перевёл %s рублей. Номер платежа в яндекс кассе %s''' + % (pay.invoice.bill.user.email, str(pay.invoice.price), str(data['invoiceId'])), + 'robo@skillbox.ru', + [pay.invoice.bill.opener.email], + bcc='dmitry.dolya@skillbox.ru', + ) + + msg.send() + return HttpResponse(xml_res, content_type='application/xml') From fa7261821c54376c4e75868213c7f110286056f9 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 15 Mar 2018 18:44:54 +0300 Subject: [PATCH 10/26] pay --- finance/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/finance/views.py b/finance/views.py index 8ae4166..9d52610 100644 --- a/finance/views.py +++ b/finance/views.py @@ -252,7 +252,7 @@ class YandexCheckView(APIView): % (pay.invoice.bill.user.email, str(pay.invoice.real_price), str(data['invoiceId'])), 'robo@skillbox.ru', [pay.invoice.bill.opener.email], - bcc='dmitry.dolya@skillbox.ru', + bcc=['dmitry.dolya@skillbox.ru'], ) msg.send() @@ -295,7 +295,7 @@ class YandexAvisoView(APIView): % (pay.invoice.bill.user.email, str(pay.invoice.price), str(data['invoiceId'])), 'robo@skillbox.ru', [pay.invoice.bill.opener.email], - bcc='dmitry.dolya@skillbox.ru', + bcc=['dmitry.dolya@skillbox.ru'], ) msg.send() From 8da2c4205d4ef4f4e50c0f37de871d71fccb93cb Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 15 Mar 2018 18:53:19 +0300 Subject: [PATCH 11/26] pay --- finance/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/finance/views.py b/finance/views.py index 9d52610..3c03ac0 100644 --- a/finance/views.py +++ b/finance/views.py @@ -292,7 +292,7 @@ class YandexAvisoView(APIView): msg = EmailMessage( 'Успешная оплата.', '''Пользователь "%s", перевёл %s рублей. Номер платежа в яндекс кассе %s''' - % (pay.invoice.bill.user.email, str(pay.invoice.price), str(data['invoiceId'])), + % (pay.invoice.bill.user.email, str(pay.shop_amount), str(data['invoiceId'])), 'robo@skillbox.ru', [pay.invoice.bill.opener.email], bcc=['dmitry.dolya@skillbox.ru'], From 53cb094345c7307c18005449e6beac33d5e6566a Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 16 Mar 2018 11:41:54 +0300 Subject: [PATCH 12/26] pay --- finance/views.py | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/finance/views.py b/finance/views.py index 3c03ac0..1656baa 100644 --- a/finance/views.py +++ b/finance/views.py @@ -71,6 +71,21 @@ class BillListView(APIView): invoice.yandex_pay = yandex_pay invoice.save() + msg = EmailMessage( + 'Выставден новый счёт.', + '''Менеджер %s выставил счёт пользователю %s на курс "%s".''' + % ( + invoice.bill.opener.full_name(), + invoice.bill.user.email, + Course.objects.get(invoice.bill.course_token).title, + ), + 'robo@skillbox.ru', + [invoice.bill.opener.email], + bcc=['dmitry.dolya@skillbox.ru'], + ) + + msg.send() + invoices = [j for j in invoices if not j.id == invoice.id] [i.delete() for i in invoices] @@ -159,6 +174,17 @@ class YandexPay(APIView): 'shopFailURL': settings.YANDEX_MONEY_FAIL_URL, }) + msg = EmailMessage( + 'Пользователь перешёл на страницу оплаты.', + '''Пользователь "%s", переводит %s рублей.''' + % (pay.invoice.bill.user.email, str(pay.invoice.real_price)), + 'robo@skillbox.ru', + [pay.invoice.bill.opener.email], + bcc=['dmitry.dolya@skillbox.ru'], + ) + + msg.send() + return redirect(r.url) except Payment.DoesNotExist: @@ -177,8 +203,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(date__lt=date_to) if date_to else invoices - invoices = invoices.filter(date__gte=date_from) if date_from else invoices + 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 response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename="%s.csv"' % file_name @@ -189,8 +215,8 @@ def get_invoices(request): for i in invoices.order_by('-date'): course_api = CourseParamsApi(i.bill.course_token) writer.writerow([ - i.date.date(), - i.date.time(), + i.yandex_pay.performed_datetime.date(), + i.yandex_pay.performed_datetime.time(), i.bill.user.email, i.bill.user.get_full_name(), course_api.get_slug_and_title()['title'], @@ -246,17 +272,6 @@ class YandexCheckView(APIView): logger_yandex.info(xml_res) - msg = EmailMessage( - 'Списание средств с карты пользователя.', - '''Пользователь "%s", переволит %s рублей. Номер платежа в яндекс кассе %s''' - % (pay.invoice.bill.user.email, str(pay.invoice.real_price), str(data['invoiceId'])), - 'robo@skillbox.ru', - [pay.invoice.bill.opener.email], - bcc=['dmitry.dolya@skillbox.ru'], - ) - - msg.send() - return HttpResponse(xml_res, content_type='application/xml') From 19021a4eab12a51cfdc0fb526c330002ebc70888 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 16 Mar 2018 11:50:03 +0300 Subject: [PATCH 13/26] pay --- finance/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/finance/views.py b/finance/views.py index 1656baa..9b99799 100644 --- a/finance/views.py +++ b/finance/views.py @@ -75,7 +75,7 @@ class BillListView(APIView): 'Выставден новый счёт.', '''Менеджер %s выставил счёт пользователю %s на курс "%s".''' % ( - invoice.bill.opener.full_name(), + invoice.bill.opener.get_full_name(), invoice.bill.user.email, Course.objects.get(invoice.bill.course_token).title, ), From a11d6c698fe21c322614fe34c8508ec524c1b99b Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 16 Mar 2018 12:04:18 +0300 Subject: [PATCH 14/26] pay --- finance/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/finance/views.py b/finance/views.py index 9b99799..d43b591 100644 --- a/finance/views.py +++ b/finance/views.py @@ -77,7 +77,7 @@ class BillListView(APIView): % ( invoice.bill.opener.get_full_name(), invoice.bill.user.email, - Course.objects.get(invoice.bill.course_token).title, + Course.objects.get(token=invoice.bill.course_token).title, ), 'robo@skillbox.ru', [invoice.bill.opener.email], From f1b91d347ed3d003bf8546e948ba309c762a607b Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 16 Mar 2018 12:13:38 +0300 Subject: [PATCH 15/26] pay --- finance/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/finance/views.py b/finance/views.py index d43b591..c0f9505 100644 --- a/finance/views.py +++ b/finance/views.py @@ -72,7 +72,7 @@ class BillListView(APIView): invoice.save() msg = EmailMessage( - 'Выставден новый счёт.', + 'Выставлен новый счёт.', '''Менеджер %s выставил счёт пользователю %s на курс "%s".''' % ( invoice.bill.opener.get_full_name(), @@ -176,8 +176,8 @@ class YandexPay(APIView): msg = EmailMessage( 'Пользователь перешёл на страницу оплаты.', - '''Пользователь "%s", переводит %s рублей.''' - % (pay.invoice.bill.user.email, str(pay.invoice.real_price)), + '''Пользователь "%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'], From b4d4402c73897db372e0b9f8c9ec081c6a3888b5 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 16 Mar 2018 13:23:21 +0300 Subject: [PATCH 16/26] pay --- finance/views.py | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/finance/views.py b/finance/views.py index c0f9505..98a0725 100644 --- a/finance/views.py +++ b/finance/views.py @@ -42,24 +42,40 @@ class BillListView(APIView): or request.user.is_superuser): 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'] + user = get_user_model().objects.get(email=bill['user']) + opener = get_user_model().objects.get(email=bill['opener']) + description = bill['description'] + comment = bill['comment'] + course_token = bill['course_token'] + + try: + bill_obj = Bill.objects.get(user=user, course_token=course_token) + except Bill.DoesNotExist: + bill_obj = Bill.objects.create(user=user, course_token=course_token) + + bill_obj.opener = opener + bill_obj.description = description + bill_obj.comment = comment + bill_obj.save() - 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) + status = get_real_name(elem=i['status'], array=Invoice.BILL_STATUSES) + try: + invoice = Invoice.objects.get(id=i['id']) + if invoice.status == "P" or invoice.status == status: + continue + + except Invoice.DoesNotExist: + i['method'] = get_real_name(elem=i['method'], array=Invoice.BILL_METHOD) + i['status'] = status + i['bill'] = bill_obj + i['yandex_pay'] = None + invoice = Invoice.objects.create(**i) + if i['method'] == 'Y' and invoice.yandex_pay is None: yandex_pay = Payment.objects.create( order_amount=i['price'], From 9364171ac05c618b1cc7f3ce1ad5a67305442b74 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 16 Mar 2018 13:30:50 +0300 Subject: [PATCH 17/26] pay --- finance/views.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/finance/views.py b/finance/views.py index 98a0725..800786c 100644 --- a/finance/views.py +++ b/finance/views.py @@ -60,8 +60,6 @@ class BillListView(APIView): bill_obj.comment = comment bill_obj.save() - invoices = bill_obj.invoice_set.all() - for i in children: status = get_real_name(elem=i['status'], array=Invoice.BILL_STATUSES) try: @@ -102,10 +100,6 @@ class BillListView(APIView): msg.send() - 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()], From 3c28c27bd55b9665187571c9e2129b63e4fb7ef7 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 16 Mar 2018 13:37:04 +0300 Subject: [PATCH 18/26] pay --- finance/views.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/finance/views.py b/finance/views.py index 800786c..5d6f2ae 100644 --- a/finance/views.py +++ b/finance/views.py @@ -63,9 +63,17 @@ class BillListView(APIView): for i in children: status = get_real_name(elem=i['status'], array=Invoice.BILL_STATUSES) try: - invoice = Invoice.objects.get(id=i['id']) - if invoice.status == "P" or invoice.status == status: - continue + invoice_id = i['id'] + except KeyError: + invoice_id = None + + try: + if not invoice_id is None: + invoice = Invoice.objects.get(id=i['id']) + if invoice.status == "P" or invoice.status == status: + continue + else: + raise Invoice.DoesNotExist except Invoice.DoesNotExist: i['method'] = get_real_name(elem=i['method'], array=Invoice.BILL_METHOD) From 36fce7172c9f71c2b78454c3276f323b0ad397b2 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 16 Mar 2018 15:42:10 +0300 Subject: [PATCH 19/26] pay --- finance/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/finance/views.py b/finance/views.py index 5d6f2ae..c785ca9 100644 --- a/finance/views.py +++ b/finance/views.py @@ -325,7 +325,7 @@ class YandexAvisoView(APIView): msg = EmailMessage( 'Успешная оплата.', '''Пользователь "%s", перевёл %s рублей. Номер платежа в яндекс кассе %s''' - % (pay.invoice.bill.user.email, str(pay.shop_amount), str(data['invoiceId'])), + % (pay.invoice.bill.user.email, str(pay.invoice.price), str(data['invoiceId'])), 'robo@skillbox.ru', [pay.invoice.bill.opener.email], bcc=['dmitry.dolya@skillbox.ru'], From 9293ae5697c0824d98ee300b15f2fa16fff50659 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 16 Mar 2018 18:11:21 +0300 Subject: [PATCH 20/26] pay --- finance/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/finance/views.py b/finance/views.py index c785ca9..ea823cb 100644 --- a/finance/views.py +++ b/finance/views.py @@ -328,7 +328,7 @@ class YandexAvisoView(APIView): % (pay.invoice.bill.user.email, str(pay.invoice.price), str(data['invoiceId'])), 'robo@skillbox.ru', [pay.invoice.bill.opener.email], - bcc=['dmitry.dolya@skillbox.ru'], + bcc=['dmitry.dolya@skillbox.ru', 'vera.procenko@skillbox.ru'], ) msg.send() From 71fd94d61faf63f5c120b87c48c06102adabafca Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 19 Mar 2018 17:50:22 +0300 Subject: [PATCH 21/26] pay --- courses/serializers.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/courses/serializers.py b/courses/serializers.py index 359386b..e4fe7ce 100644 --- a/courses/serializers.py +++ b/courses/serializers.py @@ -1,3 +1,4 @@ +from django.contrib.auth import get_user_model from rest_framework import serializers from courses.models import Course, Lesson, Topic @@ -82,11 +83,16 @@ class CourseDetailSerializer(serializers.ModelSerializer): level = serializers.SerializerMethodField() direction = serializers.SerializerMethodField() statistic = serializers.SerializerMethodField() + teacher_emails = serializers.SerializerMethodField() class Meta: model = Course exclude = ('id', ) + @staticmethod + def get_teacher_emails(self): + return [get_user_model().objects.get(out_key=i).email for i in self.teacher_tokens] + @staticmethod def get_level(self): return self.get_level_display() From 77bcaa95f6c39d5df6085d919c1d39fc758fd1ba Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 19 Mar 2018 17:55:59 +0300 Subject: [PATCH 22/26] pay --- courses/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/courses/serializers.py b/courses/serializers.py index e4fe7ce..139b545 100644 --- a/courses/serializers.py +++ b/courses/serializers.py @@ -91,7 +91,7 @@ class CourseDetailSerializer(serializers.ModelSerializer): @staticmethod def get_teacher_emails(self): - return [get_user_model().objects.get(out_key=i).email for i in self.teacher_tokens] + return [i.email for i in get_user_model().objects.filter(out_key__in=self.teacher_tokens)] @staticmethod def get_level(self): From 63ccf9f0853ffde282b3a11b23ff3819a565c69f Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 19 Mar 2018 18:13:20 +0300 Subject: [PATCH 23/26] pay --- courses/serializers.py | 6 ------ courses/views.py | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/courses/serializers.py b/courses/serializers.py index 139b545..359386b 100644 --- a/courses/serializers.py +++ b/courses/serializers.py @@ -1,4 +1,3 @@ -from django.contrib.auth import get_user_model from rest_framework import serializers from courses.models import Course, Lesson, Topic @@ -83,16 +82,11 @@ class CourseDetailSerializer(serializers.ModelSerializer): level = serializers.SerializerMethodField() direction = serializers.SerializerMethodField() statistic = serializers.SerializerMethodField() - teacher_emails = serializers.SerializerMethodField() class Meta: model = Course exclude = ('id', ) - @staticmethod - def get_teacher_emails(self): - return [i.email for i in get_user_model().objects.filter(out_key__in=self.teacher_tokens)] - @staticmethod def get_level(self): return self.get_level_display() diff --git a/courses/views.py b/courses/views.py index 1a6138b..5db4617 100644 --- a/courses/views.py +++ b/courses/views.py @@ -89,7 +89,7 @@ class LessonInfoView(APIView): lesson = Lesson.objects.get(token=token) except Lesson.DoesNotExist: return Response('Урок не найден', status=404) - if request.user.is_authenticated and request.user.out_key in lesson.topic.course.teacher_tokens: + if request.user.is_authenticated: return Response(TeacherLessonSerializer(lesson).data, self.status_code) return Response("Пользователь не является преподователем по курсу", status=403) From a0fc46bdb2acb5743f2e9beb20663c331cdfbcd1 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 20 Mar 2018 11:40:42 +0300 Subject: [PATCH 24/26] pay --- progress/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress/views.py b/progress/views.py index 50d2b61..01513e8 100644 --- a/progress/views.py +++ b/progress/views.py @@ -127,7 +127,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], ) From 8c4aec26fad06cbae5a3b5e6182bd6fe28c92987 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 20 Mar 2018 11:55:20 +0300 Subject: [PATCH 25/26] pay --- finance/views.py | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/finance/views.py b/finance/views.py index ea823cb..0020e53 100644 --- a/finance/views.py +++ b/finance/views.py @@ -257,28 +257,41 @@ class YandexCheckView(APIView): val = i.split('=')[1] data[key] = val - logger_yandex.info(data) + logger_yandex.info('Проверка платежа запрос', exc_info=True, extra={ + 'request': data, + }) + try: pay = Payment.objects.get(order_number=data['orderNumber']) except Payment.DoesNotExist: - logger_yandex.error("Payment with id=%s not found" % data['orderNumber']) + logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={ + 'request': "Payment with id=%s not found" % data['orderNumber'], + }) return Response(status=204) if not pay.status == Payment.STATUS.PROCESSED: - logger_yandex.error("Payment with id=%s have status %s" % (data['orderNumber'], pay.status)) + logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={ + 'request': "Payment with id=%s have status %s" % (data['orderNumber'], pay.status), + }) return Response(status=204) if not pay.shop_id == int(data['shopId']): - logger_yandex.error("ShopId=%s not match" % (data['shopId'],)) + logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={ + 'request': "ShopId=%s not match" % (data['shopId'],), + }) return Response(status=204) if not pay.scid == int(data['scid']): - logger_yandex.error("scid=%s not match" % (data['scid'],)) + logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={ + 'request': "scid=%s not match" % (data['scid'],) + }) return Response(status=204) if not pay.order_amount == float(data['orderSumAmount']): - logger_yandex.error("Expected amount is %s received amount is %s" - % (pay.order_amount, data['orderSumAmount'])) + logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={ + 'request': "Expected amount is %s received amount is %s" + % (pay.order_amount, data['orderSumAmount']), + }) return Response(status=204) now = timezone.now() @@ -288,7 +301,9 @@ class YandexCheckView(APIView): xml_res = """ """ % (pay.performed_datetime, str(data['invoiceId']), str(pay.shop_id)) - logger_yandex.info(xml_res) + logger_yandex.info('Проверка платежа ответ', exc_info=True, extra={ + 'request': xml_res, + }) return HttpResponse(xml_res, content_type='application/xml') From a3a5011a06fb2a498026378229d8354de12aee35 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 20 Mar 2018 12:07:28 +0300 Subject: [PATCH 26/26] finance logging --- finance/views.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/finance/views.py b/finance/views.py index 0020e53..4a4de84 100644 --- a/finance/views.py +++ b/finance/views.py @@ -302,7 +302,7 @@ class YandexCheckView(APIView): """ % (pay.performed_datetime, str(data['invoiceId']), str(pay.shop_id)) logger_yandex.info('Проверка платежа ответ', exc_info=True, extra={ - 'request': xml_res, + 'response': xml_res, }) return HttpResponse(xml_res, content_type='application/xml') @@ -322,10 +322,14 @@ class YandexAvisoView(APIView): try: pay = Payment.objects.get(order_number=data['orderNumber']) except Payment.DoesNotExist: - logger_yandex.error("Payment with invoice_id=%s not found" % data['orderNumber']) + logger_yandex.error('Ошибка подтверждения платежа', exc_info=True, extra={ + 'request': "Payment with invoice_id=%s not found" % data['orderNumber'], + }) return Response(status=204) - logger_yandex.info('Get success pay with invoice_id(yandex) %s' % str(data['invoiceId'])) + logger_yandex.info('Подтверждение платежа запрос', exc_info=True, extra={ + 'request': 'Get success pay with invoice_id(yandex) %s' % str(data['invoiceId']), + }) pay.shop_amount = data['shopSumAmount'] pay.status = Payment.STATUS.SUCCESS @@ -335,7 +339,10 @@ class YandexAvisoView(APIView): xml_res = """ """ % (pay.performed_datetime, str(data['invoiceId']), str(pay.shop_id)) - logger_yandex.info(xml_res) + logger_yandex.info('Подтверждение платежа ответ', exc_info=True, extra={ + 'response': xml_res, + }) + msg = EmailMessage( 'Успешная оплата.',