diff --git a/access/migrations/0004_invite_password.py b/access/migrations/0004_invite_password.py new file mode 100644 index 0000000..5cf47c2 --- /dev/null +++ b/access/migrations/0004_invite_password.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.6 on 2017-12-08 18:14 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('access', '0003_auto_20171129_1639'), + ] + + operations = [ + migrations.AddField( + model_name='invite', + name='password', + field=models.CharField(blank=True, max_length=63, null=True), + ), + ] diff --git a/access/migrations/0005_auto_20171208_1820.py b/access/migrations/0005_auto_20171208_1820.py new file mode 100644 index 0000000..2960a9b --- /dev/null +++ b/access/migrations/0005_auto_20171208_1820.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.6 on 2017-12-08 18:20 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('access', '0004_invite_password'), + ] + + operations = [ + migrations.AlterField( + model_name='invite', + name='date', + field=models.DateTimeField(blank=True, null=True, verbose_name='Дата сгорания приглошения'), + ), + migrations.AlterField( + model_name='invite', + name='hash', + field=models.CharField(max_length=15, verbose_name='Уникальный код'), + ), + migrations.AlterField( + model_name='invite', + name='owner', + field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Кому приглошение'), + ), + migrations.AlterField( + model_name='invite', + name='password', + field=models.CharField(blank=True, max_length=63, null=True, verbose_name='Новый пароль, если есть'), + ), + ] diff --git a/access/migrations/0006_auto_20171208_1849.py b/access/migrations/0006_auto_20171208_1849.py new file mode 100644 index 0000000..cf87187 --- /dev/null +++ b/access/migrations/0006_auto_20171208_1849.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.6 on 2017-12-08 18:49 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('access', '0005_auto_20171208_1820'), + ] + + operations = [ + migrations.AlterField( + model_name='invite', + name='hash', + field=models.CharField(max_length=15, unique=True, verbose_name='Уникальный код'), + ), + ] diff --git a/access/models/other.py b/access/models/other.py index 38cbce8..87ef350 100644 --- a/access/models/other.py +++ b/access/models/other.py @@ -5,10 +5,12 @@ from courses.models import Course, Vertex from maps.models import CourseRoute from django.db.models import Q + class Invite(models.Model): - owner = models.OneToOneField(to=settings.AUTH_USER_MODEL, null=True) - hash = models.CharField(max_length=15) - date = models.DateTimeField(null=True, blank=True) + owner = models.OneToOneField(to=settings.AUTH_USER_MODEL, verbose_name="Кому приглошение", null=True) + hash = models.CharField(verbose_name="Уникальный код", max_length=15, unique=True) + date = models.DateTimeField(verbose_name="Дата сгорания приглошения", null=True, blank=True) + password = models.CharField(max_length=63, verbose_name="Новый пароль, если есть", blank=True, null=True) class Meta: verbose_name = 'Приглошение в систему' diff --git a/access/views.py b/access/views.py index db4fbdc..51bf92c 100644 --- a/access/views.py +++ b/access/views.py @@ -1,5 +1,9 @@ +import random +import string + from django.contrib.auth import get_user_model from django.contrib import auth +from django.core.mail import send_mail from django.shortcuts import redirect from rest_framework.permissions import IsAuthenticated from rest_framework.views import APIView @@ -32,6 +36,40 @@ class CheckUserView(APIView): return Response('anonymous', status=200) +class ResetPasswordView(APIView): + renderer_classes = (JSONRenderer,) + + @staticmethod + def post(request): + if not request.user.is_authenticated(): + email = request.JSON.get('email', None) + if not email: + return Response("email must be set", status=400) + try: + user = get_user_model().objects.get(email=email) + try: + invite = Invite.objects.get(password__isnull=False, owner=user) + except Invite.DoesNotExist: + invite = Invite.objects.create( + owner=user, + hash=''.join(random.choice(string.ascii_letters) for _x in range(15)), + password=''.join(random.choice(string.ascii_letters) for _x in range(8)), + ) + send_mail( + subject="Сброс пароля", + message=''' + Ваш новый пароль %s, (в последствии вы сможите сменить его в личном кабинете), + если вы не отправляли заявку на сброс пароля просто проигнорируйте это сообщение, + для подтверждения регистрации смены пароля перейдите по ссылке + https://go.skillbox.ru/api/v1/users/reset/?hash=%s''' % (invite.password, invite.hash), + from_email='robo@skillbox.ru', + recipient_list=[user.email], + ) + return Response(status=204) + except get_user_model().DoesNotExist: + return Response("user doesn't exist", status=404) + + class FindUserView(APIView): renderer_classes = (JSONRenderer,) status_code = 200 @@ -98,7 +136,7 @@ class RegistrationView(APIView): @staticmethod def get(request): try: - invite = Invite.objects.get(hash=request.GET['hash']) + invite = Invite.objects.get(hash=request.GET['hash'], password__isnull=True) invite.owner.is_active = True invite.owner.save() auth.login(request, invite.owner) @@ -110,7 +148,7 @@ class RegistrationView(APIView): @staticmethod def post(request): try: - user = get_user_model().objects.get(email=request.JSON['email'].lower()) + get_user_model().objects.get(email=request.JSON['email'].lower()) return Response('user already exist', status=403) except get_user_model().DoesNotExist: password = request.JSON.get('password')