Browse Source

added registration form

funding-tag
Holger Frey 5 years ago
parent
commit
7f93777d7b
  1. 7
      ordr3/resources.py
  2. 37
      ordr3/static/style.css
  3. 51
      ordr3/templates/account/breached_password.jinja2
  4. 22
      ordr3/templates/account/login.jinja2
  5. 25
      ordr3/templates/account/registration.jinja2
  6. 34
      ordr3/templates/account/registration_complete.jinja2
  7. 23
      ordr3/templates/deform/email.pt
  8. 109
      ordr3/templates/deform/form.pt
  9. 3
      ordr3/templates/deform/hidden.pt
  10. 48
      ordr3/templates/deform/mapping_item.pt
  11. 23
      ordr3/templates/deform/textinput.pt
  12. 22
      ordr3/templates/deform/textinput_disabled.pt
  13. 29
      ordr3/templates/deform/viewable_password.pt
  14. 4
      ordr3/templates/layout_full.jinja2
  15. 25
      ordr3/templates/layout_small.jinja2
  16. 6
      ordr3/views/__init__.py
  17. 123
      ordr3/views/account.py
  18. 47
      ordr3/views/root.py

7
ordr3/resources.py

@ -56,7 +56,12 @@ class Root(BaseResource):
def __acl__(self): def __acl__(self):
""" access controll list """ """ access controll list """
return [(Allow, Everyone, "view")] return [
(Allow, Everyone, "login"),
(Allow, Everyone, "logout"),
(Allow, Everyone, "registration"),
(Allow, Everyone, "view"),
]
def includeme(config): def includeme(config):

37
ordr3/static/style.css

@ -1,3 +1,40 @@
.alert a {
color:inherit;
font-weight:bold;
}
.o3-login-card { .o3-login-card {
margin-top:7em; margin-top:7em;
} }
.o3-registration-card {
margin-top:1em;
margin-bottom:2em;
}
.o3-registration-card .alert-danger {
font-size: 80%;
text-align: center;
}
.o3-registration-card .help-block {
color: #6c757d!important;
font-size: 80%;
font-weight: 400;
display: block;
margin-top: .25rem;
}
.o3-pwd-dots .bi-eye-slash, .o3-pwd-text .bi-eye {
display:inline;
}
.o3-pwd-dots .bi-eye, .o3-pwd-text .bi-eye-slash {
display:none;
}
.form-group.deform-form-buttons {
margin-top:2em;
}

51
ordr3/templates/account/breached_password.jinja2

@ -0,0 +1,51 @@
{% extends "ordr3:templates/layout_small.jinja2" %}
{% block subtitle %} Log In {% endblock subtitle %}
{% block content %}
<div class="container">
<div class="row o3-registration-card">
<div class="col"></div>
<div class="col">
<div class="card">
<div class="card-header bg-dark text-light">
<h2 class="card-title text-center pt-1">Ordr</h5>
</div>
<div class="card-body">
<h6>Why is Ordr telling me my password is compromised?</h6>
<p>
Ordr itself has not suffered a breach. This is a protective measure to
reduce the risk of <a href="https://www.owasp.org/index.php/Credential_stuffing" target="_blank" rel="noopener">credential stuffing</a>
attacks against Ordr and its users.
</p>
<p>
Each time a user supplies a password while registering or updating their
password — Ordr securely checks whether that password has appeared in
public data breaches.
</p>
<p>
During each of these processes, Ordr generates a SHA-1 hash of the
supplied password and uses the first five (5) characters of the hash to
check the <a href="https://haveibeenpwned.com/API/v2#SearchingPwnedPasswordsByRange" target="_blank" rel="noopener">Have I Been Pwned API</a>
and determine if the password has been previously compromised.
The plaintext password is never stored by Ordr or submitted to the
Have I Been Pwned API.
</p>
<p>
If you receive an error message saying that
"This password appears in a breach or has been compromised.",
you should change it all other places that you use it as soon as possible.
</p>
<p class="small text-secondary">
This text originally appeared on the <a href="https://pypi.org/help/#compromised-password" target="_blank" rel="noopener">PyPI FAQ</a>.
<p>
</div>
</div>
</div>
<div class="col"></div>
</div>
</div>
{% endblock content %}

22
ordr3/templates/root/login.jinja2 → ordr3/templates/account/login.jinja2

@ -1,21 +1,13 @@
<!DOCTYPE html> {% extends "ordr3:templates/layout_small.jinja2" %}
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Ordr - Log In</title> {% block subtitle %} Log In {% endblock subtitle %}
<link href="{{request.static_url('ordr3:static/favicon.ico')}}" type="image/x-icon" rel="shortcut icon"> {% block content %}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<link rel="stylesheet" href="{{request.static_url('ordr3:static/style.css')}}" type="text/css" media="screen" />
</head>
<body>
<div class="container"> <div class="container">
<div class="row o3-login-card"> <div class="row o3-login-card">
<div class="col"></div> <div class="col"></div>
<div class="col"> <div class="col">
<div class="card" style="width: 18rem;"> <div class="card">
<div class="card-header bg-dark text-light"> <div class="card-header bg-dark text-light">
<h2 class="card-title text-center pt-1">Ordr</h5> <h2 class="card-title text-center pt-1">Ordr</h5>
</div> </div>
@ -37,7 +29,7 @@
</form> </form>
<ul class="list-group list-group-flush text-center"> <ul class="list-group list-group-flush text-center">
<li class="list-group-item"><a href="{{request.resource_url(request.root, 'forgot')}}" class="text-secondary">Forgot your password?</a></li> <li class="list-group-item"><a href="{{request.resource_url(request.root, 'forgot')}}" class="text-secondary">Forgot your password?</a></li>
<li class="list-group-item"><a href="{{request.resource_url(request.root, 'register')}}" class="text-secondary">Register a new account.</a></li> <li class="list-group-item"><a href="{{request.resource_url(request.root, 'registration')}}" class="text-secondary">Register a new account.</a></li>
</ul> </ul>
</div> </div>
</div> </div>
@ -45,5 +37,5 @@
<div class="col"></div> <div class="col"></div>
</div> </div>
</div> </div>
</body>
</html> {% endblock content %}

25
ordr3/templates/account/registration.jinja2

@ -0,0 +1,25 @@
{% extends "ordr3:templates/layout_small.jinja2" %}
{% block subtitle %} Registration {% endblock subtitle %}
{% block content %}
<div class="container">
<div class="row o3-registration-card">
<div class="col"></div>
<div class="col">
<div class="card">
<div class="card-header bg-dark text-light">
<h2 class="card-title text-center pt-1">Ordr</h5>
</div>
<div class="card-body">
<h6 class="card-subtitle mb-2 text-muted text-center mt-1 mb-4">Register a new account</h6>
{{form.render()|safe}}
</div>
</div>
</div>
<div class="col"></div>
</div>
</div>
{% endblock content %}

34
ordr3/templates/account/registration_complete.jinja2

@ -0,0 +1,34 @@
{% extends "ordr3:templates/layout_small.jinja2" %}
{% block subtitle %} Registration completed {% endblock subtitle %}
{% block content %}
<div class="container">
<div class="row o3-registration-card">
<div class="col"></div>
<div class="col">
<div class="card">
<div class="card-header bg-dark text-light">
<h2 class="card-title text-center pt-1">Ordr</h5>
</div>
<div class="card-body">
<h6 class="card-subtitle mb-2 text-muted text-center mt-1 mb-4">Registration completed</h6>
{% for message in request.session.pop_flash("warning") %}
<div class="alert alert-warning" role="alert">
<p class="h6">{{message[0]}}</p>
<p class="small">{{message[1]|safe}}</p>
</div>
{% endfor %}
<p>The registration is completed.<p>
<p>The account needs to be activated by an administrator.</p>
<p>You should receive an email as soon as the account is activated.</p>
</div>
</div>
</div>
<div class="col"></div>
</div>
</div>
{% endblock content %}

23
ordr3/templates/deform/email.pt

@ -0,0 +1,23 @@
<span tal:define="name name|field.name;
css_class css_class|field.widget.css_class;
oid oid|field.oid;
mask mask|field.widget.mask;
mask_placeholder mask_placeholder|field.widget.mask_placeholder;
style style|field.widget.style;
"
tal:omit-tag="">
<input type="email" name="${name}" value="${cstruct}"
tal:attributes="required string: ${required|'required' or ''};
class string: form-control ${css_class or ''} ${'is-invalid' if field.error else ''};
style style;
attributes|field.widget.attributes|{};"
id="${oid}"/>
<script tal:condition="mask" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$("#" + oid).mask("${mask}",
{placeholder:"${mask_placeholder}"});
});
</script>
</span>

109
ordr3/templates/deform/form.pt

@ -0,0 +1,109 @@
<form
tal:define="style style|field.widget.style;
css_class css_class|string:${field.widget.css_class or field.css_class or ''};
item_template item_template|field.widget.item_template;
autocomplete autocomplete|field.autocomplete;
title title|field.title;
errormsg errormsg|field.errormsg;
description description|field.description;
buttons buttons|field.buttons;
use_ajax use_ajax|field.use_ajax;
ajax_options ajax_options|field.ajax_options;
formid formid|field.formid;
action action|field.action or None;
method method|field.method;"
tal:attributes="autocomplete autocomplete;
style style;
class css_class;
action action;
attributes|field.widget.attributes|{};"
id="${formid}"
method="${method}"
enctype="multipart/form-data"
accept-charset="utf-8"
i18n:domain="deform"
>
<fieldset class="deform-form-fieldset">
<legend tal:condition="title">${title}</legend>
<input type="hidden" name="_charset_" />
<input type="hidden" name="__formid__" value="${formid}"/>
<div class="alert alert-danger" tal:condition="field.error">
<div class="error-msg-lbl" i18n:translate=""
>There was a problem with your submission</div>
<div class="error-msg-detail" i18n:translate=""
>Errors have been highlighted below</div>
<p class="error-msg" tal:condition="field.errormsg">${field.errormsg}</p>
</div>
<p class="section first" tal:condition="description">
${description}
</p>
<div tal:repeat="child field"
tal:replace="structure child.render_template(item_template)"/>
<div class="form-group deform-form-buttons">
<tal:loop tal:repeat="button buttons">
<button
tal:define="btn_disposition repeat.button.start and 'btn-primary' or 'btn-outline-secondary';"
tal:attributes="disabled button.disabled if button.disabled else None;
attributes|button.attributes|{};"
id="${formid+button.name}"
name="${button.name}"
type="${button.type}"
class="btn ${button.css_class or btn_disposition}"
value="${button.value}"
tal:condition="button.type != 'link'">
<span tal:condition="button.icon" class="glyphicon glyphicon-${button.icon}"></span>
${button.title}
</button>
<a
tal:define="btn_disposition repeat.button.start and 'btn-primary' or 'btn-outline-secondary';
btn_href button.value|''"
class="btn ${button.css_class or btn_disposition}"
id="${field.formid + button.name}"
href="${btn_href}"
tal:condition="button.type == 'link'">
<span tal:condition="button.icon" class="glyphicon glyphicon-${button.icon}"></span>
${button.title}
</a>
</tal:loop>
</div>
</fieldset>
<script type="text/javascript" tal:condition="use_ajax">
deform.addCallback(
'${formid}',
function(oid) {
var target = '#' + oid;
var options = {
target: target,
replaceTarget: true,
success: function() {
deform.processCallbacks();
deform.focusFirstInput(target);
},
beforeSerialize: function() {
// See http://bit.ly/1agBs9Z (hack to fix tinymce-related ajax bug)
if ('tinymce' in window) {
$(tinymce.get()).each(
function(i, el) {
var content = el.getContent();
var editor_input = document.getElementById(el.id);
editor_input.value = content;
});
}
}
};
var extra_options = ${ajax_options} || {};
$('#' + oid).ajaxForm($.extend(options, extra_options));
}
);
</script>
</form>

3
ordr3/templates/deform/hidden.pt

@ -0,0 +1,3 @@
<input type="hidden" name="${name|field.name}" value="${cstruct}"
id="${oid|field.oid}"/>

48
ordr3/templates/deform/mapping_item.pt

@ -0,0 +1,48 @@
<div tal:define="error_class error_class|field.widget.error_class;
description description|field.description;
title title|field.title;
oid oid|field.oid;
hidden hidden|field.widget.hidden;
category category|field.widget.category;
structural hidden or category == 'structural';
required required|field.required;"
class="form-group ${field.error and 'has-error' or ''} ${field.widget.item_css_class or ''} ${field.default_item_css_class()}"
title="${description}"
id="item-${oid}"
tal:omit-tag="structural"
i18n:domain="deform">
<label for="${oid}"
class="control-label ${required and 'required' or ''}"
tal:condition="not structural"
id="req-${oid}"
>
${title}
</label>
<div tal:define="input_prepend field.widget.input_prepend | None;
input_append field.widget.input_append | None"
tal:omit-tag="not (input_prepend or input_append)"
class="input-group">
<span class="input-group-addon"
tal:condition="input_prepend">${input_prepend}</span
><span tal:replace="structure field.serialize(cstruct).strip()"
/><span class="input-group-addon"
tal:condition="input_append">${input_append}</span>
</div>
<div class="invalid-feedback"
tal:define="errstr 'error-%s' % field.oid"
tal:repeat="msg field.error.messages()"
i18n:translate=""
tal:attributes="id repeat.msg.index==0 and errstr or
('%s-%s' % (errstr, repeat.msg.index))"
tal:condition="field.error and not field.widget.hidden and not field.typ.__class__.__name__=='Mapping'">
${msg}
</div>
<p tal:condition="field.description and not field.widget.hidden"
class="help-block" >
${field.description}
</p>
</div>

23
ordr3/templates/deform/textinput.pt

@ -0,0 +1,23 @@
<span tal:define="name name|field.name;
css_class css_class|field.widget.css_class;
oid oid|field.oid;
mask mask|field.widget.mask;
mask_placeholder mask_placeholder|field.widget.mask_placeholder;
style style|field.widget.style;
"
tal:omit-tag="">
<input type="text" name="${name}" value="${cstruct}"
tal:attributes="required string: ${required|'required' or ''};
class string: form-control ${css_class or ''} ${'is-invalid' if field.error else ''}
style style;
attributes|field.widget.attributes|{};"
id="${oid}"/>
<script tal:condition="mask" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$("#" + oid).mask("${mask}",
{placeholder:"${mask_placeholder}"});
});
</script>
</span>

22
ordr3/templates/deform/textinput_disabled.pt

@ -0,0 +1,22 @@
<span tal:define="name name|field.name;
css_class css_class|field.widget.css_class;
oid oid|field.oid;
mask mask|field.widget.mask|None;
mask_placeholder mask_placeholder|field.widget.mask_placeholder|'_';
style style|field.widget.style;
"
tal:omit-tag="">
<input type="text" name="${name}" value="${cstruct}"
tal:attributes="class string: form-control ${css_class or ''} ${'is-invalid' if field.error else ''}
style style"
id="${oid}"
readonly="readonly"/>
<script tal:condition="mask" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$("#" + oid).mask("${mask}",
{placeholder:"${mask_placeholder}"});
});
</script>
</span>

29
ordr3/templates/deform/viewable_password.pt

@ -0,0 +1,29 @@
<div class="input-group">
<input
type="password"
name="${name|field.name}"
value="${field.widget.redisplay and cstruct or ''}"
tal:attributes="required string: ${required|'required' or ''};
style style|field.widget.style;
class string: form-control o3-pwd-field ${css_class|field.widget.css_class or ''} ${'is-invalid' if field.error else ''};
attributes|field.widget.attributes|{};
"
id="${oid|field.oid}"
/>
<div class="input-group-append o3-pwd-visibility o3-pwd-dots">
<div class="input-group-text">
<svg class="bi bi-eye" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.134 13.134 0 001.66 2.043C4.12 11.332 5.88 12.5 8 12.5c2.12 0 3.879-1.168 5.168-2.457A13.134 13.134 0 0014.828 8a13.133 13.133 0 00-1.66-2.043C11.879 4.668 10.119 3.5 8 3.5c-2.12 0-3.879 1.168-5.168 2.457A13.133 13.133 0 001.172 8z" clip-rule="evenodd"/>
<path fill-rule="evenodd" d="M8 5.5a2.5 2.5 0 100 5 2.5 2.5 0 000-5zM4.5 8a3.5 3.5 0 117 0 3.5 3.5 0 01-7 0z" clip-rule="evenodd"/>
</svg>
<svg class="bi bi-eye-slash" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 00-2.79.588l.77.771A5.944 5.944 0 018 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0114.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755-.165.165-.337.328-.517.486l.708.709z"/>
<path d="M11.297 9.176a3.5 3.5 0 00-4.474-4.474l.823.823a2.5 2.5 0 012.829 2.829l.822.822zm-2.943 1.299l.822.822a3.5 3.5 0 01-4.474-4.474l.823.823a2.5 2.5 0 002.829 2.829z"/>
<path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 001.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 018 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709z"/>
<path fill-rule="evenodd" d="M13.646 14.354l-12-12 .708-.708 12 12-.708.708z" clip-rule="evenodd"/>
</svg>
</div>
</div>
</div>

4
ordr3/templates/layout.jinja2 → ordr3/templates/layout_full.jinja2

@ -9,6 +9,10 @@
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<link rel="stylesheet" href="{{request.static_url('ordr3:static/style.css')}}" type="text/css" media="screen" /> <link rel="stylesheet" href="{{request.static_url('ordr3:static/style.css')}}" type="text/css" media="screen" />
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
</head> </head>
<body> <body>

25
ordr3/templates/layout_small.jinja2

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Ordr | {% block subtitle %} Subtitle {% endblock subtitle %}</title>
<link href="{{request.static_url('ordr3:static/favicon.ico')}}" type="image/x-icon" rel="shortcut icon">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<link rel="stylesheet" href="{{request.static_url('ordr3:static/style.css')}}" type="text/css" media="screen" />
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<script src="{{request.static_url('ordr3:static/script.js')}}"></script>
</head>
<body>
{% block content %}
<p>No content</p>
{% endblock content %}
</body>
</html>

6
ordr3/views/__init__.py

@ -3,15 +3,13 @@
some view helpers are defined here some view helpers are defined here
""" """
from collections import namedtuple
# a message for session.flash() from .. import models
FlashMessage = namedtuple("FlashMessage", ["message", "description"])
def flash(request, channel, message, description=""): def flash(request, channel, message, description=""):
""" small wrapper around request.session.flash """ """ small wrapper around request.session.flash """
msg = FlashMessage(message, description) msg = models.FlashMessage(message, description)
request.session.flash(msg, channel, allow_duplicate=False) request.session.flash(msg, channel, allow_duplicate=False)

123
ordr3/views/account.py

@ -0,0 +1,123 @@
""" static and login pages """
import deform
from pyramid.view import view_config
from pyramid.security import forget, remember
from pyramid.httpexceptions import HTTPFound
from .. import models, security, services
from ..schemas.account import RegistrationSchema
@view_config(
context="ordr3:resources.Root",
name="login",
permission="login",
request_method="GET",
renderer="ordr3:templates/account/login.jinja2",
)
def login(context, request):
return {"error": False}
@view_config(
context="ordr3:resources.Root",
name="login",
permission="login",
request_method="POST",
require_csrf=False,
renderer="ordr3:templates/account/login.jinja2",
)
def check_credentials(context, request):
username = request.POST.get("username", "")
password = request.POST.get("password", "")
crypt_context = security.get_passlib_context()
user = services.verify_credentials(
request.repo, crypt_context, username, password
)
if user is not None and user.is_active:
headers = remember(request, user.id)
return HTTPFound(
request.resource_path(request.root, "orders"), headers=headers
)
return {"error": True}
@view_config(
context="ordr3:resources.Root", name="logout", permission="logout"
)
def logout(context, request):
""" logout of a user """
return HTTPFound(
request.resource_path(request.root, "login"), headers=forget(request)
)
@view_config(
context="ordr3:resources.Root",
name="registration",
permission="registration",
request_method="GET",
renderer="ordr3:templates/account/registration.jinja2",
)
def registration(context, request):
form = RegistrationSchema.as_form(request)
return {"form": form}
@view_config(
context="ordr3:resources.Root",
name="registration",
permission="registration",
request_method="POST",
renderer="ordr3:templates/account/registration.jinja2",
)
def register_new_user(context, request):
if "Cancel" in request.POST:
return HTTPFound(request.resource_path(request.root))
form = RegistrationSchema.as_form(request)
data = request.POST.items()
try:
appstruct = form.validate(data)
except deform.ValidationFailure:
return {"form": form}
account = models.User(
id=None,
password=None,
username=appstruct["user_name"],
first_name=appstruct["first_name"],
last_name=appstruct["last_name"],
email=appstruct["email"],
role=models.UserRole.NEW,
)
warnings = services.set_new_password(account, appstruct["password"])
request.repo.add_user(account)
for message in warnings:
request.flash("warning", message.message, message.description)
return HTTPFound(request.resource_path(request.root, "registered"))
@view_config(
context="ordr3:resources.Root",
name="registered",
permission="view",
renderer="ordr3:templates/account/registration_complete.jinja2",
)
def registration_complete(context, request):
return {}
@view_config(
context="ordr3:resources.Root",
name="breached",
permission="view",
renderer="ordr3:templates/account/breached_password.jinja2",
)
def breached_password(context, request):
return {}

47
ordr3/views/root.py

@ -2,11 +2,8 @@
from pyramid.view import view_config from pyramid.view import view_config
from pyramid.security import forget, remember
from pyramid.httpexceptions import HTTPFound from pyramid.httpexceptions import HTTPFound
from .. import security, services
@view_config( @view_config(
context="ordr3:resources.Root", permission="view", context="ordr3:resources.Root", permission="view",
@ -16,47 +13,3 @@ def root(context, request):
return HTTPFound(request.resource_path(request.root, "orders")) return HTTPFound(request.resource_path(request.root, "orders"))
else: else:
return HTTPFound(request.resource_path(request.root, "login")) return HTTPFound(request.resource_path(request.root, "login"))
@view_config(
context="ordr3:resources.Root",
name="login",
permission="view",
request_method="GET",
renderer="ordr3:templates/root/login.jinja2",
)
def login(context, request):
return {"error": False}
@view_config(
context="ordr3:resources.Root",
name="login",
permission="view",
request_method="POST",
require_csrf=False,
renderer="ordr3:templates/root/login.jinja2",
)
def check_credentials(context, request):
username = request.POST.get("username", "")
password = request.POST.get("password", "")
crypt_context = security.get_passlib_context()
user = services.verify_credentials(
request.repo, crypt_context, username, password
)
if user is not None and user.is_active:
headers = remember(request, user.id)
return HTTPFound(
request.resource_path(request.root, "orders"), headers=headers
)
return {"error": True}
@view_config(context="ordr3:resources.Root", name="logout", permission="view")
def logout(context, request):
""" logout of a user """
headers = forget(request)
return HTTPFound(
request.resource_path(request.root, "login"), headers=headers
)

Loading…
Cancel
Save