Merge branch 'feature/static-login-page' into 'master'

Feature/static login page

See merge request lilschool/site!368
remotes/origin/hotfix/js-error
Danil 7 years ago
commit 1d66a162f0
  1. 49
      apps/auth/templates/auth/login.html
  2. 42
      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. 51
      apps/auth/views.py
  7. 5
      project/templates/blocks/user_menu.html
  8. 46
      project/templates/lilcity/index.html
  9. 83
      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="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>
{% 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="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 content %}
{% 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="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:
return JsonResponse({
"success": False,
'errors': {'__all__': [{'message': 'Возможно вы уже зарегистрированы?'}]}
}, status=400)
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)
return JsonResponse({"success": True}, status=201)
if self.request.is_ajax():
return JsonResponse({"success": True}, status=201)
else:
return super().form_valid(form)
def form_invalid(self, form):
return JsonResponse(form.errors.get_json_data(escape_html=True), status=400)
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
return JsonResponse({"success": True})
if self.request.is_ajax():
return JsonResponse({"success": True})
else:
return super().form_valid(form)
def form_invalid(self, form):
return JsonResponse({"success": False, "errors": form.errors.get_json_data(escape_html=True)}, status=400)
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)
return JsonResponse({"success": True})
if self.request.is_ajax():
return JsonResponse({"success": True})
else:
return super().form_valid(form)
class PasswordResetConfirmView(views.PasswordResetConfirmView):

@ -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,46 +143,48 @@ $(document).ready(function () {
let authButton = $('#learner-auth__button');
authButton.addClass('loading');
$.ajax(authForm.attr('action'), {
method: 'POST',
data: authForm.serialize(),
})
.done(function (data) {
if (data.success === true) {
const nextUrl = popup.data('next-url');
if(nextUrl){
window.location.href = nextUrl;
}
else{
window.location.reload();
if(! authForm.data('no-ajax')){
$.ajax(authForm.attr('action'), {
method: 'POST',
data: authForm.serialize(),
})
.done(function (data) {
if (data.success === true) {
const nextUrl = popup.data('next-url');
if(nextUrl){
window.location.href = nextUrl;
}
else{
window.location.reload();
}
} else {
authButton.removeClass('loading');
}
} else {
})
.fail(function (xhr) {
console.log('error', xhr);
authButton.removeClass('loading');
}
})
.fail(function (xhr) {
console.log('error', xhr);
authButton.removeClass('loading');
if (xhr.status === 400) {
if (xhr.responseJSON.errors) {
for (let errorField in xhr.responseJSON.errors) {
if (!xhr.responseJSON.errors.hasOwnProperty(errorField)) {
continue;
if (xhr.status === 400) {
if (xhr.responseJSON.errors) {
for (let errorField in xhr.responseJSON.errors) {
if (!xhr.responseJSON.errors.hasOwnProperty(errorField)) {
continue;
}
const errorMessage = xhr.responseJSON.errors[errorField][0].message;
if (errorField === '__all__') {
$('#learner-auth-field-error__all').text(errorMessage).show();
} else {
$(`#learner-auth-field-error__${errorField}`).text(errorMessage);
$(`#learner-auth-field__${errorField}`).addClass('error');
}
}
const errorMessage = xhr.responseJSON.errors[errorField][0].message;
if (errorField === '__all__') {
$('#learner-auth-field-error__all').text(errorMessage).show();
} else {
$(`#learner-auth-field-error__${errorField}`).text(errorMessage);
$(`#learner-auth-field__${errorField}`).addClass('error');
}
}
return;
return;
}
}
}
$('#learner-auth-field-error__all').text('Произошла незвестная ошибка');
});
$('#learner-auth-field-error__all').text('Произошла незвестная ошибка');
});
}
});
let registrationForm = $('#learner-registration-form');
@ -230,10 +232,11 @@ $(document).ready(function () {
let registrationButton = $('#learner-registration-form__submit-button');
registrationButton.addClass('loading');
$.ajax(registrationForm.attr('action'), {
method: 'POST',
data: registrationForm.serialize(),
})
if(! registrationForm.data('no-ajax')){
$.ajax(registrationForm.attr('action'), {
method: 'POST',
data: registrationForm.serialize(),
})
.done(function (data) {
if (data.success === true) {
const nextUrl = popup.data('next-url');
@ -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