diff --git a/apps/course/migrations/0021_auto_20180205_1559.py b/apps/course/migrations/0021_auto_20180205_1559.py new file mode 100644 index 00000000..c4a6a6de --- /dev/null +++ b/apps/course/migrations/0021_auto_20180205_1559.py @@ -0,0 +1,35 @@ +# Generated by Django 2.0.2 on 2018-02-05 15:59 + +from django.db import migrations +from django.contrib.contenttypes.models import ContentType + + +def fwrd_func(apps, schema_editor): + CourseComment = apps.get_model('course', 'CourseComment') + LessonComment = apps.get_model('course', 'LessonComment') + db_alias = schema_editor.connection.alias + if CourseComment.objects.exists(): + coursecomment_content_type = ContentType.objects.get( + app_label='course', model='coursecomment', + ) + CourseComment.objects.using(db_alias).all().update( + polymorphic_ctype=coursecomment_content_type, + ) + if LessonComment.objects.exists(): + lessoncomment_content_type = ContentType.objects.get( + app_label='course', model='lessoncomment', + ) + LessonComment.objects.using(db_alias).all().update( + polymorphic_ctype=lessoncomment_content_type, + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ('course', '0020_auto_20180202_1716'), + ] + + operations = [ + migrations.RunPython(fwrd_func) + ] diff --git a/apps/course/migrations/0022_auto_20180205_1615.py b/apps/course/migrations/0022_auto_20180205_1615.py new file mode 100644 index 00000000..87bc49b7 --- /dev/null +++ b/apps/course/migrations/0022_auto_20180205_1615.py @@ -0,0 +1,35 @@ +# Generated by Django 2.0.2 on 2018-02-05 16:15 + +from django.db import migrations +from django.contrib.contenttypes.models import ContentType + + +def fwrd_func(apps, schema_editor): + CourseComment = apps.get_model('course', 'CourseComment') + LessonComment = apps.get_model('course', 'LessonComment') + db_alias = schema_editor.connection.alias + if CourseComment.objects.using(db_alias).all().exists(): + coursecomment_content_type = ContentType.objects.get( + app_label='course', model='coursecomment', + ) + CourseComment.objects.using(db_alias).all().update( + polymorphic_ctype=coursecomment_content_type, + ) + if LessonComment.objects.using(db_alias).all().exists(): + lessoncomment_content_type = ContentType.objects.get( + app_label='course', model='lessoncomment', + ) + LessonComment.objects.using(db_alias).all().update( + polymorphic_ctype=lessoncomment_content_type, + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ('course', '0021_auto_20180205_1559'), + ] + + operations = [ + migrations.RunPython(fwrd_func) + ] diff --git a/apps/course/templates/course/_items.html b/apps/course/templates/course/_items.html index 13de9f80..fe9a5a3d 100644 --- a/apps/course/templates/course/_items.html +++ b/apps/course/templates/course/_items.html @@ -7,7 +7,11 @@ {% if course.is_deferred_start %}data-future-course data-future-course-time={{ course.deferred_start_at.timestamp }}{% endif %} > + {% if course.cover %} + {% else %} + + {% endif %}
Подробнее
{% if course.is_featured %}
diff --git a/apps/user/forms.py b/apps/user/forms.py new file mode 100644 index 00000000..697d3910 --- /dev/null +++ b/apps/user/forms.py @@ -0,0 +1,49 @@ +from django import forms +from django.contrib.auth import get_user_model + +User = get_user_model() + + +class UserEditForm(forms.ModelForm): + # first_name = forms.CharField() + # last_name = forms.CharField() + # email = forms.CharField() + # city = forms.CharField() + # country = forms.CharField() + birthday = forms.DateField(input_formats=['%d.%m.%Y']) + # gender = forms.ChoiceField(choices=User.GENDER_CHOICES, required=False) + gender = forms.CharField(required=False) + # about = forms.CharField() + old_password = forms.CharField(required=False) + new_password1 = forms.CharField(required=False) + new_password2 = forms.CharField(required=False) + instagram = forms.URLField(required=False) + facebook = forms.URLField(required=False) + twitter = forms.URLField(required=False) + pinterest = forms.URLField(required=False) + youtube = forms.URLField(required=False) + vkontakte = forms.URLField(required=False) + photo = forms.ImageField(required=False) + + class Meta: + model = User + fields = ( + 'first_name', + 'last_name', + 'email', + 'city', + 'country', + 'birthday', + 'gender', + 'about', + 'old_password', + 'new_password1', + 'new_password2', + 'instagram', + 'facebook', + 'twitter', + 'pinterest', + 'youtube', + 'vkontakte', + 'photo', + ) diff --git a/apps/user/migrations/0005_user_birthday.py b/apps/user/migrations/0005_user_birthday.py new file mode 100644 index 00000000..479a9294 --- /dev/null +++ b/apps/user/migrations/0005_user_birthday.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.2 on 2018-02-06 13:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0004_auto_20180129_1259'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='birthday', + field=models.DateField(blank=True, null=True, verbose_name='День рождения'), + ), + ] diff --git a/apps/user/migrations/0006_auto_20180206_1352.py b/apps/user/migrations/0006_auto_20180206_1352.py new file mode 100644 index 00000000..b65c014a --- /dev/null +++ b/apps/user/migrations/0006_auto_20180206_1352.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.2 on 2018-02-06 13:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0005_user_birthday'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='about', + field=models.CharField(blank=True, max_length=1000, null=True, verbose_name='О себе'), + ), + ] diff --git a/apps/user/migrations/0007_auto_20180207_0808.py b/apps/user/migrations/0007_auto_20180207_0808.py new file mode 100644 index 00000000..98dd1616 --- /dev/null +++ b/apps/user/migrations/0007_auto_20180207_0808.py @@ -0,0 +1,23 @@ +# Generated by Django 2.0.2 on 2018-02-07 08:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0006_auto_20180206_1352'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='city', + field=models.CharField(blank=True, max_length=85, null=True, verbose_name='Город'), + ), + migrations.AlterField( + model_name='user', + name='country', + field=models.CharField(blank=True, max_length=50, null=True, verbose_name='Страна'), + ), + ] diff --git a/apps/user/models.py b/apps/user/models.py index 7a59786c..141073ce 100644 --- a/apps/user/models.py +++ b/apps/user/models.py @@ -13,17 +13,21 @@ class User(AbstractUser): (AUTHOR_ROLE, 'автор'), (ADMIN_ROLE, 'администратор'), ) + NOT_DEFINED = 'n' + MALE = 'm' + FEMALE = 'f' GENDER_CHOICES = ( - ('n', 'не указан'), - ('m', 'Мужчина'), - ('f', 'Женщина'), + (NOT_DEFINED, 'не указан'), + (MALE, 'Мужчина'), + (FEMALE, 'Женщина'), ) email = models.EmailField(_('email address'), unique=True) role = models.PositiveSmallIntegerField('Роль', default=0, choices=ROLE_CHOICES) gender = models.CharField('Пол', max_length=1, default='n', choices=GENDER_CHOICES) - country = models.CharField('Страна', max_length=50, default='') - city = models.CharField('Город', max_length=85, default='') - about = models.CharField('О себе', max_length=1000, default='', blank=True) + birthday = models.DateField('День рождения', null=True, blank=True) + country = models.CharField('Страна', max_length=50, null=True, blank=True) + city = models.CharField('Город', max_length=85, null=True, blank=True) + about = models.CharField('О себе', max_length=1000, null=True, blank=True) instagram = models.URLField(default='', null=True, blank=True) facebook = models.URLField(default='', null=True, blank=True) twitter = models.URLField(default='', null=True, blank=True) diff --git a/apps/user/templates/user/profile-settings.html b/apps/user/templates/user/profile-settings.html new file mode 100644 index 00000000..4af4e6ba --- /dev/null +++ b/apps/user/templates/user/profile-settings.html @@ -0,0 +1,209 @@ +{% extends "templates/lilcity/index.html" %} {% load static %} {% block content %} +
+
+ +
+
+{% comment %} + +{% endcomment %} +{% if messages %} +
+
+ {% for message in messages %} +
{{ message }}
+ {% endfor %} +
+
+{% endif %} +{{form.errors}} +
+
+
+
+ {% csrf_token %} +
+
Личные данные
+
+ {% if user.photo %} + + {% else %} + + {% endif %} + +
+ + + +
+
+
+
+
ИМЯ
+
+ +
+
+
+
ФАМИЛИЯ
+
+ +
+
+
+
+
Почта
+
+ +
+
+
+
+
ГОРОД
+
+ +
+
+
+
СТРАНА
+
+ +
+
+
+
+
+
ДАТА РОЖДЕНИЯ
+
+ +
+
+
+
ПОЛ
+
+
+
+ {% if user.gender == 'f' %}Ж{% elif user.gender == 'm' %}M{% else %}М / Ж{% endif %} +
+
+
+
М
+
+
+
Ж
+
+
+ +
+
+
+
+
+
О себе
+
+ +
+
+
+
+
Пароль
+
+
ТЕКУЩИЙ ПАРОЛЬ
+
+ +
+
+
+
НОВЫЙ ПАРОЛЬ
+
+ +
+
+
+
ПОДТВЕРДИТЬ НОВЫЙ ПАРОЛЬ
+
+ +
+
+
+
+
Соцсети
+
+
INSTAGRAM
+
+ +
+
+
+
FACEBOOK
+
+ +
+
+
+
TWITTER
+
+ +
+
+
+
PINTEREST
+
+ +
+
+
+
YOUTUBE
+
+ +
+
+
+
VKONTAKTE
+
+ +
+
+
+
+ +
+
+
+
+
+ +{% endblock content %} \ No newline at end of file diff --git a/apps/user/templates/user/profile.html b/apps/user/templates/user/profile.html index 2142dca5..c4085f29 100644 --- a/apps/user/templates/user/profile.html +++ b/apps/user/templates/user/profile.html @@ -2,7 +2,7 @@
- Редактировать + Редактировать {% if user.photo %}
diff --git a/apps/user/views.py b/apps/user/views.py index 18d7c9ce..3b3f1daa 100644 --- a/apps/user/views.py +++ b/apps/user/views.py @@ -1,9 +1,20 @@ -from django.shortcuts import render -from django.views.generic import DetailView +from io import BytesIO +from PIL import Image +from os.path import splitext +from django.contrib.auth import login +from django.shortcuts import render, reverse +from django.views.generic import DetailView, UpdateView +from django.contrib import messages from django.contrib.auth import get_user_model +from django.contrib.auth.decorators import login_required, permission_required +from django.contrib.auth.hashers import check_password, make_password +from django.http import Http404 +from django.utils.decorators import method_decorator from apps.course.models import Course +from .forms import UserEditForm + User = get_user_model() @@ -13,6 +24,65 @@ class UserView(DetailView): def get_context_data(self, object): context = super().get_context_data() - context['published'] = Course.objects.filter(author=self.object, status=Course.PUBLISHED) + context['published'] = Course.objects.filter( + author=self.object, status=Course.PUBLISHED + ) context['paid'] = Course.objects.none() return context + + +class UserEditView(UpdateView): + model = User + template_name = 'user/profile-settings.html' + form_class = UserEditForm + + @method_decorator(login_required) + def dispatch(self, request, *args, **kwargs): + self.object = self.get_object() + if request.user != self.object: + raise Http404() + return super().dispatch(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + # it's magic *-*-*-*-* + if 'photo' in request.FILES: + photo_fp = request.FILES.pop('photo')[0] + fname = photo_fp.name + photo = Image.open(photo_fp) + lowest_side = min(photo.size) + horizontal_padding = (lowest_side - photo.size[0]) / 2 + vertical_padding = (lowest_side - photo.size[1]) / 2 + photo = photo.crop( + ( + -horizontal_padding, + -vertical_padding, + photo.size[0] + horizontal_padding, + photo.size[1] + vertical_padding + ) + ) + if photo.size[0] > 512: + photo = photo.resize((512, 512,)) + buffer = BytesIO() + ext = splitext(fname)[1][1:].upper() + if ext == 'JPG': + ext = 'JPEG' + photo.save(buffer, ext) + self.object.photo.save(fname, buffer) + buffer.close() + if not request.POST._mutable: + request.POST._mutable = True + old_password = request.POST.pop('old_password')[0] + new_password1 = request.POST.pop('new_password1')[0] + new_password2 = request.POST.pop('new_password2')[0] + if old_password: + if request.user.check_password(old_password) and new_password1 == new_password2: + request.user.set_password(new_password1) + request.user.save() + login(request, request.user) + else: + messages.error(request, 'Неверный пароль.') + messages.info(request, 'Данные сохранены.') + return super().post(request, *args, **kwargs) + + def get_success_url(self): + return reverse('user-edit', args=[self.object.id]) diff --git a/docker-compose.yml b/docker-compose.yml index 9465b2a4..f42e5b6b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,7 +22,7 @@ services: restart: always volumes: - .:/lilcity - command: bash -c "python manage.py migrate && python manage.py loaddata /lilcity/apps/*/fixtures/*.json && python manage.py runserver 0.0.0.0:8000 && celery worker -A project -Q web" + command: bash -c "python manage.py migrate && python manage.py loaddata /lilcity/apps/*/fixtures/*.json && python manage.py runserver 0.0.0.0:8000 && celery worker -A project" environment: - DJANGO_SETTINGS_MODULE=project.settings - DATABASE_SERVICE_HOST=db diff --git a/project/settings.py b/project/settings.py index 17c6ec7e..a450d5b2 100644 --- a/project/settings.py +++ b/project/settings.py @@ -162,7 +162,7 @@ STATICFILES_DIRS = [ MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, "media") - +LOGIN_URL = '/' # Email # https://github.com/anymail/django-anymail diff --git a/project/templates/lilcity/index.html b/project/templates/lilcity/index.html index 7b068127..43ae104b 100644 --- a/project/templates/lilcity/index.html +++ b/project/templates/lilcity/index.html @@ -33,7 +33,7 @@ - +