add login view and logic to display it
This commit is contained in:
parent
cfd59cfec3
commit
eb75c9b475
6 changed files with 163 additions and 13 deletions
|
@ -25,6 +25,9 @@ header #user small {
|
|||
margin-top: -3px;
|
||||
color: #606c76;
|
||||
}
|
||||
header #user small:empty {
|
||||
display:none;
|
||||
}
|
||||
|
||||
input {
|
||||
font-family: inherit;
|
||||
|
@ -45,12 +48,26 @@ input {
|
|||
|
||||
main {
|
||||
flex-grow: 1;
|
||||
border: 0 solid #CCCCCC;
|
||||
border-top-width: 1px;
|
||||
padding: 10px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
main.map {
|
||||
/*noinspection CssUnknownTarget*/
|
||||
background: url('../../img/loader.gif') no-repeat center;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
border-top-width: 0;
|
||||
}
|
||||
|
||||
main.account form {
|
||||
max-width: 400px;
|
||||
}
|
||||
#modal-content :last-child {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#map {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
|
@ -165,6 +182,9 @@ main:not([data-view=route-result]) #route-result-buttons {
|
|||
|
||||
h2 {
|
||||
font-size: 2.5rem;
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
.details-head h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
@ -453,7 +473,7 @@ main:not([data-view=route-result]) #route-dots {
|
|||
.buttons > *:hover, .buttons > *:active {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
button, .button {
|
||||
main.map button, main.map .button {
|
||||
font-size: 1.3rem;
|
||||
line-height: 1.3;
|
||||
height: 3.3rem;
|
||||
|
@ -588,6 +608,7 @@ main:not([data-view=route-result]) #route-summary {
|
|||
top: 8px;
|
||||
right: 8px;
|
||||
font-size: 30px;
|
||||
padding: 0;
|
||||
color: #b2b2b2;
|
||||
}
|
||||
#close-modal:hover {
|
||||
|
@ -611,3 +632,41 @@ main:not([data-view=route-result]) #route-summary {
|
|||
main > .share-ui {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
ul.errorlist {
|
||||
margin-bottom:0.5rem;
|
||||
color:red;
|
||||
list-style-type:none;
|
||||
}
|
||||
|
||||
ul.messages {
|
||||
list-style-type:none;
|
||||
}
|
||||
ul.messages li {
|
||||
padding:1.0rem;
|
||||
border-radius: .4rem;
|
||||
border: 0.1rem solid #666666;
|
||||
background-color:#EEEEEE;
|
||||
}
|
||||
|
||||
ul.messages li.info {
|
||||
color: #006688;
|
||||
border-color: #006688;
|
||||
background-color:#DDE4FF;
|
||||
}
|
||||
ul.messages li.success {
|
||||
color: #338800;
|
||||
border-color: #339900;
|
||||
background-color:#E4FFDD;
|
||||
}
|
||||
ul.messages li.warning {
|
||||
color: #CC6600;
|
||||
border-color: #FF9900;
|
||||
background-color:#FFFFDD;
|
||||
}
|
||||
ul.messages li.error {
|
||||
color: #CC0000;
|
||||
border-color: #CC0000;
|
||||
background-color:#FFEEEE;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,10 @@ c3nav = {
|
|||
$('#route-search-buttons').find('.close').on('click', c3nav._route_buttons_close_click);
|
||||
$('#map').on('click', '.location-popup .button-clear', c3nav._popup_button_click);
|
||||
|
||||
$('#modal').on('click', c3nav._modal_click);
|
||||
$('#modal').on('click', c3nav._modal_click)
|
||||
.on('click', 'a', c3nav._modal_link_click)
|
||||
.on('submit', 'form', c3nav._modal_submit);
|
||||
$('header #user').on('click', c3nav._modal_link_click);
|
||||
|
||||
window.onpopstate = c3nav._onpopstate;
|
||||
},
|
||||
|
@ -713,20 +716,44 @@ c3nav = {
|
|||
|
||||
open_modal: function (content) {
|
||||
var $modal = $('#modal');
|
||||
$modal.toggleClass('loading', !content)
|
||||
.find('#modal-content')
|
||||
.html('<button class="button-clear material-icons" id="close-modal">clear</button>')
|
||||
.append(content || '');
|
||||
c3nav._set_modal_content(content);
|
||||
if (!$modal.is('.show')) {
|
||||
c3nav._push_state({modal: true, sidebar: true});
|
||||
$modal.addClass('show');
|
||||
}
|
||||
},
|
||||
_set_modal_content: function(content) {
|
||||
$('#modal').toggleClass('loading', !content)
|
||||
.find('#modal-content')
|
||||
.html('<button class="button-clear material-icons" id="close-modal">clear</button>')
|
||||
.append(content || '');
|
||||
},
|
||||
_modal_click: function(e) {
|
||||
if (e.target.id === 'modal' || e.target.id === 'close-modal') {
|
||||
history.back();
|
||||
}
|
||||
},
|
||||
_modal_link_click: function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
c3nav.open_modal();
|
||||
$.get($(this).attr('href'), c3nav._modal_loaded).fail(c3nav._modal_error);
|
||||
},
|
||||
_modal_submit: function(e) {
|
||||
e.preventDefault();
|
||||
$.post($(this).attr('action'), $(this).serialize(), c3nav._modal_loaded).fail(c3nav._modal_error);
|
||||
},
|
||||
_modal_loaded: function(data) {
|
||||
if (data.startsWith('{')) {
|
||||
c3nav._set_user_data(JSON.parse(data));
|
||||
history.back();
|
||||
return;
|
||||
}
|
||||
c3nav._set_modal_content($('<div>'+data+'</div>').find('main').html());
|
||||
},
|
||||
_modal_error: function(data) {
|
||||
$('#modal').removeClass('loading').find('#modal-content').html('<h3>Error '+data.status+'</h3>');
|
||||
},
|
||||
|
||||
// map
|
||||
init_map: function () {
|
||||
|
@ -929,8 +956,13 @@ c3nav = {
|
|||
window.setTimeout(c3nav.refresh_tile_access, 16000);
|
||||
},
|
||||
refresh_tile_access: function () {
|
||||
$.ajax('/api/users/current/');
|
||||
$.get('/api/users/current/', c3nav._set_user_data);
|
||||
c3nav.schedule_refresh_tile_access();
|
||||
},
|
||||
_set_user_data: function (data) {
|
||||
var $user = $('header #user');
|
||||
$user.find('span').text(data.title);
|
||||
$user.find('small').text(data.subtitle || '');
|
||||
}
|
||||
};
|
||||
$(document).ready(c3nav.init);
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
{% if not embed %}
|
||||
<header>
|
||||
<h1>c3nav</h1>
|
||||
<a href="#" id="user">
|
||||
<a href="/account/" id="user">
|
||||
<span>{{ user_data.title }}</span>
|
||||
{% if user_data.subtitle %}<small>{{ user_data.subtitle }}</small>{% endif %}
|
||||
<small>{% if user_data.subtitle %}{{ user_data.subtitle }}{% endif %}</small>
|
||||
</a>
|
||||
</header>
|
||||
{% endif %}
|
||||
|
|
14
src/c3nav/site/templates/site/login.html
Normal file
14
src/c3nav/site/templates/site/login.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
{% extends 'site/base.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<main class="account">
|
||||
<h2>{% trans 'Log in' %}</h2>
|
||||
|
||||
<form method="post" action="{{ request.path_info }}?{{ request.GET.urlencode }}">
|
||||
{% csrf_token %}
|
||||
{{ form }}
|
||||
<button type="submit">{% trans 'Log in' %}</button>
|
||||
</form>
|
||||
</main>
|
||||
{% endblock %}
|
|
@ -1,6 +1,6 @@
|
|||
from django.conf.urls import url
|
||||
|
||||
from c3nav.site.views import map_index, qr_code
|
||||
from c3nav.site.views import account_view, login_view, logout_view, map_index, qr_code
|
||||
|
||||
slug = r'(?P<slug>[a-z0-9-_.:]+)'
|
||||
slug2 = r'(?P<slug2>[a-z0-9-_.:]+)'
|
||||
|
@ -13,6 +13,9 @@ urlpatterns = [
|
|||
url(r'^%s(?P<mode>[od])/%s/%s$' % (embed, slug, pos), map_index, name='site.index'),
|
||||
url(r'^%sr/%s/%s/%s%s$' % (embed, slug, slug2, details, pos), map_index, name='site.index'),
|
||||
url(r'^%s(?P<mode>r)/%s$' % (embed, pos), map_index, name='site.index'),
|
||||
url(r'^%s$' % pos, map_index, name='site.index'),
|
||||
url(r'^qr/(?P<path>.*)$', qr_code, name='site.qr'),
|
||||
url(r'^%s$' % pos, map_index, name='site.index')
|
||||
url(r'^login$', login_view, name='site.login'),
|
||||
url(r'^logout$', logout_view, name='site.logout'),
|
||||
url(r'^account/$', account_view, name='site.account'),
|
||||
]
|
||||
|
|
|
@ -3,10 +3,14 @@ from typing import Optional
|
|||
|
||||
import qrcode
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import login, logout
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.forms import AuthenticationForm
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.http import HttpResponse, HttpResponseBadRequest
|
||||
from django.shortcuts import render
|
||||
from django.views.decorators.cache import cache_control
|
||||
from django.shortcuts import redirect, render
|
||||
from django.urls import reverse
|
||||
from django.views.decorators.cache import cache_control, never_cache
|
||||
from django.views.decorators.clickjacking import xframe_options_exempt
|
||||
from django.views.decorators.http import etag
|
||||
|
||||
|
@ -111,3 +115,41 @@ def qr_code(request, path):
|
|||
response = HttpResponse(content_type='image/png')
|
||||
qr.make_image().save(response, 'PNG')
|
||||
return response
|
||||
|
||||
|
||||
def close_response(request):
|
||||
ajax = request.is_ajax() or 'ajax' in request.GET
|
||||
if ajax:
|
||||
return HttpResponse(json.dumps(get_user_data(request), cls=DjangoJSONEncoder).encode(),
|
||||
content_type='text/plain')
|
||||
redirect_path = request.GET['next'] if request.GET.get('next', '').startswith('/') else reverse('site.index')
|
||||
return redirect(redirect_path)
|
||||
|
||||
|
||||
@never_cache
|
||||
def login_view(request):
|
||||
if request.user.is_authenticated:
|
||||
return close_response(request)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = AuthenticationForm(request, data=request.POST)
|
||||
if form.is_valid():
|
||||
login(request, form.user_cache)
|
||||
return close_response(request)
|
||||
else:
|
||||
form = AuthenticationForm(request)
|
||||
|
||||
return render(request, 'site/login.html', {'form': form})
|
||||
|
||||
|
||||
@never_cache
|
||||
def logout_view(request):
|
||||
logout(request)
|
||||
return close_response(request)
|
||||
|
||||
|
||||
@never_cache
|
||||
@login_required(login_url='site.login')
|
||||
def account_view(request):
|
||||
# todo: show account info here
|
||||
pass
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue