Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
aa.gusti
/
opensipkd-base
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Settings
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit 5ee39d73
authored
Aug 14, 2022
by
aagusti
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
penambahan view_next
1 parent
1d304fb0
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
261 additions
and
163 deletions
opensipkd/base/__init__.py
opensipkd/base/views/api.py
opensipkd/base/views/base_views.py
opensipkd/base/views/templates/login.pt
opensipkd/base/views/user_rpc.py
opensipkd/base/views/widget_os.py
opensipkd/base/views/widgets/image.pt
opensipkd/base/views/widgets/readonly/captcha.pt
opensipkd/base/views/widgets/readonly/image.pt
opensipkd/detable/detable.py
opensipkd/detable/templates/detable.pt
opensipkd/jsonrpc_auth/__init__.py
setup.py
opensipkd/base/__init__.py
View file @
5ee39d7
...
...
@@ -2,6 +2,8 @@ import locale
import
logging
import
re
import
colander
try
:
from
urllib
import
(
urlencode
,
quote
,
quote_plus
,
)
except
ImportError
:
...
...
@@ -101,6 +103,8 @@ def has_permission_(request, perm_names, context=None):
if
request
.
has_permission
(
perm_name
,
context
):
return
True
def
_get_params
(
request
,
params
,
default
=
None
,
settings
=
None
,
context
=
None
):
return
get_params
(
params
,
default
,
settings
)
@subscriber
(
BeforeRender
)
def
add_global
(
event
):
...
...
@@ -422,16 +426,12 @@ def main(global_config, **settings):
config
.
add_request_method
(
is_devel
,
'devel'
,
reify
=
True
)
config
.
add_request_method
(
get_host
,
'_host'
,
reify
=
True
)
config
.
add_request_method
(
get_home
,
'home'
,
reify
=
True
)
# config.add_request_method(api_has_permission_, 'api_has_permission', reify=True)
config
.
add_request_method
(
google_signin_client_id
,
'google_signin_client_id'
,
reify
=
True
)
config
.
add_request_method
(
google_signin_client_ids
,
'google_signin_client_ids'
,
reify
=
True
)
config
.
add_request_method
(
allow_register
,
'allow_register'
,
reify
=
True
)
config
.
add_request_method
(
disable_responsive
,
'disable_responsive'
,
reify
=
True
)
# config.add_request_method(get_params, 'get_params', reify=True)
# config.add_request_method(get_ini_params, 'get_ini', reify=True)
config
.
add_request_method
(
get_ini
,
'get_ini'
,
reify
=
True
)
config
.
add_translation_dirs
(
'opensipkd.base:locale/'
)
...
...
opensipkd/base/views/api.py
View file @
5ee39d7
# from pyramid_rpc.amfgateway import PyramidGateway
from
pyramid_rpc.jsonrpc
import
jsonrpc_method
from
opensipkd.tools.api
import
JsonRpcInvalidData
Error
,
JsonRpcInvalidLoginError
from
opensipkd.tools.api
import
JsonRpcInvalidData
,
JsonRpcInvalidLoginError
from
ziggurat_foundations.models.services.user
import
UserService
from
opensipkd.models
import
Partner
,
User
...
...
opensipkd/base/views/base_views.py
View file @
5ee39d7
...
...
@@ -6,7 +6,6 @@ from datetime import datetime
from
datatables
import
ColumnDT
from
dateutil.relativedelta
import
relativedelta
from
opensipkd.tools.captcha
import
get_captcha
from
pyramid.httpexceptions
import
HTTPFound
...
...
@@ -209,6 +208,9 @@ class BaseView(object):
def
get_bindings
(
self
,
row
=
None
):
return
{}
def
next_view
(
self
,
form
,
**
kwargs
):
return
self
.
route_list
()
def
view_view
(
self
):
# row = query_id(request).first()
request
=
self
.
req
row
=
self
.
query_id
()
.
first
()
...
...
@@ -218,14 +220,16 @@ class BaseView(object):
form
=
self
.
get_form
(
self
.
edit_schema
,
buttons
=
(
btn_close
,),
bindings
=
bindings
)
if
request
.
POST
:
return
self
.
route_list
()
result
=
self
.
next_view
(
form
)
if
result
:
return
result
form
.
set_appstruct
(
self
.
get_values
(
row
))
table
=
self
.
get_item_table
(
row
)
return
dict
(
form
=
form
.
render
(
readonly
=
True
),
table
=
table
and
table
.
render
()
or
None
,
scripts
=
self
.
form_scripts
)
def
before_add
(
self
):
return
{}
...
...
@@ -254,8 +258,8 @@ class BaseView(object):
columns
=
[]
for
d
in
self
.
list_schema
():
global_search
=
hasattr
(
d
,
"searchable"
)
and
\
hasattr
(
d
,
"searchable"
)
==
False
and
False
\
or
True
hasattr
(
d
,
"searchable"
)
==
False
and
False
\
or
True
if
hasattr
(
d
,
"field"
):
if
type
(
d
.
field
)
==
str
:
columns
.
append
(
...
...
opensipkd/base/views/templates/login.pt
View file @
5ee39d7
...
...
@@ -139,7 +139,6 @@
window
.
onload
=
function
(
e
)
{
const
value
=
document
.
cookie
;
const
parts
=
value
.
split
(
`g_state=`
);
console
.
log
(
parts
.
length
)
if
(
parts
.
length
===
2
)
{
document
.
cookie
=
document
.
cookie
+
";max-age=0"
;
}
...
...
opensipkd/base/views/user_rpc.py
View file @
5ee39d7
...
...
@@ -8,7 +8,7 @@ from opensipkd.base.views.partner_base import NamaSchema
from
opensipkd.jsonrpc_auth
import
JsonRpcInvalidLogin
from
opensipkd.tools
import
create_now
from
opensipkd.tools.api
import
(
JsonRpcInvalidLoginError
,
JsonRpcInvalidData
Error
,
JsonRpcInvalidLoginError
,
JsonRpcInvalidData
,
JsonRpcUserNotFoundError
)
from
pyramid.i18n
import
TranslationStringFactory
from
pyramid.security
import
remember
,
forget
...
...
@@ -234,7 +234,7 @@ def set_profile_(request, data):
controls
=
form
.
validate
(
controls
)
except
ValidationFailure
as
e
:
print
(
e
.
error
,
type
(
e
.
error
))
raise
JsonRpcInvalidData
Error
(
data
=
e
.
error
.
asdict
())
raise
JsonRpcInvalidData
(
data
=
e
.
error
.
asdict
())
values
=
dict
(
controls
)
partner
=
Partner
.
query
()
.
filter_by
(
email
=
values
[
"email"
])
.
first
()
if
not
partner
:
...
...
opensipkd/base/views/widget_os.py
View file @
5ee39d7
...
...
@@ -275,3 +275,50 @@ class CaptchaWidget(Widget):
if
not
pstruct
:
return
null
return
pstruct
class
ImageWidget
(
Widget
):
"""
Renders an ``<img src="src"/>`` widget.
**Attributes/Arguments**
template
The template name used to render the widget. Default:
``image``.
readonly_template
The template name used to render the widget in read-only mode.
Default: ``readonly/image``.
strip
If true, during deserialization, strip the value of leading
and trailing whitespace (default ``True``).
"""
template
=
"opensipkd.base:views/widgets/image.pt"
readonly_template
=
"image"
strip
=
True
requirements
=
()
def
__init__
(
self
,
**
kw
):
super
()
.
__init__
(
**
kw
)
def
serialize
(
self
,
field
,
cstruct
,
**
kw
):
if
cstruct
in
(
null
,
None
):
cstruct
=
""
readonly
=
kw
.
get
(
"readonly"
,
self
.
readonly
)
template
=
readonly
and
self
.
readonly_template
or
self
.
template
values
=
self
.
get_template_values
(
field
,
cstruct
,
kw
)
return
field
.
renderer
(
template
,
**
values
)
def
deserialize
(
self
,
field
,
pstruct
):
if
pstruct
is
null
:
return
null
elif
not
isinstance
(
pstruct
,
string_types
):
raise
Invalid
(
field
.
schema
,
"Pstruct is not a string"
)
if
self
.
strip
:
pstruct
=
pstruct
.
strip
()
if
not
pstruct
:
return
null
return
pstruct
opensipkd/base/views/widgets/image.pt
0 → 100644
View file @
5ee39d7
<span tal:define="name name|field.name;
css_class css_class|field.widget.css_class;
oid oid|field.oid;
style style|field.widget.style;
"
tal:omit-tag="">
<img style="height:30px; width:auto; margin-bottom:5px;" src="${cstruct}">
</span>
opensipkd/base/views/widgets/readonly/captcha.pt
0 → 100644
View file @
5ee39d7
<span tal:define="name name|field.name;
css_class css_class|field.widget.css_class;
oid oid|field.oid;
style style|field.widget.style;
"
tal:omit-tag="">
<img style="height:30px; width:auto; margin-bottom:5px;" src="${cstruct}">
<input type="text" name="${name}" value=""
tal:attributes="class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};"
id="${oid}"/>
<script>
deform.addCallback(
'${oid}',
function (oid) {
$("#" + oid).on('input', function (evt) {
$(this).val(function (_, val) {
return val.toUpperCase();
});
});
});
</script>
</span>
opensipkd/base/views/widgets/readonly/image.pt
0 → 100644
View file @
5ee39d7
<span tal:define="name name|field.name;
css_class css_class|field.widget.css_class;
oid oid|field.oid;
style style|field.widget.style;
"
tal:omit-tag="">
<img style="height:30px; width:auto; margin-bottom:5px;" src="${cstruct}">
</span>
opensipkd/detable/detable.py
View file @
5ee39d7
...
...
@@ -10,6 +10,7 @@ from chameleon.utils import Markup
from
deform
import
compat
from
deform
import
field
from
.
import
widget
# from deform import widget
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -129,7 +130,7 @@ class DeTable(field.Field):
btn_pdf_js
=
"{window.open(o
%
sUri+'/pdf/act
%
s');}"
%
(
tableid
,
params
)
action_suffix
=
f
"{action_suffix}{params}"
field
.
Field
.
__init__
(
self
,
schema
,
**
kw
)
self
.
request
=
kw
.
get
(
"request"
)
self
.
request
=
kw
.
get
(
"request"
)
_buttons
=
[]
for
button
in
buttons
:
if
isinstance
(
button
,
compat
.
string_types
):
...
...
@@ -179,31 +180,28 @@ class DeTable(field.Field):
if
hasattr
(
f
,
'visible'
):
d
[
"visible"
]
=
f
.
visible
data
.
append
(
f
"visible: {f.visible}"
)
if
hasattr
(
f
,
'orderable'
):
d
[
"orderable"
]
=
f
.
orderable
data
.
append
(
f
"orderable: {f.orderable}"
)
if
hasattr
(
f
,
"url"
):
request
=
kw
.
get
(
"request"
)
request
=
kw
.
get
(
"request"
)
if
request
:
d
[
"url"
]
=
request
.
static_url
(
f
.
url
)
d
[
"url"
]
=
request
.
static_url
(
f
.
url
)
log
.
debug
(
d
[
"url"
])
if
hasattr
(
f
,
"action"
):
d
[
"action"
]
=
f
.
action
else
:
d
[
"action"
]
=
True
d
[
"action"
]
=
True
if
isinstance
(
f
.
widget
,
deform
.
widget
.
HiddenWidget
):
d
[
"visible"
]
=
False
if
isinstance
(
f
.
widget
,
deform
.
widget
.
CheckboxWidget
):
d
[
"checkbox"
]
=
True
else
:
d
[
"checkbox"
]
=
False
d
[
"checkbox"
]
=
False
thousand
=
hasattr
(
f
,
'thousand'
)
and
f
.
thousand
or
None
separator
=
thousand
and
"separator"
in
thousand
and
thousand
[
...
...
@@ -213,10 +211,11 @@ class DeTable(field.Field):
point
=
thousand
and
"point"
in
thousand
and
thousand
[
"point"
]
or
0
currency
=
thousand
and
"currency"
in
thousand
and
thousand
[
"currency"
]
or
""
if
thousand
or
type
(
f
.
typ
)
==
colander
.
Float
()
or
type
(
f
.
typ
)
==
colander
.
Integer
():
d
[
"render"
]
=
f
"<script>$.fn.dataTable.render.number( '{separator}', "
\
f
"'{decimal}', {point}, '{currency}' )</script>"
if
thousand
or
isinstance
(
f
.
typ
,
colander
.
Float
)
or
\
isinstance
(
f
.
typ
,
colander
.
Integer
):
d
[
"render"
]
=
\
f
"<script>$.fn.dataTable.render.number( '{separator}', "
\
f
"'{decimal}', {point}, '{currency}' )</script>"
if
'className'
not
in
d
:
d
[
"className"
]
=
"text-right"
columns
.
append
(
d
)
...
...
opensipkd/detable/templates/detable.pt
View file @
5ee39d7
<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;
server_side server_side|field.server_side;
data data|field.data;
allow_edit allow_edit|field.allow_edit;
allow_delete allow_delete|field.allow_delete;
"
tal:attributes="style style; class css_class; attributes|field.widget.attributes|{};"
i18n:domain="detable"
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;
server_side server_side|field.server_side;
data data|field.data;
allow_edit allow_edit|field.allow_edit;
allow_delete allow_delete|field.allow_delete;
"
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"
id="${tableid}"
class="table table-bordered table-hover table-condensed dataTable no-footer"
>
<thead>
<tr>
<th tal:repeat="child field">${child.title}</th>
</tr>
<tr>
<th tal:repeat="child field">${child.title}</th>
</tr>
</thead>
<tbody></tbody>
</table>
...
...
@@ -43,121 +43,118 @@
</header>
<script type="text/javascript">
var m${tableid}ID;
var o${tableid};
var o${tableid}Uri = "${url}";
var o${tableid}Url = o${tableid}Uri + "${url_suffix}";
deform.addCallback
('${tableid}', function (oid) {
let m${tableid}ID;
let o${tableid};
let o${tableid}Uri = "${url}";
let o${tableid}Url = o${tableid}Uri + "${url_suffix}";
let tb_array = [
'<div class="btn-group pull-left">',
'${structure:buttons}',
' ',
'</div>',
]
let columns = ${structure: columns};
// $(document).ready(function () {
function render_checkbox(value) {
if (value == true) {
return '<i class="fas fa-check-square" aria-hidden="true">';
}
return 'Archived';
}
for (let co in columns) {
console.log(columns[co]);
if (columns[co].checkbox === true) {
columns[co].className = "text-center";
columns[co].width = "30pt";
columns[co].render = function (val) {
if (["", false, 0].indexOf(val) === -1) {
return render_checkbox(true);
} else return render_checkbox(false);
}
}else if (columns[co].hasOwnProperty("url")){
let url = columns[co].url;
columns[co].render = function (data) {
let result = '<a href="'+url+'/' + data + '" target="_blank">'+data+'</a> ';
return result;
}
}else if(columns[co].data == "id" && columns[co].action == true){
columns[co].render = function (id) {
let result = '<a href="${url}/' + id + '/view"><i class="fas fa-eye" aria-hidden="true"></i></a> ';
if (${allow_edit}) {
result += '<a href="${url}/' + id + '/edit"><i class="fas fa-edit" aria-hidden="true"></i></a> '
}
if (${allow_delete}) {
result += '<a href="${url}/' + id + '/delete"><i class="fas fa-trash" aria-hidden="true"></i></a>';
}
let tb_array = [
'<div class="btn-group pull-left">',
'${structure:buttons}',
' ',
'</div>',
]
let ${tableid}Columns = ${structure: columns};
return result;
}
columns[co].width = "30pt";
columns[co].orderable = false;
columns[co].className = "text-center";
columns[co].visible = true;
//columns[1].order = "order_asc";
function render_checkbox(value) {
if (value === true) {
return '<i class="fas fa-check-square" aria-hidden="true">';
}
return 'Archived';
}
for (let co in ${tableid}Columns) {
if (${tableid}Columns[co].checkbox === true) {
${tableid}Columns[co].className = "text-center";
${tableid}Columns[co].width = "30pt";
${tableid}Columns[co].render = function (val) {
if (["", false, 0].indexOf(val) === -1) {
return render_checkbox(true);
} else return render_checkbox(false);
}
} else if (${tableid}Columns[co].hasOwnProperty("url")) {
let url = ${tableid}Columns[co].url;
${tableid}Columns[co].render = function (data) {
let result = '<a href="' + url + '/' + data + '" target="_blank">Link</a> ';
return result;
}
} else if (${tableid}Columns[co].data === "id" && ${tableid}Columns[co].action === true) {
${tableid}Columns[co].render = function (id) {
let result = '<a href="${url}/' + id + '/view"><i class="fas fa-eye" aria-hidden="true"></i></a> ';
if (${allow_edit}) {
result += '<a href="${url}/' + id + '/edit"><i class="fas fa-edit" aria-hidden="true"></i></a> '
}
}
let 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 "
};
let params = {
dom: '<"row"<"col-md-8"<"toolbar">Bl><"col-md-4"fr>>tip',
processing: true,
serverSide: ${server_side},
stateSave: false,
scrollCollapse: true,
sort: ${sorts},
info: false,
filter: ${filters},
autoWidth: false,
paginate: ${paginates},
paginationType: "full_numbers",
order: [],
lengthMenu: [
[10, 25, 50, 100],
[10, 25, 50, 100]
],
columns: columns,
"language": language,
if (${allow_delete}) {
result += '<a href="${url}/' + id + '/delete"><i class="fas fa-trash" aria-hidden="true"></i></a>';
}
return result;
}
${tableid}Columns[co].width = "30pt";
${tableid}Columns[co].orderable = false;
${tableid}Columns[co].className = "text-center";
${tableid}Columns[co].visible = true;
//columns[1].order = "order_asc";
}
if (${server_side}==false
)
{
params.data = ${data};
}
else
{
params.ajax = o${tableid}Url;
}
let ${tableid}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 "
};
let ${tableid}Params = {
dom: '<"row"<"col-md-8"<"toolbar">Bl><"col-md-4"fr>>tip',
processing: true,
serverSide: ${server_side},
stateSave: false,
scrollCollapse: true,
sort: ${sorts},
info: false,
filter: ${filters},
autoWidth: false,
paginate: ${paginates},
paginationType: "full_numbers",
order: [],
lengthMenu: [
[10, 25, 50, 100],
[10, 25, 50, 100]
],
columns: ${tableid}Columns,
"language": ${tableid}Language,
}
if (!${server_side}) {
${tableid}Params.data = ${data};
} else {
${tableid}Params.ajax = o${tableid}Url;
}
o${tableid} = $('#${tableid}').DataTable(${tableid}Params);
let 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 {
let aData = o${tableid}.row(this).data();
o${tableid}.$('tr.selected').removeClass('selected');
$(this).addClass('selected');
m${tableid}ID = aData.id;
//console.log("m${tableid}ID", m${tableid}ID);
o${tableid}.$('tr.row_selected').removeClass('row_selected');
$(this).addClass('row_selected');
}
o${tableid} = $('#${tableid}').DataTable(params);
let 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 {
let 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}
});
${structure:btnscripts}
});
</script>
</div>
opensipkd/jsonrpc_auth/__init__.py
View file @
5ee39d7
import
decimal
import
json
import
logging
from
datetime
import
datetime
import
colander
from
icecream
import
ic
from
pyramid.httpexceptions
import
HTTPForbidden
from
pyramid.httpexceptions
import
HTTPNotFound
from
pyramid.renderers
import
null_renderer
,
render
from
pyramid.renderers
import
null_renderer
,
render
,
JSON
from
pyramid.response
import
Response
from
pyramid.security
import
NO_PERMISSION_REQUIRED
,
remember
from
pyramid_rpc.jsonrpc
import
(
...
...
@@ -255,6 +259,13 @@ class EndpointPredicate(object):
# return a valid JSON-RPC response.
return
True
def
json_rpc
():
json_r
=
JSON
()
json_r
.
add_adapter
(
datetime
.
datetime
,
lambda
v
,
request
:
v
.
isoformat
())
json_r
.
add_adapter
(
datetime
.
date
,
lambda
v
,
request
:
v
.
isoformat
())
json_r
.
add_adapter
(
decimal
.
Decimal
,
lambda
v
,
request
:
str
(
v
))
json_r
.
add_adapter
(
colander
.
null
,
lambda
v
,
request
:
None
)
return
json_r
def
includeme
(
config
):
""" Set up standard configurator registrations. Use via:
...
...
setup.py
View file @
5ee39d7
...
...
@@ -33,7 +33,7 @@ requires = [
'google-api-python-client'
,
'google'
,
'pyjwt'
,
'z3c.rml'
,
#
'z3c.rml',
'opensipkd-tools @git+https://git.opensipkd.com/aa.gusti/opensipkd-tools.git'
,
]
...
...
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment