Enhance form handling and response structure in BaseView and user login flow

1 parent c69c7bef
......@@ -20,6 +20,7 @@ from opensipkd.tools.buttons import btn_save, btn_cancel, btn_close, btn_delete,
btn_pdf, btn_unpost, btn_post
from opensipkd.tools.captcha import get_captcha
from opensipkd.tools.report import csv_response, file_response
from pyramid.request import Response
from .common import DataTables
from .. import DBSession, get_params, get_urls
from ..scripts.initializedb import append_csv
......@@ -199,7 +200,19 @@ class BaseView(object):
'jenis'] or self.jenis
self.ses['jenis'] = self.jenis
def form2dict(self, field):
children = []
for c in field.children:
children.append(self.form2dict(c))
d = {
"id": field.oid,
"name": field.name,
"error" : {"msg": field.error and field.error.msg or ""},
"children":children
}
return d
def query_register(self, **kwargs):
pass
......@@ -546,6 +559,10 @@ class BaseView(object):
return self.route_list(**kwargs)
def returned_form(self, form, table=None, **kwargs):
if self.req.is_xhr:
d = self.form2dict(form.field)
return Response(json=d)
resources = form.get_widget_resources()
readonly = "readonly" in kwargs and kwargs["readonly"] or False
kwargs["readonly"] = readonly
......@@ -556,18 +573,21 @@ class BaseView(object):
table = table["form"]
# resources["js"] = list(resources["js"])
# resources["css"] = list(resources["css"])
if is_object:
return dict(form=form,
table=table and table.render() or None,
scripts=self.form_scripts,
css=resources["css"],
js=resources["js"],
**kwargs
)
return dict(form=form.render(readonly=readonly),
if not is_object:
form = form.render(readonly=readonly)
# return dict(form=form,
# table=table and table.render() or None,
# scripts=self.form_scripts,
# css=resources["css"],
# js=resources["js"],
# **kwargs
# )
return dict(form=form,
table=table and table.render() or None,
scripts=self.form_scripts, css=resources["css"],
scripts=self.form_scripts,
css=resources["css"],
js=resources["js"],
**kwargs
)
......
......@@ -312,7 +312,7 @@ class Registrasi(BaseView):
forget(self.req)
self.ses.delete()
@view_config(route_name='register', renderer='templates/form.pt')
# @view_config(route_name='register', renderer='templates/form.pt')
def view_register(self):
self.bindings = dict(user=None)
request = self.req
......
<!DOCTYPE html>
<html lang="en"
tal:define="home request._host;">
<html lang="en" tal:define="home request._host;">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
......@@ -20,7 +20,7 @@
<!-- SmartAdmin Styles : Caution! DO NOT change the order -->
<link rel="stylesheet" type="text/css" media="screen"
href="${home}/static/v3/css/smartadmin-production-plugins.min.css">
href="${home}/static/v3/css/smartadmin-production-plugins.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/smartadmin-production.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/smartadmin-skins.min.css">
......@@ -31,181 +31,178 @@
</head>
<body>
<div id="content" class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-6 col-md-offset-3 col-lg-4 col-lg-offset-4" style="margin-top:50px">
<div class="well no-padding">
<form id="deform" method="POST" enctype="multipart/form-data" accept-charset="utf-8"
class="smart-form client-form panel form-signin" style="border:0px;">
<header class="bg-color-blue">
<h1 class="txt-color-white login-header-big" align="center"
style="letter-spacing:1px;">${request.app_name}</h1>
</header>
<fieldset class="deformFormFieldset">
<input type="hidden" name="_charset_"/>
<input type="hidden" name="__formid__" value="deform"/>
<div tal:condition="request.session.peek_flash()">
<div class="alert alert-success" tal:repeat="message request.session.pop_flash()"><i
class="fa fa-fw fa-lg fa-check-circle"></i>&nbsp;${message}
</div>
</div>
<div tal:condition="request.session.peek_flash('error')">
<div class="alert alert-danger" tal:repeat="message request.session.pop_flash('error')"><i
class="fa fa-fw fa-lg fa-times-circle"></i>&nbsp;${message}
<div id="content" class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-6 col-md-offset-3 col-lg-4 col-lg-offset-4" style="margin-top:50px">
<div class="well no-padding">
<form id="deform" method="POST" enctype="multipart/form-data" accept-charset="utf-8"
class="smart-form client-form panel form-signin" style="border:0px;">
<header class="bg-color-blue">
<h1 class="txt-color-white login-header-big" align="center" style="letter-spacing:1px;">
${request.app_name}</h1>
</header>
<fieldset class="deformFormFieldset">
<input type="hidden" name="_charset_" />
<input type="hidden" name="__formid__" value="deform" />
<div tal:condition="request.session.peek_flash()">
<div class="alert alert-success" tal:repeat="message request.session.pop_flash()"><i
class="fa fa-fw fa-lg fa-check-circle"></i>&nbsp;${message}
</div>
</div>
</div>
<div class="col-md-12" align="center">
<img src="${home}/static/img/logo.png"
class="img-float img-thumbnail" style="height:auto;width:auto;border:none;"/>
</div>
<div class="clearfix"></div>
<section>
<label class="label">USERNAME</label>
<label class="input"> <i class="icon-append fa fa-user"></i>
<input id="username" type="text" name="username" class="form-control">
<b class="tooltip tooltip-top-right">
<i class="fa fa-user txt-color-teal"></i>
ISI DENGAN USERNAME ANDA</b></label>
</section>
<section>
<label class="label">PASSWORD</label>
<label class="input"> <i class="icon-append fa fa-lock"></i>
<input id="password" type="password" name="password" class="form-control">
<b class="tooltip tooltip-top-right"><i class="fa fa-lock txt-color-teal"></i> ISI
DENGAN PASSWORD ANDA</b> </label>
</section>
<section>
<div class="form-group">
<label class=" checkbox checkbox-inline">
<input id="show_password" type="checkbox" style="left: 20px;">Show Password</label>
<div class="note">
<a href="${home}/reset-password" id="lupa" >Lupa Password?</a>
<div tal:condition="request.session.peek_flash('error')">
<div class="alert alert-danger" tal:repeat="message request.session.pop_flash('error')"><i
class="fa fa-fw fa-lg fa-times-circle"></i>&nbsp;${message}
</div>
</div>
</section>
<div class="col-md-12" align="center">
<img src="${home}/static/img/logo.png" class="img-float img-thumbnail"
style="height:auto;width:auto;border:none;" />
</div>
<div class="clearfix"></div>
<section>
<label class="label">USERNAME</label>
<label class="input"> <i class="icon-append fa fa-user"></i>
<input id="username" type="text" name="username" class="form-control">
<b class="tooltip tooltip-top-right">
<i class="fa fa-user txt-color-teal"></i>
ISI DENGAN USERNAME ANDA</b></label>
</section>
<section>
<label class="label">PASSWORD</label>
<label class="input"> <i class="icon-append fa fa-lock"></i>
<input id="password" type="password" name="password" class="form-control">
<b class="tooltip tooltip-top-right"><i class="fa fa-lock txt-color-teal"></i> ISI
DENGAN PASSWORD ANDA</b> </label>
</section>
<section>
<div class="form-group">
<label class=" checkbox checkbox-inline">
<input id="show_password" type="checkbox" style="left: 20px;">Show Password</label>
<div class="note">
<a href="${home}/reset-password" id="lupa">Lupa Password?</a>
</div>
</div>
</section>
<section>
<div tal:condition="'csrf_token' in form">
<div tal:define="field form['csrf_token']" style="display: none;">
<section>
<div tal:condition="'csrf_token' in form">
<div tal:define="field form['csrf_token']" style="display: none;">
${structure:field.serialize()}
</div>
</div>
</div>
</section>
</fieldset>
<footer>
<section>
<div class="row" style="float:right">
<button type="submit" id="login-btn" name="login"
class="btn btn-primary" style="float:left"
value="Login">
Login
</button>
<button tal:condition="allow_register(request)"
id="register" name="register" class="btn btn-info"
</section>
</fieldset>
<footer>
<section>
<div class="row" style="float:right">
<button type="submit" id="login-btn" name="login" class="btn btn-primary" style="float:left"
value="Login">
Login
</button>
<button tal:condition="allow_register(request)" id="register" name="register" class="btn btn-info"
value="Register" style="float:left">
Register
</button>
<!--? <div class="clearfix"></div>-->
</div>
</section>
</footer>
<footer>
<section>
<div class="row" tal:condition="request.google_signin_client_id and allow_register(request)">
<div id="g_id_onload"
data-client_id="${request.google_signin_client_id}"
data-callback="onSignIn">
Register
</button>
<!--? <div class="clearfix"></div>-->
</div>
<div class="g_id_signin" data-type="standard"></div>
</div>
</section>
<section>
<input id="provider_name" type="hidden" name="provider_name" class="form-control">
<input id="id_token" type="hidden" name="id_token" class="form-control">
</section>
</footer>
</section>
</footer>
<footer>
<section>
<div class="row" tal:condition="request.google_signin_client_id and allow_register(request)">
<div id="g_id_onload" data-client_id="${request.google_signin_client_id}" data-callback="onSignIn">
</div>
<div class="g_id_signin" data-type="standard"></div>
</div>
</section>
<section>
<input id="provider_name" type="hidden" name="provider_name" class="form-control">
<input id="id_token" type="hidden" name="id_token" class="form-control">
</section>
</footer>
</form>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" src="${home}/deform_static/scripts/jquery-2.0.3.min.js"></script>
<script type="text/javascript" src="${home}/deform_static/scripts/bootstrap.min.js"></script>
<script type="text/javascript" src="${home}/deform_static/scripts/deform.js"></script>
<!--? <script tal:condition="request.google_signin_client_id"-->
<!--? src="https://apis.google.com/js/platform.js" async defer></script>-->
<script tal:condition="request.google_signin_client_id"
src="https://accounts.google.com/gsi/client" async defer></script>
<script tal:condition="request.google_signin_client_id">
window.onload = function (e) {
const value = document.cookie;
const parts = value.split(`g_state=`);
if (parts.length === 2) {
document.cookie = document.cookie + ";max-age=0";
}
}
function onSignIn(googleUser) {
// var profile = googleUser.getBasicProfile();
// console.log('ID: ' + profile.getId()); // Do not send to your backend! Use an ID token instead.
// console.log('Name: ' + profile.getName());
// console.log('Image URL: ' + profile.getImageUrl());
// console.log('Email: ' + profile.getEmail()); // This is null if the 'email' scope is not present.
//getId(), getName(), getGivenName(), getFamilyName(), getImageUrl(), getEmail() methods, and
// console.log(googleUser);
// console.log(googleUser.getId());
// console.log(googleUser.getName());
// var id_token = googleUser.getAuthResponse().id_token;
document.getElementById('provider_name').value = "google";
document.getElementById('id_token').value = JSON.stringify(googleUser);
document.getElementById("deform").submit();
// var xhr = new XMLHttpRequest();
// xhr.open('POST', '/googlesignin');
// xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// xhr.onload = function() {
// console.log('Signed in as: ' + xhr.responseText);
// };
// xhr.send('idtoken=' + id_token);
}
$(document).ready(function () {
$("form#deform").keypress(function (event) {
var keycode = (event.keyCode ? event.keyCode : event.which);
if (keycode == '13') {
event.preventDefault();
$("button#login-btn").click();
<!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" src="${home}/deform_static/scripts/jquery-2.0.3.min.js"></script>
<script type="text/javascript" src="${home}/deform_static/scripts/bootstrap.min.js"></script>
<script type="text/javascript" src="${home}/deform_static/scripts/deform.js"></script>
<!--? <script tal:condition="request.google_signin_client_id"-->
<!--? src="https://apis.google.com/js/platform.js" async defer></script>-->
<script tal:condition="request.google_signin_client_id" src="https://accounts.google.com/gsi/client" async
defer></script>
<script tal:condition="request.google_signin_client_id">
window.onload = function (e) {
const value = document.cookie;
const parts = value.split(`g_state=`);
if (parts.length === 2) {
document.cookie = document.cookie + ";max-age=0";
}
}
function onSignIn(googleUser) {
// var profile = googleUser.getBasicProfile();
// console.log('ID: ' + profile.getId()); // Do not send to your backend! Use an ID token instead.
// console.log('Name: ' + profile.getName());
// console.log('Image URL: ' + profile.getImageUrl());
// console.log('Email: ' + profile.getEmail()); // This is null if the 'email' scope is not present.
//getId(), getName(), getGivenName(), getFamilyName(), getImageUrl(), getEmail() methods, and
// console.log(googleUser);
// console.log(googleUser.getId());
// console.log(googleUser.getName());
// var id_token = googleUser.getAuthResponse().id_token;
document.getElementById('provider_name').value = "google";
document.getElementById('id_token').value = JSON.stringify(googleUser);
document.getElementById("deform").submit();
// var xhr = new XMLHttpRequest();
// xhr.open('POST', '/googlesignin');
// xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// xhr.onload = function() {
// console.log('Signed in as: ' + xhr.responseText);
// };
// xhr.send('idtoken=' + id_token);
}
$(document).ready(function () {
$("form#deform").keypress(function (event) {
var keycode = (event.keyCode ? event.keyCode : event.which);
if (keycode == '13') {
event.preventDefault();
$("button#login-btn").click();
}
});
});
});
</script>
<script>
$(document).ready(function () {
$("#show_password").on("click", function () {
var x = $("#password");
if (x.attr("type") === "password") {
x.attr("type","text");
} else {
x.attr("type","password");
}
</script>
<script>
$(document).ready(function () {
$("#show_password").on("click", function () {
var x = $("#password");
if (x.attr("type") === "password") {
x.attr("type", "text");
} else {
x.attr("type", "password");
}
});
});
});
</script>
</script>
</body>
</html>
\ No newline at end of file
<html metal:use-macro="load: ./base3.1.pt" tal:define="
scripts scripts|scripts;
readonly readonly|readonly;">
<div metal:fill-slot="content">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-fw fa-plus"></i>&nbsp;${request.title}</h3>
</div>
<div class="panel-body">
<div tal:content="structure form.render(readonly=readonly)"></div>
</div>
</div>
</div>
<div metal:fill-slot="scripts">
<script>
$(document).ready(function () {
// $(".read-only").attr("readonly", true);
$(".readonly").attr("readonly", true);
$(".date").attr("readonly", true);
// $(".date").datepicker({
// format: 'dd-mm-yyyy'
// });
${ structure: scripts }
});
</script>
<div metal:define-slot="scripts"></div>
</div>
</html>
\ No newline at end of file
......@@ -23,7 +23,7 @@ import os
import re
from datetime import timedelta, datetime
from importlib import import_module
from pyramid.request import Response
import colander
from deform import widget, Form, ValidationFailure, Button
from pyramid.csrf import new_csrf_token
......@@ -196,7 +196,12 @@ class ViewLogin(BaseView):
except ValidationFailure as e:
msg = 'Login gagal'
set_user_log(msg, request, log, identity)
if self.req.is_xhr:
d = self.form2dict(form.field)
return Response(json=d)
request.session.flash(msg, 'error')
return HTTPFound(location=get_urls(request.route_url('login')))
values = dict(c)
......
<form
tal:define="style style|field.widget.style;
<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;
......@@ -11,62 +10,45 @@
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;
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"
class="deform ${field.bootstrap_form_style | 'form-horizontal'}"
i18n:domain="deform"
>
attributes|field.widget.attributes|{};" id="${formid}" method="${method}" enctype="multipart/form-data"
accept-charset="utf-8" class="deform ${field.bootstrap_form_style | 'form-horizontal'}" i18n:domain="deform">
<fieldset class="deform-form-fieldset">
<div class="row">
<legend tal:condition="title">${title}</legend>
<input type="hidden" name="_charset_"/>
<input type="hidden" name="__formid__" value="${formid}"/>
<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">${field.errormsg}</p>
</div>
<p class="section first" tal:condition="description">
${description}
${description}
</p>
<div tal:repeat="child field"
tal:replace="structure child.render_template(item_template)"/>
<div tal:repeat="child field" tal:replace="structure child.render_template(item_template)" />
</div>
<div class="row">
<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-default';"
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'">
<button tal:define="btn_disposition repeat.button.start and 'btn-primary' or 'btn-default';"
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.title}
</button>
<a
tal:define="btn_disposition repeat.button.start and 'btn-primary' or 'btn-default';
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'">
<a tal:define="btn_disposition repeat.button.start and 'btn-primary' or 'btn-default';
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}
${button.title}
</a>
</tal:loop>
</div>
......@@ -75,34 +57,38 @@
<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;
});
}
'${formid}',
function (oid) {
var target = '#' + oid;
var options = {
// target: target,
// replaceTarget: true,
replaceTarget: false,
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));
}
};
var extra_options = ${ ajax_options }|| {};
$('#' + oid).ajaxForm($.extend(options, extra_options));
// $('#' + oid).ajaxForm(
// function () {
// alert("test");
// }
// );
}
);
</script>
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!