diff --git a/apps/notification/management/__init__.py b/apps/notification/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/notification/management/commands/__init__.py b/apps/notification/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/notification/management/commands/send_certificates.py b/apps/notification/management/commands/send_certificates.py new file mode 100644 index 00000000..ee1e4b3b --- /dev/null +++ b/apps/notification/management/commands/send_certificates.py @@ -0,0 +1,73 @@ +from django.core.management.base import BaseCommand +from email.mime.image import MIMEImage +from django.contrib.staticfiles.storage import staticfiles_storage +from django.utils.timezone import now +from django.contrib.auth import get_user_model + +from apps.notification.models import UserNotification +from apps.notification.utils import send_email +from apps.payment.models import Payment, SchoolPayment, CoursePayment + + +User = get_user_model() + + +class Command(BaseCommand): + help = 'Send certificates at the end of subscription' + + def add_arguments(self, parser): + # Named (optional) arguments + parser.add_argument( + '--email', + dest='email', + help='Test email', + ) + parser.add_argument( + '--dry-run', + action='store_true', + dest='dry_run', + help='Only display emails', + ) + + def handle(self, *args, **options): + path_pattern = 'img/user-certificates/%d.jpg' + if options.get('email'): + file = open(staticfiles_storage.path(path_pattern % 1), 'rb') + try: + send_email('Грамота от Lil School', options['email'], 'notification/email/certificate.html', + attachments=[(file.name, file.read(), 'image/jpeg')]) + except: + pass + else: + print('Email has been sent') + finally: + file.close() + return + + today = now().date() + users = SchoolPayment.objects.filter(date_end=today, add_days=False).values_list('user_id', flat=True) + user_notifications_qs = UserNotification.objects.filter(user_id__in=users) + user_notifications = {un.user.id: un for un in user_notifications_qs} + notified_users = user_notifications_qs.filter(certificate_last_email__date=today).values_list('user_id', flat=True) + for user_id in users: + if user_id in notified_users: + continue + un = user_notifications.get(user_id, UserNotification(user_id=user_id)) + print(un.user.email) + if options.get('dry_run'): + continue + + un.certificate_number = un.certificate_number + 1 \ + if un.certificate_number and staticfiles_storage.exists(path_pattern % (un.certificate_number + 1)) \ + else 1 + file = open(staticfiles_storage.path(path_pattern % un.certificate_number), 'rb') + try: + send_email('Грамота от Lil School', un.user.email, 'notification/email/certificate.html', + attachments=[(file.name, file.read(), 'image/jpeg')]) + except: + print('Not OK') + continue + finally: + file.close() + un.certificate_last_email = now() + un.save() diff --git a/apps/notification/migrations/0001_initial.py b/apps/notification/migrations/0001_initial.py new file mode 100644 index 00000000..f531bd53 --- /dev/null +++ b/apps/notification/migrations/0001_initial.py @@ -0,0 +1,26 @@ +# Generated by Django 2.0.6 on 2018-10-02 03:38 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='UserNotification', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('certificate_number', models.SmallIntegerField(blank=True, null=True)), + ('certificate_last_email', models.DateTimeField(blank=True, null=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/apps/notification/models.py b/apps/notification/models.py new file mode 100644 index 00000000..6aa5d513 --- /dev/null +++ b/apps/notification/models.py @@ -0,0 +1,11 @@ +from django.db import models +from django.contrib.auth import get_user_model + + +User = get_user_model() + + +class UserNotification(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + certificate_number = models.SmallIntegerField(blank=True, null=True) + certificate_last_email = models.DateTimeField(blank=True, null=True) diff --git a/apps/notification/templates/notification/email/certificate.html b/apps/notification/templates/notification/email/certificate.html new file mode 100644 index 00000000..051a2d94 --- /dev/null +++ b/apps/notification/templates/notification/email/certificate.html @@ -0,0 +1,28 @@ +{% extends "notification/email/_base.html" %} + +{% block content %} +

Дорогие родители!

+
+

Это письмо адресовано вашим детям - ученикам Lil School. + Если они еще не умеют читать, прочитайте им наше послание, громко и с выражением.
+ Спасибо! +

+
+
+ Привет, друг!
+ Вот и прошёл месяц обучения на платформе «Lil School» - месяц удивительных, творческих приключений и открытий. + Ты так много узнал и столько всего нарисовал! + Как же здорово у тебя все получается! +
+
+ Скорее смотри что прикреплено к письму. Да это же ГРАМОТА! Ее можно распечатать и повесить + на видное место в твоей комнате. + Можно показать ее друзьям вместе со всеми работами, над которыми ты так трудился. +
+
+ Поздравляем! Мы ждём тебя в новом месяце в рядах наших учеников. +
+
+ Команда «Lil School». +
+{% endblock content %} diff --git a/apps/notification/utils.py b/apps/notification/utils.py index c04b3c0e..d556bd96 100644 --- a/apps/notification/utils.py +++ b/apps/notification/utils.py @@ -7,9 +7,9 @@ from project.celery import app @app.task -def send_email(subject, to_email, template_name, **kwargs): +def send_email(subject, to_email, template_name, attachments=[], **kwargs): html = get_template(template_name).render(kwargs) - email = EmailMessage(subject, html, to=[to_email]) + email = EmailMessage(subject, html, to=[to_email], attachments=attachments) email.content_subtype = 'html' email.send() diff --git a/apps/payment/migrations/0024_auto_20181002_0338.py b/apps/payment/migrations/0024_auto_20181002_0338.py new file mode 100644 index 00000000..a3f72da9 --- /dev/null +++ b/apps/payment/migrations/0024_auto_20181002_0338.py @@ -0,0 +1,17 @@ +# Generated by Django 2.0.6 on 2018-10-02 03:38 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('payment', '0023_payment_bonus'), + ] + + operations = [ + migrations.AlterModelOptions( + name='userbonus', + options={'ordering': ('created_at',)}, + ), + ] diff --git a/web/src/img/user-certificates/1.jpg b/web/src/img/user-certificates/1.jpg new file mode 100644 index 00000000..8a939423 Binary files /dev/null and b/web/src/img/user-certificates/1.jpg differ diff --git a/web/src/img/user-certificates/2.jpg b/web/src/img/user-certificates/2.jpg new file mode 100644 index 00000000..85687bad Binary files /dev/null and b/web/src/img/user-certificates/2.jpg differ diff --git a/web/src/img/user-certificates/3.jpg b/web/src/img/user-certificates/3.jpg new file mode 100644 index 00000000..ae7f1f76 Binary files /dev/null and b/web/src/img/user-certificates/3.jpg differ diff --git a/web/src/img/user-certificates/4.jpg b/web/src/img/user-certificates/4.jpg new file mode 100644 index 00000000..bc09d1ce Binary files /dev/null and b/web/src/img/user-certificates/4.jpg differ diff --git a/web/src/img/user-certificates/5.jpg b/web/src/img/user-certificates/5.jpg new file mode 100644 index 00000000..3add7a60 Binary files /dev/null and b/web/src/img/user-certificates/5.jpg differ diff --git a/web/src/img/user-certificates/6.jpg b/web/src/img/user-certificates/6.jpg new file mode 100644 index 00000000..cbbd4eaa Binary files /dev/null and b/web/src/img/user-certificates/6.jpg differ diff --git a/web/src/img/user-certificates/7.jpg b/web/src/img/user-certificates/7.jpg new file mode 100644 index 00000000..203e09b8 Binary files /dev/null and b/web/src/img/user-certificates/7.jpg differ diff --git a/web/src/img/user-certificates/8.jpg b/web/src/img/user-certificates/8.jpg new file mode 100644 index 00000000..3c048f76 Binary files /dev/null and b/web/src/img/user-certificates/8.jpg differ diff --git a/web/src/img/user-certificates/9.jpg b/web/src/img/user-certificates/9.jpg new file mode 100644 index 00000000..34e8d728 Binary files /dev/null and b/web/src/img/user-certificates/9.jpg differ diff --git a/web/webpack.config.js b/web/webpack.config.js index f91b4e9e..7455fec9 100644 --- a/web/webpack.config.js +++ b/web/webpack.config.js @@ -12,7 +12,8 @@ module.exports = { contestRedactor: "./src/js/contest-redactor.js", mixpanel: "./src/js/third_party/mixpanel-2-latest.js", sprite: glob('./src/icons/*.svg'), - images: glob('./src/img/*'), + images: glob('./src/img/*.*'), + imagesCertificates: glob('./src/img/user-certificates/*'), fonts: glob('./src/fonts/*') }, output: { @@ -84,9 +85,14 @@ module.exports = { }, { test: /\.(png|gif|jpg|svg)$/, - exclude: path.resolve(__dirname, 'src/icons'), + exclude: [path.resolve(__dirname, 'src/icons'), path.resolve(__dirname, 'src/img/user-certificates')], loader: 'file-loader?name=[name].[ext]&outputPath=./img/' }, + { + test: /\.(png|jpg)$/, + include: path.resolve(__dirname, 'src/img/user-certificates'), + loader: 'file-loader?name=[name].[ext]&outputPath=./img/user-certificates/' + }, { test: /\.(ttf|otf|eot|woff(2)?)(\?[a-z0-9]+)?$/, loader: 'file-loader?name=[name].[ext]'