Merge branch 'master' of gitlab.com:lilschool/site into feature/packages-page-1-08-19

remotes/origin/feature/packages-page-1-08-19
gzbender 7 years ago
commit 407590f5a1
  1. 49
      apps/auth/templates/auth/login.html
  2. 44
      apps/auth/templates/auth/password_reset.html
  3. 14
      apps/auth/templates/auth/password_reset_email.html
  4. 0
      apps/auth/templates/auth/password_reset_email.txt
  5. 102
      apps/auth/templates/auth/registration-learner.html
  6. 33
      apps/auth/views.py
  7. 7
      apps/payment/tasks.py
  8. 70
      project/settings.py
  9. 5
      project/templates/blocks/user_menu.html
  10. 46
      project/templates/lilcity/index.html
  11. 5
      web/src/js/modules/auth.js

@ -0,0 +1,49 @@
{% extends "templates/lilcity/layer.html" %} {% load static %}
{% block layer_body %}
<div class="outer js-outer">
{% include "templates/blocks/header.html" with no_auth_btn=True %}
<div id="lilcity-vue-app" class="container">
<div class="section">
<div class="section__center center" style="max-width: 400px;">
<div class="title">Авторизация</div>
<form id="learner-auth-form" method="post" action="{% url 'lilcity:login' %}" data-no-ajax="1">
{% csrf_token %}
<div id="learner-auth-field__username" class="auth__field field learner-auth-form__field">
<div class="field__label">ПОЧТА</div>
<div class="field__wrap">
<input id="learner-auth-form__email" class="field__input" type="email" name="username" placeholder="name@website.com"
tabindex="1" value="{{ form.username.value|default:'' }}" />
</div>
{% for error in form.username.errors %}
<div class="field__error learner-auth-form__field-error" style="display: block;">{{ error }}</div>
{% endfor %}
</div>
<div id="learner-auth-field__password" class="auth__field field learner-auth-form__field">
<div class="field__label">ПАРОЛЬ
<a class="field__link js-auth-go-pass" href="{% url 'lilcity:password_reset' %}" tabindex="4">Забыли пароль?
</a>
</div>
<div class="field__wrap">
<input id="learner-auth-form__password" class="field__input field__input--password" name="password"
type="password" placeholder="Минимум 5 символов" tabindex="2" />
</div>
{% for error in form.password.errors %}
<div class="field__error learner-auth-form__field-error" style="display: block;">{{ error }}</div>
{% endfor %}
{% for error in form.non_field_errors %}
<div class="auth-register__common-error
form__common-error learner-auth-form__field-error" style="display: block;">{{ error }}</div>
{% endfor %}
</div>
<div class="auth__foot">
<button id="learner-auth__button" class="auth__btn btn btn_light" tabindex="3" type="submit">ВОЙТИ</button>
<div class="auth__or">или</div>
<a href="{% url 'lilcity:registration-learner' %}" class="auth__btn btn">Зарегистрироваться</a>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock layer_body %}

@ -1,14 +1,32 @@
{% extends "notification/email/_base.html" %}
{% extends "templates/lilcity/layer.html" %} {% load static %}
{% block content %}
<p style="margin: 0 0 20px">Для восстановления пароля нажмите кнопку ниже.</p>
<div style="margin-bottom: 10px;">
<a href="{{ domain }}{% url 'lilcity:password_reset_confirm' uidb64=uid token=token %}"
style="text-decoration: none; position: relative; padding: 13px 24px 12px;
background-image: linear-gradient(-225deg, #D1FF7F 0%, #56FFFD 100%); display: inline-block;
border-radius: 3px; font-size: 12px; color: #191919; text-transform: uppercase;
letter-spacing: 2px; text-align: center; transition: all .2s; z-index: 2;">Нажмите для восстановления</a>
<p>Или скопируйте ссылку ниже, и вставьте её в адресную строку браузера.</p>
<p>{{ domain }}{% url 'lilcity:password_reset_confirm' uidb64=uid token=token %}</p>
</div>
{% endblock content %}
{% block layer_body %}
<div class="outer js-outer">
{% include "templates/blocks/header.html" with no_auth_btn=True %}
<div id="lilcity-vue-app" class="container">
<div class="section">
<div class="section__center center" style="max-width: 400px;">
<div class="title">Восстановление пароля</div>
<form id="password-reset-form" method="post" action="{% url 'lilcity:password_reset' %}">
{% csrf_token %}
<div class="auth__enter js-auth-enter">
<div id="password-reset__email-field" class="auth__field field">
<div class="field__label">ПОЧТА
<a class="field__link js-auth-go-enter" href="{% url 'lilcity:login' %}">Войти</a>
</div>
<div class="field__wrap">
<input id="password-reset__email" class="field__input" type="email" name="email" placeholder="name@website.com">
</div>
<div id="password-reset-field-error__email" class="field__error password-reset-form__field-error"></div>
<div id="password-reset-field-error__all" class="form__common-error password-reset-form__field-error"></div>
</div>
<div class="auth__foot">
<button id="password-reset__button" type="submit" class="auth__btn btn btn_light">ОТПРАВИТЬ</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock layer_body %}

@ -0,0 +1,14 @@
{% extends "notification/email/_base.html" %}
{% block content %}
<p style="margin: 0 0 20px">Для восстановления пароля нажмите кнопку ниже.</p>
<div style="margin-bottom: 10px;">
<a href="{{ domain }}{% url 'lilcity:password_reset_confirm' uidb64=uid token=token %}"
style="text-decoration: none; position: relative; padding: 13px 24px 12px;
background-image: linear-gradient(-225deg, #D1FF7F 0%, #56FFFD 100%); display: inline-block;
border-radius: 3px; font-size: 12px; color: #191919; text-transform: uppercase;
letter-spacing: 2px; text-align: center; transition: all .2s; z-index: 2;">Нажмите для восстановления</a>
<p>Или скопируйте ссылку ниже, и вставьте её в адресную строку браузера.</p>
<p>{{ domain }}{% url 'lilcity:password_reset_confirm' uidb64=uid token=token %}</p>
</div>
{% endblock content %}

@ -1,10 +1,92 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
</html>
{% extends "templates/lilcity/layer.html" %} {% load static %}
{% block layer_body %}
<div class="outer js-outer">
{% include "templates/blocks/header.html" with no_auth_btn=True %}
<div id="lilcity-vue-app" class="container">
<div class="section">
<div class="section__center center" style="max-width: 400px;">
<div class="title">Регистрация</div>
<form id="learner-registration-form" method="post" action="{% url 'lilcity:registration-learner' %}">
{% csrf_token %}
{% if referrer %}
<input type="hidden" name="referrer" value="{{ referrer.id }}">
<div class="auth__text">
Спасибо за&nbsp;то, что&nbsp;вы&nbsp;с&nbsp;нами! Вас&nbsp;пригласил ваш&nbsp;друг {{ referrer.get_full_name }}.
При&nbsp;первой покупке {{ config.REFERRAL_BONUS }}% от&nbsp;суммы услуги будут зачислены на&nbsp;ваш бонусный счет.
Приятного обучения!
</div>
{% endif %}
<div class="auth__fieldset">
<div id="learner-registration-field__first-name" class="auth__field field learner-registration-form__field">
<div class="field__label">ИМЯ</div>
<div class="field__wrap">
<input id="learner-registration-form__first-name" class="field__input" type="text" name="first_name"
placeholder="" value="{{ form.first_name.value|default:'' }}">
</div>
{% for error in form.first_name.errors %}
<div id="learner-registration-field-error__first-name" style="display: block;"
class="field__error learner-registration-form__field-error">{{ error }}</div>
{% endfor %}
</div>
<div id="learner-registration-field__last-name" class="auth__field field learner-registration-form__field">
<div class="field__label">ФАМИЛИЯ</div>
<div class="field__wrap">
<input id="learner-registration-form__last-name" class="field__input" type="text" name="last_name"
placeholder="" value="{{ form.last_name.value|default:'' }}">
</div>
{% for error in form.last_name.errors %}
<div id="learner-registration-field-error__last-name" style="display: block;"
class="field__error learner-registration-form__field-error">{{ error }}</div>
{% endfor %}
</div>
</div>
<div id="learner-registration-field__email" class="auth__field field learner-registration-form__field">
<div class="field__label">ПОЧТА</div>
<div class="field__wrap">
<input id="learner-registration-form__email" class="field__input" type="email" name="email"
placeholder="name@website.com" value="{{ form.email.value|default:'' }}">
</div>
{% for error in form.email.errors %}
<div style="display: block;" class="field__error learner-registration-form__field-error">{{ error }}</div>
{% endfor %}
</div>
<div id="learner-registration-field__password" class="auth__field field learner-registration-form__field">
<div class="field__label">ПАРОЛЬ</div>
<div class="field__wrap">
<input id="learner-registration-form__password" class="field__input field__input--password" type="password" name="password"
placeholder="Минимум 5 символов">
</div>
{% for error in form.password.errors %}
<div style="display: block;" class="field__error learner-registration-form__field-error">{{ error }}</div>
{% endfor %}
{% for error in form.non_field_errors %}
<div style="display: block;"
class="auth-register__common-error form__common-error learner-registration-form__field-error">{{ error }}</div>
{% endfor %}
{% if error %}
<div style="display: block;"
class="auth-register__common-error form__common-error learner-registration-form__field-error">{{ error }}</div>
{% endif %}
</div>
<div class="auth__text">
Согласен с <a target="_blank" href="{% url 'privacy' %}">условиями обработки данных</a> и&nbsp;<a target="_blank" href="{% url 'refund_policy' %}">возвратом услуги</a>.
</div>
<label class="auth__label switch">
<input class="switch__input" name="newsletter" value="true" type="checkbox" checked>
<span class="switch__content">Согласен на важную рассылку: новости школы и курсов</span>
</label>
<div class="auth__foot">
<button class="auth__btn btn btn_light">
ЗАРЕГИСТРИРОВАТЬСЯ
</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock layer_body %}

@ -31,6 +31,7 @@ User = get_user_model()
class LearnerRegistrationView(FormView):
form_class = LearnerRegistrationForm
template_name = "auth/registration-learner.html"
success_url = '/'
def form_valid(self, form):
config = Config.load()
@ -44,10 +45,15 @@ class LearnerRegistrationView(FormView):
)
if not created:
if self.request.is_ajax():
return JsonResponse({
"success": False,
'errors': {'__all__': [{'message': 'Возможно вы уже зарегистрированы?'}]}
}, status=400)
else:
context = self.get_context_data(form=form)
context['error'] = 'Возможно вы уже зарегистрированы?'
return self.render_to_response(context)
user.username = email
user.first_name = first_name
@ -71,10 +77,16 @@ class LearnerRegistrationView(FormView):
url = http_referer + str(reverse_lazy('lilcity:verification-email', args=[token, user.id]))
send_email('Вы успешно прошли регистрацию', email, "notification/email/verification_email.html", url=url, config=config)
if self.request.is_ajax():
return JsonResponse({"success": True}, status=201)
else:
return super().form_valid(form)
def form_invalid(self, form):
if self.request.is_ajax():
return JsonResponse(form.errors.get_json_data(escape_html=True), status=400)
else:
return super().form_invalid(form)
class LogoutView(View):
@ -86,14 +98,21 @@ class LogoutView(View):
class LoginView(FormView):
form_class = AuthenticationForm
template_name = "auth/login.html"
success_url = '/'
def form_valid(self, form):
login(self.request, form.get_user())
self.request.session['referrer'] = None
if self.request.is_ajax():
return JsonResponse({"success": True})
else:
return super().form_valid(form)
def form_invalid(self, form):
if self.request.is_ajax():
return JsonResponse({"success": False, "errors": form.errors.get_json_data(escape_html=True)}, status=400)
else:
return super().form_invalid(form)
class VerificationEmailView(View):
@ -116,20 +135,19 @@ class SuccessVerificationEmailView(TemplateView):
template_name = 'auth/success-verification.html'
class PasswordResetView(views.PasswordContextMixin, BaseFormView):
email_template_name = 'auth/password_reset.txt'
class PasswordResetView(views.PasswordContextMixin, FormView):
email_template_name = 'auth/password_reset_email.txt'
subject_template_name = "auth/password_reset_subject.txt"
form_class = views.PasswordResetForm
template_name = "auth/password_reset.html"
success_url = '/'
extra_email_context = None
from_email = None
html_email_template_name = "auth/password_reset.html"
html_email_template_name = "auth/password_reset_email.html"
title = 'Password reset'
token_generator = views.default_token_generator
def get(self, *args, **kwargs):
raise Http404()
def form_valid(self, form):
config = Config.load()
extra_email_context = {'config': config}
@ -147,7 +165,10 @@ class PasswordResetView(views.PasswordContextMixin, BaseFormView):
'extra_email_context': extra_email_context,
}
form.save(**opts)
if self.request.is_ajax():
return JsonResponse({"success": True})
else:
return super().form_valid(form)
class PasswordResetConfirmView(views.PasswordResetConfirmView):

@ -55,4 +55,11 @@ def transaction_to_roistat(user_id, payment_id, event_name, amount, time, status
key = settings.ROISTAT_KEY
url = settings.ROISTAT_API_URL + f'/project/add-orders?key={key}&project={project}'
resp = requests.post(url, json=body)
try:
resp_json = resp.json()
except:
resp_json = None
if resp.status_code != 200 or not resp_json or not resp_json.get('processed'):
logger.error('TRANSACTION_TO_ROISTAT for payment # %d, %s RUB: %s' % (payment_id, amount, resp.text))
else:
logger.info('TRANSACTION_TO_ROISTAT: ' + str(resp))

@ -162,6 +162,76 @@ USE_L10N = True
# USE_TZ = True
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
},
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue'
}
},
'formatters': {
'verbose': {
'format': '%(levelname)s:%(name)s: %(message)s '
'(%(asctime)s; %(filename)s:%(lineno)d)',
'datefmt': "%Y-%m-%d %H:%M:%S",
},
'simple': {
'format': '{levelname} {message}',
'style': '{',
},
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
},
'console': {
'level': 'DEBUG',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
'log_file': {
'level': 'DEBUG',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'django.request': {
'handlers': ['mail_admins', 'console'],
'level': 'ERROR',
'propagate': True,
},
'django': {
'handlers': ['console', ],
},
'py.warnings': {
'handlers': ['console', ],
},
'': {
'handlers': ['console', 'log_file',],
'level': "INFO",
},
}
}
if os.path.exists(os.path.join(BASE_DIR, '/media/logs')):
LOGGING['handlers']['log_file'] = {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': 'media/logs/main.log',
'maxBytes': 1024 * 1024 * 15, # 5 MB
'backupCount': 7,
'formatter': 'verbose',
'filters': ['require_debug_false'],
}
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/

@ -47,6 +47,7 @@
</div>
</div>
{% else %}
<button class="header__enter js-header-enter" data-popup=".js-popup-auth">ВХОД&nbsp;/ РЕГИСТРАЦИЯ
</button>
{% if not no_auth_btn %}
<a href="{% url 'lilcity:login' %}" class="header__enter js-header-enter" data-popup=".js-popup-auth">ВХОД&nbsp;/ РЕГИСТРАЦИЯ</a>
{% endif %}
{% endif %}

@ -5,28 +5,6 @@
{% load compress %}
{% block layer_head %}
<script src="https://js.pusher.com/4.1/pusher.min.js"></script>
<script>
LIL_SERVER_TIME = "{% now 'U' %}";
LIL_SERVER_TIME_DIFF = Math.floor((new Date().getTime()) / 1000) - parseInt(LIL_SERVER_TIME);
USER_ID = "{{ request.user.id }}";
COURSE_ID = "{{ course.id }}";
MIXPANEL_CUSTOM_LIB_URL = "/static/mixpanel-2-latest.js";
</script>
<!-- Start of LiveChat (www.livechatinc.com) code -->
<script type="text/javascript">
window.__lc = window.__lc || {};
window.__lc.license = 9917240;
{% if request.user.is_authenticated %}
window.__lc.visitor = { name: '{{ request.user.get_full_name }}', email: '{{ request.user.email }}' };
{% endif %}
(function() {
var lc = document.createElement('script'); lc.type = 'text/javascript'; lc.async = true;
lc.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'cdn.livechatinc.com/tracking.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(lc, s);
})();
</script>
<!-- End of LiveChat code -->
{% block head %}{% endblock head %}
{% endblock layer_head %}
@ -52,6 +30,7 @@
{% include "templates/blocks/popup_capture_email.html" %}
{% include "templates/blocks/popup_bonuses_came.html" %}
</div>
{% block foot %}{% endblock foot %}
{% include 'templates/blocks/lil_store_js.html' %}
{% block pre_app_js %}{% endblock pre_app_js %}
<script type="text/javascript" src="{% static "app.js" %}"></script>
@ -63,6 +42,27 @@
<script>
(function(w, d, s, h, id) { w.roistatProjectId = id; w.roistatHost = h; var p = d.location.protocol == "https:" ? "https://" : "http://"; var u = /^.*roistat_visit=[^;]+(.*)?$/.test(d.cookie) ? "/dist/module.js" : "/api/site/1.0/"+id+"/init"; var js = d.createElement(s); js.charset="UTF-8"; js.async = 1; js.src = p+h+u; var js2 = d.getElementsByTagName(s)[0]; js2.parentNode.insertBefore(js, js2);})(window, document, 'script', 'cloud.roistat.com', '{% setting "ROISTAT_COUNTER_ID" %}');
</script>
{% block foot %}{% endblock foot %}
<script src="https://js.pusher.com/4.1/pusher.min.js"></script>
<script>
LIL_SERVER_TIME = "{% now 'U' %}";
LIL_SERVER_TIME_DIFF = Math.floor((new Date().getTime()) / 1000) - parseInt(LIL_SERVER_TIME);
USER_ID = "{{ request.user.id }}";
COURSE_ID = "{{ course.id }}";
MIXPANEL_CUSTOM_LIB_URL = "/static/mixpanel-2-latest.js";
</script>
<!-- Start of LiveChat (www.livechatinc.com) code -->
<script type="text/javascript">
window.__lc = window.__lc || {};
window.__lc.license = 9917240;
{% if request.user.is_authenticated %}
window.__lc.visitor = { name: '{{ request.user.get_full_name }}', email: '{{ request.user.email }}' };
{% endif %}
(function() {
var lc = document.createElement('script'); lc.type = 'text/javascript'; lc.async = true;
lc.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'cdn.livechatinc.com/tracking.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(lc, s);
})();
</script>
<!-- End of LiveChat code -->
{% block foot_js %}{% endblock foot_js %}
{% endblock layer_body %}

@ -143,6 +143,7 @@ $(document).ready(function () {
let authButton = $('#learner-auth__button');
authButton.addClass('loading');
if(! authForm.data('no-ajax')){
$.ajax(authForm.attr('action'), {
method: 'POST',
data: authForm.serialize(),
@ -183,6 +184,7 @@ $(document).ready(function () {
}
$('#learner-auth-field-error__all').text('Произошла незвестная ошибка');
});
}
});
let registrationForm = $('#learner-registration-form');
@ -230,6 +232,7 @@ $(document).ready(function () {
let registrationButton = $('#learner-registration-form__submit-button');
registrationButton.addClass('loading');
if(! registrationForm.data('no-ajax')){
$.ajax(registrationForm.attr('action'), {
method: 'POST',
data: registrationForm.serialize(),
@ -271,12 +274,14 @@ $(document).ready(function () {
$('#learner-registration-field-error__all').text('Произошла незвестная ошибка');
});
}
});
$.ajaxSetup({cache: true});
load_facebook();
const facebookButton = $('button.btn_fb');
facebookButton.show();
facebookButton.on('click', function () {
$('.auth-register__common-error').hide();
facebookButton.addClass('loading');

Loading…
Cancel
Save