Commit 91124f84 by aagusti

list simple

1 parent 6354fa0b
$(document).ready(function () {
$('#parent_nm').bind('typeahead:selected', function (obj, datum, name) {
$('#parent_id').val(datum.id);
$('#parent_kd').val(datum.kode);
console.log(datum.kode);
});
});
\ No newline at end of file \ No newline at end of file
/* dataTables Customize */ /* dataTables Customize */
table.dataTable thead { table.dataTable thead {
-- background-color: #EAEAEA; background-color: #EAEAEA;
} }
table.table-hover>tbody>tr:hover {
table.table-hover > tbody > tr:hover {
background-color: #9FAFD1; background-color: #9FAFD1;
} }
table.dataTable tr.even.selected td { table.dataTable tr.even.selected td {
background-color: #B0BED9; background-color: #B0BED9;
} }
table.dataTable tr.odd.selected td { table.dataTable tr.odd.selected td {
background-color: #9FAFD1; background-color: #9FAFD1;
} }
@media only screen and (max-width: 980px) { @media only screen and (max-width: 980px) {
aside { aside {
padding-bottom:60px; padding-bottom: 60px;
} }
} }
aside span.footer-side { aside span.footer-side {
position:absolute; position: absolute;
bottom:10px; bottom: 10px;
display:block; display: block;
text-align:center; text-align: center;
width:100%; width: 100%;
font-size:12px; font-size: 12px;
color:#c0bbb7; color: #c0bbb7;
} }
.minified aside span.footer-side { .minified aside span.footer-side {
display:none; display: none;
} }
.loading { .loading {
background:url(../img/loading.gif) left center no-repeat; background: url(../img/loading.gif) left center no-repeat;
padding-left:30px !Important; padding-left: 30px !Important;
} }
input.tt-hint { input.tt-hint {
padding-left:30px !Important; padding-left: 30px !Important;
}
.tab-content {
padding-top: 20px
}
.help-block {
color: #ff0000;
font-weight: bold;
}
.SmallBox p {
letter-spacing: 0.1px;
}
.SmallBox span {
letter-spacing: 0.1px;
}
.navbar-default .navbar-nav>.open>a,
.navbar-default .navbar-nav>.open>a:hover {
color: #555!important
}
#loading {
width: 100%;
height: 100%;
top: 0;
left: 0;
position: fixed;
display: block;
opacity: 0.7;
background-color: #fff;
z-index: 1000;
text-align: center;
}
#loading-image {
display:block;
margin-top: auto;
margin-bottom: auto;
margin-left: auto;
margin-right: auto;
/*width: 10%;*/
z-index: 1000;
}
body {
background: 0 0;
background-image: url(/static/img/background.png);
background-position: center;
background-repeat: no-repeat;
background-size: cover;
background-attachment: fixed
}
.navbar-default .navbar-nav>li>a {
color: #fff
}
.navbar-default .navbar-nav>li>a:hover {
color: #fff
}
.project-context .title-page {
font-size: 16px;
line-height: 40px;
color: #474544
}
.dataTable td {
transition: opacity 1s ease 0s
}
body,
html {
overflow-x: hidden
}
.well {
background-color: #fff
}
#header {
background-image: none!important;
background-color: #57889c!important;
box-shadow: none!important;
border: 0!important;
height:auto !important;
}
.container {
height: 100%
}
.fixed-navigation nav>ul {
height: auto
}
#header #logo-group {
padding: 2px 5px
}
#header #logo-group #logo {
margin: 0
}
#header #logo-group #logo img {
height: 44px;
width: auto;
margin: 0
}
.project-context .title-page {
font-weight: 400;
color: #fff
}
#header .header-dropdown-list a.dropdown-toggle,
.project-context .label,
.project-context .project-selector {
color: #fff
}
.project-context .label {
text-shadow: none
}
#header #fullscreen a,
#header #hide-menu a {
background-image: none;
background-color: #fff;
border: 0;
color:#222;
}
.alert {
border-left-width: 0
}
.btn-primary {
background-color: #57889c!important;
color: #fff!important;
border: 0
}
.btn-default {
background-color: #e6e6e6!important;
color: #676767!important;
border: 0
}
.alert-info,
.btn-info {
background-color: #1956af!important;
color: #fff!important
}
.alert-success,
.btn-success {
background-color: #00a65a!important;
color: #fff!important
}
.alert-warning,
.btn-warning {
background-color: #f39c12!important;
color: #fff!important
}
.alert-danger,
.btn-danger {
background-color: #dd4b39!important;
color: #fff!important
}
.btn {
border: 0!important
}
.help-block {
color: #f30303!important
}
nav ul li a i {
width: 24px!important
}
@media only screen and (max-width:768px) {
#header #fullscreen a,
#header #hide-menu a {
background-image: none;
background-color: rgba(255, 255, 255, 0);
border: 0
}
#hide-menu i {
color: #fff!important
}
}
.btn,
a:link,
button {
-webkit-tap-highlight-color: rgba(87, 136, 156, .5)
}
.panel {
border: 1px solid #ddd!important
}
.panel-danger {
border-color: #dd4b39
}
.panel-success {
border-color: #00a65a
}
.panel-info {
/*border-color: #1956af*/
border-color: #57889c
} }
.tab-content { padding-top:20px }
.help-block { color: #ff0000; font-weight: bold; }
.SmallBox p { letter-spacing: 0.1px; }
.SmallBox span { letter-spacing: 0.1px; }
\ No newline at end of file \ No newline at end of file
.panel-warning {
border-color: #f39c12
}
.panel-danger>.panel-heading {
color: #fff;
background-color: #dd4b39;
border-color: #dd4b39
}
.panel-success>.panel-heading {
color: #fff;
background-color: #00a65a;
border-color: #00a65a
}
.panel-info>.panel-heading {
color: #fff;
/*background-color: #1956af;*/
background-color: #57889c;
border-color: #57889c
/*border-color: #1956af*/
}
.panel-warning>.panel-heading {
color: #fff;
background-color: #f39c12;
border-color: #f39c12
}
table.dataTable tr.selected td {
background-color: #9fafd1
}
:fullscreen #fullscreen>:first-child>a {
color: #6d6a69
}
.select2-selection__rendered {
padding-left: 0
}
.select2-selection--single {
height: 32px!important;
border-radius: 0!important;
border: 1px solid #ccc!important
}
div.toolbar::after {
content: "\0020";
width:100vw;
display:block;
clear:both;
}
div.dataTables_length select,
div.dataTables_filter input {
display:inline;
}
div.dataTables_filter label {
margin-bottom:0px;
}
div.dataTables_length label {
margin-bottom:0px;
}
.dataTables_wrapper {
overflow-x:scroll !important;
}
.col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-xs-1, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9 {
padding-left:7px;
padding-right:7px;
}
.dataTables_length {
margin-left:6px;
}
.ui-autocomplete-loading {
padding-right:10px;
background: url("../img/loading.gif") right 10px center no-repeat !important;
}
.ui-autocomplete {
max-height: 200px;
overflow-y: auto;
overflow-x: hidden;
}
.panel-body {
margin: 0 auto !important;
}
.col-md-5 {
padding: 0px 15px !important;
}
form.form-horizontal {
padding: 0 !important;
}
div.col-md-6 {
padding-right: 12px !important;
padding-left: 15px !important;
}
.twitter-typeahead .tt-query,
.twitter-typeahead .tt-hint {
padding: .25rem .5rem !important;
line-height: normal;
font-size: 12px;
border-radius: 0 !important;
}
.form-control{
font-size:10px !important;
height: 26px;
padding: 3px 6px;
margin-bottom: 1px !important;
}
.form-control-static {
border: 1px solid #ccc;
padding: 6px 6px;
height: 26px;
background-color: #ccc;
font-size: 10px;
margin-bottom: 1px;
}
.control-label{
font-size:10px !important;
padding: 3px 6px!important;
margin-top: 1px !important;
margin-bottom: 1px !important;
}
.help-block{
font-size:10px !important;
padding: 1px 1px !important;
}
.input-group-addon {
padding: 3px 3px !important;
font-size: 10px !important;
}
.input-group-addon:first-child {
padding: 3px 3px !important;
font-size: 10px !important;
}
.input-group {
padding: 3px 3px 7px !important;
font-size: 10px !important;
}
.form-group {
text-align: left;
margin-top:5px !important;
margin-bottom:5px !important;
}
.dataTables_filter .input-group-addon{
width: 32px !important;
margin-top: 0 !important;
float: left !important;
height: 26px !important;
padding-top: 4px !important;
}
.fc-border-separate thead tr, .table thead tr {
font-size:10px !important;
}
.twitter-typeahead{
font-size: 10px !important;
margin-bottom: 0;
width: 100%;
height: 26px;
position: absolute;
top: 0;
left: 0;
z-index:2;
}
.twitter-typeahead .tt-query, .twitter-typeahead .tt-hint {
font-size: 10px !important;
margin-bottom: 0;
width: 100%;
height: 26px;
position: absolute;
top: 0;
left: 0;
z-index:2;
}
.table-responsive {
overflow-x: hidden !important;
}
.dataTables_wrapper {
overflow-x: hidden !important;
}
.dataTables_filter{
margin-left: -8px !important;
}
.table tbody tr td {
font-size: 10px;
}
.span-new {
border-left: 0;
margin: -5px;
border: -12px;
padding: 7px !important;
}
.form-horizontal .checkbox, .form-horizontal .radio {
padding: 0px;
}
.checkbox, .radio {
position: relative;
display: block;
margin-top: 3px;
margin-bottom: 3px;
}
.form-tutup {
margin-left: 5px;
}
.footer-me {
padding-top: -16px;
margin-top: 4px;
}
.alert-success {
margin-bottom: 5px;
margin-left: 8px;
margin-right: 8px;
}
.alert-danger {
margin-bottom: 5px;
margin-left: 8px;
margin-right: 8px;
}
.twitter-typeahead .tt-query, .twitter-typeahead .tt-hint {
font-size: 10px !important;
}
.disabled {
color:
#000;
}
.checkbox label, .radio label {
font-size: 10px !important;
}
input[type="checkbox"], input[type="radio"] {
margin-top: 1px !important;
}
.list-group, .list-group-item {
font-size: 10px !important;
padding: 6px 15px !important;
}
function showError(msg) {
$("#success").css('display', 'none', 'important');
$("#errors").css('display', 'box', 'important');
$("#errors").html("<span class='glyphicon glyphicon-remove'></span> " + msg);
console.log(msg);
};
function showSuccess(msg) {
$("#errors").css('display', 'none', 'important');
$("#success").css('display', 'box', 'important');
$("#success").html("<span class='glyphicon glyphicon-ok'></span> " + msg);
};
$(function () {
var current = location.pathname;
$('nav li a').each(function () {
var $this = $(this);
if ($this.attr('href') != '' && $this.attr('href') != '#') {
if ($this.attr('href') == current) {
$this.parent().addClass('active');
var ul_parent = $this.parents('ul');
ul_parent.show();
ul_parent.parents('li').addClass('open');
}
}
})
});
$(document).ready(function () {
// DO NOT REMOVE : GLOBAL FUNCTIONS!
pageSetUp();
/*
* PAGE RELATED SCRIPTS
*/
});
function number_format(number, decimals, dec_point, thousands_sep) {
// Strip all characters but numerical ones.
number = (number + '').replace(/[^0-9+\-Ee.]/g, '');
var n = !isFinite(+number) ? 0 : +number,
prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
s = '',
toFixedFix = function (n, prec) {
var k = Math.pow(10, prec);
return '' + Math.round(n * k) / k;
};
// Fix for IE parseFloat(0.55).toFixed(0) = 0;
s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
if (s[0].length > 3) {
s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
}
if ((s[1] || '').length < prec) {
s[1] = s[1] || '';
s[1] += new Array(prec - s[1].length + 1).join('0');
}
return s.join(dec);
}
import os import os
import re import re
from datetime import datetime from datetime import datetime
from datatables import ColumnDT
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from opensipkd.tools.captcha import get_captcha from opensipkd.tools.captcha import get_captcha
from pyramid.httpexceptions import HTTPFound from pyramid.httpexceptions import HTTPFound
from .common import DataTables
from .. import DBSession, get_params from .. import DBSession, get_params
from opensipkd.tools import dmy, dmy_to_date, get_settings, get_ext from opensipkd.tools import dmy, dmy_to_date, get_settings, get_ext
import colander import colander
from deform import (widget, Form, ValidationFailure, ) from deform import (widget, Form, ValidationFailure, )
from email.utils import parseaddr from email.utils import parseaddr
from opensipkd.tools.buttons import btn_save, btn_cancel, btn_close, btn_delete from opensipkd.tools.buttons import btn_save, btn_cancel, btn_close, btn_delete, btn_view, btn_add, btn_edit, btn_csv, \
btn_pdf
from ..models import User from ..models import User
from ...detable import DeTable
class BaseView(object): class BaseView(object):
...@@ -102,11 +107,14 @@ class BaseView(object): ...@@ -102,11 +107,14 @@ class BaseView(object):
self.list_route = 'home' self.list_route = 'home'
self.list_col_defs = "" self.list_col_defs = ""
self.list_cols = "" self.list_cols = ""
self.list_buttons = 'btn_view, btn_add, btn_edit, btn_delete, ' \ # self.list_buttons = 'btn_view, btn_add, btn_edit, btn_delete, ' \
'btn_close' # 'btn_close'
self.list_report = (btn_csv, btn_pdf)
self.list_buttons = (btn_view, btn_add, btn_edit, btn_delete, btn_close)
self.form_params = dict(scripts="") self.form_params = dict(scripts="")
self.list_url = '' self.list_url = ''
self.list_route = '' self.list_route = ''
self.list_schema = ""
self.form_scripts = """ self.form_scripts = """
$('#parent_nm').bind('typeahead:selected', function(obj, datum) { $('#parent_nm').bind('typeahead:selected', function(obj, datum) {
$('#parent_id').val(datum.id); $('#parent_id').val(datum.id);
...@@ -121,7 +129,9 @@ class BaseView(object): ...@@ -121,7 +129,9 @@ class BaseView(object):
self.headers = None self.headers = None
self.bindings = {} self.bindings = {}
self.autocomplete = 'on' self.autocomplete = 'on'
# self.captcha = ""
def delete_msg(self, row):
return f'Data ID {row.id} sudah dihapus.'
def route_list(self, msg=None, error=""): def route_list(self, msg=None, error=""):
if msg: if msg:
...@@ -139,8 +149,8 @@ class BaseView(object): ...@@ -139,8 +149,8 @@ class BaseView(object):
def get_form(self, class_form, row=None, buttons=(btn_save, btn_cancel), **bindings): def get_form(self, class_form, row=None, buttons=(btn_save, btn_cancel), **bindings):
buttons = self.buttons and self.buttons or buttons buttons = self.buttons and self.buttons or buttons
bindings = self.bindings and self.bindings or bindings bindings = self.bindings and self.bindings or self.get_bindings()
schema = class_form(validator=self.form_validator) # schema = class_form(validator=self.form_validator)
schema = schema.bind(request=self.req, **bindings) schema = schema.bind(request=self.req, **bindings)
schema.request = self.req schema.request = self.req
if row: if row:
...@@ -153,18 +163,28 @@ class BaseView(object): ...@@ -153,18 +163,28 @@ class BaseView(object):
return r return r
def view_list(self, arg=None): def view_list(self, arg=None):
arg = not arg and {} or arg if self.list_schema:
table = DeTable(self.list_schema(), action=self.req.route_url(self.list_route),
action_suffix="/grid/act",
buttons=self.list_buttons)
resources = table.get_widget_resources()
return dict(form=table.render(), scripts="", css=resources["css"], js=resources["js"])
arg = arg and arg or {}
arg.update(url=self.list_url, col_defs=self.list_col_defs, arg.update(url=self.list_url, col_defs=self.list_col_defs,
cols=self.list_cols, buttons=self.list_buttons) cols=self.list_cols, buttons=self.list_buttons)
return arg return arg
def get_bindings(self, row=None):
return {}
def view_view(self): # row = query_id(request).first() def view_view(self): # row = query_id(request).first()
request = self.req request = self.req
row = self.query_id().first() row = self.query_id().first()
if not row: if not row:
return self.id_not_found() return self.id_not_found()
bindings = hasattr(self, "get_bindings") and self.get_bindings() or None bindings = self.get_bindings(row)
form = self.get_form(self.edit_schema, buttons=(btn_close,), bindings=bindings) form = self.get_form(self.edit_schema, buttons=(btn_close,), **bindings)
if request.POST: if request.POST:
return self.route_list() return self.route_list()
...@@ -174,15 +194,52 @@ class BaseView(object): ...@@ -174,15 +194,52 @@ class BaseView(object):
scripts=self.form_scripts) scripts=self.form_scripts)
def before_add(self): def before_add(self):
return return {}
def validation_failure(self, value): def validation_failure(self, value):
return value return value
def cancel_act(self): def cancel_act(self):
pass pass
def after_add(self, row, values):
return
def next_act(self):
return
def list_join(self, query):
return query
def view_act(self):
url_dict = self.req.matchdict
if url_dict['act'] == 'grid':
columns = []
for d in self.list_schema():
global_search = hasattr(d, "searchable") and hasattr(d, "searchable") == False and False or True
if hasattr(d, "field"):
if type(d.field) == str:
columns.append(
ColumnDT(getattr(self.table, d.field), mData=d.name, global_search=global_search))
else:
columns.append(ColumnDT(d.field, mData=d.name))
else:
columns.append(ColumnDT(getattr(self.table, d.name), mData=d.name))
query = DBSession.query().select_from(self.table)
query = self.list_join(query)
if self.req.user.company_id and hasattr(self.table, "company_id"):
query = query.filter(self.table.company_id == self.req.user.company_id)
row_table = DataTables(self.req.GET, query, columns)
return row_table.output_result()
else:
self.next_act()
def view_add(self): def view_add(self):
form = self.get_form(self.add_schema) bindings = self.get_bindings()
form = self.get_form(self.add_schema, **bindings)
table = self.get_item_table()
resources = form.get_widget_resources()
if self.req.POST: if self.req.POST:
if 'save' in self.req.POST: if 'save' in self.req.POST:
controls = self.req.POST.items() controls = self.req.POST.items()
...@@ -192,17 +249,19 @@ class BaseView(object): ...@@ -192,17 +249,19 @@ class BaseView(object):
value = self.validation_failure(e.cstruct) value = self.validation_failure(e.cstruct)
value.update(self.before_add()) value.update(self.before_add())
form.render(appstruct=value) form.render(appstruct=value)
return dict(form=form.render(), scripts=self.form_scripts) return dict(form=form.render(), table=table and table.render() or None,
self.save_request(dict(controls)) scripts=self.form_scripts, css=resources["css"], js=resources["js"])
values = dict(controls)
row = self.save_request(values)
self.after_add(row, values)
if "cancel" in self.req.POST or 'batal' in self.req.POST: if "cancel" in self.req.POST or 'batal' in self.req.POST:
self.cancel_act() self.cancel_act()
return self.route_list() return self.route_list()
values = self.before_add() values = self.before_add()
form.set_appstruct(values) form.set_appstruct(values)
table = self.get_item_table()
return dict(form=form.render(), table=table and table.render() or None, return dict(form=form.render(), table=table and table.render() or None,
scripts=self.form_scripts) scripts=self.form_scripts, css=resources["css"], js=resources["js"])
def before_save(self, row, values): def before_save(self, row, values):
return row return row
...@@ -230,9 +289,9 @@ class BaseView(object): ...@@ -230,9 +289,9 @@ class BaseView(object):
def save_request(self, values, row=None): def save_request(self, values, row=None):
params = self.req.params params = self.req.params
for p in params: for k, v in params.items():
values[p] = params[p] if v:
values[k] = v
return self.save(values, self.req.user, row) return self.save(values, self.req.user, row)
def id_not_found(self): def id_not_found(self):
...@@ -262,7 +321,11 @@ class BaseView(object): ...@@ -262,7 +321,11 @@ class BaseView(object):
row = self.query_id().first() row = self.query_id().first()
if not row: if not row:
return self.id_not_found() return self.id_not_found()
if not self.bindings:
self.bindings = self.get_bindings(row)
form = self.get_form(self.edit_schema) form = self.get_form(self.edit_schema)
table = self.get_item_table(row)
resources = form.get_widget_resources()
if request.POST: if request.POST:
if 'save' in request.POST: if 'save' in request.POST:
controls = request.POST.items() controls = request.POST.items()
...@@ -270,15 +333,19 @@ class BaseView(object): ...@@ -270,15 +333,19 @@ class BaseView(object):
controls = form.validate(controls) controls = form.validate(controls)
except ValidationFailure as e: except ValidationFailure as e:
form.set_appstruct(e.cstruct) form.set_appstruct(e.cstruct)
return dict(form=form.render(), scripts=self.form_scripts) return dict(form=form.render(), table=table and table.render() or None,
scripts=self.form_scripts, css=resources["css"], js=resources["js"])
self.save_request(dict(controls), row) self.save_request(dict(controls), row)
return self.route_list() return self.route_list()
values = self.get_values(row) values = self.get_values(row)
form.set_appstruct(values) form.set_appstruct(values)
form = self.before_edit(form) form = self.before_edit(form)
table = self.get_item_table(row) return dict(form=form.render(), table=table and table.render() or None,
return dict(form=form.render(), table=table and table.render() or None, scripts=self.form_scripts) scripts=self.form_scripts, css=resources["css"], js=resources["js"])
def before_delete(self, row):
pass
def view_delete(self): def view_delete(self):
request = self.req request = self.req
...@@ -288,15 +355,18 @@ class BaseView(object): ...@@ -288,15 +355,18 @@ class BaseView(object):
return self.id_not_found() return self.id_not_found()
if request.POST: if request.POST:
if 'delete' in request.POST: if 'delete' in request.POST:
msg = f'Data ID {row.id} sudah dihapus.' msg = self.delete_msg(row)
self.before_delete(row)
q.delete() q.delete()
DBSession.flush() DBSession.flush()
request.session.flash(msg) request.session.flash(msg)
return self.route_list() return self.route_list()
form = self.get_form(self.edit_schema, buttons=(btn_delete, btn_cancel)) form = self.get_form(self.edit_schema, buttons=(btn_delete, btn_cancel))
form.set_appstruct(self.get_values(row))
table = self.get_item_table(row) table = self.get_item_table(row)
return dict(form=form.render(), table=table and table.render() or None, scripts=self.form_scripts) resources = form.get_widget_resources()
form.set_appstruct(self.get_values(row))
return dict(form=form.render(readonly=True), table=table and table.render() or None,
scripts=self.form_scripts, css=resources["css"], js=resources["js"])
def query_id(self): def query_id(self):
q = DBSession.query(self.table).filter_by( q = DBSession.query(self.table).filter_by(
...@@ -305,6 +375,11 @@ class BaseView(object): ...@@ -305,6 +375,11 @@ class BaseView(object):
q = q.filter_by(company_id=self.req.user.company_id) q = q.filter_by(company_id=self.req.user.company_id)
return q return q
def filter_company(self, query):
if self.req.user.company_id:
return query.filter(self.table.company_id == self.req.user.company_id)
return query
@colander.deferred @colander.deferred
def deferred_status(node, kw): def deferred_status(node, kw):
...@@ -346,6 +421,7 @@ def need_captcha(): ...@@ -346,6 +421,7 @@ def need_captcha():
is_captcha = get_params("reg_captcha") is_captcha = get_params("reg_captcha")
return is_captcha == '1' or is_captcha == "True" or is_captcha == "true" or is_captcha == True return is_captcha == '1' or is_captcha == "True" or is_captcha == "true" or is_captcha == True
def need_verify(): def need_verify():
result = get_params("reg_verify") result = get_params("reg_verify")
return result == '1' or result == "True" or result == "true" or result == True return result == '1' or result == "True" or result == "true" or result == True
......
...@@ -50,7 +50,7 @@ class ViewCompany(BaseView): ...@@ -50,7 +50,7 @@ class ViewCompany(BaseView):
self.list_buttons = 'btn_view, btn_add, btn_edit, btn_delete, ' \ self.list_buttons = 'btn_view, btn_add, btn_edit, btn_delete, ' \
'btn_close' 'btn_close'
self.form_params = dict(scripts="") self.form_params = dict(scripts="")
self.list_url = 'company' # self.list_url = 'company'
self.list_route = 'company' self.list_route = 'company'
self.add_schema = AddSchema self.add_schema = AddSchema
self.edit_schema = EditSchema self.edit_schema = EditSchema
......
import json
import colander import colander
from deform import (widget, Form, ) from deform import (widget, )
from opensipkd.tools.buttons import btn_close, btn_cancel, btn_save, btn_add, btn_edit, btn_delete
from pyramid.view import (view_config, ) from pyramid.view import (view_config, )
from . import widget_os from . import widget_os
from opensipkd.detable import DeTable
from .provinsi import provinsi_widget from .provinsi import provinsi_widget
from ..models import DBSession, ResDati2, kategori_dati2, ResProvinsi from ..models import DBSession, ResDati2, kategori_dati2, ResProvinsi
from ..views import ColumnDT, DataTables, BaseView from ..views import ColumnDT, DataTables, BaseView
...@@ -51,7 +47,7 @@ class ListSchema(colander.Schema): ...@@ -51,7 +47,7 @@ class ListSchema(colander.Schema):
kode = colander.SchemaNode(colander.String(), width='100pt', title="Kode") kode = colander.SchemaNode(colander.String(), width='100pt', title="Kode")
nama = colander.SchemaNode(colander.String(), title="Nama") nama = colander.SchemaNode(colander.String(), title="Nama")
provinsi = colander.SchemaNode(colander.String()) provinsi = colander.SchemaNode(colander.String())
status = colander.SchemaNode(colander.Integer(),width="30pt") status = colander.SchemaNode(colander.Integer(), width="30pt")
class ViewDati2(BaseView): class ViewDati2(BaseView):
...@@ -64,6 +60,7 @@ class ViewDati2(BaseView): ...@@ -64,6 +60,7 @@ class ViewDati2(BaseView):
self.add_schema = AddSchema self.add_schema = AddSchema
self.edit_schema = EditSchema self.edit_schema = EditSchema
self.table = ResDati2 self.table = ResDati2
self.list_schema = ListSchema
######## ########
# List # # List #
...@@ -103,43 +100,20 @@ class ViewDati2(BaseView): ...@@ -103,43 +100,20 @@ class ViewDati2(BaseView):
elif found: elif found:
err_nama() err_nama()
def get_form(self, class_form, row=None, buttons=(btn_save, btn_cancel)): def get_bindings(self, row=None):
schema = class_form(validator=self.form_validator) return dict(request=self.req,
schema = schema.bind(request=self.req,
provinsi_list=ResProvinsi.get_list()) provinsi_list=ResProvinsi.get_list())
schema.request = self.req
if row:
schema.deserialize(row)
return Form(schema, buttons=buttons)
@view_config(route_name='dati2', @view_config(route_name='dati2',
renderer='templates/form_input.pt', renderer='templates/table.pt',
permission='dati2') permission='dati2')
def view_list(self): def view_list(self):
table = DeTable(ListSchema(title="Kabupaten/Kota"), action=f"{self.home}/dati2", return super(ViewDati2, self).view_list()
buttons=(btn_close, btn_add, btn_edit, btn_delete))
return dict(form=table.render(), scripts=self.form_scripts)
@view_config(route_name='dati2-view', @view_config(route_name='dati2-view',
renderer='templates/form_input.pt', permission='dati2') renderer='templates/form.pt', permission='dati2')
def view_view(self): # row = query_id(request).first() def view_view(self): # row = query_id(request).first()
request = self.req return super(ViewDati2, self).view_view()
row = self.query_id().first()
if not row:
return self.id_not_found()
form = self.get_form(EditSchema, buttons=(btn_close,))
if request.POST:
return self.route_list()
form.set_appstruct(self.get_values(row))
return dict(form=form.render(readonly=True), scripts=self.form_scripts)
# @view_config(route_name='dati2',
# renderer='templates/list.pt',
# permission='dati2')
# def view_list(self):
# return super().viewlist()
@view_config(route_name='dati2-act', renderer='json', @view_config(route_name='dati2-act', renderer='json',
permission='view') permission='view')
...@@ -175,9 +149,6 @@ class ViewDati2(BaseView): ...@@ -175,9 +149,6 @@ class ViewDati2(BaseView):
def view_edt(self): def view_edt(self):
return super(ViewDati2, self).view_edit() return super(ViewDati2, self).view_edit()
##########
# Delete
##########
@view_config(route_name='dati2-delete', @view_config(route_name='dati2-delete',
renderer='templates/form_input.pt', permission='dati2') renderer='templates/form_input.pt', permission='dati2')
def view_delete(self): def view_delete(self):
......
import csv import csv
import json
import os import os
import shutil import shutil
from datetime import datetime from datetime import datetime
import colander import colander
from deform import (Form, widget, ValidationFailure, ) from deform import (widget, )
from deform.widget import AutocompleteInputWidget from deform.widget import AutocompleteInputWidget
from pyramid.httpexceptions import (HTTPFound, ) from opensipkd.tools import (get_ext, get_random_string, get_settings)
from pyramid.view import (view_config, ) from pyramid.view import (view_config, )
from sqlalchemy import func from sqlalchemy import func
from sqlalchemy.orm import aliased from sqlalchemy.orm import aliased
from opensipkd.tools import (get_ext, get_random_string, get_settings)
from opensipkd.tools.buttons import btn_cancel, btn_save, btn_delete, btn_close
from .company import company_widget from .company import company_widget
from .upload import AddSchema as UploadSchema from .upload import AddSchema as UploadSchema
from .. import renderer from ..models import DBSession, Departemen, Partner, PartnerDepartemen
from ..models import DBSession, Departemen, Partner, PartnerDepartemen, ResCompany
from ..views import ColumnDT, DataTables, BaseView from ..views import ColumnDT, DataTables, BaseView
SESS_ADD_FAILED = 'Tambah departemen gagal' SESS_ADD_FAILED = 'Tambah departemen gagal'
...@@ -40,11 +36,19 @@ def departemen_widget(node, kw): ...@@ -40,11 +36,19 @@ def departemen_widget(node, kw):
class AddSchema(colander.Schema): class AddSchema(colander.Schema):
parent_id = colander.SchemaNode(colander.Integer(), parent_id = colander.SchemaNode(
widget=widget.HiddenWidget(), oid="parent_id", missing=colander.drop, ) colander.Integer(),
widget=widget.HiddenWidget(), oid="parent_id", missing=colander.drop,
)
parent_nm = colander.SchemaNode(
colander.String(), missing=colander.drop,
widget=widget.AutocompleteInputWidget(
size=60, min_length=3,
requirements=(("typeahead", None), ("deform", None),
{"js": "opensipkd.base:static/js/form/departemen.js"})
),
parent_nm = colander.SchemaNode(colander.String(), missing=colander.drop,
widget=AutocompleteInputWidget(size=60, min_length=3, ),
oid="parent_nm", title="Induk") oid="parent_nm", title="Induk")
parent_kd = colander.SchemaNode(colander.String(), parent_kd = colander.SchemaNode(colander.String(),
widget=widget.TextInputWidget(css_class="readonly"), widget=widget.TextInputWidget(css_class="readonly"),
...@@ -72,12 +76,19 @@ class AddSchema(colander.Schema): ...@@ -72,12 +76,19 @@ class AddSchema(colander.Schema):
def after_bind(self, schema, kwargs): def after_bind(self, schema, kwargs):
request = kwargs["request"] request = kwargs["request"]
self["parent_nm"] = colander.SchemaNode(colander.String(), # self["parent_nm"] = colander.SchemaNode(
missing=colander.drop, # colander.String(),
widget=AutocompleteInputWidget(size=60, min_length=3, # missing=colander.drop,
values=f"{request._host}/departemen/hon/act"), # widget=AutocompleteInputWidget(
oid="parent_nm", # size=60, min_length=3,
title="Induk", ) # values=f"{request.route_url('departemen')}/hon/act"),
# oid="parent_nm",
# title="Induk", )
self["parent_nm"].widget = widget.AutocompleteInputWidget(
size=60, min_length=3,
requirements=(("typeahead", None), ("deform", None),
{"js": "opensipkd.base:static/js/form/departemen.js"}),
values=f"{request.route_url('departemen')}/hon/act")
if request.user.company_id: if request.user.company_id:
self["company_id"].widget = widget.HiddenWidget() self["company_id"].widget = widget.HiddenWidget()
self["company_id"].default = request.user.company_id self["company_id"].default = request.user.company_id
...@@ -88,56 +99,43 @@ class EditSchema(AddSchema): ...@@ -88,56 +99,43 @@ class EditSchema(AddSchema):
widget=widget.HiddenWidget(readonly=True)) widget=widget.HiddenWidget(readonly=True))
class ListSchema(colander.Schema):
id = colander.SchemaNode(colander.String(), title="ID", visible=False)
kode = colander.SchemaNode(colander.String(), title="Kode", width='100pt')
nama = colander.SchemaNode(colander.String(), title="Nama")
status = colander.SchemaNode(colander.Boolean(), title="Status", width='50pt')
level_id = colander.SchemaNode(colander.String(), title="Level", width='50pt')
parent = colander.SchemaNode(colander.String(), title="Induk", width='200pt')
class ViewDepartemen(BaseView): class ViewDepartemen(BaseView):
def __init__(self, request): def __init__(self, request):
super(ViewDepartemen, self).__init__(request) super(ViewDepartemen, self).__init__(request)
self.form_scripts = """ self.list_schema = ListSchema
$(document).ready(function () { self.add_schema = AddSchema
$('#parent_nm').typeahead({ self.edit_schema = EditSchema
"hint" : true,
"highlight": true,
"minLength": 1,
"remote" : {
url: "/departemen/hon/act?term=%QUERY",
beforeSend: function () {
$('#parent_nm').addClass("loading");
},
filter: function(parsedResponse){
$('#parent_nm').removeClass('loading');
return parsedResponse;
}
},
},{
"name" : 'parent_nm',
"displayKey": 'value',
});
$('#parent_nm').bind('typeahead:selected', function(obj, datum, name) {
$('#parent_id').val(datum.id);
$('#parent_kd').val(datum.kode);
});
});
"""
self.list_col_defs = json.dumps(
[{"searchable": False, "visible": False, "targets": [0], }, {
"searchable": True, "orderable": True, "targets": [1, 2],
}])
self.list_cols = [{'title': "ID", 'data': "id"},
{'title': "Kode", 'data': "kode", 'width': '100pt'},
{'title': "Nama", 'data': "nama"}, ]
self.list_buttons = 'btn_view, btn_add, btn_edit, btn_delete, ' \
'btn_close'
self.form_params = dict(scripts="")
self.list_url = 'departemen'
self.list_route = 'departemen'
self.table = Departemen self.table = Departemen
# self.list_url = 'departemen'
self.list_route = 'departemen'
self.form_scripts = ""
# """
# self.list_col_defs = json.dumps(
# [{"searchable": False, "visible": False, "targets": [0], }, {
# "searchable": True, "orderable": True, "targets": [1, 2],
# }])
# self.list_cols = [{'title': "ID", 'data': "id"},
# {'title': "Kode", 'data': "kode", 'width': '100pt'},
# {'title': "Nama", 'data': "nama"}, ]
# self.list_buttons = 'btn_view, btn_add, btn_edit, btn_delete, ' \
# 'btn_close'
# self.form_params = dict(scripts="")
######## ########
# List # # List #
######## ########
@staticmethod def form_validator(self, form, value):
def form_validator(form, value):
def err_kode(): def err_kode():
raise colander.Invalid(form, 'Kode %s sudah digunakan oleh %s' % ( raise colander.Invalid(form, 'Kode %s sudah digunakan oleh %s' % (
value['kode'], found.nama)) value['kode'], found.nama))
...@@ -154,16 +152,22 @@ class ViewDepartemen(BaseView): ...@@ -154,16 +152,22 @@ class ViewDepartemen(BaseView):
else: else:
current = None current = None
found = Departemen.query_kode(value['kode']). \ found = Departemen.query_kode(value['kode'])
filter_by(company_id=value["company_id"]).first() if "company_id" in value and value["company_id"]:
found = found.filter_by(company_id=value["company_id"]).first()
else:
found = self.filter_company(found).first()
if current: if current:
if found and found.id != current.id: if found and found.id != current.id:
err_kode() err_kode()
elif found: elif found:
err_kode() err_kode()
found = Departemen.query_nama(value['nama']). \ found = Departemen.query_nama(value['nama'])
filter_by(company_id=value["company_id"]).first() if "company_id" in value and value["company_id"]:
found = found.filter_by(company_id=value["company_id"]).first()
else:
found = self.filter_company(found).first()
if current: if current:
if found and found.id != current.id: if found and found.id != current.id:
err_nama() err_nama()
...@@ -178,58 +182,64 @@ class ViewDepartemen(BaseView): ...@@ -178,58 +182,64 @@ class ViewDepartemen(BaseView):
if child.children: if child.children:
self.update_children(child.children) self.update_children(child.children)
def save(self, values, user, row=None): def before_save(self, row, values):
if not row: for k, v in values.items():
row = Departemen() if not v:
row.created = datetime.now() setattr(row, k, None)
row.create_uid = user.id
if 'parent_id' in values and not values['parent_id']:
del values['parent_id']
row.from_dict(values)
row.updated = datetime.now()
row.update_uid = user.id
row.status = 'status' in values and values['status'] and 1 or 0
row.level_id = 1
DBSession.add(row)
DBSession.flush()
if row.parent_id:
row.level_id = (row.parent.level_id or 0) + 1
DBSession.add(row)
if row.children:
for child in row.children:
child.level_id = child.parent.level_id + 1
DBSession.add(child)
DBSession.flush()
return row return row
def save_request(self, values, row=None): # def save(self, values, user, row=None)
request = self.req # if not row:
if 'id' in request.matchdict: # row = Departemen()
values['id'] = request.matchdict['id'] # row.created = datetime.now()
values["company_id"] = request.user.company_id # row.create_uid = user.id
row = self.save(values, request.user, row) # if 'parent_id' in values and not values['parent_id']:
request.session.flash( # del values['parent_id']
"Departemen {nama} sudah disimpan.".format(nama=row.nama)) #
# row.from_dict(values)
# row.updated = datetime.now()
# row.update_uid = user.id
# row.status = 'status' in values and values['status'] and 1 or 0
# row.level_id = 1
# DBSession.add(row)
# DBSession.flush()
# if row.parent_id:
# row.level_id = (row.parent.level_id or 0) + 1
#
# DBSession.add(row)
# if row.children:
# for child in row.children:
# child.level_id = child.parent.level_id + 1
# DBSession.add(child)
# DBSession.flush()
#
# return row
#
# def save_request(self, values, row=None):
# request = self.req
# if 'id' in request.matchdict:
# values['id'] = request.matchdict['id']
# values["company_id"] = request.user.company_id
# row = self.save(values, request.user, row)
# request.session.flash(
# "Departemen {nama} sudah disimpan.".format(nama=row.nama))
# def route_list(self, ): # def route_list(self, ):
# return HTTPFound(location=self.req.route_url(self.list_route)) # return HTTPFound(location=self.req.route_url(self.list_route))
def get_form(self, class_form, row=None, buttons=(btn_save, btn_cancel)): # def get_form(self, class_form, row=None, buttons=(btn_save, btn_cancel)):
schema = class_form(validator=self.form_validator) # schema = class_form(validator=self.form_validator)
schema = schema.bind(request=self.req, # schema = schema.bind(request=self.req,
company_list=ResCompany.get_list()) # company_list=ResCompany.get_list())
schema.request = self.req # schema.request = self.req
if row: # if row:
schema.deserialize(row) # schema.deserialize(row)
return Form(schema, buttons=buttons) # return Form(schema, buttons=buttons)
#
def session_failed(self, session_name): # def session_failed(self, session_name):
r = dict(form=self.req.session[session_name]) # r = dict(form=self.req.session[session_name])
del self.req.session[session_name] # del self.req.session[session_name]
return r # return r
# def query_id(self): # def query_id(self):
# return DBSession.query(Departemen).filter_by( # return DBSession.query(Departemen).filter_by(
...@@ -243,20 +253,21 @@ class ViewDepartemen(BaseView): ...@@ -243,20 +253,21 @@ class ViewDepartemen(BaseView):
@view_config(route_name='departemen-view', @view_config(route_name='departemen-view',
renderer='templates/form_input.pt', permission='departemen') renderer='templates/form_input.pt', permission='departemen')
def view_view(self): # row = query_id(request).first() def view_view(self): # row = query_id(request).first()
request = self.req return super(ViewDepartemen, self).view_view()
row = self.query_id().first() # request = self.req
if not row: # row = self.query_id().first()
return self.id_not_found() # if not row:
# return self.id_not_found()
form = self.get_form(EditSchema, buttons=(btn_close,)) #
if request.POST: # form = self.get_form(EditSchema, buttons=(btn_close,))
return self.route_list() # if request.POST:
# return self.route_list()
form.set_appstruct(self.get_values(row)) #
return dict(form=form.render(readonly=True), scripts=self.form_scripts) # form.set_appstruct(self.get_values(row))
# return dict(form=form.render(readonly=True), scripts=self.form_scripts)
@view_config(route_name='departemen', @view_config(route_name='departemen',
renderer='templates/list.pt', renderer='templates/table.pt',
permission='departemen') permission='departemen')
def view_list(self): def view_list(self):
return super().view_list() return super().view_list()
...@@ -281,8 +292,7 @@ class ViewDepartemen(BaseView): ...@@ -281,8 +292,7 @@ class ViewDepartemen(BaseView):
ColumnDT(Departemen.level_id, mData='level_id'), ] ColumnDT(Departemen.level_id, mData='level_id'), ]
query = DBSession.query().select_from(Departemen).outerjoin( query = DBSession.query().select_from(Departemen).outerjoin(
dep_alias, Departemen.parent_id == dep_alias.id) dep_alias, Departemen.parent_id == dep_alias.id)
if self.req.user.company_id: query = self.filter_company(query)
query = query.filter(Departemen.company_id == self.req.user.company_id)
row_table = DataTables(request.GET, query, columns) row_table = DataTables(request.GET, query, columns)
return row_table.output_result() return row_table.output_result()
...@@ -311,8 +321,7 @@ class ViewDepartemen(BaseView): ...@@ -311,8 +321,7 @@ class ViewDepartemen(BaseView):
Departemen.kode) \ Departemen.kode) \
.ilike('%%%s%%' % term)) \ .ilike('%%%s%%' % term)) \
.order_by(Departemen.nama) .order_by(Departemen.nama)
if self.req.user.company_id: q = self.filter_company(q)
q = q.filter(Departemen.company_id == self.req.user.company_id)
rows = q.all() rows = q.all()
r = [] r = []
for k in rows: for k in rows:
...@@ -381,48 +390,34 @@ class ViewDepartemen(BaseView): ...@@ -381,48 +390,34 @@ class ViewDepartemen(BaseView):
r.append(d) r.append(d)
return r return r
@view_config(route_name='departemen-add', @view_config(route_name='departemen-add', renderer='templates/form_input.pt',
renderer='templates/form_input.pt', permission='departemen') permission='departemen')
def view_add(self): def view_add(self):
request = self.req return super(ViewDepartemen, self).view_add()
form = self.get_form(AddSchema)
if request.POST:
if 'save' in request.POST:
controls = request.POST.items()
try:
controls = form.validate(controls)
except ValidationFailure as e:
form.render(appstruct=e.cstruct)
return dict(form=form.render(), scripts=self.form_scripts)
self.save_request(dict(controls))
return self.route_list()
return dict(form=form.render(), scripts=self.form_scripts)
########
# Edit #
########
@view_config(route_name='departemen-edit', @view_config(route_name='departemen-edit',
renderer='templates/form_input.pt', permission='departemen') renderer='templates/form_input.pt', permission='departemen')
def view_edt(self): def view_edit(self):
request = self.req return super(ViewDepartemen, self).view_edit()
row = self.query_id().first() # request = self.req
if not row: # row = self.query_id().first()
return self.id_not_found() # if not row:
# return self.id_not_found()
form = self.get_form(EditSchema) #
if request.POST: # form = self.get_form(EditSchema)
if 'save' in request.POST: # if request.POST:
controls = request.POST.items() # if 'save' in request.POST:
try: # controls = request.POST.items()
controls = form.validate(controls) # try:
except ValidationFailure as e: # controls = form.validate(controls)
form.set_appstruct(e.cstruct) # except ValidationFailure as e:
return dict(form=form.render(), scripts=self.form_scripts) # form.set_appstruct(e.cstruct)
# return dict(form=form.render(), scripts=self.form_scripts)
self.save_request(dict(controls), row) #
return self.route_list() # self.save_request(dict(controls), row)
form.set_appstruct(self.get_values(row)) # return self.route_list()
return dict(form=form.render(), scripts=self.form_scripts) # form.set_appstruct(self.get_values(row))
# return dict(form=form.render(), scripts=self.form_scripts)
########## ##########
# Delete # # Delete #
...@@ -430,22 +425,24 @@ class ViewDepartemen(BaseView): ...@@ -430,22 +425,24 @@ class ViewDepartemen(BaseView):
@view_config(route_name='departemen-delete', @view_config(route_name='departemen-delete',
renderer='templates/form_input.pt', permission='departemen') renderer='templates/form_input.pt', permission='departemen')
def view_delete(self): def view_delete(self):
request = self.req return super(ViewDepartemen, self).view_delete()
q = self.query_id()
row = q.first() # request = self.req
if not row: # q = self.query_id()
return self.id_not_found() # row = q.first()
if request.POST: # if not row:
if 'delete' in request.POST: # return self.id_not_found()
msg = 'Departemen ID %d %s sudah dihapus.' % (row.id, row.nama) # if request.POST:
q.delete() # if 'delete' in request.POST:
DBSession.flush() # msg = 'Departemen ID %d %s sudah dihapus.' % (row.id, row.nama)
request.session.flash(msg) # q.delete()
return self.route_list() # DBSession.flush()
form = self.get_form(EditSchema, # request.session.flash(msg)
buttons=(btn_delete, btn_cancel)) # return self.route_list()
form.set_appstruct(self.get_values(row)) # form = self.get_form(EditSchema,
return dict(form=form.render(readonly=True), scripts=self.form_scripts) # buttons=(btn_delete, btn_cancel))
# form.set_appstruct(self.get_values(row))
# return dict(form=form.render(readonly=True), scripts=self.form_scripts)
########## ##########
# Upload # # Upload #
...@@ -507,18 +504,17 @@ class ViewDepartemen(BaseView): ...@@ -507,18 +504,17 @@ class ViewDepartemen(BaseView):
values["parent_kd"] = parent.kode values["parent_kd"] = parent.kode
return values return values
def save_upload(self, kode, csv_row):
def save_upload(request, kode, csv_row):
row = Departemen.query_kode(kode).first() row = Departemen.query_kode(kode).first()
if not row: if not row:
row = Departemen() row = Departemen()
row.created = datetime.now() row.created = datetime.now()
row.create_uid = request.user.id row.create_uid = self.req.user.id
row.level_id = kode.count('.') + 1 row.level_id = kode.count('.') + 1
row.status = 1 row.status = 1
else: else:
row.updated = datetime.now() row.updated = datetime.now()
row.update_uid = request.user.id row.update_uid = self.req.user.id
row.kode = kode row.kode = kode
row.nama = csv_row['nama'] row.nama = csv_row['nama']
DBSession.add(row) DBSession.add(row)
......
...@@ -38,6 +38,7 @@ class EditSchema(AddSchema): ...@@ -38,6 +38,7 @@ class EditSchema(AddSchema):
id = colander.SchemaNode(colander.String(), missing=colander.drop, id = colander.SchemaNode(colander.String(), missing=colander.drop,
widget=widget.HiddenWidget(readonly=True)) widget=widget.HiddenWidget(readonly=True))
class ListSchema(colander.Schema): class ListSchema(colander.Schema):
id = colander.SchemaNode(colander.Integer(), searchable=False, orderable=False, visible=False) id = colander.SchemaNode(colander.Integer(), searchable=False, orderable=False, visible=False)
kode = colander.SchemaNode(colander.String(), width='100pt', title="Kode") kode = colander.SchemaNode(colander.String(), width='100pt', title="Kode")
...@@ -45,30 +46,18 @@ class ListSchema(colander.Schema): ...@@ -45,30 +46,18 @@ class ListSchema(colander.Schema):
kecamatan = colander.SchemaNode(colander.String()) kecamatan = colander.SchemaNode(colander.String())
status = colander.SchemaNode(colander.Integer(), width="30pt") status = colander.SchemaNode(colander.Integer(), width="30pt")
class ViewDesa(BaseView): class ViewDesa(BaseView):
def __init__(self, request): def __init__(self, request):
super(ViewDesa, self).__init__(request) super(ViewDesa, self).__init__(request)
self.form_scripts = "" self.form_scripts = ""
self.list_col_defs = json.dumps(
[{"searchable": False, "visible": False, "targets": [0], }, {
"searchable": True, "orderable": True, "targets": [1, 2],
}])
self.list_cols = [{'title': "ID", 'data': "id"},
{'title': "Kecamatan", 'data': "kecamatan", 'width': '200pt'},
{'title': "Kode", 'data': "kode", 'width': '100pt'},
{'title': "Nama", 'data': "nama"}, ]
self.list_buttons = 'btn_view, btn_add, btn_edit, btn_delete, ' \
'btn_close'
self.form_params = dict(scripts="") self.form_params = dict(scripts="")
self.list_url = 'desa' self.list_url = 'desa'
self.list_route = 'desa' self.list_route = 'desa'
self.add_schema = AddSchema self.add_schema = AddSchema
self.edit_schema = EditSchema self.edit_schema = EditSchema
self.table = ResDesa self.table = ResDesa
self.list_schema = ListSchema
########
# List #
########
def form_validator(self, form, value): def form_validator(self, form, value):
def err_kode(): def err_kode():
...@@ -104,17 +93,13 @@ class ViewDesa(BaseView): ...@@ -104,17 +93,13 @@ class ViewDesa(BaseView):
elif found: elif found:
err_nama() err_nama()
def get_form(self, class_form, row=None, buttons=(btn_save, btn_cancel)): def get_bindings(self, row=None):
schema = class_form(validator=self.form_validator) return dict(request=self.req,
schema = schema.bind(request=self.req,
kecamatan_list=ResKecamatan.get_list()) kecamatan_list=ResKecamatan.get_list())
schema.request = self.req
if row:
schema.deserialize(row)
return Form(schema, buttons=buttons)
@view_config(route_name='desa-view', @view_config(route_name='desa-view',
renderer='templates/form_input.pt', permission='desa') renderer='templates/form.pt', permission='desa')
def view_view(self): # row = query_id(request).first() def view_view(self): # row = query_id(request).first()
request = self.req request = self.req
row = self.query_id().first() row = self.query_id().first()
...@@ -129,12 +114,10 @@ class ViewDesa(BaseView): ...@@ -129,12 +114,10 @@ class ViewDesa(BaseView):
return dict(form=form.render(readonly=True), scripts=self.form_scripts) return dict(form=form.render(readonly=True), scripts=self.form_scripts)
@view_config(route_name='desa', @view_config(route_name='desa',
renderer='templates/form_input.pt', renderer='templates/table.pt',
permission='desa') permission='desa')
def view_list(self): def view_list(self):
table = DeTable(ListSchema(title="Desa/Kelurahan"), action=f"{self.home}/desa", return super(ViewDesa, self).view_list()
buttons=(btn_close, btn_add, btn_edit, btn_delete))
return dict(form=table.render(), scripts=self.form_scripts)
@view_config(route_name='desa-act', renderer='json', @view_config(route_name='desa-act', renderer='json',
permission='view') permission='view')
...@@ -146,7 +129,7 @@ class ViewDesa(BaseView): ...@@ -146,7 +129,7 @@ class ViewDesa(BaseView):
ColumnDT(ResDesa.kode, mData='kode'), ColumnDT(ResDesa.kode, mData='kode'),
ColumnDT(ResDesa.nama, mData='nama'), ColumnDT(ResDesa.nama, mData='nama'),
ColumnDT(ResDesa.status, mData='status'), ColumnDT(ResDesa.status, mData='status'),
ColumnDT(ResKecamatan.nama, mData='kecamatan'),] ColumnDT(ResKecamatan.nama, mData='kecamatan'), ]
query = DBSession.query().select_from(ResDesa) \ query = DBSession.query().select_from(ResDesa) \
.join(ResKecamatan, ResKecamatan.id == ResDesa.kecamatan_id) .join(ResKecamatan, ResKecamatan.id == ResDesa.kecamatan_id)
row_table = DataTables(request.GET, query, columns) row_table = DataTables(request.GET, query, columns)
...@@ -157,24 +140,17 @@ class ViewDesa(BaseView): ...@@ -157,24 +140,17 @@ class ViewDesa(BaseView):
result = {f"{k[0]}": k[1] for k in data} result = {f"{k[0]}": k[1] for k in data}
return result return result
@view_config(route_name='desa-add', @view_config(route_name='desa-add',
renderer='templates/form_input.pt', permission='desa') renderer='templates/form.pt', permission='desa')
def view_add(self): def view_add(self):
return super(ViewDesa, self).view_add() return super(ViewDesa, self).view_add()
########
# Edit #
########
@view_config(route_name='desa-edit', @view_config(route_name='desa-edit',
renderer='templates/form_input.pt', permission='desa') renderer='templates/form.pt', permission='desa')
def view_edt(self): def view_edt(self):
return super(ViewDesa, self).view_edit() return super(ViewDesa, self).view_edit()
##########
# Delete
##########
@view_config(route_name='desa-delete', @view_config(route_name='desa-delete',
renderer='templates/form_input.pt', permission='desa') renderer='templates/form.pt', permission='desa')
def view_delete(self): def view_delete(self):
return super(ViewDesa, self).view_delete() return super(ViewDesa, self).view_delete()
import os
import uuid
# from ..tools import row2dict, xls_reader
from datetime import datetime from datetime import datetime
from sqlalchemy import not_, func
from pyramid.view import (
view_config,
)
from pyramid.httpexceptions import (
HTTPFound,
)
import colander import colander
from deform import ( from deform import (
Form, Form,
widget, widget,
ValidationFailure, ValidationFailure,
) )
from ..views import ColumnDT, DataTables, BaseView from pyramid.httpexceptions import (
HTTPFound,
)
from pyramid.view import (
view_config,
)
from ..models import ( from ..models import (
DBSession, DBSession,
Eselon Eselon
) )
from ..views import ColumnDT, DataTables, BaseView
SESS_ADD_FAILED = 'Tambah eselon gagal' SESS_ADD_FAILED = 'Tambah eselon gagal'
SESS_EDIT_FAILED = 'Edit eselon gagal' SESS_EDIT_FAILED = 'Edit eselon gagal'
...@@ -33,13 +31,6 @@ class AddSchema(colander.Schema): ...@@ -33,13 +31,6 @@ class AddSchema(colander.Schema):
nama = colander.SchemaNode( nama = colander.SchemaNode(
colander.String(), colander.String(),
oid="nama") oid="nama")
# eselon = colander.SchemaNode(
# colander.String(),
# oid = "eselon")
# ruang = colander.SchemaNode(
# colander.String(),
# oid = "ruang")
# edit
status = colander.SchemaNode( status = colander.SchemaNode(
colander.Boolean(), colander.Boolean(),
oid="status") oid="status")
...@@ -51,10 +42,7 @@ class EditSchema(AddSchema): ...@@ -51,10 +42,7 @@ class EditSchema(AddSchema):
widget=widget.HiddenWidget()) widget=widget.HiddenWidget())
class view_eselon(BaseView): class Views(BaseView):
########
# List #
########
@view_config(route_name='eselon', renderer='templates/eselon/list.pt', @view_config(route_name='eselon', renderer='templates/eselon/list.pt',
permission='eselon') permission='eselon')
def view_list(self): def view_list(self):
......
from pyramid.view import view_config
from pyramid.httpexceptions import (
HTTPFound,
HTTPNotFound,
)
from pyramid.i18n import TranslationStringFactory
import colander import colander
from deform import (
Form,
widget,
ValidationFailure,
Button,
)
from datatables import ( from datatables import (
ColumnDT, ColumnDT,
DataTables, DataTables,
) )
from opensipkd.tools.buttons import btn_save, btn_cancel, btn_close from deform import widget
from pyramid.httpexceptions import HTTPFound
from pyramid.i18n import TranslationStringFactory
from pyramid.view import view_config
from . import BaseView
from ..models import ( from ..models import (
DBSession, DBSession,
Group, Group,
...@@ -27,27 +19,6 @@ from ..models import ( ...@@ -27,27 +19,6 @@ from ..models import (
_ = TranslationStringFactory('user') _ = TranslationStringFactory('user')
# class NameValidator:
# def __init__(self, group):
# self.group = group
#
# def __call__(self, node, value):
# group_name = clean_name(value)
# if self.group and self.group.group_name.lower() == group_name.lower():
# return
# q = DBSession.query(Group). \
# filter(Group.group_name.ilike(group_name))
# found = q.first()
# if not found:
# return
# data = dict(group_name=group_name, gid=found.id)
# ts = _(
# 'group-name-already-used',
# default='Group name ${group_name} already used by ID ${gid}',
# mapping=data)
# raise colander.Invalid(node, ts)
@colander.deferred @colander.deferred
def name_validator(node, kw): def name_validator(node, kw):
return NameValidator(kw['group']) return NameValidator(kw['group'])
...@@ -67,32 +38,52 @@ class AddSchema(colander.Schema): ...@@ -67,32 +38,52 @@ class AddSchema(colander.Schema):
colander.Set(), widget=permissions_widget, title='Hak akses') colander.Set(), widget=permissions_widget, title='Hak akses')
######## class EditSchema(AddSchema):
# List # id = colander.SchemaNode(colander.Integer(),
######## widget=widget.HiddenWidget(readonly=True),
@view_config( missing=colander.drop)
route_name='group', renderer='templates/group/list.pt',
permission='user-view')
def view_list(request): class ListSchema(colander.Schema):
return dict() id = colander.SchemaNode(colander.Integer(), visible=False)
group_name = colander.SchemaNode(
colander.String(), )
description = colander.SchemaNode(colander.String())
class Views(BaseView):
def __init__(self, request):
super(Views, self).__init__(request)
self.list_schema = ListSchema
self.list_route = "group"
self.table = Group
self.add_schema = AddSchema
self.edit_schema = EditSchema
########## def get_bindings(self, row=None):
# Action # return dict(group=row,
########## permissions_list=get_permissions_list())
@view_config(
@view_config(
route_name='group', renderer='templates/table.pt',
permission='user-view')
def view_list(self):
return super(Views, self).view_list()
@view_config(
route_name='group-act', renderer='json', permission='user-view') route_name='group-act', renderer='json', permission='user-view')
def view_act(request): def view_act(self):
params = request.params params = self.params
request = self.req
url_dict = request.matchdict url_dict = request.matchdict
if url_dict['act'] == 'grid': if url_dict['act'] == 'grid':
columns = [ColumnDT(Group.id, mData="id"), columns = [ColumnDT(Group.id, mData="id"),
ColumnDT(Group.group_name, mData="name"), ColumnDT(Group.group_name, mData="group_name"),
ColumnDT(Group.description, mData="desc"), ColumnDT(Group.description, mData="description"),
ColumnDT(Group.member_count, mData="member")] ColumnDT(Group.member_count, mData="member_count")]
q = DBSession.query().select_from(Group).order_by(Group.group_name) q = DBSession.query().select_from(Group).order_by(Group.group_name)
rowTable = DataTables(request.GET, q, columns) row_table = DataTables(request.GET, q, columns)
return rowTable.output_result() return row_table.output_result()
elif url_dict['act'] == 'hon': elif url_dict['act'] == 'hon':
term = 'term' in params and params['term'] or '' term = 'term' in params and params['term'] or ''
q = DBSession.query(Group.id, Group.description).filter( q = DBSession.query(Group.id, Group.description).filter(
...@@ -105,10 +96,71 @@ def view_act(request): ...@@ -105,10 +96,71 @@ def view_act(request):
r.append(d) r.append(d)
return r return r
@view_config(
route_name='group-add', renderer='templates/group/add.pt',
permission='user-edit')
def view_add(self):
return super(Views, self).view_add()
def save_request(self, values, row=None):
insert = not row
row = self.save(values, self.req.user, row)
existing = group_permission_set(row)
unused = existing - values['permissions']
if unused:
q = DBSession.query(GroupPermission).filter_by(group_id=row.id). \
filter(GroupPermission.perm_name.in_(unused))
q.delete(synchronize_session=False)
new = values['permissions'] - existing
for perm_name in new:
gp = GroupPermission()
gp.group_id = row.id
gp.perm_name = perm_name
DBSession.add(gp)
data = dict(group_name=row.group_name)
if insert:
ts = _('group-added', default='{group_name} group has been added.', mapping=data)
else:
ts = _('group-updated', default='${group_name} group profile updated', mapping=data)
self.ses.flash(ts)
return row
def get_values(self, row, istime=False):
values = super(Views, self).get_values(row, istime)
values['permissions'] = group_permission_set(row)
return values
@view_config(
route_name='group-view', renderer='templates/group/edit.pt',
permission='user-view')
def view_view(self):
return super(Views, self).view_view()
@view_config(
route_name='group-edit', renderer='templates/group/edit.pt',
permission='user-edit')
def view_edit(self):
return super(Views, self).view_edit()
def delete_msg(self, row):
data = dict(group_name=row.group_name)
ts = _(
'group-deleted',
default='{group_name} group has been deleted.',
mapping=data)
self.ses.flash(ts)
@view_config(
route_name='group-delete', renderer='templates/group/delete.pt',
permission='user-edit')
def view_delete(self):
return super(Views, self).view_delete()
q.delete()
request.session.flash(ts)
return HTTPFound(location=request.route_url('group'))
#######
# Add #
#######
def clean_name(s): def clean_name(s):
s = s.strip() s = s.strip()
while s.find(' ') > -1: while s.find(' ') > -1:
...@@ -124,6 +176,7 @@ class NameValidator: ...@@ -124,6 +176,7 @@ class NameValidator:
group_name = clean_name(value) group_name = clean_name(value)
if self.group and self.group.group_name.lower() == group_name.lower(): if self.group and self.group.group_name.lower() == group_name.lower():
return return
q = DBSession.query(Group). \ q = DBSession.query(Group). \
filter(Group.group_name.ilike(group_name)) filter(Group.group_name.ilike(group_name))
found = q.first() found = q.first()
...@@ -157,157 +210,9 @@ def get_permissions_list(): ...@@ -157,157 +210,9 @@ def get_permissions_list():
return r return r
def get_form(request, group=None, buttons=(btn_save, btn_cancel)):
schema = AddSchema()
schema = schema.bind(permissions_list=get_permissions_list(), group=group)
# btn_save = Button('save', _('Simpan'))
# btn_cancel = Button('cancel', _('Batal'))
# buttons = (btn_save, btn_cancel)
return Form(schema, buttons=buttons)
def insert(values):
group = Group()
group.group_name = values['group_name']
if 'description' in values:
group.description = values['description']
DBSession.add(group)
DBSession.flush()
for perm_name in values['permissions']:
gp = GroupPermission()
gp.group_id = group.id
gp.perm_name = perm_name
DBSession.add(gp)
return group
@view_config(
route_name='group-add', renderer='templates/group/add.pt',
permission='user-edit')
def view_add(request):
form = get_form(request)
if not request.POST:
return dict(form=form.render())
if 'save' not in request.POST:
return HTTPFound(location=request.route_url('group'))
items = request.POST.items()
try:
c = form.validate(items)
except ValidationFailure as e:
return dict(form=e.render())
group = insert(dict(c.items()))
data = dict(group_name=group.group_name)
ts = _(
'group-added',
default='${group_name} group has been added.',
mapping=data)
request.session.flash(ts)
return HTTPFound(location=request.route_url('group'))
########
# Edit #
########
def group_permission_set(group): def group_permission_set(group):
q = DBSession.query(GroupPermission).filter_by(group_id=group.id) q = DBSession.query(GroupPermission).filter_by(group_id=group.id)
r = [] r = []
for gp in q: for gp in q:
r.append(gp.perm_name) r.append(gp.perm_name)
return set(r) return set(r)
def update(group, values):
group.group_name = values['group_name']
if 'description' in values:
group.description = values['description']
DBSession.add(group)
existing = group_permission_set(group)
unused = existing - values['permissions']
if unused:
q = DBSession.query(GroupPermission).filter_by(group_id=group.id). \
filter(GroupPermission.perm_name.in_(unused))
q.delete(synchronize_session=False)
new = values['permissions'] - existing
for perm_name in new:
gp = GroupPermission()
gp.group_id = group.id
gp.perm_name = perm_name
DBSession.add(gp)
@view_config(
route_name='group-edit', renderer='templates/group/edit.pt',
permission='user-edit')
def view_edit(request):
q = DBSession.query(Group).filter_by(id=request.matchdict['id'])
group = q.first()
if not group:
return HTTPNotFound()
form = get_form(request, group)
resp = dict(title=_('Edit group'))
if not request.POST:
d = group.to_dict_without_none()
d['permissions'] = group_permission_set(group)
resp['form'] = form.render(appstruct=d)
return resp
if 'save' not in request.POST:
return HTTPFound(location=request.route_url('group'))
# resp['form'] = form.render()
items = request.POST.items()
try:
c = form.validate(items)
except ValidationFailure:
resp['form'] = form.render()
return resp
update(group, dict(c.items()))
data = dict(group_name=group.group_name)
ts = _('group-updated', default='${group_name} group profile updated', mapping=data)
request.session.flash(ts)
return HTTPFound(location=request.route_url('group'))
@view_config(
route_name='group-view', renderer='templates/group/edit.pt',
permission='user-view')
def view_VIEW(request):
q = DBSession.query(Group).filter_by(id=request.matchdict['id'])
group = q.first()
if not group:
return HTTPNotFound()
form = get_form(request, group, buttons=(btn_close,))
resp = dict(title=_('View group'))
if not request.POST:
d = group.to_dict_without_none()
d['permissions'] = group_permission_set(group)
resp['form'] = form.render(appstruct=d, readonly=True)
return resp
return HTTPFound(location=request.route_url('group'))
##########
# Delete #
##########
@view_config(
route_name='group-delete', renderer='templates/group/delete.pt',
permission='user-edit')
def view_delete(request):
q = DBSession.query(Group).filter_by(id=request.matchdict['id'])
group = q.first()
if not group:
return HTTPNotFound()
if not request.POST:
btn_delete = Button('delete', _('Delete'))
btn_cancel = Button('cancel', _('Cancel'))
buttons = (btn_delete, btn_cancel)
form = Form(colander.Schema(), buttons=buttons)
return dict(form=form.render(), row=group)
if 'delete' not in request.POST:
return HTTPFound(location=request.route_url('group'))
data = dict(group_name=group.group_name)
ts = _(
'group-deleted',
default='{group_name} group has been deleted.',
mapping=data)
q.delete()
request.session.flash(ts)
return HTTPFound(location=request.route_url('group'))
...@@ -50,30 +50,16 @@ class ListSchema(colander.Schema): ...@@ -50,30 +50,16 @@ class ListSchema(colander.Schema):
status = colander.SchemaNode(colander.Integer(), width="30pt") status = colander.SchemaNode(colander.Integer(), width="30pt")
class ViewDati2(BaseView): class Views(BaseView):
def __init__(self, request): def __init__(self, request):
super(ViewDati2, self).__init__(request) super(Views, self).__init__(request)
self.form_scripts = ""
# self.list_col_defs = json.dumps(
# [{"searchable": False, "visible": False, "targets": [0], }, {
# "searchable": True, "orderable": True, "targets": [1, 2],
# }])
# self.list_cols = [{'title': "ID", 'data': "id"},
# {'title': "Kab/Kota", 'data': "dati2", 'width': '200pt'},
# {'title': "Kode", 'data': "kode", 'width': '100pt'},
# {'title': "Nama", 'data': "nama"}, ]
# self.list_buttons = 'btn_view, btn_add, btn_edit, btn_delete, ' \
# 'btn_close'
self.form_params = dict(scripts="") self.form_params = dict(scripts="")
self.list_url = 'kecamatan' self.list_url = 'kecamatan'
self.list_route = 'kecamatan' self.list_route = 'kecamatan'
self.add_schema = AddSchema self.add_schema = AddSchema
self.edit_schema = EditSchema self.edit_schema = EditSchema
self.table = ResKecamatan self.table = ResKecamatan
self.list_schema = ListSchema
########
# List #
########
def form_validator(self, form, value): def form_validator(self, form, value):
def err_kode(): def err_kode():
...@@ -119,8 +105,9 @@ class ViewDati2(BaseView): ...@@ -119,8 +105,9 @@ class ViewDati2(BaseView):
return Form(schema, buttons=buttons) return Form(schema, buttons=buttons)
@view_config(route_name='kecamatan-view', @view_config(route_name='kecamatan-view',
renderer='templates/form_input.pt', permission='kecamatan') renderer='templates/form.pt', permission='kecamatan')
def view_view(self): # row = query_id(request).first() def view_view(self): # row = query_id(request).first()
request = self.req request = self.req
row = self.query_id().first() row = self.query_id().first()
if not row: if not row:
...@@ -134,12 +121,10 @@ class ViewDati2(BaseView): ...@@ -134,12 +121,10 @@ class ViewDati2(BaseView):
return dict(form=form.render(readonly=True), scripts=self.form_scripts) return dict(form=form.render(readonly=True), scripts=self.form_scripts)
@view_config(route_name='kecamatan', @view_config(route_name='kecamatan',
renderer='templates/form_input.pt', renderer='templates/table.pt',
permission='kecamatan') permission='kecamatan')
def view_list(self): def view_list(self):
table = DeTable(ListSchema(title="Kecamatan"), action=f"{self.home}/kecamatan", return super(Views, self).view_list(self)
buttons=(btn_close, btn_add, btn_edit, btn_delete))
return dict(form=table.render(), scripts=self.form_scripts)
@view_config(route_name='kecamatan-act', renderer='json', @view_config(route_name='kecamatan-act', renderer='json',
permission='view') permission='view')
...@@ -163,22 +148,19 @@ class ViewDati2(BaseView): ...@@ -163,22 +148,19 @@ class ViewDati2(BaseView):
return result return result
@view_config(route_name='kecamatan-add', @view_config(route_name='kecamatan-add',
renderer='templates/form_input.pt', permission='kecamatan') renderer='templates/form.pt', permission='kecamatan')
def view_add(self): def view_add(self):
return super(ViewDati2, self).view_add() return super(Views, self).view_add()
########
# Edit #
########
@view_config(route_name='kecamatan-edit', @view_config(route_name='kecamatan-edit',
renderer='templates/form_input.pt', permission='kecamatan') renderer='templates/form.pt', permission='kecamatan')
def view_edt(self): def view_edt(self):
return super(ViewDati2, self).view_edit() return super(Views, self).view_edit()
########## ##########
# Delete # Delete
########## ##########
@view_config(route_name='kecamatan-delete', @view_config(route_name='kecamatan-delete',
renderer='templates/form_input.pt', permission='kecamatan') renderer='templates/form.pt', permission='kecamatan')
def view_delete(self): def view_delete(self):
return super(ViewDati2, self).view_delete() return super(Views, self).view_delete()
...@@ -11,7 +11,6 @@ from sqlalchemy.orm import aliased ...@@ -11,7 +11,6 @@ from sqlalchemy.orm import aliased
from . import widget_os from . import widget_os
from ..models import DBSession, ResProvinsi, kategori_provinsi, flush from ..models import DBSession, ResProvinsi, kategori_provinsi, flush
from ..views import ColumnDT, DataTables, BaseView from ..views import ColumnDT, DataTables, BaseView
from ...detable import DeTable
SESS_ADD_FAILED = 'Tambah provinsi gagal' SESS_ADD_FAILED = 'Tambah provinsi gagal'
SESS_EDIT_FAILED = 'Edit provinsi gagal' SESS_EDIT_FAILED = 'Edit provinsi gagal'
...@@ -59,6 +58,7 @@ class ViewProvinsi(BaseView): ...@@ -59,6 +58,7 @@ class ViewProvinsi(BaseView):
self.form_scripts = "" self.form_scripts = ""
self.form_params = dict(scripts="") self.form_params = dict(scripts="")
self.list_route = 'provinsi' self.list_route = 'provinsi'
self.list_schema = ListSchema
self.add_schema = AddSchema self.add_schema = AddSchema
self.edit_schema = EditSchema self.edit_schema = EditSchema
self.table = ResProvinsi self.table = ResProvinsi
...@@ -100,63 +100,31 @@ class ViewProvinsi(BaseView): ...@@ -100,63 +100,31 @@ class ViewProvinsi(BaseView):
err_nama() err_nama()
@view_config(route_name='provinsi-view', @view_config(route_name='provinsi-view',
renderer='templates/form_input.pt', permission='provinsi') renderer='templates/form.pt', permission='provinsi')
def view_view(self): # row = query_id(request).first() def view_view(self): # row = query_id(request).first()
request = self.req return super(ViewProvinsi, self).view_view()
row = self.query_id().first()
if not row:
return self.id_not_found()
form = self.get_form(EditSchema, buttons=(btn_close,))
if request.POST:
return self.route_list()
form.set_appstruct(self.get_values(row))
return dict(form=form.render(readonly=True), scripts=self.form_scripts)
@view_config(route_name='provinsi', @view_config(route_name='provinsi',
renderer='templates/list_table.pt', renderer='templates/table.pt',
permission='provinsi') permission='provinsi')
def view_list(self): def view_list(self):
table = DeTable(ListSchema(), action=f"{self.home}/provinsi", return super(ViewProvinsi, self).view_list()
action_suffix="/grid/act",
buttons=(btn_view, btn_add, btn_edit, btn_delete, btn_close))
return dict(table=table.render(), scripts="")
##########
# Action #
##########
@view_config(route_name='provinsi-act', renderer='json', @view_config(route_name='provinsi-act', renderer='json',
permission='view') permission='view')
def view_act(self): def view_act(self):
request = self.req return super(ViewProvinsi, self).view_act()
url_dict = request.matchdict
if url_dict['act'] == 'grid':
columns = [ColumnDT(ResProvinsi.id, mData='id'),
ColumnDT(ResProvinsi.kode, mData='kode'),
ColumnDT(ResProvinsi.nama, mData='nama'),
ColumnDT(ResProvinsi.ibu_kota, mData='ibu_kota'),
ColumnDT(ResProvinsi.status, mData='status'), ]
query = DBSession.query().select_from(ResProvinsi)
row_table = DataTables(request.GET, query, columns)
return row_table.output_result()
@view_config(route_name='provinsi-add', @view_config(route_name='provinsi-add',
renderer='templates/form_input.pt', permission='provinsi') renderer='templates/form_input.pt', permission='provinsi')
def view_add(self): def view_add(self):
return super(ViewProvinsi, self).view_add() return super(ViewProvinsi, self).view_add()
########
# Edit #
########
@view_config(route_name='provinsi-edit', @view_config(route_name='provinsi-edit',
renderer='templates/form_input.pt', permission='provinsi') renderer='templates/form_input.pt', permission='provinsi')
def view_edt(self): def view_edt(self):
return super(ViewProvinsi, self).view_edit() return super(ViewProvinsi, self).view_edit()
##########
# Delete
##########
@view_config(route_name='provinsi-delete', @view_config(route_name='provinsi-delete',
renderer='templates/form_input.pt', permission='provinsi') renderer='templates/form_input.pt', permission='provinsi')
def view_delete(self): def view_delete(self):
......
# Module ini digunakan untuk registrasi user external # # Module ini digunakan untuk registrasi user external
# Restriction dari module ini tidak boleh diubah emailnya # # Restriction dari module ini tidak boleh diubah emailnya
from email.utils import parseaddr # from email.utils import parseaddr
import colander # import colander
from deform import (Form, widget, ValidationFailure, Button) # from deform import (Form, widget, ValidationFailure, Button)
from opensipkd.tools.api import custom_error # from opensipkd.tools.api import custom_error
from opensipkd.base.views.user_login import get_login_headers # from opensipkd.base.views.user_login import get_login_headers
from opensipkd.base.views.user import insert as save_user # from opensipkd.base.views.user import insert as save_user
from pyramid.httpexceptions import HTTPFound # from pyramid.httpexceptions import HTTPFound
from pyramid.i18n import TranslationStringFactory # from pyramid.i18n import TranslationStringFactory
from pyramid.view import view_config # from pyramid.view import view_config
from ziggurat_foundations.models.services.user import UserService # from ziggurat_foundations.models.services.user import UserService
#
# from . import get_login_headers # # from . import get_login_headers
# from .register import mobile_found_partner, save_partner, nik_found # # from .register import mobile_found_partner, save_partner, nik_found
from .user_group import save as save_groups # from .user_group import save as save_groups
from ..models import DBSession, Partner, Group, ExternalIdentity, User, ExternalIdentityService # from ..models import DBSession, Partner, Group, ExternalIdentity, User, ExternalIdentityService
from opensipkd.tools import get_settings # from opensipkd.tools import get_settings
from opensipkd.tools.captcha import get_captcha # from opensipkd.tools.captcha import get_captcha
from ..views import BaseView # from ..views import BaseView
#
# from .user import email_validator # # from .user import email_validator
_ = TranslationStringFactory('user') # _ = TranslationStringFactory('user')
#
#
def email_validator(node, value): # def email_validator(node, value):
name, email = parseaddr(value) # name, email = parseaddr(value)
if not email or email.find('@') < 0: # if not email or email.find('@') < 0:
raise colander.Invalid(node, 'Invalid email format') # raise colander.Invalid(node, 'Invalid email format')
#
#
class PrimarySchema(colander.Schema): # class PrimarySchema(colander.Schema):
kode = colander.SchemaNode( # kode = colander.SchemaNode(
colander.String(), # colander.String(),
widget=widget.TextInputWidget(), # widget=widget.TextInputWidget(),
oid="kode", # oid="kode",
title="NIK" # title="NIK"
) # )
#
email = colander.SchemaNode( # email = colander.SchemaNode(
colander.String(), # colander.String(),
widget=widget.TextInputWidget(readonly=True), # widget=widget.TextInputWidget(readonly=True),
missing=colander.drop, # missing=colander.drop,
title="E-mail", # title="E-mail",
validator=email_validator, # validator=email_validator,
oid="email") # oid="email")
#
#
class SecondarySchema(colander.Schema): # class SecondarySchema(colander.Schema):
nama = colander.SchemaNode( # nama = colander.SchemaNode(
colander.String(), # colander.String(),
oid="nama") # oid="nama")
alamat_1 = colander.SchemaNode( # alamat_1 = colander.SchemaNode(
colander.String(), # colander.String(),
title="Alamat", # title="Alamat",
oid="alamat_1") # oid="alamat_1")
alamat_2 = colander.SchemaNode( # alamat_2 = colander.SchemaNode(
colander.String(), # colander.String(),
title="", # title="",
missing=colander.drop, # missing=colander.drop,
oid="alamat_2") # oid="alamat_2")
#
#
class RegSchema(colander.Schema): # class RegSchema(colander.Schema):
primari = PrimarySchema() # primari = PrimarySchema()
mobile = colander.SchemaNode( # mobile = colander.SchemaNode(
colander.String(), # colander.String(),
widget=widget.TextInputWidget(), # widget=widget.TextInputWidget(),
oid="mobile") # oid="mobile")
secondari = SecondarySchema() # secondari = SecondarySchema()
captcha = colander.SchemaNode( # captcha = colander.SchemaNode(
colander.String(), # colander.String(),
oid="captcha") # oid="captcha")
#
#
class RegEditSchema(colander.Schema): # class RegEditSchema(colander.Schema):
primari = PrimarySchema() # primari = PrimarySchema()
mobile = colander.SchemaNode( # mobile = colander.SchemaNode(
colander.String(), # colander.String(),
widget=widget.TextInputWidget(readonly=True), # widget=widget.TextInputWidget(readonly=True),
missing=colander.drop, # missing=colander.drop,
oid="mobile") # oid="mobile")
secondari = SecondarySchema() # secondari = SecondarySchema()
id = colander.SchemaNode( # id = colander.SchemaNode(
colander.Integer(), # colander.Integer(),
missing=colander.drop, # missing=colander.drop,
widget=widget.HiddenWidget(), # widget=widget.HiddenWidget(),
) # )
#
#
def form_validator(form, value): # def form_validator(form, value):
# value.update(value['secondari']) # # value.update(value['secondari'])
# value.update(value['primari']) # # value.update(value['primari'])
#
def err_captcha(): # def err_captcha():
msg = 'Captcha harus diisi' # msg = 'Captcha harus diisi'
raise colander.Invalid(form, msg) # raise colander.Invalid(form, msg)
#
def err_email(): # def err_email():
raise colander.Invalid( # raise colander.Invalid(
form, 'e-mail %s sudah ada yang menggunakan' % value['email']) # form, 'e-mail %s sudah ada yang menggunakan' % value['email'])
#
def err_nik(kode): # def err_nik(kode):
raise colander.Invalid( # raise colander.Invalid(
form, 'NIK %s sudah ada yang menggunakan' % kode) # form, 'NIK %s sudah ada yang menggunakan' % kode)
#
def err_login(): # def err_login():
raise colander.Invalid( # raise colander.Invalid(
form, 'User atau Password tidak sesuai') # form, 'User atau Password tidak sesuai')
#
def err_mobile(): # def err_mobile():
raise colander.Invalid( # raise colander.Invalid(
form, 'Nomor %s sudah ada yang menggunakan' % value['mobile']) # form, 'Nomor %s sudah ada yang menggunakan' % value['mobile'])
#
request = form.request # request = form.request
# Cek Login # # Cek Login
if 'password' in value: # if 'password' in value:
user = form.request.user # user = form.request.user
if not user or not UserService.check_password(user, value['password']): # if not user or not UserService.check_password(user, value['password']):
err_login() # err_login()
#
if not request.user: # if not request.user:
if 'captcha' not in value or not value['captcha'] \ # if 'captcha' not in value or not value['captcha'] \
or 'captcha' not in request.session or not request.session['captcha']: # or 'captcha' not in request.session or not request.session['captcha']:
err_captcha() # err_captcha()
#
captcha = 'captcha' in value and value['captcha'].upper() or None # captcha = 'captcha' in value and value['captcha'].upper() or None
#
if not captcha or captcha != request.session['captcha']: # if not captcha or captcha != request.session['captcha']:
err_captcha() # err_captcha()
#
if 'id' in request.matchdict: # if 'id' in request.matchdict:
uid = request.matchdict['id'] # uid = request.matchdict['id']
q = DBSession.query(Partner).filter_by(id=uid) # q = DBSession.query(Partner).filter_by(id=uid)
partner = q.first() # partner = q.first()
else: # else:
partner = None # partner = None
#
# CEK NIK apakah Sudah Ada di tabel Partner? # # CEK NIK apakah Sudah Ada di tabel Partner?
#
primari = value['primari'] # primari = value['primari']
kode = 'kode' in primari and primari['kode'] or "" # kode = 'kode' in primari and primari['kode'] or ""
if not kode: # if not kode:
kode = primari["email"] # kode = primari["email"]
#
found_nik = nik_found(primari['kode']) # found_nik = nik_found(primari['kode'])
if partner: # if partner:
if found_nik and found_nik.id != partner.id: # if found_nik and found_nik.id != partner.id:
err_nik(kode) # err_nik(kode)
elif found_nik: # elif found_nik:
err_nik(kode) # err_nik(kode)
#
if 'mobile' in value and value['mobile']: # if 'mobile' in value and value['mobile']:
mobile = value['mobile'] # mobile = value['mobile']
#
found = mobile_found_partner(mobile).first() # found = mobile_found_partner(mobile).first()
if partner: # if partner:
if found and found.id != partner.id: # if found and found.id != partner.id:
err_mobile() # err_mobile()
elif found: # elif found:
err_mobile() # err_mobile()
#
# user = email_found_user(email) # # user = email_found_user(email)
# # jika ada user dan statusnya register di buat error # # # jika ada user dan statusnya register di buat error
# if user and not form.request.user: # # if user and not form.request.user:
# err_email() # # err_email()
# # #
# # jika update periksa apakah email digunakan oleh user lain # # # jika update periksa apakah email digunakan oleh user lain
# if user and form.request.user: # # if user and form.request.user:
# if user.id != form.request.user.id: # # if user.id != form.request.user.id:
# err_email() # # err_email()
#
#
def get_form(request, class_form, buttons=None, validator=form_validator): # def get_form(request, class_form, buttons=None, validator=form_validator):
schema = class_form(validator=validator) # schema = class_form(validator=validator)
schema = schema.bind() # schema = schema.bind()
schema.request = request # schema.request = request
if buttons: # if buttons:
return Form(schema, buttons=buttons) # return Form(schema, buttons=buttons)
return Form(schema, buttons=('batal', 'simpan')) # return Form(schema, buttons=('batal', 'simpan'))
#
#
def save(values, user=None, row=None, request=None): # def save(values, user=None, row=None, request=None):
""" # """
Digunakan untuk menyimpan User External # Digunakan untuk menyimpan User External
:param values: dictionary of # :param values: dictionary of
external_id # external_id
external_user_name # external_user_name
provider_name # provider_name
access_token # access_token
alt_token # alt_token
token_secret # token_secret
#
:param user: object user if none create new user # :param user: object user if none create new user
:param row: object external_identify if none create new # :param row: object external_identify if none create new
:return: user objek # :return: user objek
""" # """
if not user: # if not user:
user_ = dict(user_name=values['external_user_name'], # user_ = dict(user_name=values['external_user_name'],
email=values['external_email']) # email=values['external_email'])
user, remail = save_user(request, user_) # user, remail = save_user(request, user_)
#
if not row: # if not row:
row = ExternalIdentity() # row = ExternalIdentity()
#
row.from_dict(values) # row.from_dict(values)
# try: # # try:
# except: # # except:
# transaction.rollback() # # transaction.rollback()
#
row.local_user_id = user.id # row.local_user_id = user.id
DBSession.add(row) # DBSession.add(row)
DBSession.flush() # DBSession.flush()
return user # return user
#
#
def save_request(values, request, row=None): # def save_request(values, request, row=None):
if 'id' in request.matchdict: # if 'id' in request.matchdict:
values['id'] = request.matchdict['id'] # values['id'] = request.matchdict['id']
#
id_info = request.session['id_info'] # id_info = request.session['id_info']
user = ExternalIdentityService.user_by_external_id_and_provider( # user = ExternalIdentityService.user_by_external_id_and_provider(
id_info['sub'], id_info['iss']) # id_info['sub'], id_info['iss'])
if not user: # if not user:
user = save(values, user, row, request) # user = save(values, user, row, request)
#
partner = Partner.query_email(id_info['email']).first() # partner = Partner.query_email(id_info['email']).first()
# if not partner: # # if not partner:
values['email'] = id_info['email'] # values['email'] = id_info['email']
if 'kode' not in values and not values['kode']: # if 'kode' not in values and not values['kode']:
values['kode'] = id_info['email'] # values['kode'] = id_info['email']
values['user_id'] = user.id # values['user_id'] = user.id
save_partner(values, partner) # save_partner(values, partner)
##Untuk SIMKEL## # ##Untuk SIMKEL##
settings = get_settings() # settings = get_settings()
if 'default_group'in settings: # if 'default_group'in settings:
groups = settings['default_group'].split(',') # groups = settings['default_group'].split(',')
for group in groups: # for group in groups:
group_data = Group.query_group_name(group).first() # group_data = Group.query_group_name(group).first()
if not group_data: # if not group_data:
raise custom_error(-1,"Group Not Found.") # raise custom_error(-1,"Group Not Found.")
data=dict(group_id= group_data.id, # data=dict(group_id= group_data.id,
user_id= user.id) # user_id= user.id)
save_groups(data,None) # save_groups(data,None)
return user # return user
#
#
def route_list(request): # def route_list(request):
return HTTPFound(location=request.route_url('home')) # return HTTPFound(location=request.route_url('home'))
#
#
def reg_buttons(): # def reg_buttons():
btn_register = Button(name='register', css_class='btn-success', type="submit") # btn_register = Button(name='register', css_class='btn-success', type="submit")
btn_cancel = Button(name='batal', css_class='btn-primary', type="submit") # btn_cancel = Button(name='batal', css_class='btn-primary', type="submit")
return btn_cancel, btn_register # return btn_cancel, btn_register
#
#
class RegistrasiExternal(BaseView): # class RegistrasiExternal(BaseView):
@view_config(route_name='register-external', renderer='templates/register.pt') # @view_config(route_name='register-external', renderer='templates/register.pt')
def view_add(self): # def view_add(self):
request = self.req # request = self.req
if 'id_info' not in request.session: # if 'id_info' not in request.session:
return HTTPFound(location=request.route_url("login")) # return HTTPFound(location=request.route_url("login"))
#
if request.user: # if request.user:
partner = Partner.query_email(request.user.email).first() # partner = Partner.query_email(request.user.email).first()
if partner: # if partner:
return HTTPFound(location=request.route_url("profile-external", # return HTTPFound(location=request.route_url("profile-external",
id=partner.id)) # id=partner.id))
#
id_info = request.session['id_info'] # id_info = request.session['id_info']
form = get_form(request, RegSchema, reg_buttons()) # form = get_form(request, RegSchema, reg_buttons())
if request.POST: # if request.POST:
if 'register' in request.POST: # if 'register' in request.POST:
controls = request.POST.items() # controls = request.POST.items()
try: # try:
controls = form.validate(controls) # controls = form.validate(controls)
except ValidationFailure as e: # except ValidationFailure as e:
values = e.cstruct # values = e.cstruct
values['primari']['email'] = id_info['email'] # values['primari']['email'] = id_info['email']
# values['detail']['captcha'] # # values['detail']['captcha']
form.set_appstruct(values) # form.set_appstruct(values)
return dict(form=form, captcha=get_captcha(request), scripts="") # return dict(form=form, captcha=get_captcha(request), scripts="")
#
dicts = dict(controls) # dicts = dict(controls)
values = dicts['primari'] # values = dicts['primari']
values.update(dicts['secondari']) # values.update(dicts['secondari'])
values['mobile'] = dicts['mobile'] # values['mobile'] = dicts['mobile']
values['email'] = id_info['email'] # values['email'] = id_info['email']
values['external_id'] = id_info['sub'] # values['external_id'] = id_info['sub']
values['external_user_name'] = id_info["name"] # values['external_user_name'] = id_info["name"]
values['external_email'] = id_info["email"] # values['external_email'] = id_info["email"]
values['provider_name'] = id_info["iss"] # values['provider_name'] = id_info["iss"]
# todo: what is this???? # # todo: what is this????
# values['access_token'] # # values['access_token']
# values['alt_token'] # # values['alt_token']
# values['token_secret'] # # values['token_secret']
user = save_request(values, request) # user = save_request(values, request)
#
headers = get_login_headers(request, user) # headers = get_login_headers(request, user)
request.session.flash('Registrasi Sukses.') # request.session.flash('Registrasi Sukses.')
if 'captcha' in request.session: # if 'captcha' in request.session:
del(request.session['captcha']) # del(request.session['captcha'])
return HTTPFound(location=request.route_url('home'), headers=headers) # return HTTPFound(location=request.route_url('home'), headers=headers)
#
values = dict() # values = dict()
values['primari'] = dict( # values['primari'] = dict(
email=id_info['email']) # email=id_info['email'])
#
values['secondari'] = dict( # values['secondari'] = dict(
nama=id_info['name']) # nama=id_info['name'])
#
if request.user: # if request.user:
partner = Partner.query_user_id(request.user.id).first() # partner = Partner.query_user_id(request.user.id).first()
if partner: # if partner:
values['primari'].update(partner.to_dict()) # values['primari'].update(partner.to_dict())
values['secondari'].update(partner.to_dict()) # values['secondari'].update(partner.to_dict())
#
form.set_appstruct(values) # form.set_appstruct(values)
# return dict() # # return dict()
# return dict(captcha=get_captcha(request)) # # return dict(captcha=get_captcha(request))
return dict(form=form.render(), captcha=get_captcha(request), scripts="") # return dict(form=form.render(), captcha=get_captcha(request), scripts="")
#
@view_config(route_name='profile-external', renderer='templates/register.pt', # @view_config(route_name='profile-external', renderer='templates/register.pt',
permission='view') # permission='view')
def profile_external(self): # def profile_external(self):
request = self.req # request = self.req
query = query_id(request) # query = query_id(request)
row = query.first() # row = query.first()
if not row: # if not row:
return HTTPFound(location=request.route_url("register-external")) # return HTTPFound(location=request.route_url("register-external"))
#
form = get_form(request, RegEditSchema) # form = get_form(request, RegEditSchema)
if request.POST: # if request.POST:
if 'simpan' in request.POST: # if 'simpan' in request.POST:
controls = request.POST.items() # controls = request.POST.items()
try: # try:
controls = form.validate(controls) # controls = form.validate(controls)
except ValidationFailure as e: # except ValidationFailure as e:
values = e.cstruct # values = e.cstruct
form.set_appstruct(values) # form.set_appstruct(values)
return dict(form=form) # return dict(form=form)
values = dict(controls) # values = dict(controls)
save_request(values['secondari'], request, row) # save_request(values['secondari'], request, row)
request.session.flash('Sukses Update Profile.') # request.session.flash('Sukses Update Profile.')
#
return route_list(request) # return route_list(request)
#
values = row.to_dict() # values = row.to_dict()
email = row.email # email = row.email
emails = email.split('@') # emails = email.split('@')
result = emails[0][:3] # result = emails[0][:3]
for a in range(3, len(emails[0])): # for a in range(3, len(emails[0])):
result = "".join([result, "*"]) # result = "".join([result, "*"])
#
n = emails[1].find(".") # n = emails[1].find(".")
provider = emails[1][:n] # provider = emails[1][:n]
ext = emails[1][n:] # ext = emails[1][n:]
result = "".join([result, '@', provider[:3]]) # result = "".join([result, '@', provider[:3]])
#
for a in range(3, len(provider)): # for a in range(3, len(provider)):
result = "".join([result, "*"]) # result = "".join([result, "*"])
#
result = "".join([result, ext]) # result = "".join([result, ext])
mobile = row.mobile # mobile = row.mobile
result2 = "".join([mobile[:4], "****", mobile[8:]]) # result2 = "".join([mobile[:4], "****", mobile[8:]])
# values['email'] = result # # values['email'] = result
values['secondari'] = row.to_dict() # values['secondari'] = row.to_dict()
values['primari'] = row.to_dict() # values['primari'] = row.to_dict()
values['primari']["email"] = result # values['primari']["email"] = result
values["mobile"] = result2 # values["mobile"] = result2
#
form.set_appstruct(values) # form.set_appstruct(values)
return dict(form=form, captcha=None) # return dict(form=form, captcha=None)
#
#
######## # ########
# Edit # # # Edit #
######## # ########
def query_id(request): # def query_id(request):
return DBSession.query(Partner).\ # return DBSession.query(Partner).\
join(User, Partner.user_id == User.id).\ # join(User, Partner.user_id == User.id).\
filter(User.id == request.user.id) # filter(User.id == request.user.id)
#
#
def id_not_found(request): # def id_not_found(request):
msg = 'Register ID %s Tidak Ditemukan.' % request.matchdict['id'] # msg = 'Register ID %s Tidak Ditemukan.' % request.matchdict['id']
request.session.flash(msg, 'error') # request.session.flash(msg, 'error')
return route_list(request) # return route_list(request)
<html metal:use-macro="load: ./base3.1.pt">
<js metal:fill-slot="js_files">
<script src="${home}/static/v3/js/plugin/datatables/jquery.dataTables.min.js"></script>
<script src="${home}/static/v3/js/plugin/datatables/dataTables.colVis.min.js"></script>
<script src="${home}/static/v3/js/plugin/datatables/dataTables.tableTools.min.js"></script>
<script src="${home}/static/v3/js/plugin/datatables/dataTables.bootstrap.min.js"></script>
<script src="${home}/static/v3/js/plugin/datatable-responsive/datatables.responsive.min.js"></script>
</js>
</html>
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
tal:define=" tal:define="
home request.route_url('home')[:-1]; home request.route_url('home')[:-1];
user_path ['user', 'user-add', 'user-edit', 'user-view', 'user-delete']; user_path ['user', 'user-add', 'user-edit', 'user-view', 'user-delete'];
user_ext_path ['user-ext', 'user-ext-view', 'user-ext-delete'];
group_path ['group', 'group-add', 'group-edit', 'group-view', 'group-delete']; group_path ['group', 'group-add', 'group-edit', 'group-view', 'group-delete'];
param_path ['parameter', 'parameter-add', 'parameter-edit', 'parameter-view', 'parameter-delete']; param_path ['parameter', 'parameter-add', 'parameter-edit', 'parameter-view', 'parameter-delete'];
dep_path ['departemen', 'departemen-add', 'departemen-edit', 'departemen-view', 'departemen-delete']; dep_path ['departemen', 'departemen-add', 'departemen-edit', 'departemen-view', 'departemen-delete'];
...@@ -15,6 +16,8 @@ ...@@ -15,6 +16,8 @@
dati2_path ['dati2', 'dati2-add', 'dati2-edit', 'dati2-view', 'dati2-delete']; dati2_path ['dati2', 'dati2-add', 'dati2-edit', 'dati2-view', 'dati2-delete'];
kecamatan_path ['kecamatan', 'kecamatan-add', 'kecamatan-edit', 'kecamatan-view', 'kecamatan-delete']; kecamatan_path ['kecamatan', 'kecamatan-add', 'kecamatan-edit', 'kecamatan-view', 'kecamatan-delete'];
desa_path ['desa', 'desa-add', 'desa-edit', 'desa-view', 'desa-delete']; desa_path ['desa', 'desa-add', 'desa-edit', 'desa-view', 'desa-delete'];
css css|[];
js js|[];
"> ">
<head> <head>
...@@ -26,6 +29,10 @@ ...@@ -26,6 +29,10 @@
<meta name="author" content=""> <meta name="author" content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<!-- FAVICONS -->
<link rel="shortcut icon" href="${home}/static/v3/img/favicon.png" type="image/x-icon">
<link rel="icon" href="${home}/static/v3/img/favicon.png" type="image/x-icon">
<!-- GOOGLE FONT --> <!-- GOOGLE FONT -->
<link rel="stylesheet" href="${home}/static/v3/css/gf_open_sans-400italic_700italic_300_400_700.css"> <link rel="stylesheet" href="${home}/static/v3/css/gf_open_sans-400italic_700italic_300_400_700.css">
...@@ -43,45 +50,18 @@ ...@@ -43,45 +50,18 @@
<!-- We recommend you use "your_style.css" to override SmartAdmin <!-- We recommend you use "your_style.css" to override SmartAdmin
specific styles this will also ensure you retrain your customization with each SmartAdmin update. --> specific styles this will also ensure you retrain your customization with each SmartAdmin update. -->
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/osipkd.css">
<!-- FAVICONS -->
<link rel="shortcut icon" href="${home}/static/v3/img/favicon.png" type="image/x-icon">
<link rel="icon" href="${home}/static/v3/img/favicon.png" type="image/x-icon">
<!-- OTHER CSS --> <!-- OTHER CSS -->
<link href="${home}/static/v3/js/plugin/bootstrap-datepicker/css/bootstrap-datepicker.min.css" <tal:loop tal:repeat="css_resource css">
rel="stylesheet"> <link rel="stylesheet" href="${home}${request.static_path(css_resource)}"
type="text/css">
</tal:loop>
<!--? <link href="${home}/static/v3/js/plugin/bootstrap-datepicker/css/bootstrap-datepicker.min.css"-->
<!--? rel="stylesheet">-->
<link href="${home}/deform_static/css/form.css" rel="stylesheet"> <link href="${home}/deform_static/css/form.css" rel="stylesheet">
<link href="${home}/deform_static/css/typeahead.css" rel="stylesheet"> <!--? <link href="${home}/static/v3/css/select2.min.css" rel="stylesheet" type="text/css">-->
<link href="${home}/static/v3/css/select2.min.css" rel="stylesheet" type="text/css">
<link href="${home}/static/css/custom.css" rel="stylesheet" type="text/css">
<metal:css define-slot="css_files"></metal:css> <metal:css define-slot="css_files"></metal:css>
<style metal:define-slot="style"> <link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/osipkd.css">
.twitter-typeahead {
font-size: 12px !important;
margin-bottom: 0;
width: 100%;
height: 26px;
position: absolute;
top: 0;
left: 0;
z-index: auto;
}
.twitter-typeahead .tt-query, .twitter-typeahead .tt-hint {
font-size: 12px !important;
margin-bottom: 0;
width: 100%;
height: 26px;
position: absolute;
top: 0;
left: 0;
z-index: auto;
}
</style>
</head> </head>
<body class="fixed-header"> <body class="fixed-header">
...@@ -92,14 +72,11 @@ ...@@ -92,14 +72,11 @@
<!-- #HEADER --> <!-- #HEADER -->
<header id="header"> <header id="header">
<div id="logo-group"> <div id="logo-group">
<!-- PLACE YOUR LOGO HERE --> <!-- PLACE YOUR LOGO HERE -->
<h3 id="logo"> <h3 id="logo">
<a href="${home}/"><img src="${home}/static/img/logo.png" alt="LOGO"></a>
<a href="${home}/"><img src="${home}/static/img/logo.png" alt=""></a>
</h3> </h3>
<!-- END LOGO PLACEHOLDER --> <!-- END LOGO PLACEHOLDER -->
</div> </div>
<!-- #PROJECTS: projects dropdown --> <!-- #PROJECTS: projects dropdown -->
...@@ -113,7 +90,6 @@ ...@@ -113,7 +90,6 @@
<div class="pull-right"> <div class="pull-right">
<div tal:condition="request.user" class="project-context hidden-xs"> <div tal:condition="request.user" class="project-context hidden-xs">
<span class="label"><i class="fa fa-sm fa-fw fa-institution"></i> ${request.company}</span> <span class="label"><i class="fa fa-sm fa-fw fa-institution"></i> ${request.company}</span>
<span tal:condition="request.user" class="project-selector dropdown-toggle" data-toggle="dropdown">Pilih Module <i <span tal:condition="request.user" class="project-selector dropdown-toggle" data-toggle="dropdown">Pilih Module <i
class="fa fa-angle-down"></i></span> class="fa fa-angle-down"></i></span>
<ul tal:condition="request.user" class="dropdown-menu"> <ul tal:condition="request.user" class="dropdown-menu">
...@@ -121,7 +97,6 @@ ...@@ -121,7 +97,6 @@
<a href="${home}/${menu}">${request.menus[menu]}</a> <a href="${home}/${menu}">${request.menus[menu]}</a>
</li> </li>
</ul> </ul>
</div> </div>
<!-- collapse menu button --> <!-- collapse menu button -->
<div id="hide-menu" class="btn-header pull-right"> <div id="hide-menu" class="btn-header pull-right">
...@@ -132,8 +107,8 @@ ...@@ -132,8 +107,8 @@
<!-- fullscreen button --> <!-- fullscreen button -->
<div id="fullscreen" class="btn-header transparent pull-right"> <div id="fullscreen" class="btn-header transparent pull-right">
<span> <a href="javascript:void(0);" data-action="launchFullscreen" title="Full Screen"><i <span> <a href="javascript:void(0);" data-action="launchFullscreen" title="Full Screen">
class="fa fa-arrows-alt"></i></a> </span> <i class="fa fa-arrows-alt"></i></a> </span>
</div> </div>
<!-- end fullscreen button --> <!-- end fullscreen button -->
...@@ -142,8 +117,7 @@ ...@@ -142,8 +117,7 @@
<li> <li>
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-lg fa-fw fa-user"></i> <span <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-lg fa-fw fa-user"></i> <span
style="text-transform:capitalize"> ${request.user and request.user.nice_username() or ""} </span> style="text-transform:capitalize"> ${request.user and request.user.nice_username() or ""} </span>
<i <i class="fa fa-angle-down"></i> </a>
class="fa fa-angle-down"></i> </a>
<ul class="dropdown-menu pull-right"> <ul class="dropdown-menu pull-right">
<li><a style="text-transform:capitalize" href="${request.route_url('profile')}">Profile</a></li> <li><a style="text-transform:capitalize" href="${request.route_url('profile')}">Profile</a></li>
<li tal:condition="not request.user.external"> <li tal:condition="not request.user.external">
...@@ -161,10 +135,8 @@ ...@@ -161,10 +135,8 @@
</li> </li>
</ul> </ul>
<!-- end user info --> <!-- end user info -->
</div> </div>
<!-- end pulled right: nav area --> <!-- end pulled right: nav area -->
</header> </header>
<!-- END HEADER --> <!-- END HEADER -->
...@@ -172,32 +144,27 @@ ...@@ -172,32 +144,27 @@
<!-- Left panel : Navigation area --> <!-- Left panel : Navigation area -->
<!-- Note: This width of the aside area can be adjusted through LESS variables --> <!-- Note: This width of the aside area can be adjusted through LESS variables -->
<aside id="left-panel" style="padding-bottom:67px"> <aside id="left-panel" style="padding-bottom:67px">
<!-- NAVIGATION : This navigation is also responsive--> <!-- NAVIGATION : This navigation is also responsive-->
<nav style=""> <nav style="">
<!-- Modul Menu --> <!-- Modul Menu -->
<ul metal:define-slot="navs"></ul> <ul metal:define-slot="navs"></ul>
<!-- Admin Menu --> <!-- Admin Menu -->
<ul <ul tal:condition="has_permission(request, user_path)" style="margin-top: 0; padding-top: 0;">
tal:condition="has_permission(request, user_path)"
style="margin-top: 0; padding-top: 0;">
<li> <li>
<a href="#"><i class="fa fa-lg fa-fw fa-shield"></i> <a href="#"><i class="fa fa-lg fa-fw fa-shield"></i><span class="menu-item-parent">Admin</span></a>
<span class="menu-item-parent">Admin</span></a>
<ul> <ul>
<li tal:condition="has_permission(request, ['user-view', 'user-edit'])" <li tal:condition="has_permission(request, ['user-view', 'user-edit'])"
tal:attributes="class request.matched_route.name in user_path and 'active'"> tal:attributes="class request.matched_route.name in user_path and 'active'">
<a href="${home}/user">User</a> <a href="${home}/user">User</a>
</li> </li>
<li tal:condition="has_permission(request, ['user-view', 'user-edit'])" <li tal:condition="has_permission(request, ['user-view', 'user-edit'])"
tal:attributes="class request.matched_route.name in user_ext_path and 'active'">
<a href="${home}/user/ext">External User</a>
</li>
<li tal:condition="has_permission(request, ['user-view', 'user-edit'])"
tal:attributes="class request.matched_route.name in group_path and 'active'"> tal:attributes="class request.matched_route.name in group_path and 'active'">
<a href="${home}/group">Group</a> <a href="${home}/group">Group</a>
</li> </li>
<!-- <li tal:condition="has_permission(request, 'user-group')"-->
<!-- tal:attributes="class request.matched_route.name in ['user-group'] and 'active'">-->
<!-- <a href="${home}/user/group">User Group</a></li>-->
<li tal:condition="has_permission(request, 'upload-logo')" <li tal:condition="has_permission(request, 'upload-logo')"
tal:attributes="class request.matched_route.name in ['upload-logo'] and 'active'"> tal:attributes="class request.matched_route.name in ['upload-logo'] and 'active'">
<a href="${home}/upload/logo">Upload Logo</a></li> <a href="${home}/upload/logo">Upload Logo</a></li>
...@@ -217,10 +184,6 @@ ...@@ -217,10 +184,6 @@
<li tal:condition="has_permission(request, 'departemen')" <li tal:condition="has_permission(request, 'departemen')"
tal:attributes="class request.matched_route.name in dep_path and 'active'"> tal:attributes="class request.matched_route.name in dep_path and 'active'">
<a href="${home}/departemen">Departemen</a></li> <a href="${home}/departemen">Departemen</a></li>
<!-- <li tal:condition="has_permission(request, 'departemen-user')"-->
<!-- tal:attributes="class request.matched_route.name in ['departemen-user'] and 'active'">-->
<!-- <a href="${home}/departemen/user">User Departemen</a></li>-->
<li tal:condition="has_permission(request, 'partner')" <li tal:condition="has_permission(request, 'partner')"
tal:attributes="class request.matched_route.name in partner_path and 'active'"> tal:attributes="class request.matched_route.name in partner_path and 'active'">
<a href="${home}/partner">Partner</a></li> <a href="${home}/partner">Partner</a></li>
...@@ -233,7 +196,6 @@ ...@@ -233,7 +196,6 @@
<li tal:condition="has_permission(request, 'dati2')" <li tal:condition="has_permission(request, 'dati2')"
tal:attributes="class request.matched_route.name in dati2_path and 'active'"> tal:attributes="class request.matched_route.name in dati2_path and 'active'">
<a href="${home}/dati2">Kabupaten/Kota</a></li> <a href="${home}/dati2">Kabupaten/Kota</a></li>
<li tal:condition="has_permission(request, 'kecamatan')" <li tal:condition="has_permission(request, 'kecamatan')"
tal:attributes="class request.matched_route.name in kecamatan_path and 'active'"> tal:attributes="class request.matched_route.name in kecamatan_path and 'active'">
<a href="${home}/kecamatan">Kecamatan</a></li> <a href="${home}/kecamatan">Kecamatan</a></li>
...@@ -246,7 +208,6 @@ ...@@ -246,7 +208,6 @@
</ul> </ul>
</li> </li>
</ul> </ul>
</nav> </nav>
<span class="minifyme" data-action="minifyMenu"> <span class="minifyme" data-action="minifyMenu">
<i class="fa fa-arrow-circle-left hit"></i> <i class="fa fa-arrow-circle-left hit"></i>
...@@ -265,14 +226,11 @@ ...@@ -265,14 +226,11 @@
document.write('<script src="${home}/static/v3/js/libs/jquery-2.1.1.min.js"><\/script>'); document.write('<script src="${home}/static/v3/js/libs/jquery-2.1.1.min.js"><\/script>');
} }
</script> </script>
<!--?<script src="${home}/static/v3/js/jquery-ui-1.10.3.min.js"></script>-->
<script src="${home}/static/v3/js/jquery-ui-1.10.3.min.js"></script>
<script> <script>
if (!window.jQuery.ui) { // if (!window.jQuery.ui) {
document.write('<script src="${home}/static/v3/js/libs/jquery-ui-1.10.3.min.js"><\/script>'); <!--? document.write('<script src="${home}/static/v3/js/libs/jquery-ui-1.10.3.min.js"><\/script>');-->
} // }
</script> </script>
<!-- IMPORTANT: APP CONFIG --> <!-- IMPORTANT: APP CONFIG -->
...@@ -294,83 +252,27 @@ ...@@ -294,83 +252,27 @@
<script src="${home}/static/v3/js/app.min.js"></script> <script src="${home}/static/v3/js/app.min.js"></script>
<!-- PAGE RELATED PLUGIN(S) --> <!-- PAGE RELATED PLUGIN(S) -->
<script src="${home}/static/v3/js/plugin/datatables/jquery.dataTables.min.js"></script> <!--?<script src="${home}/static/v3/js/plugin/datatables/jquery.dataTables.min.js"></script>-->
<script src="${home}/static/v3/js/plugin/datatables/dataTables.colVis.min.js"></script> <!--?<script src="${home}/static/v3/js/plugin/datatables/dataTables.colVis.min.js"></script>-->
<script src="${home}/static/v3/js/plugin/datatables/dataTables.tableTools.min.js"></script> <!--?<script src="${home}/static/v3/js/plugin/datatables/dataTables.tableTools.min.js"></script>-->
<script src="${home}/static/v3/js/plugin/datatables/dataTables.bootstrap.min.js"></script> <!--?<script src="${home}/static/v3/js/plugin/datatables/dataTables.bootstrap.min.js"></script>-->
<script src="${home}/static/v3/js/plugin/datatable-responsive/datatables.responsive.min.js"></script> <!--?<script src="${home}/static/v3/js/plugin/datatable-responsive/datatables.responsive.min.js"></script>-->
<script src="${home}/static/v3/js/plugin/bootstrap-datepicker/js/bootstrap-datepicker.min.js"></script> <!--?<script src="${home}/static/v3/js/plugin/bootstrap-datepicker/js/bootstrap-datepicker.min.js"></script>-->
<script src="${home}/static/v3/js/plugin/bootstrap-timepicker/bootstrap-timepicker.min.js"></script> <!--?<script src="${home}/static/v3/js/plugin/bootstrap-timepicker/bootstrap-timepicker.min.js"></script>-->
<script src="${home}/deform_static/scripts/deform.js"></script> <!--?<script src="${home}/deform_static/scripts/deform.js"></script>-->
<script src="${home}/deform_static/scripts/typeahead.min.js"></script> <!--?<script src="${home}/deform_static/scripts/typeahead.min.js"></script>-->
<script src="${home}/deform_static/scripts/jquery.maskMoney-3.1.1.min.js"></script> <!--?<script src="${home}/deform_static/scripts/jquery.maskMoney-3.1.1.min.js"></script>-->
<script src="${home}/deform_static/tinymce/tinymce.min.js"></script> <!--?<script src="${home}/deform_static/tinymce/tinymce.min.js"></script>-->
<script src="${home}/static/v3/js/tools.js"></script> <!--?<script src="${home}/static/v3/js/tools.js"></script>-->
<script src="${home}/static/v3/js/notification/SmartNotification.min.js"></script> <!--?<script src="${home}/static/v3/js/notification/SmartNotification.min.js"></script>-->
<script src="${home}/static/v3/js/plugin/masked-input/jquery.maskedinput.min.js"></script> <!--?<script src="${home}/static/v3/js/plugin/masked-input/jquery.maskedinput.min.js"></script>-->
<script src="${home}/static/v3/js/select2.full.min.js"></script> <!--?<script src="${home}/static/v3/js/select2.full.min.js"></script>-->
<script src="${home}/deform_static/scripts/file_upload.js"></script> <!--?<script src="${home}/deform_static/scripts/file_upload.js"></script>-->
<script src="${home}/static/v3/js/osipkd.js"></script>
<script> <tal:loop tal:repeat="js_resource js">
function showError(msg) { <script src="${home}${request.static_path(js_resource)}"></script>
$("#success").css('display', 'none', 'important'); </tal:loop>
$("#errors").css('display', 'box', 'important');
$("#errors").html("<span class='glyphicon glyphicon-remove'></span> " + msg);
console.log(msg);
};
function showSuccess(msg) {
$("#errors").css('display', 'none', 'important');
$("#success").css('display', 'box', 'important');
$("#success").html("<span class='glyphicon glyphicon-ok'></span> " + msg);
};
$(function () {
var current = location.pathname;
$('nav li a').each(function () {
var $this = $(this);
if ($this.attr('href') != '' && $this.attr('href') != '#') {
if ($this.attr('href') == current) {
$this.parent().addClass('active');
var ul_parent = $this.parents('ul');
ul_parent.show();
ul_parent.parents('li').addClass('open');
}
}
})
});
$(document).ready(function () {
// DO NOT REMOVE : GLOBAL FUNCTIONS!
pageSetUp();
/*
* PAGE RELATED SCRIPTS
*/
});
function number_format(number, decimals, dec_point, thousands_sep) {
// Strip all characters but numerical ones.
number = (number + '').replace(/[^0-9+\-Ee.]/g, '');
var n = !isFinite(+number) ? 0 : +number,
prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
s = '',
toFixedFix = function (n, prec) {
var k = Math.pow(10, prec);
return '' + Math.round(n * k) / k;
};
// Fix for IE parseFloat(0.55).toFixed(0) = 0;
s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
if (s[0].length > 3) {
s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
}
if ((s[1] || '').length < prec) {
s[1] = s[1] || '';
s[1] += new Array(prec - s[1].length + 1).join('0');
}
return s.join(dec);
}
</script>
<metal:js define-slot="js_files"></metal:js> <metal:js define-slot="js_files"></metal:js>
......
<html metal:use-macro="load: ./base3.1.pt"> <html metal:use-macro="load: ./_table.pt">
<span metal:fill-slot="scripts"> <span metal:fill-slot="scripts">
<script> <script>
var btn_view='<button id="btn_view" class="btn btn btn-general" type="button">'+ var btn_view='<button id="btn_view" class="btn btn btn-general" type="button">'+
......
<html metal:use-macro="load: ../base3.1.pt"> <html metal:use-macro="load: ../_table.pt">
<link metal:fill-slot="css_files" rel="stylesheet" type="text/css" media="screen" href="/static/v3/css/custom-datatable.css"> <link metal:fill-slot="css_files" rel="stylesheet" type="text/css" media="screen" href="/static/v3/css/custom-datatable.css">
<div metal:fill-slot="content"> <div metal:fill-slot="content">
<div class="jarviswidget" style="border-top:1px solid #ccc!important"> <div class="jarviswidget" style="border-top:1px solid #ccc!important">
......
<html metal:use-macro="load: ./base3.1.pt">
<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"></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>
<div metal:use-macro="load: ../main.pt">
<div metal:fill-slot="content">
<div class="well">
<div tal:content="structure form"/>
</div>
</div>
</div>
<div metal:use-macro="load: ../main.pt">
<div metal:fill-slot="content">
<div class="well">
<div tal:content="structure form"/>
</div>
</div>
</div>
<div metal:use-macro="load: ../main.pt">
<div metal:fill-slot="content">
<div class="jarviswidget" style="border-top:1px solid #ccc!important">
<div role="content">
<table id="table1" class="table table-bordered table-hover table-condensed">
<thead>
<tr>
<th>ID</th>
<th>Nama Group</th>
<th>Deskripsi</th>
<th>Jml. Anggota</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
<script type="text/javascript" metal:fill-slot="scripts">
var mID;
var oTable;
var oTableUri = "${home}/group"
var oTableUrl = oTableUri + "/grid/act";
$(document).ready(function () {
oTable = $('#table1').DataTable({
dom: '<"row"<"col-md-8"<"toolbar">l><"col-md-4"f>>rtip',
processing: true,
serverSide: true,
ajax: oTableUrl,
stateSave: true,
scrollCollapse: true,
sort: true,
info: false,
filter: true,
autoWidth: false,
paginate: true,
paginationType: "full_numbers",
lengthMenu: [
[10, 25, 50, 100],
[10, 25, 50, 100]
],
columnDefs: [{
searchable: false,
visible: false,
targets: [0]
}],
columns: [{
"data": "id"
},
{
"data": "name",
"width": "200px",
"class": "left"
},
{
"data": "desc"
},
{
"data": "member",
"width": "200px",
"class": "center"
},
],
"language": {
"search": "Cari: ",
"paginate": {
"first": "Pertama ",
"last": "Akhir ",
"previous": "",
"next": "",
},
"lengthMenu": "Tampil _MENU_ baris "
},
});
var tb_array = [
'<div class="btn-group pull-left"> ',
' <button id="btn_view" class="btn btn btn-warning" type="button" data-toggle="tooltip" title="View"> ' +
' <i class="fa fa-eye"></i></button>',
' <button id="btn_add" class="btn btn btn-success" type="button" data-toggle="tooltip" title="Tambah">' +
' <i class="fa fa-plus"></i></button>',
' <button id="btn_edit" class="btn btn btn-warning" type="button" data-toggle="tooltip" title="Ubah">' +
' <i class="fa fa-edit"></i></button>',
' <button id="btn_delete" class="btn btn btn-danger" type="button" data-toggle="tooltip" title="Hapus">' +
' <i class="fa fa-trash-o"></i></button>',
' <button id="btn_pdf" class="btn btn btn-primary" type="button" data-toggle="tooltip" title="PDF">' +
' <i class="fa fa-file-pdf-o"></i></button>',
' <button id="btn_csv" class="btn btn btn-primary" type="button" data-toggle="tooltip" title="CSV">' +
' <i class="fa fa-file-excel-o"></i></button>',
' <button id="btn_close" class="btn btn btn-warning" type="button" data-toggle="tooltip" title="Tutup">' +
' <i class="fa fa-arrow-right"></i></button>',
' &nbsp;',
'</div>',
];
var tb = tb_array.join(' ');
$("div.toolbar").html(tb);
$("div.toolbar").attr('style', 'display:block; float: left; margin-bottom:6px; line-height:16px;');
$('#table1 tbody').on('click', 'tr', function () {
if ($(this).hasClass('selected')) {
$(this).removeClass('selected');
} else {
var aData = oTable.row(this).data();
oTable.$('tr.selected').removeClass('selected');
$(this).addClass('selected');
mID = aData.id;
console.log(mID);
oTable.$('tr.row_selected').removeClass('row_selected');
$(this).addClass('row_selected');
/*oTable2.fnReloadAjax("egaji/grid2?id=" + mID);*/
}
});
$('#btn_add').click(function () {
window.location = oTableUri + '/add';
});
$('#btn_edit').click(function () {
if (mID) window.location = oTableUri + '/' + mID + '/edit';
else
$.SmartMessageBox({
title: "Edit",
content: "Pilih Baris yang akan di edit...",
buttons: '[Oke]'
});
;
});
$('#btn_view').click(function () {
if (mID) window.location = oTableUri + '/' + mID + '/view';
else
$.SmartMessageBox({
title: "View",
content: "Pilih Baris yang akan di lihat...",
buttons: '[Ok]'
});
;
});
$('#btn_delete').click(function () {
if (mID) window.location = oTableUri + '/' + mID + '/delete';
else
$.SmartMessageBox({
title: "Hapus",
content: "Pilih Baris yang akan di hapus...",
buttons: '[Oke]'
});
});
$('#btn_csv').click(function () {
url = oTableUri + "/csv/rpt";
window.open(url);
});
$('#btn_pdf').click(function () {
url = oTableUri + "/pdf/rpt";
window.open(url);
});
$("#btn_close").click(function () {
window.location = '/';
return false;
});
});
</script>
</div>
<html metal:use-macro="load: ../base3.1.pt"> <html metal:use-macro="load: ../_table.pt">
<link metal:fill-slot="css_files" rel="stylesheet" type="text/css" media="screen" <link metal:fill-slot="css_files" rel="stylesheet" type="text/css" media="screen"
href="/static/v3/css/custom-datatable.css"> href="/static/v3/css/custom-datatable.css">
<div metal:fill-slot="content"> <div metal:fill-slot="content">
......
<html metal:use-macro="load: ../main.pt"> <html metal:use-macro="load: ../_table.pt">
<!-- content --> <!-- content -->
<div metal:fill-slot="content"> <div metal:fill-slot="content">
......
<html metal:use-macro="load: ../main.pt"> <html metal:use-macro="load: ../_table.pt">
<div metal:fill-slot="content"> <div metal:fill-slot="content">
<div class="jarviswidget" style="border-top:1px solid #ccc!important"> <div class="jarviswidget" style="border-top:1px solid #ccc!important">
......
<html metal:use-macro="load: ../main.pt"> <html metal:use-macro="load: ./_table.pt">
<div metal:fill-slot="content">
<!-- content --> <div class="panel panel-default">
<div metal:fill-slot="content">
<div class="panel panel-danger">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title">Hapus data</h3> <h3 class="panel-title"><i class="fa fa-fw fa-plus"></i>&nbsp;${request.title}</h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
Hapus Group #${row.group_name} ${row.description} ? <div tal:content="structure form"></div>
</div> </div>
</div> </div>
<div tal:content="structure form"/> </div>
</div>
<!-- end content -->
</html> </html>
<div metal:use-macro="load: ../main.pt">
<div metal:fill-slot="content">
<div class="well">
<div tal:content="structure form"/>
</div>
</div>
</div>
\ No newline at end of file \ No newline at end of file
<div metal:use-macro="load: ../main.pt">
<div metal:fill-slot="content">
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title" i18n:translate="Warning">Warning</h3>
</div>
<div class="panel-body" i18n:translate="warning-delete-user">
Delete <span tal:replace="user.email" i18n:name="email"/>
ID <span tal:replace="user.id" i18n:name="uid"/> ?
</div>
</div>
<div tal:content="structure form"/>
</div>
</div>
<div metal:use-macro="load: ../main.pt">
<div metal:fill-slot="content">
<div class="well">
<div tal:content="structure form"/>
</div>
</div>
</div>
\ No newline at end of file \ No newline at end of file
<div metal:use-macro="load: ../main.pt">
<!-- content -->
<div metal:fill-slot="content">
<div class="jarviswidget" style="border-top:1px solid #ccc!important">
<div role="content">
<table id="table1" class="table table-bordered table-hover table-condensed">
<thead>
<tr>
<th>ID</th>
<th>Email</th>
<th>User Name</th>
<th>Status</th>
<th>Last Login</th>
<th>Registered Date</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
<!-- end content -->
<script type="text/javascript" metal:fill-slot="scripts">var mID;
var mID;
var oTable;
var oTableUri = "${home}/user"
var oTableUrl = oTableUri + "/grid/act";
$(document).ready(function () {
oTable = $('#table1').DataTable({
dom: '<"row"<"col-md-8"<"toolbar">l><"col-md-4"f>>rtip',
processing: true,
serverSide: true,
ajax: oTableUrl,
stateSave: true,
scrollCollapse: true,
sort: true,
info: false,
filter: true,
autoWidth: false,
paginate: true,
paginationType: "full_numbers",
lengthMenu: [
[10, 25, 50, 100],
[10, 25, 50, 100]
],
columnDefs: [{
searchable: false,
visible: false,
targets: [0]
}],
columns: [{
"data": "id"
},
{
"data": "email",
"width": "200px",
"className": "text-left"
},
{
"data": "name"
},
{
"data": "status",
"width": "200px",
"className": "text-center",
"render": function (data, type, full, meta) {
if (data == 0) return 'NonAktif';
else if (data == 1) return 'Aktif';
else return "-";
}
},
{
"data": "last_login",
"width": "200px",
"className": "text-center"
},
{
"data": "registered",
"width": "200px",
"className": "text-center"
}
],
"language": {
"search": "Cari : ",
"paginate": {
"first": "Pertama ",
"last": "Akhir ",
"previous": "",
"next": "",
},
"lengthMenu": "Tampil _MENU_ baris "
},
});
var tb_array = [
'<div class="btn-group pull-left">',
' <button id="btn_view" class="btn btn btn-warning" type="button" data-toggle="tooltip" title="View"> <i class="fa fa-eye"></i></button>',
' <button tal:condition="has_permission(request, 'user-edit')" id="btn_add" class="btn btn btn-success" type="button" data-toggle="tooltip" title="Tambah"><i class="fa fa-plus"></i></button>',
' <button tal:condition="has_permission(request, 'user-edit')" id="btn_edit" class="btn btn btn-warning" type="button" data-toggle="tooltip" title="Koreksi"><i class="fa fa-edit"></i></button>',
' <button tal:condition="has_permission(request, 'user-edit')" id="btn_delete" class="btn btn btn-danger" type="button" data-toggle="tooltip" title="Hapus"><i class="fa fa-trash-o"></i></button>',
' <button id="btn_pdf" class="btn btn btn-primary" type="button" data-toggle="tooltip" title="PDF"><i class="fa fa-file-pdf-o"></i></button>',
' <button id="btn_csv" class="btn btn btn-primary" type="button" data-toggle="tooltip" title="CSV"><i class="fa fa-file-excel-o"></i></button>',
' <button id="btn_close" class="btn btn btn-warning" type="button" data-toggle="tooltip" title="Tutup"><i class="fa fa-arrow-right"></i></button>',
' &nbsp;',
'</div>',
];
var tb = tb_array.join(' ');
$("div.toolbar").html(tb);
$("div.toolbar").attr('style', 'display:block; float: left; margin-bottom:6px; line-height:16px;');
$('#table1 tbody').on('click', 'tr', function () {
if ($(this).hasClass('selected')) {
$(this).removeClass('selected');
} else {
var aData = oTable.row(this).data();
oTable.$('tr.selected').removeClass('selected');
$(this).addClass('selected');
mID = aData.id;
oTable.$('tr.row_selected').removeClass('row_selected');
$(this).addClass('row_selected');
}
});
$('#btn_add').click(function () {
window.location = oTableUri + '/add';
});
$('#btn_view').click(function () {
if (mID) window.location = oTableUri + '/' + mID + '/view';
else
$.SmartMessageBox({
title: "View",
content: "Pilih Baris yang akan di lihat...",
buttons: '[Ok]'
});
;
});
$('#btn_edit').click(function () {
if (mID) window.location = oTableUri + '/' + mID + '/edit';
else
$.SmartMessageBox({
title: "Edit",
content: "Pilih Baris yang akan di edit...",
buttons: '[Ok]'
});
;
});
$('#btn_delete').click(function () {
if (mID) window.location = oTableUri + '/' + mID + '/delete';
else
$.SmartMessageBox({
title: "Hapus",
content: "Pilih Baris yang akan di hapus...",
buttons: '[Ok]'
});
});
$('#btn_csv').click(function () {
url = oTableUri + "/csv/act";
window.open(url);
});
$('#btn_pdf').click(function () {
url = oTableUri + "/pdf/act";
window.open(url);
});
$("#btn_close").click(function () {
window.location = '/';
return false;
});
});
</script>
</div>
...@@ -2,21 +2,15 @@ import os ...@@ -2,21 +2,15 @@ import os
import re import re
import colander import colander
import transaction from deform import (widget, )
from datatables import (ColumnDT, DataTables, )
from deform import (Form, widget, ValidationFailure, Button, )
# from sqlalchemy.exc import IntegrityErrortpl
from sqlalchemy.exc import IntegrityError
from opensipkd.tools import create_now from opensipkd.tools import create_now
from opensipkd.tools.buttons import btn_cancel, btn_save, btn_close
from opensipkd.tools.report import open_rml_row, csv_response, open_rml_pdf, pdf_response from opensipkd.tools.report import open_rml_row, csv_response, open_rml_pdf, pdf_response
from pyramid.httpexceptions import (HTTPFound, HTTPNotFound, )
from pyramid.i18n import TranslationStringFactory from pyramid.i18n import TranslationStringFactory
from pyramid.view import view_config from pyramid.view import view_config
from sqlalchemy import (func, or_, ) from sqlalchemy import (func, )
from ziggurat_foundations.models.services.user import UserService from ziggurat_foundations.models.services.user import UserService
from . import BaseView
from .company import company_widget from .company import company_widget
from .user_login import ( from .user_login import (
regenerate_security_code, send_email_security_code, generate_api_key, ) regenerate_security_code, send_email_security_code, generate_api_key, )
...@@ -25,14 +19,235 @@ from ..models import (DBSession, User, Group, UserGroup, ResCompany, ) ...@@ -25,14 +19,235 @@ from ..models import (DBSession, User, Group, UserGroup, ResCompany, )
_ = TranslationStringFactory('user') _ = TranslationStringFactory('user')
######## class ListSchema(colander.Schema):
# List # id = colander.SchemaNode(colander.String(), title="ID", visible=False, searchable=False)
######## email = colander.SchemaNode(colander.String())
@view_config( user_name = colander.SchemaNode(colander.String())
route_name='user', renderer='templates/user/list.pt', status = colander.SchemaNode(colander.Integer(), width=50, searchable=False)
last_login = colander.SchemaNode(colander.String(), width=100, field="last_login_date", searchable=False)
registered = colander.SchemaNode(colander.String(), width=100, field="registered_date", searchable=False)
class Views(BaseView):
def __init__(self, request):
super(Views, self).__init__(request)
self.list_schema = ListSchema
self.list_route = 'user'
self.table = User
self.edit_schema = EditSchema
self.add_schema = AddSchema
self.list_buttons = self.list_buttons + self.list_report
def get_bindings(self, row=None):
status_list = (
('1', _('Active')),
('0', _('Archived')))
if row and row.api_key:
api_key_list = (
('', _(row.api_key)),
('0', _('Hapus')))
else:
api_key_list = (
('', _('Tidak ada')),
('1', _('Buatkan')))
group_list = get_group_list()
return dict(status_list=status_list,
group_list=group_list,
api_key_list=api_key_list,
user=row,
company_list=ResCompany.get_list())
@view_config(
route_name='user', renderer='templates/table.pt',
permission='user-view')
def view_list(self):
return super(Views, self).view_list()
@view_config(
route_name='user-act', renderer='json', permission='user-view')
def view_act(self):
return super(Views, self).view_act()
def next_act(self):
url_dict = self.req.matchdict
if url_dict['act'] == 'csv':
query = query_register()
row = query.first()
header = row.keys()
rows = [list(item) for item in query.all()]
filename = 'user.csv'
value = {
'header': header,
'rows': rows,
}
return csv_response(self.req, value, filename)
elif url_dict['act'] == 'pdf':
query = query_register()
import opensipkd.base
base_path = os.path.dirname(opensipkd.base.__file__)
path = os.path.join(base_path, 'reports')
rml_row = open_rml_row(path + '/user.row.rml')
rows = [rml_row.format(user_name=r.user_name, email=r.email,
registered_date=r.registered_date) for r in query.all()]
pdf, filename = open_rml_pdf(path + '/user.rml', rows=rows,
company=self.req.company,
departement=self.req.departement,
address=self.req.address,
base_path=base_path)
return pdf_response(self.req, pdf, filename)
def form_validator(self, form, value):
if "company_id" in value and not value["company_id"]:
value["company_id"] = None
def save_request(self, values, row=None):
request = self.req
values["email"] = values['email'].lower()
values["user_name"] = re.sub(' ', '', values['user_name']) # .lower()
values["security_code_date"] = create_now()
company_id = request.user and request.user.company_id or "company_id" in values and values["company_id"] or None
values["company_id"] = company_id
if 'is_api_key' in values:
values["api_key"] = generate_api_key()
insert = not row
row = self.save(values, self.req.user, row)
if insert:
remain = regenerate_security_code(row)
if 'password' in values:
data = dict(username=row.user_name)
ts = _(
'user-added-with-password',
default='${username} berhasil ditambahkan.', mapping=data)
else:
send_email_security_code(
self.req, row, remain, 'Welcome new user', 'email-new-user',
'email-new-user.tpl')
data = dict(email=row.email)
ts = _(
'user-added',
default='${email} berhasil ditambahkan dan email untuk ubah ' \
'kata kunci sudah dikirim.',
mapping=data)
self.ses.flash(ts)
if 'password' in values:
UserService.set_password(row, values['password'])
DBSession.add(row)
DBSession.flush()
existing = user_group_set(row)
unused = existing - values['groups']
if unused:
q = DBSession.query(UserGroup).filter_by(user_id=row.id).filter(
UserGroup.group_id.in_(unused))
q.delete(synchronize_session=False)
for gid in unused:
reduce_member_count(gid)
new = values['groups'] - existing
for gid in new:
ug = UserGroup()
ug.user_id = row.id
ug.group_id = gid
DBSession.add(ug)
add_member_count(gid)
return row
def after_add(self, row, values):
pass
@view_config(
route_name='user-add', renderer='templates/form.pt',
permission='user-view') permission='user-view')
def view_list(request): def view_add(self):
return dict() return super(Views, self).view_add()
# user, remain = insert(request, values)
def get_values(self, row, istime=False):
d = super(Views, self).get_values(row, istime)
d["groups"] = user_group_set(row)
return d
@view_config(
route_name='user-edit', renderer='templates/user/edit.pt',
permission='user-edit')
def view_edit(self):
return super(Views, self).view_edit()
# q = DBSession.query(User).filter_by(id=request.matchdict['id'])
# if request.user.company_id:
# q = q.filter_by(company_id=request.user.company_id)
# user = q.first()
# if not user:
# return HTTPNotFound()
# if user.id == request.user.id:
# form = get_form(request, AddSchema, user)
# else:
# if 'opensipkd.webr.models' in get_modules():
# form = get_form(request, EditSchema2, user)
# else:
# form = get_form(request, EditSchema, user)
# resp = dict(title=_('Edit user'))
# if not request.POST:
# d = user.to_dict()
# d['groups'] = user_group_set(user)
# resp['form'] = form.render(appstruct=d)
# return resp
# if 'save' not in request.POST:
# return HTTPFound(location=request.route_url('user'))
# items = request.POST.items()
# try:
# c = form.validate(items)
# except ValidationFailure:
# resp['form'] = form.render()
# return resp
# update(request, user, dict(c.items()))
# data = dict(username=user.user_name)
# ts = _('user-updated', default='${username} profile updated', mapping=data)
# request.session.flash(ts)
# return HTTPFound(location=request.route_url('user'))
@view_config(
route_name='user-view', renderer='templates/form.pt',
permission='user-view')
def view_view(self):
return super(Views, self).view_view()
@view_config(
route_name='user-delete', renderer='templates/form.pt',
permission='user-edit')
def view_delete(self):
return super(Views, self).view_delete()
def delete_msg(self, row):
data = dict(uid=row.id, email=row.email)
return _(
'user-deleted',
default='User ${email} ID ${uid} has been deleted',
mapping=data)
def before_delete(self, row):
gid_list = user_group_set(row)
for gid in gid_list:
reduce_member_count(gid)
def query_id(self):
q = DBSession.query(User).filter_by(id=self.req.matchdict['id'])
if self.req.user.company_id:
q = q.filter_by(company_id=self.req.user.company_id)
return q
####### #######
...@@ -90,7 +305,7 @@ REGEX_BEGIN_END_ALPHANUMERIC = re.compile('^[A-Za-z0-9]+(?:[-][A-Za-z0-9]+)*$') ...@@ -90,7 +305,7 @@ REGEX_BEGIN_END_ALPHANUMERIC = re.compile('^[A-Za-z0-9]+(?:[-][A-Za-z0-9]+)*$')
class UsernameValidator(Validator): class UsernameValidator(Validator):
def __call__(self, node, value): def __call__(self, node, value):
username = value # .lower() username = value
if self.user and self.user.user_name == username: if self.user and self.user.user_name == username:
return return
match = REGEX_ONLY_CONTAIN.search(username) match = REGEX_ONLY_CONTAIN.search(username)
...@@ -109,6 +324,7 @@ class UsernameValidator(Validator): ...@@ -109,6 +324,7 @@ class UsernameValidator(Validator):
found = q.first() found = q.first()
if not found: if not found:
return return
data = dict(username=username, uid=found.id) data = dict(username=username, uid=found.id)
ts = _( ts = _(
'username-already-used', 'username-already-used',
...@@ -127,14 +343,6 @@ def username_validator(node, kw): ...@@ -127,14 +343,6 @@ def username_validator(node, kw):
return UsernameValidator(kw['user']) return UsernameValidator(kw['user'])
def form_validator(form, value):
# new_password = value.get('new_password')
# retype_password = value.get('retype_password')
# if new_password != retype_password:
# raise colander.Invalid(form, _('Pengulangan kata kunci tidak sama'))
pass
def save_user(values, user, row=None): def save_user(values, user, row=None):
if not row: if not row:
row = User() row = User()
...@@ -182,29 +390,6 @@ def get_group_list(): ...@@ -182,29 +390,6 @@ def get_group_list():
return r return r
def get_form(request, class_form, user=None, buttons=(btn_save, btn_cancel)):
status_list = (
('1', _('Active')),
('0', _('Archived')))
if user and user.api_key:
api_key_list = (
('', _(user.api_key)),
('0', _('Hapus')))
else:
api_key_list = (
('', _('Tidak ada')),
('1', _('Buatkan')))
schema = class_form(validator=form_validator)
group_list = get_group_list()
schema = schema.bind(
status_list=status_list, group_list=group_list, user=user,
api_key_list=api_key_list,
company_list=ResCompany.get_list()
)
return Form(schema, buttons=buttons)
def add_member_count(gid): def add_member_count(gid):
q = DBSession.query(Group).filter_by(id=gid) q = DBSession.query(Group).filter_by(id=gid)
group = q.first() group = q.first()
...@@ -219,78 +404,6 @@ def reduce_member_count(gid): ...@@ -219,78 +404,6 @@ def reduce_member_count(gid):
DBSession.add(group) DBSession.add(group)
def insert(request, values):
user = User()
user.email = values['email'].lower()
user.user_name = re.sub(' ', '', values['user_name']) # .lower()
user.security_code_date = create_now()
company_id = request.user and request.user.company_id or "company_id" in values and values["company_id"] or None
user.company_id = company_id
remain = regenerate_security_code(user)
if 'is_api_key' in values:
user.api_key = generate_api_key()
if 'password' in values:
UserService.set_password(user, values['password'])
DBSession.add(user)
try:
DBSession.flush()
except IntegrityError as e:
transaction.abort()
user.user_name = user.email
DBSession.add(user)
DBSession.flush()
if 'groups' in values and values['groups']:
for gid in values['groups']:
ug = UserGroup()
ug.user_id = user.id
ug.group_id = gid
DBSession.add(ug)
add_member_count(gid)
return user, remain
@view_config(
route_name='user-add', renderer='templates/user/add.pt',
permission='user-view')
def view_add(request):
# if 'opensipkd.webr.models' in get_modules():
# form = get_form(request, AddSchema2)
# else:
form = get_form(request, AddSchema)
resp = dict(title=_('Add user'))
if not request.POST:
resp['form'] = form.render()
return resp
if 'save' not in request.POST:
return HTTPFound(location=request.route_url('user'))
items = request.POST.items()
try:
c = form.validate(items)
except ValidationFailure:
resp['form'] = form.render()
return resp
values = dict(c.items())
user, remain = insert(request, values)
if 'password' in values:
data = dict(username=user.user_name)
ts = _(
'user-added-with-password',
default='${username} berhasil ditambahkan.', mapping=data)
else:
send_email_security_code(
request, user, remain, 'Welcome new user', 'email-new-user',
'email-new-user.tpl')
data = dict(email=user.email)
ts = _(
'user-added',
default='${email} berhasil ditambahkan dan email untuk ubah ' \
'kata kunci sudah dikirim.',
mapping=data)
request.session.flash(ts)
return HTTPFound(location=request.route_url('user'))
def user_group_set(user): def user_group_set(user):
q = DBSession.query(UserGroup).filter_by(user_id=user.id) q = DBSession.query(UserGroup).filter_by(user_id=user.id)
r = [] r = []
...@@ -299,188 +412,6 @@ def user_group_set(user): ...@@ -299,188 +412,6 @@ def user_group_set(user):
return set(r) return set(r)
def update(request, user, values):
user.email = values['email'].lower()
user.user_name = re.sub(' ', '', values['user_name']) # .lower())
if user.id != request.user.id:
user.status = values['status']
is_api_key = values.get('is_api_key')
if is_api_key == '0':
user.api_key = None
elif is_api_key == '1':
user.api_key = generate_api_key()
if 'password' in values:
UserService.set_password(user, values['password'])
company_id = request.user.company_id or 'company_id' in values and values["company_id"] or None
user.company_id = company_id
DBSession.add(user)
existing = user_group_set(user)
unused = existing - values['groups']
if unused:
q = DBSession.query(UserGroup).filter_by(user_id=user.id).filter(
UserGroup.group_id.in_(unused))
q.delete(synchronize_session=False)
for gid in unused:
reduce_member_count(gid)
new = values['groups'] - existing
for gid in new:
ug = UserGroup()
ug.user_id = user.id
ug.group_id = gid
DBSession.add(ug)
add_member_count(gid)
@view_config(
route_name='user-edit', renderer='templates/user/edit.pt',
permission='user-edit')
def view_edit(request):
q = DBSession.query(User).filter_by(id=request.matchdict['id'])
if request.user.company_id:
q = q.filter_by(company_id=request.user.company_id)
user = q.first()
if not user:
return HTTPNotFound()
if user.id == request.user.id:
form = get_form(request, AddSchema, user)
else:
# if 'opensipkd.webr.models' in get_modules():
# form = get_form(request, EditSchema2, user)
# else:
form = get_form(request, EditSchema, user)
resp = dict(title=_('Edit user'))
if not request.POST:
d = user.to_dict()
d['groups'] = user_group_set(user)
resp['form'] = form.render(appstruct=d)
return resp
if 'save' not in request.POST:
return HTTPFound(location=request.route_url('user'))
items = request.POST.items()
try:
c = form.validate(items)
except ValidationFailure:
resp['form'] = form.render()
return resp
update(request, user, dict(c.items()))
data = dict(username=user.user_name)
ts = _('user-updated', default='${username} profile updated', mapping=data)
request.session.flash(ts)
return HTTPFound(location=request.route_url('user'))
@view_config(
route_name='user-view', renderer='templates/user/edit.pt',
permission='user-view')
def view_view(request):
q = DBSession.query(User).filter_by(id=request.matchdict['id'])
if request.user.company_id:
q = q.filter_by(company_id=request.user.company_id)
user = q.first()
if not user:
return HTTPNotFound()
if user.id == request.user.id:
form = get_form(request, AddSchema, user)
else:
form = get_form(request, EditSchema, user, buttons=(btn_close,))
resp = dict(title=_('View user'))
if not request.POST:
d = user.to_dict()
d['groups'] = user_group_set(user)
resp['form'] = form.render(appstruct=d, readonly=True)
return resp
return HTTPFound(location=request.route_url('user'))
@view_config(
route_name='user-delete', renderer='templates/user/delete.pt',
permission='user-edit')
def view_delete(request):
q = DBSession.query(User).filter_by(id=request.matchdict['id'])
if request.user.company_id:
q = q.filter_by(company_id=request.user.company_id)
user = q.first()
if not user:
return HTTPNotFound()
if not request.POST:
btn_delete = Button('delete', _('Delete'))
btn_cancel = Button('cancel', _('Cancel'))
buttons = (btn_delete, btn_cancel)
form = Form(colander.Schema(), buttons=buttons)
return dict(title=_('Delete user'), user=user, form=form.render())
if 'delete' not in request.POST:
return HTTPFound(location=request.route_url('user'))
gid_list = user_group_set(user)
for gid in gid_list:
reduce_member_count(gid)
data = dict(uid=user.id, email=user.email)
ts = _(
'user-deleted',
default='User ${email} ID ${uid} has been deleted',
mapping=data)
q.delete()
request.session.flash(ts)
return HTTPFound(location=request.route_url('user'))
@view_config(
route_name='user-act', renderer='json', permission='user-view')
def view_act(request):
req = request
url_dict = req.matchdict
if url_dict['act'] == 'grid':
columns = [
ColumnDT(User.id, mData='id'),
ColumnDT(User.email, mData='email'),
ColumnDT(User.user_name, mData='name'),
ColumnDT(User.status, mData='status'),
ColumnDT(func.to_char(User.last_login_date, 'DD-MM-YYYY HH24:MI:SS'),
mData='last_login'),
ColumnDT(func.to_char(User.registered_date, 'DD-MM-YYYY HH24:MI:SS'),
mData='registered'),
]
query = DBSession.query().select_from(User)
if request.user.company_id:
query = query.filter(User.company_id == request.user.company_id)
row_table = DataTables(req.GET, query, columns)
return row_table.output_result()
elif url_dict['act'] == 'csv':
query = query_register()
row = query.first()
header = row.keys()
rows = []
for item in query.all():
rows.append(list(item))
filename = 'user.csv'
value = {
'header': header,
'rows': rows,
}
return csv_response(request, value, filename)
elif url_dict['act'] == 'pdf':
# todo ganti rml jadi openoffice
query = query_register()
_here = os.path.dirname(__file__) # get current folder -> views
path = os.path.dirname(_here) # mundur 1 level
path = os.path.join(path, 'reports')
rml_row = open_rml_row(path + '/user.row.rml')
rows = []
for r in query.all():
s = rml_row.format(user_name=r.user_name, email=r.email,
registered_date=r.registered_date)
rows.append(s)
pdf, filename = open_rml_pdf(path + '/user.rml', rows=rows,
company=request.company,
departement=request.departement,
address=request.address)
return pdf_response(request, pdf, filename)
def query_register(): def query_register():
return DBSession.query(User.user_name, User.email, return DBSession.query(User.user_name, User.email,
func.to_char(User.registered_date, "DD-MM-YYYY").label("registered_date")).order_by( func.to_char(User.registered_date, "DD-MM-YYYY").label("registered_date")).order_by(
......
import os
import re
import colander import colander
import transaction
from datatables import (ColumnDT, DataTables, ) from datatables import (ColumnDT, DataTables, )
from deform import (Form, widget, ValidationFailure, Button, ) from deform import (widget, )
# from sqlalchemy.exc import IntegrityErrortpl from opensipkd.tools.buttons import btn_close, btn_delete, btn_view
from sqlalchemy.exc import IntegrityError
from opensipkd.tools import create_now
from opensipkd.tools.buttons import btn_cancel, btn_save, btn_close, btn_delete, btn_view
from opensipkd.tools.report import open_rml_row, csv_response, open_rml_pdf, pdf_response
from pyramid.httpexceptions import (HTTPFound, HTTPNotFound, )
from pyramid.i18n import TranslationStringFactory from pyramid.i18n import TranslationStringFactory
from pyramid.view import view_config from pyramid.view import view_config
from sqlalchemy import (func, or_, )
from ziggurat_foundations.models.services.user import UserService
from . import BaseView from . import BaseView
from .company import company_widget from ..models import (DBSession, User, ExternalIdentity)
from .user_login import (
regenerate_security_code, send_email_security_code, generate_api_key, )
from ..models import (DBSession, User, Group, UserGroup, ResCompany, ExternalIdentity)
_ = TranslationStringFactory('user') _ = TranslationStringFactory('user')
########
# List #
########
class AddSchema(colander.Schema): class AddSchema(colander.Schema):
external_user_name = colander.SchemaNode( external_user_name = colander.SchemaNode(
colander.String(), title=_('User Name')) colander.String(), title=_('User Name'))
...@@ -43,7 +25,7 @@ class EditSchema(AddSchema): ...@@ -43,7 +25,7 @@ class EditSchema(AddSchema):
class ListSchema(colander.Schema): class ListSchema(colander.Schema):
id = colander.SchemaNode(colander.String()) id = colander.SchemaNode(colander.String(), field="external_id")
external_user_name = colander.SchemaNode( external_user_name = colander.SchemaNode(
colander.String(), title=_('User Name')) colander.String(), title=_('User Name'))
provider_name = (colander.SchemaNode(colander.String(), title=_('Provider'))) provider_name = (colander.SchemaNode(colander.String(), title=_('Provider')))
...@@ -55,13 +37,12 @@ class UserExt(BaseView): ...@@ -55,13 +37,12 @@ class UserExt(BaseView):
super(UserExt, self).__init__(request) super(UserExt, self).__init__(request)
self.edit_schema = EditSchema self.edit_schema = EditSchema
self.list_schema = ListSchema self.list_schema = ListSchema
# self.list_url = "/user/ext"
self.list_route = "user-ext" self.list_route = "user-ext"
self.list_buttons = (btn_view, btn_delete, btn_close) self.list_buttons = (btn_view, btn_delete, btn_close)
self.table = ExternalIdentity
@view_config( @view_config(
route_name='user-ext', renderer='templates/form_input.pt', route_name='user-ext', renderer='templates/table.pt',
permission='user-view') permission='user-view')
def view_list(self): def view_list(self):
form = super(UserExt, self).view_list() form = super(UserExt, self).view_list()
...@@ -82,56 +63,10 @@ class UserExt(BaseView): ...@@ -82,56 +63,10 @@ class UserExt(BaseView):
@view_config( @view_config(
route_name='user-ext-act', renderer='json', permission='user-view') route_name='user-ext-act', renderer='json', permission='user-view')
def view_act(self): def view_act(self):
req = self.req return super(UserExt, self).view_act()
url_dict = req.matchdict
if url_dict['act'] == 'grid':
columns = [
ColumnDT(ExternalIdentity.external_id, mData='id'),
ColumnDT(ExternalIdentity.external_user_name, mData='external_user_name'),
ColumnDT(ExternalIdentity.provider_name, mData='provider_name'),
ColumnDT(ExternalIdentity.local_user_id, mData='local_user_id'),
]
query = DBSession.query().select_from(ExternalIdentity). \
outerjoin(User, User.id == ExternalIdentity.local_user_id)
if self.req.user.company_id:
query = query.filter(User.company_id == self.req.user.company_id)
row_table = DataTables(req.GET, query, columns)
return row_table.output_result()
def delete_msg(self, row): def delete_msg(self, row):
return f'Data ID {row.external_id} sudah dihapus.' return f'Data ID {row.external_id} sudah dihapus.'
def query_id(self): def query_id(self):
return DBSession.query(ExternalIdentity).filter_by(external_id=self.req.matchdict["id"]) return DBSession.query(ExternalIdentity).filter_by(external_id=self.req.matchdict["id"])
# elif url_dict['act'] == 'csv':
# query = query_register()
# row = query.first()
# header = row.keys()
# rows = []
# for item in query.all():
# rows.append(list(item))
#
# filename = 'user.csv'
# value = {
# 'header': header,
# 'rows': rows,
# }
# return csv_response(request, value, filename)
# elif url_dict['act'] == 'pdf':
# # todo ganti rml jadi openoffice
# query = query_register()
# _here = os.path.dirname(__file__) # get current folder -> views
# path = os.path.dirname(_here) # mundur 1 level
# path = os.path.join(path, 'reports')
# rml_row = open_rml_row(path + '/user.row.rml')
# rows = []
# for r in query.all():
# s = rml_row.format(user_name=r.user_name, email=r.email,
# registered_date=r.registered_date)
# rows.append(s)
# pdf, filename = open_rml_pdf(path + '/user.rml', rows=rows,
# company=request.company,
# departement=request.departement,
# address=request.address)
# return pdf_response(request, pdf, filename)
# import os
# import re
# from sqlalchemy import (
# func,
# or_,
# )
# from pyramid.i18n import TranslationStringFactory
# from pyramid.view import view_config
# from pyramid.httpexceptions import (
# HTTPFound,
# HTTPNotFound,
# )
# import colander
# from deform import (
# Form,
# widget,
# ValidationFailure,
# Button,
# )
# from ziggurat_foundations.models.services.user import UserService
# from ..models import (
# DBSession,
# User,
# Group,
# UserGroup,
# )
# from datatables import (
# ColumnDT,
# DataTables,
# )
# from ..tools import create_now
# from ..tools.report import open_rml_row, csv_response, open_rml_pdf, pdf_response
# from . import (
# regenerate_security_code,
# send_email_security_code,
# generate_api_key,
# )
#
# _ = TranslationStringFactory('user')
#
#
# ########
# # List #
# ########
# @view_config(
# route_name='user', renderer='templates/user/list.pt',
# permission='user-view')
# def view_list(request):
# return dict()
#
#
# #######
# # Add #
# #######
# @colander.deferred
# def status_widget(node, kw):
# values = kw.get('status_list', [])
# return widget.SelectWidget(values=values)
#
#
# @colander.deferred
# def group_widget(node, kw):
# values = kw.get('group_list', [])
# return widget.CheckboxChoiceWidget(values=values)
#
#
# @colander.deferred
# def api_key_widget(node, kw):
# values = kw.get('api_key_list', [])
# return widget.SelectWidget(values=values)
#
#
# class Validator:
# def __init__(self, user):
# self.user = user
#
#
# class EmailValidator(colander.Email, Validator):
# def __init__(self, user):
# colander.Email.__init__(self)
# Validator.__init__(self, user)
#
# def __call__(self, node, value):
# if self.match_object.match(value) is None:
# raise colander.Invalid(node, _('Invalid email format'))
# email = value.lower()
# if self.user and self.user.email == email:
# return
# q = DBSession.query(User).filter_by(email=email)
# found = q.first()
# if not found:
# return
# data = dict(email=email, uid=found.id)
# ts = _(
# 'email-already-used',
# default='Email ${email} already used by user ID ${uid}',
# mapping=data)
# raise colander.Invalid(node, ts)
#
#
# REGEX_ONLY_CONTAIN = re.compile('([a-z0-9-]*)')
# REGEX_BEGIN_END_ALPHANUMERIC = re.compile('^[a-z0-9]+(?:[-][a-z0-9]+)*$')
#
#
# class UsernameValidator(Validator):
# def __call__(self, node, value):
# username = value.lower()
# if self.user and self.user.user_name == username:
# return
# match = REGEX_ONLY_CONTAIN.search(username)
# if not match or match.group(1) != username or username != value:
# ts = _(
# 'username-only-contain',
# default='Only a-z, 0-9, and - characters are allowed')
# raise colander.Invalid(node, ts)
# match = REGEX_BEGIN_END_ALPHANUMERIC.search(username)
# if not match:
# ts = _(
# 'username-first-end-alphanumeric',
# default='Only a-z or 0-9 at the start and end')
# raise colander.Invalid(node, ts)
# q = DBSession.query(User).filter_by(user_name=username)
# found = q.first()
# if not found:
# return
# data = dict(username=username, uid=found.id)
# ts = _(
# 'username-already-used',
# default='Username ${username} already used by ID ${uid}',
# mapping=data)
# raise colander.Invalid(node, ts)
#
#
# @colander.deferred
# def email_validator(node, kw):
# return EmailValidator(kw['user'])
#
#
# @colander.deferred
# def username_validator(node, kw):
# return UsernameValidator(kw['user'])
#
#
# def form_validator(form, value):
# new_password = value.get('new_password')
# retype_password = value.get('retype_password')
# if new_password != retype_password:
# raise colander.Invalid(form, _('Pengulangan kata kunci tidak sama'))
#
#
# # save_user ngambil dari base lama
# def save_user(values, user, row=None):
# if not row:
# row = User()
# row.from_dict(values)
# if 'password' in values and values['password']:
# row.password = values['password']
# # row.rpc_password = values['password']
#
# DBSession.add(row)
# DBSession.flush()
# return row
#
#
# class AddSchema(colander.Schema):
# email = colander.SchemaNode(
# colander.String(), title=_('Email'),
# validator=email_validator)
# user_name = colander.SchemaNode(colander.String(), title=_('Username'),
# validator=username_validator)
# groups = colander.SchemaNode(
# colander.Set(), widget=group_widget, title=_('Group'))
# is_api_key = colander.SchemaNode(
# colander.String(), widget=api_key_widget, title=_('API Key'),
# missing=colander.drop)
# new_password = colander.SchemaNode(
# colander.String(), widget=widget.PasswordWidget(),
# missing=colander.drop, title=_('Kata kunci'))
# retype_password = colander.SchemaNode(
# colander.String(), widget=widget.PasswordWidget(),
# missing=colander.drop, title=_('Ulangi kata kunci'))
#
#
# class EditSchema(AddSchema):
# status = colander.SchemaNode(
# colander.String(), widget=status_widget, title=_('Status'))
#
#
# def get_group_list():
# r = []
# q = DBSession.query(Group).order_by(Group.group_name)
# for row in q:
# g = (str(row.id), _(row.group_name))
# r.append(g)
# return r
#
#
# def get_form(request, class_form, user=None):
# status_list = (
# ('1', _('Active')),
# ('0', _('Inactive')))
# if user and user.api_key:
# api_key_list = (
# ('', _('Sudah ada')),
# ('0', _('Hapus')))
# else:
# api_key_list = (
# ('', _('Tidak ada')),
# ('1', _('Buatkan')))
# group_list = get_group_list()
# schema = class_form(validator=form_validator)
# schema = schema.bind(
# status_list=status_list, group_list=group_list, user=user,
# api_key_list=api_key_list)
# btn_save = Button('save', _('Simpan'))
# btn_cancel = Button('cancel', _('Batal'))
# return Form(schema, buttons=(btn_save, btn_cancel))
#
#
# def add_member_count(gid):
# q = DBSession.query(Group).filter_by(id=gid)
# group = q.first()
# group.member_count += 1
# DBSession.add(group)
#
#
# def reduce_member_count(gid):
# q = DBSession.query(Group).filter_by(id=gid)
# group = q.first()
# group.member_count -= 1
# DBSession.add(group)
#
#
# def insert(values):
# user = User()
# user.email = values['email'].lower()
# user.user_name = values['user_name'].lower()
# user.security_code_date = create_now()
# remain = regenerate_security_code(user)
# if 'is_api_key' in values:
# user.api_key = generate_api_key()
# if 'new_password' in values:
# UserService.set_password(user, values['new_password'])
# DBSession.add(user)
# DBSession.flush()
# if 'groups' in values and values['groups']:
# for gid in values['groups']:
# ug = UserGroup(user_id=user.id, group_id=gid)
# DBSession.add(ug)
# add_member_count(gid)
# return user, remain
#
#
# @view_config(
# route_name='user-add', renderer='templates/user/add.pt',
# permission='user-add')
# def view_add(request):
# form = get_form(request, AddSchema)
# resp = dict(title=_('Add user'))
# if not request.POST:
# resp['form'] = form.render()
# return resp
# if 'save' not in request.POST:
# return HTTPFound(location=request.route_url('user'))
# items = request.POST.items()
# try:
# c = form.validate(items)
# except ValidationFailure:
# resp['form'] = form.render()
# return resp
# values = dict(c.items())
# user, remain = insert(values)
# if 'new_password' in values:
# data = dict(username=user.user_name)
# ts = _(
# 'user-added-with-password',
# default='${username} berhasil ditambahkan.', mapping=data)
# else:
# send_email_security_code(
# request, user, remain, 'Welcome new user', 'email-new-user',
# 'email-new-user.tpl')
# data = dict(email=user.email)
# ts = _(
# 'user-added',
# default='${email} berhasil ditambahkan dan email untuk ubah ' \
# 'kata kunci sudah dikirim.',
# mapping=data)
# request.session.flash(ts)
# return HTTPFound(location=request.route_url('user'))
#
#
# ########
# # Edit #
# ########
# def user_group_set(user):
# q = DBSession.query(UserGroup).filter_by(user_id=user.id)
# r = []
# for ug in q:
# r.append(str(ug.group_id))
# return set(r)
#
#
# def update(request, user, values):
# fnames = ['email', 'user_name']
# user.email = values['email'].lower()
# user.user_name = values['user_name'].lower()
# if user.id != request.user.id:
# user.status = values['status']
# is_api_key = values.get('is_api_key')
# if is_api_key == '0':
# user.api_key = None
# elif is_api_key == '1':
# user.api_key = generate_api_key()
# if 'new_password' in values:
# UserService.set_password(user, values['new_password'])
# DBSession.add(user)
# existing = user_group_set(user)
# unused = existing - values['groups']
# if unused:
# q = DBSession.query(UserGroup).filter_by(user_id=user.id).filter(
# UserGroup.group_id.in_(unused))
# q.delete(synchronize_session=False)
# for gid in unused:
# reduce_member_count(gid)
# new = values['groups'] - existing
# for gid in new:
# ug = UserGroup(user_id=user.id, group_id=gid)
# DBSession.add(ug)
# add_member_count(gid)
#
#
# @view_config(
# route_name='user-edit', renderer='templates/user/edit.pt',
# permission='user-edit')
# def view_edit(request):
# q = DBSession.query(User).filter_by(id=request.matchdict['id'])
# user = q.first()
# if not user:
# return HTTPNotFound()
# if user.id == request.user.id:
# form = get_form(request, AddSchema, user)
# else:
# form = get_form(request, EditSchema, user)
# resp = dict(title=_('Edit user'))
# if not request.POST:
# d = user.to_dict()
# d['groups'] = user_group_set(user)
# resp['form'] = form.render(appstruct=d)
# return resp
# if 'save' not in request.POST:
# return HTTPFound(location=request.route_url('user'))
# items = request.POST.items()
# try:
# c = form.validate(items)
# except ValidationFailure:
# resp['form'] = form.render()
# return resp
# update(request, user, dict(c.items()))
# data = dict(username=user.user_name)
# ts = _('user-updated', default='${username} profile updated', mapping=data)
# request.session.flash(ts)
# return HTTPFound(location=request.route_url('user'))
#
#
# ##########
# # Delete #
# ##########
# @view_config(
# route_name='user-delete', renderer='templates/user/delete.pt',
# permission='user-edit')
# def view_delete(request):
# q = DBSession.query(User).filter_by(id=request.matchdict['id'])
# user = q.first()
# if not user:
# return HTTPNotFound()
# if not request.POST:
# btn_delete = Button('delete', _('Delete'))
# btn_cancel = Button('cancel', _('Cancel'))
# buttons = (btn_delete, btn_cancel)
# form = Form(colander.Schema(), buttons=buttons)
# return dict(title=_('Delete user'), user=user, form=form.render())
# if 'delete' not in request.POST:
# return HTTPFound(location=request.route_url('user'))
# gid_list = user_group_set(user)
# for gid in gid_list:
# reduce_member_count(gid)
# data = dict(uid=user.id, email=user.email)
# ts = _(
# 'user-deleted',
# default='User ${email} ID ${uid} has been deleted',
# mapping=data)
# q.delete()
# request.session.flash(ts)
# return HTTPFound(location=request.route_url('user'))
#
#
# ##########
# # Action #
# ##########
# @view_config(
# route_name='user-act', renderer='json', permission='user-view')
# def view_act(request):
# ses = request.session
# req = request
# params = req.params
# url_dict = req.matchdict
# if url_dict['act'] == 'grid':
# columns = [
# ColumnDT(User.id, mData='id'),
# ColumnDT(User.email, mData='email'),
# ColumnDT(User.user_name, mData='name'),
# ColumnDT(User.status, mData='status'), # , filter=_DTstatus
# ColumnDT(func.to_char(User.last_login_date, 'DD-MM-YYYY HH24:MI:SS'), mData='last_login'),
# ColumnDT(func.to_char(User.registered_date, 'DD-MM-YYYY HH24:MI:SS'), mData='registered'),
# ]
# query = DBSession.query().select_from(User)
# rowTable = DataTables(req.GET, query, columns)
# return rowTable.output_result()
# elif url_dict['act'] == 'hon':
# term = 'term' in params and params['term'] or ''
# rows = DBSession.query(User.id, User.user_name, User.email.label('value')
# ).filter(
# User.id > 1,
# or_(User.email.ilike('%%%s%%' % term),
# User.user_name.ilike('%%%s%%' % term))
# ).all()
# r = []
# for k in rows:
# d = dict(id=k[0],
# value=k[1] + '(' + k[2] + ')')
# r.append(d)
# return r
# elif url_dict['act'] == 'hom':
# term = 'term' in params and params['term'] or ''
# rows = DBSession.query(User.id, User.email
# ).filter(User.id != '1',
# User.id != '2',
# User.email.ilike('%%%s%%' % term)
# ).all()
# r = []
# for k in rows:
# d = dict(id=k[0],
# value=k[1],
# kode=k[1],
# nama=k[2])
# r.append(d)
# return r
# elif url_dict['act'] == 'csv':
# query = query_register()
# row = query.first()
# header = row.keys()
# rows = []
# for item in query.all():
# rows.append(list(item))
#
# filename = 'user.csv'
# value = {
# 'header': header,
# 'rows': rows,
# }
# return csv_response(request, value, filename)
# elif url_dict['act'] == 'pdf':
# query = query_register()
# _here = os.path.dirname(__file__) # get current folder -> views
# path = os.path.dirname(_here) # mundur 1 level
# path = os.path.join(path, 'reports')
# rml_row = open_rml_row(path + '/user.row.rml')
# rows = []
# for r in query.all():
# s = rml_row.format(user_name=r.user_name, email=r.email,
# registered_date=r.registered_date)
# rows.append(s)
# pdf, filename = open_rml_pdf(path + '/user.rml', rows=rows,
# company=request.company,
# departement=request.departement,
# address=request.address)
# return pdf_response(request, pdf, filename)
#
#
# #######
# # RPT #
# #######
# def query_register():
# return DBSession.query(User.user_name, User.email,
# func.to_char(User.registered_date, "DD-MM-YYYY").label("registered_date")).order_by(
# User.user_name)
...@@ -116,7 +116,7 @@ class DeTable(field.Field): ...@@ -116,7 +116,7 @@ class DeTable(field.Field):
btn_view_js = "{window.location = o%sUri+'/'+m%sID+'/view%s';}" % (tableid, tableid, params) btn_view_js = "{window.location = o%sUri+'/'+m%sID+'/view%s';}" % (tableid, tableid, params)
btn_delete_js = "{window.location = o%sUri+'/'+m%sID+'/delete%s';}" % (tableid, tableid, params) btn_delete_js = "{window.location = o%sUri+'/'+m%sID+'/delete%s';}" % (tableid, tableid, params)
btn_csv_js = "{window.location = o%sUri+'/csv/act%s';}" % (tableid, params) btn_csv_js = "{window.location = o%sUri+'/csv/act%s';}" % (tableid, params)
btn_pdf_js = "{window.location = o%sUri+'/pdf/act%s';}" % (tableid, params) btn_pdf_js = "{window.open(o%sUri+'/pdf/act%s');}" % (tableid, params)
action_suffix=f"{action_suffix}{params}" action_suffix=f"{action_suffix}{params}"
field.Field.__init__(self, schema, **kw) field.Field.__init__(self, schema, **kw)
_buttons = [] _buttons = []
......
...@@ -19,7 +19,6 @@ from deform.widget import MappingWidget ...@@ -19,7 +19,6 @@ from deform.widget import MappingWidget
from deform.compat import text_ from deform.compat import text_
from .i18n import _ from .i18n import _
_BLANK = text_("") _BLANK = text_("")
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!