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 89c9884a
authored
Nov 30, 2021
by
aa.gusti
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
perbaikan menus dan upload
1 parent
7611904f
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
375 additions
and
361 deletions
.gitignore
opensipkd/base/__init__.py
opensipkd/base/scripts/initializedb.py
opensipkd/base/static/css/custom.css
opensipkd/base/static/icon/default.png
opensipkd/base/views/base_views.py
opensipkd/base/views/posisi.py
opensipkd/base/views/templates/base3.1.pt
opensipkd/base/views/templates/home.pt
opensipkd/base/views/templates/upload.pt
opensipkd/base/views/upload.py
.gitignore
View file @
89c9884
...
...
@@ -105,6 +105,8 @@ ENV/
opensipkd/base/static/img/*
opensipkd/base/static/icon/*
!opensipkd/base/static/icon/default.png
!opensipkd/base/static/img/pyramid.png
!opensipkd/base/static/img/opensipkd.png
!opensipkd/base/static/img/opensipkd_bg.png
...
...
opensipkd/base/__init__.py
View file @
89c9884
...
...
@@ -248,7 +248,13 @@ def get_menus(request):
result
=
{}
for
menu
in
menus
:
if
menu
.
find
(
':'
)
>
-
1
:
if
menu
.
find
(
','
)
>
-
1
:
key
,
val
=
menu
.
strip
()
.
split
(
','
)
key
=
key
.
strip
()
.
strip
(
'/'
)
val
=
re
.
sub
(
'[//-]'
,
' '
,
val
)
elif
menu
.
find
(
':'
)
>
-
1
:
key
,
val
=
menu
.
strip
()
.
split
(
':'
)
key
=
key
.
strip
()
.
strip
(
'/'
)
val
=
re
.
sub
(
'[//-]'
,
' '
,
val
)
...
...
opensipkd/base/scripts/initializedb.py
View file @
89c9884
...
...
@@ -52,9 +52,7 @@ def get_file(filename):
return
open
(
fullpath
)
def
restore_csv
(
table
,
filename
,
get_file_func
=
get_file
,
db_session
=
None
):
if
not
db_session
:
db_session
=
DBSession
def
restore_csv
(
table
,
filename
,
get_file_func
=
get_file
,
db_session
=
DBSession
):
q
=
db_session
.
query
(
table
)
if
q
.
first
():
return
...
...
@@ -65,20 +63,36 @@ def restore_csv(table, filename, get_file_func=get_file, db_session=None):
is_first
=
True
fmap
=
dict
()
for
cf
in
reader
:
# print(cf)
# sys.exit()
if
is_first
:
is_first
=
False
for
fieldname
in
cf
.
keys
():
t
=
fieldname
.
split
(
'/'
)
if
not
fieldname
:
continue
try
:
t
=
fieldname
.
split
(
'/'
)
except
Exception
as
e
:
print
(
fieldname
,
cf
.
keys
())
raise
e
fname_orig
=
t
[
0
]
schema
=
"public"
if
t
[
1
:]:
foreign_table
,
foreign_field
=
t
[
1
]
.
split
(
'.'
)
foreign_table
=
Table
(
foreign_table
,
Base
.
metadata
,
autoload
=
True
)
t_array
=
t
[
1
]
.
split
(
'.'
)
if
len
(
t_array
)
==
2
:
foreign_table
=
t_array
[
0
]
foreign_field
=
t_array
[
1
]
else
:
schema
=
t_array
[
0
]
foreign_table
=
t_array
[
1
]
foreign_field
=
t_array
[
2
]
# foreign_table, foreign_field = t[1].split('.')
foreign_table
=
Table
(
foreign_table
,
Base
.
metadata
,
autoload
=
True
,
schema
=
schema
)
foreign_field
=
getattr
(
foreign_table
.
c
,
foreign_field
)
foreigns
[
fieldname
]
=
(
foreign_table
,
foreign_field
)
fmap
[
fieldname
]
=
fname_orig
is_first
=
False
row
=
table
()
for
fieldname
in
cf
:
...
...
@@ -122,7 +136,6 @@ def append_csv(table, filename, keys, get_file_func=get_file,
foreigns
=
dict
()
is_first
=
True
fmap
=
dict
()
print
(
f
,
reader
)
for
cf
in
reader
:
if
is_first
:
is_first
=
False
...
...
@@ -136,19 +149,19 @@ def append_csv(table, filename, keys, get_file_func=get_file,
raise
e
fname_orig
=
t
[
0
]
schema
=
"public"
schema
=
"public"
if
t
[
1
:]:
t_array
=
t
[
1
]
.
split
(
'.'
)
if
len
(
t_array
)
==
2
:
foreign_table
=
t_array
[
0
]
if
len
(
t_array
)
==
2
:
foreign_table
=
t_array
[
0
]
foreign_field
=
t_array
[
1
]
else
:
schema
=
t_array
[
0
]
foreign_table
=
t_array
[
1
]
schema
=
t_array
[
0
]
foreign_table
=
t_array
[
1
]
foreign_field
=
t_array
[
2
]
foreign_table
=
Table
(
foreign_table
,
Base
.
metadata
,
autoload
=
True
,
schema
=
schema
)
foreign_table
=
Table
(
foreign_table
,
Base
.
metadata
,
autoload
=
True
,
schema
=
schema
)
foreign_field
=
getattr
(
foreign_table
.
c
,
foreign_field
)
foreigns
[
fname
]
=
(
foreign_table
,
foreign_field
)
...
...
@@ -204,6 +217,7 @@ def append_csv(table, filename, keys, get_file_func=get_file,
transaction
.
commit
()
# diperlukan commit per record khususnya untuk yang internal link
def
ask_password
(
name
):
while
True
:
pass1
=
getpass
(
'Tulis password untuk {}: '
.
format
(
name
))
...
...
opensipkd/base/static/css/custom.css
View file @
89c9884
...
...
@@ -227,9 +227,6 @@ button {
border-color
:
#f39c12
}
//
from
application
implementation
table
.dataTable
tr
.selected
td
{
background-color
:
#9fafd1
...
...
@@ -277,7 +274,7 @@ div.dataTables_length label {
.ui-autocomplete-loading
{
padding-right
:
10px
;
background
:
url(
../img/loading.gif)
right
10px
center
no-repeat
!important
;
background
:
url(
"../img/loading.gif")
right
10px
center
no-repeat
!important
;
}
.ui-autocomplete
{
max-height
:
200px
;
...
...
opensipkd/base/static/icon/default.png
0 → 100644
View file @
89c9884
4.25 KB
opensipkd/base/views/base_views.py
View file @
89c9884
...
...
@@ -112,12 +112,13 @@ class BaseView(object):
self
.
add_schema
=
""
self
.
table
=
""
def
route_list
(
self
,
):
def
route_list
(
self
,
msg
=
None
,
error
=
""
):
return
HTTPFound
(
location
=
self
.
req
.
route_url
(
self
.
list_route
))
@staticmethod
def
form_validator
(
form
,
value
):
def
form_validator
(
self
,
form
,
value
):
pass
def
get_params
(
self
,
params
):
return
get_params
(
params
)
...
...
opensipkd/base/views/posisi.py
View file @
89c9884
...
...
@@ -77,6 +77,7 @@ class EditSchema(AddSchema):
missing
=
colander
.
drop
,
widget
=
widget
.
HiddenWidget
())
class
ViewPartner
(
BaseView
):
def
__init__
(
self
,
request
):
super
(
ViewPartner
,
self
)
.
__init__
(
request
)
...
...
@@ -165,12 +166,12 @@ class ViewPartner(BaseView):
}])
self
.
list_cols
=
[{
'title'
:
"ID"
,
'data'
:
"id"
},
{
'title'
:
"NIP"
,
'data'
:
"nik"
,
'width'
:
'100pt'
},
{
'title'
:
"Nama"
,
'data'
:
"nama"
},
{
'title'
:
"Nama"
,
'data'
:
"nama"
},
{
'title'
:
"Unit Kerja"
,
'data'
:
"departemen"
},
{
'title'
:
"Jabatan"
,
'data'
:
"jabatan"
},
{
'title'
:
"Jenis Jabatan"
,
'data'
:
"jenis"
},
{
'title'
:
"Mulai"
,
'data'
:
"mulai"
},
{
'title'
:
"Selesai"
,
'data'
:
"selesai"
},]
{
'title'
:
"Selesai"
,
'data'
:
"selesai"
},
]
self
.
list_buttons
=
'btn_view, btn_add, btn_edit, btn_delete, '
\
'btn_close'
self
.
form_params
=
dict
(
scripts
=
""
)
...
...
@@ -198,7 +199,6 @@ class ViewPartner(BaseView):
elif
not
value
[
'partner_id'
]:
err_partner
()
def
get_form
(
self
,
class_form
,
row
=
None
,
buttons
=
(
btn_save
,
btn_cancel
)):
schema
=
class_form
(
validator
=
self
.
form_validator
)
schema
=
schema
.
bind
(
request
=
self
.
req
)
...
...
@@ -215,7 +215,6 @@ class ViewPartner(BaseView):
PartnerDBSession
.
flush
()
return
row
def
save_request
(
self
,
values
,
row
=
None
):
request
=
self
.
req
if
'id'
in
request
.
matchdict
:
...
...
@@ -230,32 +229,27 @@ class ViewPartner(BaseView):
values
[
'selesai'
]
=
date_from_str
(
values
[
'selesai'
])
else
:
values
[
'selesai'
]
=
None
query_struktural
=
DBSession
.
query
(
Jabatan
.
jenis
)
.
\
query_struktural
=
DBSession
.
query
(
Jabatan
.
jenis
)
.
\
filter
(
Jabatan
.
id
==
values
[
'jabatan_id'
])
.
scalar
()
values
[
'struktural_id'
]
=
query_struktural
row
=
self
.
save
(
values
,
request
.
user
,
row
)
request
.
session
.
flash
(
'Posisi Partner sudah disimpan.'
)
def
route_list
(
self
,
):
return
HTTPFound
(
location
=
self
.
req
.
route_url
(
self
.
list_route
))
def
session_failed
(
self
,
session_name
):
r
=
dict
(
form
=
self
.
request
.
session
[
session_name
])
del
self
.
request
.
session
[
session_name
]
return
r
def
query_id
(
self
):
return
PartnerDBSession
.
query
(
PartnerDepartemen
)
.
filter_by
(
id
=
self
.
req
.
matchdict
[
'id'
])
def
id_not_found
(
self
):
msg
=
'Posisi Partner ID
%
s Tidak Ditemukan.'
%
self
.
req
.
matchdict
[
'id'
]
self
.
request
.
session
.
flash
(
msg
,
'error'
)
return
route_list
()
self
.
req
.
session
.
flash
(
msg
,
'error'
)
return
self
.
route_list
()
########
# List #
...
...
@@ -414,7 +408,6 @@ class ViewPartner(BaseView):
form
.
set_appstruct
(
self
.
get_values
(
row
,
values
))
return
dict
(
form
=
form
.
render
(
readonly
=
True
),
scripts
=
self
.
form_scripts
)
#########
# Add #
#########
...
...
@@ -430,7 +423,7 @@ class ViewPartner(BaseView):
try
:
controls
=
form
.
validate
(
controls
)
except
ValidationFailure
as
e
:
form
.
render
(
appstruct
=
e
.
cstruct
)
form
.
render
(
appstruct
=
e
.
cstruct
)
return
dict
(
form
=
form
.
render
(),
scripts
=
self
.
form_scripts
)
self
.
save_request
(
dict
(
controls
))
return
self
.
route_list
()
...
...
@@ -522,10 +515,10 @@ class ViewPartner(BaseView):
if
jb
:
values
[
'struktural_nm'
]
=
jb
.
nama
form
.
set_appstruct
(
self
.
get_values
(
row
,
values
))
return
dict
(
row
=
row
,
form
=
form
.
render
(
readonly
=
True
),
scripts
=
self
.
form_scripts
)
return
dict
(
row
=
row
,
form
=
form
.
render
(
readonly
=
True
),
scripts
=
self
.
form_scripts
)
def
get_values
(
self
,
row
,
values
=
None
):
if
not
values
:
values
=
row
.
to_dict
()
return
values
\ No newline at end of file
return
values
opensipkd/base/views/templates/base3.1.pt
View file @
89c9884
<!DOCTYPE html>
<html
lang=
"en-us"
tal:define=
"
tal:define=
"
home request.route_url('home')[:-1];
user_path ['user', 'user-add', 'user-edit', 'user-view', 'user-delete'];
group_path ['group', 'group-add', 'group-edit', 'group-view', 'group-delete'];
param_path ['parameter', 'parameter-add', 'parameter-edit', 'parameter-view',
'parameter-delete'];
dep_path ['departemen', 'departemen-add', 'departemen-edit',
'departemen-view', 'departemen-delete'];
partner_path ['partner', 'partner-add', 'partner-edit', 'partner-view',
'partner-delete'];
part_dep_path ['partner-departemen', 'partner-departemen-add',
'partner-departemen-edit', 'partner-departemen-view',
param_path ['parameter', 'parameter-add', 'parameter-edit', 'parameter-view', 'parameter-delete'];
dep_path ['departemen', 'departemen-add', 'departemen-edit', 'departemen-view', 'departemen-delete'];
partner_path ['partner', 'partner-add', 'partner-edit', 'partner-view', 'partner-delete'];
part_dep_path ['partner-departemen', 'partner-departemen-add', 'partner-departemen-edit', 'partner-departemen-view',
'partner-departemen-delete'];
jabatan_path ['jabatan', 'jabatan-add', 'jabatan-edit', 'jabatan-view',
'jabatan-delete'];
"
>
<head>
<!--<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">-->
<title>
${request.app_name} | ${request.company}
</title>
<meta
name=
"description"
content=
""
>
<meta
name=
"author"
content=
""
>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
>
<!-- GOOGLE FONT -->
<link
rel=
"stylesheet"
href=
"${home}/static/v3/css/gf_open_sans-400italic_700italic_300_400_700.css"
>
<!-- Basic Styles -->
<link
rel=
"stylesheet"
type=
"text/css"
media=
"screen"
href=
"${home}/static/v3/css/bootstrap.min.css"
>
<link
rel=
"stylesheet"
type=
"text/css"
media=
"screen"
href=
"${home}/static/v3/css/font-awesome.min.css"
>
<!-- SmartAdmin Styles : Caution! DO NOT change the order -->
<link
rel=
"stylesheet"
type=
"text/css"
media=
"screen"
href=
"${home}/static/v3/css/smartadmin-production-plugins.min.css"
>
<link
rel=
"stylesheet"
type=
"text/css"
media=
"screen"
href=
"${home}/static/v3/css/smartadmin-production.min.css"
>
<link
rel=
"stylesheet"
type=
"text/css"
media=
"screen"
href=
"${home}/static/v3/css/smartadmin-skins.min.css"
>
<!-- We recommend you use "your_style.css" to override SmartAdmin
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 -->
<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/typeahead.css"
rel=
"stylesheet"
>
<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>
<style
metal:define-slot=
"style"
>
.twitter-typeahead
{
font-size
:
12px
!important
;
margin-bottom
:
0
;
width
:
100%
;
height
:
26px
;
position
:
absolute
;
top
:
0
;
left
:
0
;
z-index
:
auto
;
}
<!--<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">-->
<title>
${request.app_name} | ${request.company}
</title>
<meta
name=
"description"
content=
""
>
<meta
name=
"author"
content=
""
>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
>
<!-- GOOGLE FONT -->
<link
rel=
"stylesheet"
href=
"${home}/static/v3/css/gf_open_sans-400italic_700italic_300_400_700.css"
>
<!-- Basic Styles -->
<link
rel=
"stylesheet"
type=
"text/css"
media=
"screen"
href=
"${home}/static/v3/css/bootstrap.min.css"
>
<link
rel=
"stylesheet"
type=
"text/css"
media=
"screen"
href=
"${home}/static/v3/css/font-awesome.min.css"
>
<!-- SmartAdmin Styles : Caution! DO NOT change the order -->
<link
rel=
"stylesheet"
type=
"text/css"
media=
"screen"
href=
"${home}/static/v3/css/smartadmin-production-plugins.min.css"
>
<link
rel=
"stylesheet"
type=
"text/css"
media=
"screen"
href=
"${home}/static/v3/css/smartadmin-production.min.css"
>
<link
rel=
"stylesheet"
type=
"text/css"
media=
"screen"
href=
"${home}/static/v3/css/smartadmin-skins.min.css"
>
<!-- We recommend you use "your_style.css" to override SmartAdmin
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 -->
<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/typeahead.css"
rel=
"stylesheet"
>
<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>
<style
metal:define-slot=
"style"
>
.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>
.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>
<body
class=
"fixed-header"
>
<div
id=
"loading"
style=
"display:none;"
>
<img
id=
"loading-image"
src=
"${home}/static/img/ajax-loader.gif"
alt=
"Loading..."
/>
<img
id=
"loading-image"
src=
"${home}/static/img/ajax-loader.gif"
alt=
"Loading..."
/>
</div>
<!-- #HEADER -->
<header
id=
"header"
>
<div
id=
"logo-group"
>
<!-- PLACE YOUR LOGO HERE -->
<h3
id=
"logo"
>
<a
href=
"${home}/"
><img
src=
"${home}/static/img/logo.png"
alt=
""
></a>
</h3>
<!-- END LOGO PLACEHOLDER -->
<div
id=
"logo-group"
>
</div>
<!-- PLACE YOUR LOGO HERE -->
<h3
id=
"logo"
>
<!-- #PROJECTS: projects dropdown -->
<div
class=
"project-context hidden-xs"
>
<span
class=
"title-page"
>
${request.title}
</span>
</div>
<!-- end projects dropdown -->
<a
href=
"${home}/"
><img
src=
"${home}/static/img/logo.png"
alt=
""
></a>
</h3>
<!-- END LOGO PLACEHOLDER -->
<!-- #TOGGLE LAYOUT BUTTONS -->
<!-- pulled right: nav area -->
<div
class=
"pull-right"
>
<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
tal:condition=
"request.user"
class=
"project-selector dropdown-toggle"
data-toggle=
"dropdown"
>
Pilih Module
<i
class=
"fa fa-angle-down"
></i></span>
<ul
tal:condition=
"request.user"
class=
"dropdown-menu"
>
<li
tal:repeat=
"menu request.menus"
>
<a
href=
"${home}/${menu}"
>
${request.menus[menu]}
</a>
</li>
</ul>
</div>
<!-- collapse menu button -->
<div
id=
"hide-menu"
class=
"btn-header pull-right"
>
<span>
<a
href=
"javascript:void(0);"
data-action=
"toggleMenu"
title=
"Collapse Menu"
><i
class=
"fa fa-reorder"
></i></a>
</span>
</div>
<!-- end collapse menu -->
<!-- fullscreen button -->
<div
id=
"fullscreen"
class=
"btn-header transparent pull-right"
>
<span>
<a
href=
"javascript:void(0);"
data-action=
"launchFullscreen"
title=
"Full Screen"
><i
class=
"fa fa-arrows-alt"
></i></a>
</span>
<!-- #PROJECTS: projects dropdown -->
<div
class=
"project-context hidden-xs"
>
<span
class=
"title-page"
>
${request.title}
</span>
</div>
<!-- end fullscreen button -->
<!-- User info -->
<ul
tal:condition=
"request.user"
class=
"header-dropdown-list hidden-xs"
>
<li>
<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>
<i
class=
"fa fa-angle-down"
></i>
</a>
<ul
class=
"dropdown-menu pull-right"
>
<li><a
style=
"text-transform:capitalize"
href=
"${request.route_url('logout')}"
>
Logout
</a></li>
<li><a
style=
"text-transform:capitalize"
href=
"${request.route_url('password')}"
>
Ubah password
</a></li>
<li
tal:condition=
"request.user.api_key"
><a
style=
"text-transform:capitalize"
href=
"${home}/recreate-api-key"
>
API Key
</a></li>
<li
tal:condition=
"'core' in request.modules and change_unit(request)"
>
<a
style=
"text-transform:capitalize"
href=
"${home}/departemen/chg"
>
Ubah
Organisasi
</a></li>
<!-- end projects dropdown -->
<!-- #TOGGLE LAYOUT BUTTONS -->
<!-- pulled right: nav area -->
<div
class=
"pull-right"
>
<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
tal:condition=
"request.user"
class=
"project-selector dropdown-toggle"
data-toggle=
"dropdown"
>
Pilih Module
<i
class=
"fa fa-angle-down"
></i></span>
<ul
tal:condition=
"request.user"
class=
"dropdown-menu"
>
<li
tal:repeat=
"menu request.menus"
>
<a
href=
"${home}/${menu}"
>
${request.menus[menu]}
</a>
</li>
</ul>
</div>
<!-- collapse menu button -->
<div
id=
"hide-menu"
class=
"btn-header pull-right"
>
<span>
<a
href=
"javascript:void(0);"
data-action=
"toggleMenu"
title=
"Collapse Menu"
><i
class=
"fa fa-reorder"
></i></a>
</span>
</div>
<!-- end collapse menu -->
<!-- fullscreen button -->
<div
id=
"fullscreen"
class=
"btn-header transparent pull-right"
>
<span>
<a
href=
"javascript:void(0);"
data-action=
"launchFullscreen"
title=
"Full Screen"
><i
class=
"fa fa-arrows-alt"
></i></a>
</span>
</div>
<!-- end fullscreen button -->
<!-- User info -->
<ul
tal:condition=
"request.user"
class=
"header-dropdown-list hidden-xs"
>
<li>
<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>
<i
class=
"fa fa-angle-down"
></i>
</a>
<ul
class=
"dropdown-menu pull-right"
>
<li><a
style=
"text-transform:capitalize"
href=
"${request.route_url('logout')}"
>
Logout
</a></li>
<li><a
style=
"text-transform:capitalize"
href=
"${request.route_url('password')}"
>
Ubah password
</a>
</li>
<li
tal:condition=
"request.user.api_key"
><a
style=
"text-transform:capitalize"
href=
"${home}/recreate-api-key"
>
API Key
</a></li>
<li
tal:condition=
"'core' in request.modules and change_unit(request)"
>
<a
style=
"text-transform:capitalize"
href=
"${home}/departemen/chg"
>
Ubah
Organisasi
</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<!-- end user info -->
<!-- end user info -->
</div>
<!-- end pulled right: nav area -->
</div>
<!-- end pulled right: nav area -->
</header>
<!-- END HEADER -->
...
...
@@ -168,70 +167,70 @@
<!-- Note: This width of the aside area can be adjusted through LESS variables -->
<aside
id=
"left-panel"
style=
"padding-bottom:67px"
>
<!-- NAVIGATION : This navigation is also responsive-->
<nav
style=
""
>
<!-- Modul Menu -->
<ul
metal:define-slot=
"navs"
></ul>
<!-- Admin Menu -->
<ul
tal:condition=
"has_permission(request, user_path)"
style=
"margin-top: 0; padding-top: 0;"
>
<li>
<a
href=
"#"
><i
class=
"fa fa-lg fa-fw fa-shield"
></i>
<span
class=
"menu-item-parent"
>
Admin
</span></a>
<ul>
<li
tal:condition=
"has_permission(request, ['user-view', 'user-edit'])"
tal:attributes=
"class request.matched_route.name in user_path and 'active'"
>
<a
href=
"${home}/user"
>
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'"
>
<a
href=
"${home}/group"
>
Group
</a>
</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')"
tal:attributes=
"class request.matched_route.name in ['upload-logo'] and 'active'"
>
<a
href=
"${home}/upload/logo"
>
Upload
Logo
</a></li>
<li
tal:condition=
"has_permission(request, 'parameter')"
tal:attributes=
"class request.matched_route.name in param_path and 'active'"
>
<a
href=
"${home}/parameter"
>
Parameter
</a></li>
<li
tal:condition=
"has_permission(request, 'departemen')"
tal:attributes=
"class request.matched_route.name in dep_path and 'active'"
>
<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')"
tal:attributes=
"class request.matched_route.name in partner_path and 'active'"
>
<a
href=
"${home}/partner"
>
Partner
</a></li>
<li
tal:condition=
"has_permission(request, 'partner-departemen')"
tal:attributes=
"class request.matched_route.name in part_dep_path and 'active'"
>
<a
href=
"${home}/partner/departemen"
>
Partner Departemen
</a></li>
<!-- <li tal:condition="has_permission(request, 'eselon')"-->
<!-- tal:attributes="class request.path == '/eselon' and 'active'">-->
<!-- <a href="${home}/eselon">Eselon</a></li>-->
<li
tal:condition=
"has_permission(request, 'jabatan')"
tal:attributes=
"class request.matched_route.name in jabatan_path and 'active'"
>
<a
href=
"${home}/jabatan"
>
Jabatan
</a></li>
<li
tal:condition=
"has_permission(request, 'log')"
tal:attributes=
"class request.matched_route.name in ['log'] and 'active'"
>
<a
href=
"${home}/log"
>
Log
</a></li>
<!-- NAVIGATION : This navigation is also responsive-->
<nav
style=
""
>
<!-- Modul Menu -->
<ul
metal:define-slot=
"navs"
></ul>
<!-- Admin Menu -->
<ul
tal:condition=
"has_permission(request, user_path)"
style=
"margin-top: 0; padding-top: 0;"
>
<li>
<a
href=
"#"
><i
class=
"fa fa-lg fa-fw fa-shield"
></i>
<span
class=
"menu-item-parent"
>
Admin
</span></a>
<ul>
<li
tal:condition=
"has_permission(request, ['user-view', 'user-edit'])"
tal:attributes=
"class request.matched_route.name in user_path and 'active'"
>
<a
href=
"${home}/user"
>
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'"
>
<a
href=
"${home}/group"
>
Group
</a>
</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')"
tal:attributes=
"class request.matched_route.name in ['upload-logo'] and 'active'"
>
<a
href=
"${home}/upload/logo"
>
Upload
Logo
</a></li>
<li
tal:condition=
"has_permission(request, 'parameter')"
tal:attributes=
"class request.matched_route.name in param_path and 'active'"
>
<a
href=
"${home}/parameter"
>
Parameter
</a></li>
<li
tal:condition=
"has_permission(request, 'departemen')"
tal:attributes=
"class request.matched_route.name in dep_path and 'active'"
>
<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')"
tal:attributes=
"class request.matched_route.name in partner_path and 'active'"
>
<a
href=
"${home}/partner"
>
Partner
</a></li>
<li
tal:condition=
"has_permission(request, 'partner-departemen')"
tal:attributes=
"class request.matched_route.name in part_dep_path and 'active'"
>
<a
href=
"${home}/partner/departemen"
>
Partner Departemen
</a></li>
<!-- <li tal:condition="has_permission(request, 'eselon')"-->
<!-- tal:attributes="class request.path == '/eselon' and 'active'">-->
<!-- <a href="${home}/eselon">Eselon</a></li>-->
<li
tal:condition=
"has_permission(request, 'jabatan')"
tal:attributes=
"class request.matched_route.name in jabatan_path and 'active'"
>
<a
href=
"${home}/jabatan"
>
Jabatan
</a></li>
<li
tal:condition=
"has_permission(request, 'log')"
tal:attributes=
"class request.matched_route.name in ['log'] and 'active'"
>
<a
href=
"${home}/log"
>
Log
</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
<span
class=
"minifyme"
data-action=
"minifyMenu"
>
</nav>
<span
class=
"minifyme"
data-action=
"minifyMenu"
>
<i
class=
"fa fa-arrow-circle-left hit"
></i>
</span>
<span
class=
"footer-side"
>
©
OpenSIPKD.com
<span
class=
"footer-side"
>
©
OpenSIPKD.com
<script>
document
.
write
(
new
Date
().
getFullYear
());
</script>
</span>
</aside>
...
...
@@ -241,16 +240,16 @@
<!-- JS -->
<script
src=
"${home}/static/v3/js/jquery-2.1.1.min.js"
></script>
<script>
if
(
!
window
.
jQuery
)
{
document
.
write
(
'<script src="${home}/static/v3/js/libs/jquery-2.1.1.min.js"><\/script>'
);
}
if
(
!
window
.
jQuery
)
{
document
.
write
(
'<script src="${home}/static/v3/js/libs/jquery-2.1.1.min.js"><\/script>'
);
}
</script>
<script
src=
"${home}/static/v3/js/jquery-ui-1.10.3.min.js"
></script>
<script>
if
(
!
window
.
jQuery
.
ui
)
{
document
.
write
(
'<script src="${home}/static/v3/js/libs/jquery-ui-1.10.3.min.js"><\/script>'
);
}
if
(
!
window
.
jQuery
.
ui
)
{
document
.
write
(
'<script src="${home}/static/v3/js/libs/jquery-ui-1.10.3.min.js"><\/script>'
);
}
</script>
...
...
@@ -293,63 +292,63 @@
<script
src=
"${home}/deform_static/scripts/file_upload.js"
></script>
<script>
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'
);
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
);
}
}
})
});
$
(
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'
);
if
((
s
[
1
]
||
''
).
length
<
prec
)
{
s
[
1
]
=
s
[
1
]
||
''
;
s
[
1
]
+=
new
Array
(
prec
-
s
[
1
].
length
+
1
).
join
(
'0'
);
}
return
s
.
join
(
dec
);
}
return
s
.
join
(
dec
);
}
</script>
<metal:js
define-slot=
"js_files"
></metal:js>
...
...
@@ -359,43 +358,43 @@
<!-- End isi Script-->
<!-- MAIN PANEL -->
<div
id=
"main"
role=
"main"
>
<!-- MAIN CONTENT -->
<div
id=
"content"
>
<!-- Error session flash -->
<div
tal:condition=
"request.session.peek_flash()"
>
<div
class=
"alert alert-success"
tal:repeat=
"message request.session.pop_flash()"
><i
class=
"fa fa-fw fa-lg fa-check-circle"
></i>
${message}
</div>
</div>
<div
tal:condition=
"request.session.peek_flash('error')"
>
<div
class=
"alert alert-danger"
tal:repeat=
"message request.session.pop_flash('error')"
><i
class=
"fa fa-fw fa-lg fa-times-circle"
></i>
${message}
</div>
</div>
<!-- Error session flash -->
<!-- MAIN CONTENT -->
<div
id=
"content"
>
<!-- Error session flash -->
<div
tal:condition=
"request.session.peek_flash()"
>
<div
class=
"alert alert-success"
tal:repeat=
"message request.session.pop_flash()"
><i
class=
"fa fa-fw fa-lg fa-check-circle"
></i>
${message}
</div>
</div>
<div
tal:condition=
"request.session.peek_flash('error')"
>
<div
class=
"alert alert-danger"
tal:repeat=
"message request.session.pop_flash('error')"
><i
class=
"fa fa-fw fa-lg fa-times-circle"
></i>
${message}
</div>
</div>
<!-- Error session flash -->
<!-- <div id="errors" name="errors"> -->
<div
class=
"alert alert-danger"
id=
"errors"
name=
"errors"
style=
"display:none;"
>
errors
</div>
<div
class=
"alert alert-success"
id=
"success"
name=
"success"
style=
"display:none;"
>
success
</div>
<!-- <div id="errors" name="errors"> -->
<!-- Global Alert -->
<div
tal:condition=
"request.session.peek_flash()"
>
<div
class=
"alert alert-success"
tal:repeat=
"message request.session.pop_flash()"
>
${message}
</div>
</div>
<div
tal:condition=
"request.session.peek_flash('error')"
>
<div
class=
"alert alert-danger"
tal:repeat=
"message request.session.pop_flash('error')"
>
${message}
</div>
</div>
<!-- End Global Alert -->
<!-- SLOT KONTEN -->
<div
metal:define-slot=
"content"
></div>
<!-- END SLOT KONTEN -->
<!-- <div id="errors" name="errors"> -->
<div
class=
"alert alert-danger"
id=
"errors"
name=
"errors"
style=
"display:none;"
>
errors
</div>
<div
class=
"alert alert-success"
id=
"success"
name=
"success"
style=
"display:none;"
>
success
</div>
<!-- <div id="errors" name="errors"> -->
<!-- Global Alert -->
<div
tal:condition=
"request.session.peek_flash()"
>
<div
class=
"alert alert-success"
tal:repeat=
"message request.session.pop_flash()"
>
${message}
</div>
</div>
<div
tal:condition=
"request.session.peek_flash('error')"
>
<div
class=
"alert alert-danger"
tal:repeat=
"message request.session.pop_flash('error')"
>
${message}
</div>
</div>
<!-- End Global Alert -->
<!-- SLOT KONTEN -->
<div
metal:define-slot=
"content"
></div>
<!-- END SLOT KONTEN -->
</div>
<!-- END MAIN CONTENT -->
<!-- END MAIN CONTENT -->
</div>
<!-- END MAIN PANEL -->
</body>
...
...
opensipkd/base/views/templates/home.pt
View file @
89c9884
...
...
@@ -37,18 +37,6 @@
<div
id=
"content"
class=
"container"
>
<div
class=
"row"
>
<div
class=
"col-sm-10 col-sm-offset-1"
>
<!--div class="col-sm-4 padding-thin">
<div class="box about">
<a href="#" data-toggle="modal"
data-target="#about-us"
style="color:#fff; text-decoration:none;">
<i class="fa fa-info-circle"></i>
<span class="about-text">Powered by</span>
<img id="" src="${home}static/img/opensipkd.png"
alt="">
</a>
</div>
</div-->
<div
class=
"col-sm-12 padding-thin"
>
<div
class=
"box appname"
>
<div
class=
"col-sm-3 padding-medium"
align=
"center"
>
...
...
@@ -64,10 +52,17 @@
</div>
<div
class=
"col-sm-12 no-padding"
align=
"center"
>
<div
tal:repeat=
"modul modules"
class=
"col-sm-3 col-xs-6 module padding-thin"
>
<a
href=
"${home}${modul}"
icon=
"${modul.replace('/','_')}"
class=
"box"
>
<a
tal:condition=
"modul.find('://')<0"
href=
"${home}${modul}"
icon=
"${modul.replace('/','_')}"
class=
"box"
>
<img
alt=
""
class=
"icon-modul"
src=
"${home}static/icon/${modul.replace('/','_')}.png"
>
<span>
${modules[modul]}
</span>
</a>
<a
tal:condition=
"modul.find('://')>-1"
target=
"_blank"
href=
"${modul}"
class=
"box"
>
<img
alt=
""
class=
"icon-modul"
src=
"${home}static/icon/${modul.replace('://','').replace('https','').replace('http','')}.png"
>
<span>
${modules[modul]}
</span>
</a>
</div>
</div>
...
...
opensipkd/base/views/templates/upload.pt
View file @
89c9884
<html
metal:use-macro=
"load: main.pt"
>
<!-- content -->
<div
metal:fill-slot=
"content"
>
<!-- content -->
<div
metal:fill-slot=
"content"
>
<div
class=
"row"
>
<div
class=
"row"
>
<div
class=
"panel panel-default"
>
<div
class=
"panel panel-default"
>
<div
class=
"panel-body"
>
<div
class=
"col-md-10 col-md-offset-1"
>
<blockquote>
<p>
Untuk Background, beri nama background pada file
<br>
Untuk Logo beri nama logo pada file
</p>
</blockquote>
<div
tal:content=
"structure form"
/>
</div>
</div>
<div
class=
"panel-body"
>
<div
class=
"col-md-10 col-md-offset-1"
>
<blockquote>
<p>
Untuk Background, beri nama background pada file
<br>
Untuk Logo beri nama logo pada file
</p>
</blockquote>
<div
tal:content=
"structure form"
/>
</div>
</div>
</div>
</div>
<!-- end content -->
</div>
<!-- end content -->
</html>
\ No newline at end of file
opensipkd/base/views/upload.py
View file @
89c9884
...
...
@@ -51,11 +51,15 @@ class AddSchema(colander.Schema):
FileData
(),
widget
=
widget
.
FileUploadWidget
(
tmpstore
),
title
=
'Unggah'
)
typ
=
colander
.
SchemaNode
(
colander
.
String
(),
widget
=
widget
.
SelectWidget
(
values
=
((
'img'
,
"Image"
),
(
'icon'
,
"Icon"
))),
title
=
'Jenis'
)
def
get_form
(
schema_cls
):
schema
=
schema_cls
()
return
Form
(
schema
,
buttons
=
(
'simpan'
,
'batal
kan
'
))
return
Form
(
schema
,
buttons
=
(
'simpan'
,
'batal'
))
@view_config
(
route_name
=
'upload-logo'
,
...
...
@@ -65,7 +69,6 @@ def view_file(request):
form
=
get_form
(
AddSchema
)
if
request
.
POST
:
if
'simpan'
in
request
.
POST
:
settings
=
get_settings
()
input_file
=
request
.
POST
[
'upload'
]
.
file
filename
=
request
.
POST
[
'upload'
]
.
filename
.
lower
()
ext
=
get_ext
(
filename
)
.
lower
()
...
...
@@ -81,8 +84,13 @@ def view_file(request):
elif
filename
.
startswith
(
'background'
):
fname
=
f
"background{ext}"
else
:
fname
=
filename
fullpath
=
os
.
path
.
join
(
static_path
,
'img/'
+
fname
)
fname
=
filename
folder
=
os
.
path
.
join
(
static_path
,
request
.
POST
[
'typ'
])
if
not
os
.
path
.
exists
(
folder
):
os
.
makedirs
(
folder
)
fullpath
=
os
.
path
.
join
(
folder
,
fname
)
output_file
=
open
(
fullpath
,
'wb'
)
input_file
.
seek
(
0
)
while
True
:
...
...
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