Commit 5bcb5039 by aagusti

move to record

1 parent 59fadecd
from datetime import datetime
from deform import ValidationFailure, Form, Button
from opensipkd.models import flush, DBSession, Menus
from pyramid_rpc.jsonrpc import JsonRpcError
from opensipkd.tools.form_api import formfield2dict
class BaseApi(object):
def __init__(self, request):
self.request = request
self.url = request.home + '/rpc/pbb/eta'
self.add_schema = {}
self.buttons = ()
self.data = {}
def make_response(self, data, **kwargs):
resp = {"data": data}
code = kwargs.get("code")
message = kwargs.get("message")
if code: resp.update({"code": code})
if message: resp.update({"message": message})
return resp
def get_form(self, class_form, row=None, **kwargs):
bindings = kwargs.get("bindings")
validator = kwargs.get("validator")
self.buttons = kwargs.get("buttons", self.buttons)
if "url" in kwargs:
url = kwargs.get("url", "")
else:
url = self.url
if validator:
schema = class_form(validator=validator)
else:
schema = class_form() # validator=validator
if bindings:
schema = schema.bind(request=self.request, **bindings)
else:
schema = schema.bind(request=self.request)
if row:
schema.deserialize(row)
return Form(schema, url=url, buttons=self.buttons)
def validate_field(self, form):
resp = {}
controls = ((k, v) for k, v in self.data.items())
try:
c = form.validate(controls)
except ValidationFailure as e:
form.set_appstruct(e.cstruct)
resp.update(formfield2dict(form))
message = "\n".join([v for k, v in e.error.asdict().items()])
raise JsonRpcError(message=message, data=resp)
return dict(c)
def get_menu_buttons(self, kode):
qry = Menus.get(kode).order_by(Menus.order_id)
if self.request.user:
qry = qry.filter_by(need_login=1)
else:
qry = qry.filter(Menus.need_login != 1)
buttons = []
for row in qry.all():
if not self.request.user:
if row.need_login:
continue
if row.permissions:
if not self.request.user or not self.request.has_permission(
row.permissions):
continue
buttons.append(Button(row.kode, title=row.title, type="button",
value=row.url, icon=row.icon,))
# attributes=dict(method=row.url)))
return tuple(buttons)
def update_headers(self, headers):
self.request.headers.update(headers)
self.request.response.headers.update(headers)
def _view_add(self, **kwargs):
form = self.get_form(self.add_schema, **kwargs)
self.action = self.data.get("action", "")
if 'save' == self.action:
values = self.validate_field(form)
row = self.save_request(values)
elif "cancel" == self.action or 'batal' == self.action:
self.cancel_act()
else:
next = self.next_add(form)
if next:
return next
# return self.route_list()
values = self.before_add()
form.set_appstruct(values)
return form
def view_add_api(self, **kwargs):
form = self._view_add(**kwargs)
resp = formfield2dict(form)
return dict(data=resp)
def save(self, values, user, row=None):
self.ses["old_email"] = user and user.email or None
if not row:
row = self.table()
row.created = datetime.now()
row.create_uid = user and user.id or None
else:
row.updated = datetime.now()
row.update_uid = user and user.id or None
row.from_dict(values)
row.status = 'status' in values and values['status'] and 1 or 0
flush(row)
return row
def save_request(self, values, row=None):
for k, v in self.request.GET.items():
if k not in values:
if v:
values[k] = v
return self.save(values, self.request.user, row)
def id_not_found(self):
msg = f"Data yang dicari Tidak Ditemukan ID:" \
f" {self.request.matchdict['id']}."
self.request.session.flash(msg, 'error')
return self.route_list()
def next_add(self, form):
"""
Digunakan untuk memverifikasi button yang lainnya
:param form: Object Form
:return:
"""
return ""
def query_id(self):
q = DBSession.query(self.table).filter_by(
id=self.req.matchdict['id'])
if hasattr(self.table, 'company_id') and self.req.user.company_id:
q = q.filter_by(company_id=self.req.user.company_id)
return q
def route_list(self, msg=None, error=""):
if msg:
self.ses.flash(msg, error)
if self.headers:
return HTTPFound(location=self.req.route_url(self.list_route),
headers=self.headers)
else:
return HTTPFound(location=self.req.route_url(self.list_route))
def before_add(self):
return {}
......@@ -7,6 +7,7 @@ from pyramid.view import (view_config, )
from sqlalchemy.orm import aliased
from ..views import ColumnDT, DataTables, BaseView
_ = TranslationStringFactory("opensipkd")
SESS_ADD_FAILED = 'Tambah menu gagal'
......@@ -45,6 +46,14 @@ class AddSchema(colander.Schema):
kode = colander.SchemaNode(colander.String(),
validator=colander.Length(max=32), oid="kode")
nama = colander.SchemaNode(colander.String(), oid="nama")
url = colander.SchemaNode(colander.String(), oid="url",
title="URL/METHOD")
icon = colander.SchemaNode(colander.String(),
missing=colander.drop)
class_name = colander.SchemaNode(colander.String(), oid="url",
missing=colander.drop)
need_login = colander.SchemaNode(colander.Boolean())
title = colander.SchemaNode(colander.String())
status = colander.SchemaNode(colander.Boolean(), oid="status")
def after_bind(self, schema, kwargs):
......
......@@ -14,7 +14,6 @@ from pyramid.i18n import TranslationStringFactory
from pyramid.security import remember, forget
from pyramid_rpc.jsonrpc import jsonrpc_method
from .base_views_api import BaseApi
from .user import EmailValidator as EmailValidatorBase
from .user_group import save as save_groups
from .user_login import (ChangePassword, change_password_validator,
......
TODO
- docs
- column formating (left, right, center)
- numeric formating
- date formating
"""Detable."""
import os
from pkg_resources import resource_filename
from . import detable # API
from deform.field import Field # API
from .detable import Button # API
from .detable import DeTable # API
from deform import ZPTRendererFactory # API
from deform import default_renderer # API
deform_templates = resource_filename('deform', 'templates')
path = os.path.dirname(__file__)
path = os.path.join(path, 'templates')
search_path = (path, deform_templates) #,
# renderer = ZPTRendererFactory(search_path)
DeTable.set_zpt_renderer(search_path)
"""I18n."""
from translationstring import TranslationStringFactory
_ = TranslationStringFactory("detable")
<div tal:define="style style|field.widget.style;
css_class css_class|string:${field.widget.css_class or field.css_class or 'jarviswidget jarviswidget-color-blueLight'};
item_template item_template|field.widget.item_template;
title title|field.title;
errormsg errormsg|field.errormsg;
description description|field.description;
buttons buttons|field.buttons;
tableid tableid|field.tableid;
columns columns|field.columns;
btnscripts scripts|field.scripts;
url url|field.url;
url_suffix url_suffix|field.url_suffix;
sorts sorts|field.sorts;
filters filters|field.filters;
paginates paginates|field.paginates;
"
tal:attributes="style style;
class css_class;
attributes|field.widget.attributes|{};"
i18n:domain="detable">
<header role="heading" class="txt-color-grayDark">
<h2 tal:condition="title">
<i class="fa fa-fw fa-table"></i>${title}
</h2>
<div role="content">
<div class="widget-body">
<table id="${tableid}"
class="table table-bordered table-hover table-condensed dataTable no-footer">
<thead>
<tr>
<th tal:repeat="child field">${child.title}</th>
<!--? <th>Action</th>-->
</tr>
</thead>
<tbody>
</tbody>
</table>
</div> <!-- widget-body -->
</div>
</header>
<script type="text/javascript">
deform.addCallback(
'${tableid}',
function (oid) {
var m${tableid}ID;
var o${tableid};
var o${tableid}Uri = "${url}";
var o${tableid}Url = o${tableid}Uri + "${url_suffix}";
var tb_array = [
'<div class="btn-group pull-left">',
'${structure:buttons}',
' &nbsp;',
'</div>',
]
var language = {
"search": "Cari: ",
"paginate": {
"first": '<span class="glyphicon glyphicon-step-backward"></span> ',
"last": '<span class="glyphicon glyphicon glyphicon-step-forward"></span> ',
"previous": '<span class="glyphicon glyphicon-backward"></span> ',
"next": '<span class="glyphicon glyphicon-forward"></span> ',
},
"lengthMenu": " _MENU_ baris "
};
o${tableid} = $('#${tableid}').DataTable({
dom: '<"row"<"col-md-8"<"toolbar">Bl><"col-md-4"fr>>tip',
processing: true,
serverSide: true,
ajax: o${tableid}Url,
stateSave: false,
scrollCollapse: true,
sort: ${sorts},
info: false,
filter: ${filters},
autoWidth: false,
paginate: ${paginates},
paginationType: "full_numbers",
lengthMenu: [
[10, 25, 50, 100],
[10, 25, 50, 100]
],
columns: ${structure:columns},
"language": language,
});
var tb = tb_array.join(' ');
$("div.toolbar").html(tb);
$("div.toolbar").attr('style', 'display:block; float: left; margin-bottom:6px; line-height:16px;');
$('#${tableid} tbody').on('click', 'tr', function () {
if ($(this).hasClass('selected')) {
$(this).removeClass('selected');
} else {
var aData = o${tableid}.row(this).data();
o${tableid}.$('tr.selected').removeClass('selected');
$(this).addClass('selected');
m${tableid}ID = aData.id;
// console.log(mID);
o${tableid}.$('tr.row_selected').removeClass('row_selected');
$(this).addClass('row_selected');
}
});
${structure:btnscripts}
});
</script>
</div>
\ No newline at end of file
"""Widget."""
# Standard Library
import csv
import json
import random
# Pyramid
from colander import Invalid
from colander import Mapping
from colander import SchemaNode
from colander import SchemaType
from colander import Sequence
from colander import String
from colander import null
from iso8601.iso8601 import ISO8601_REGEX
from translationstring import TranslationString
from deform.widget import MappingWidget
from deform.compat import text_
from .i18n import _
_BLANK = text_("")
class TableWidget(MappingWidget):
"""
The top-level widget; represents an entire table.
**Attributes/Arguments**
template
The template name used to render the widget. Default:
``detable``.
"""
template = "detable"
readonly_template = "readonly/detable"
requirements = (("deform", None),
{"js": "opensipkd.base:static/v3/js/plugin/datatables/jquery.dataTables.min.js"})
......@@ -162,6 +162,7 @@ class DeTable(field.Field):
self.server_side = server_side
self.data = data
columns = []
headers = []
cols2 = []
for f in schema:
d = {'data': f.name}
......@@ -219,8 +220,17 @@ class DeTable(field.Field):
if 'className' not in d:
d["className"] = "text-right"
columns.append(d)
headers.append(f.title)
cols2.append(data)
# for t in d:
# if "title" in t:
# headers.append(t["title"])
# else:
# headers.append(t)
self.headers = headers
self.head = headers
self.columns = json.dumps(columns)
self.columns = self.columns.replace('"<script>', "").replace(
'</script>"', "").replace("\n", "")
......@@ -229,6 +239,7 @@ class DeTable(field.Field):
self.sorts = sorts
self.paginates = paginates
self.filters = filters
print(self.headers)
class Button(object):
......
from sqlalchemy import func
from sqlalchemy.sql import sqltypes
from .. import Base
from opensipkd.tools import round_up
from opensipkd.tools.api import JsonRpcDataNotFoundError
from opensipkd.tools.pbb import FixNop, FixKelurahan, FixBlok
class BaseApiTableFilter(object):
"""Function untuk standarisasi filtering table"""
def __init__(self, orm, data):
self.orm = orm
self.data = data
def filter_nop(self, qry, val):
kode = FixNop(val)
return qry.filter_by(kd_propinsi=kode["kd_propinsi"],
kd_dati2=kode["kd_dati2"],
kd_kecamatan=kode["kd_kecamatan"],
kd_kelurahan=kode["kd_kelurahan"],
kd_blok=kode["kd_blok"],
no_urut=kode["no_urut"],
kd_jns_op=kode["kd_jns_op"])
def filter_desa(self, qry, val):
kode = FixKelurahan(val)
return qry.filter_by(kd_propinsi=kode["kd_propinsi"],
kd_dati2=kode["kd_dati2"],
kd_kecamatan=kode["kd_kecamatan"],
kd_kelurahan=kode["kd_kelurahan"]
)
def filter_blok(self, qry, val):
kode = FixBlok(val)
return qry.filter_by(kd_propinsi=kode["kd_propinsi"],
kd_dati2=kode["kd_dati2"],
kd_kecamatan=kode["kd_kecamatan"],
kd_kelurahan=kode["kd_kelurahan"],
kd_blok=kode["kd_blok"])
def get_data(self):
data = self.data
orm = self.orm
qry = self.orm.query()
if "where" in data:
for w in data["where"]:
if hasattr(orm, w['key']):
key = w["key"]
val = w["val"]
if key == "nop":
qry = self.filter_nop(qry, val)
elif key == "desa":
qry = self.filter_desa(qry, val)
elif key == "blok":
qry = self.filter_blok(qry, val)
else:
key = getattr(orm, key)
if isinstance(key.type, sqltypes.String):
qry = qry.filter(func.trim(key) == val)
else:
qry = qry.filter(key == val)
if "order" in data:
for o in data["order"]:
key = getattr(orm, o)
qry = qry.order_by(key)
page_size = "page_size" in data and int(data["page_size"]) or 20
page = "page" in data and int(data["page"]) or 1
total_page = round_up(qry.count() / page_size)
if total_page and page > total_page:
page = int(total_page)
offset = (page - 1) * page_size
qry = qry.offset(offset).limit(page_size)
return qry, page, total_page
def get_filter(self):
qry, page, total_page = self.get_data()
row = qry.first()
if not row:
raise JsonRpcDataNotFoundError
result = []
for row in qry.all():
result.append(row.to_dict())
return dict(record=result,
total_page=total_page,
page=page)
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!