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 89ac5da4
authored
Aug 06, 2022
by
aagusti
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
perbaikan register
1 parent
a8e83cf0
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
143 additions
and
98 deletions
opensipkd/base/views/register.py
opensipkd/models/users.py
opensipkd/base/views/register.py
View file @
89ac5da
...
@@ -30,6 +30,8 @@ import os
...
@@ -30,6 +30,8 @@ import os
import
colander
import
colander
from
deform
import
(
widget
,
Button
,
FileData
)
from
deform
import
(
widget
,
Button
,
FileData
)
from
pyramid.threadlocal
import
get_current_registry
from
opensipkd.tools
import
Upload
,
mem_tmp_store
,
image_validator
from
opensipkd.tools
import
Upload
,
mem_tmp_store
,
image_validator
from
pyramid.httpexceptions
import
HTTPFound
from
pyramid.httpexceptions
import
HTTPFound
from
pyramid.i18n
import
TranslationStringFactory
from
pyramid.i18n
import
TranslationStringFactory
...
@@ -37,8 +39,10 @@ from pyramid.security import forget
...
@@ -37,8 +39,10 @@ from pyramid.security import forget
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
opensipkd.base
import
get_params
from
opensipkd.base
import
get_params
,
partner_idcard_folder
from
opensipkd.base.views.user
import
email_validator
,
add_member_count
from
opensipkd.base.views.user
import
email_validator
,
add_member_count
from
opensipkd.tools.buttons
import
btn_cancel
,
btn_register
,
btn_save
from
.
import
widget_os
from
.
import
widget_os
from
.base_views
import
need_captcha
,
need_verify
,
get_url_captcha
from
.base_views
import
need_captcha
,
need_verify
,
get_url_captcha
from
.user_login
import
regenerate_security_code
,
get_login_headers
,
\
from
.user_login
import
regenerate_security_code
,
get_login_headers
,
\
...
@@ -79,7 +83,9 @@ class AddSchema(colander.Schema):
...
@@ -79,7 +83,9 @@ class AddSchema(colander.Schema):
def
after_bind
(
self
,
schema
,
kw
):
def
after_bind
(
self
,
schema
,
kw
):
request
=
kw
.
get
(
"request"
)
request
=
kw
.
get
(
"request"
)
is_id_card
=
get_params
(
'reg_idcard'
)
is_id_card
=
get_params
(
'reg_idcard'
)
if
"id_info"
in
request
.
session
:
user
=
request
.
user
external_user
=
user
and
user
.
external_identities
.
count
()
>
0
or
False
if
"id_info"
in
request
.
session
or
external_user
:
self
[
"email"
]
.
widget
=
widget
.
TextInputWidget
(
readonly
=
True
)
self
[
"email"
]
.
widget
=
widget
.
TextInputWidget
(
readonly
=
True
)
self
[
"email"
]
.
missing
=
colander
.
drop
self
[
"email"
]
.
missing
=
colander
.
drop
...
@@ -95,13 +101,15 @@ class AddSchema(colander.Schema):
...
@@ -95,13 +101,15 @@ class AddSchema(colander.Schema):
widget
=
widget
.
FileUploadWidget
(
mem_tmp_store
),
widget
=
widget
.
FileUploadWidget
(
mem_tmp_store
),
title
=
_
(
"ID Card"
),
title
=
_
(
"ID Card"
),
validator
=
image_validator
)
validator
=
image_validator
)
if
not
request
.
user
and
need_captcha
():
if
not
request
.
user
and
need_captcha
():
self
[
"captcha"
]
=
colander
.
SchemaNode
(
self
[
"captcha"
]
=
colander
.
SchemaNode
(
colander
.
String
(),
colander
.
String
(),
widget
=
widget_os
.
CaptchaWidget
(),
widget
=
widget_os
.
CaptchaWidget
(),
oid
=
"captcha"
,
title
=
_
(
"Captcha"
))
oid
=
"captcha"
,
title
=
_
(
"Captcha"
))
if
request
.
user
and
request
.
user
.
id
:
if
request
.
user
and
request
.
user
.
id
and
not
external_user
:
# todo: external user tidak ada password
# validasi harusnya menggunakan authentikasi ke provider lagi
self
[
"password"
]
=
colander
.
SchemaNode
(
self
[
"password"
]
=
colander
.
SchemaNode
(
colander
.
String
(),
colander
.
String
(),
widget
=
widget
.
PasswordWidget
(),
widget
=
widget
.
PasswordWidget
(),
...
@@ -110,7 +118,9 @@ class AddSchema(colander.Schema):
...
@@ -110,7 +118,9 @@ class AddSchema(colander.Schema):
class
EditSchema
(
AddSchema
):
class
EditSchema
(
AddSchema
):
pass
def
after_bind
(
self
,
schema
,
kw
):
super
()
.
after_bind
(
schema
,
kw
)
del
self
[
"email"
]
def
user_found
(
identity
):
def
user_found
(
identity
):
...
@@ -138,18 +148,18 @@ def show_error(request, msg):
...
@@ -138,18 +148,18 @@ def show_error(request, msg):
return
HTTPFound
(
location
=
request
.
route_url
(
'home'
))
return
HTTPFound
(
location
=
request
.
route_url
(
'home'
))
def
reg_buttons
():
#
def reg_buttons():
btn_register
=
Button
(
name
=
'save'
,
css_class
=
'btn-success'
,
type
=
"submit"
,
#
btn_register = Button(name='save', css_class='btn-success', type="submit",
title
=
"Register"
)
#
title="Register")
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
Registrasi
(
BaseView
):
class
Registrasi
(
BaseView
):
def
__init__
(
self
,
request
):
def
__init__
(
self
,
request
):
super
(
Registrasi
,
self
)
.
__init__
(
request
)
super
(
Registrasi
,
self
)
.
__init__
(
request
)
self
.
autocomplete
=
"off"
self
.
autocomplete
=
"off"
self
.
buttons
=
reg_buttons
(
)
self
.
buttons
=
(
btn_register
,
btn_cancel
)
self
.
add_schema
=
AddSchema
self
.
add_schema
=
AddSchema
self
.
edit_schema
=
EditSchema
self
.
edit_schema
=
EditSchema
self
.
table
=
User
self
.
table
=
User
...
@@ -211,11 +221,13 @@ class Registrasi(BaseView):
...
@@ -211,11 +221,13 @@ class Registrasi(BaseView):
ses_captcha
=
request
.
session
.
pop
(
'captcha'
)
ses_captcha
=
request
.
session
.
pop
(
'captcha'
)
if
captcha
!=
ses_captcha
:
if
captcha
!=
ses_captcha
:
err_captcha
()
err_captcha
()
is_logged
=
form
.
request
.
user
is_logged
=
form
.
request
.
user
if
not
"email"
in
value
and
"id_info"
in
session
:
if
not
"email"
in
value
and
"id_info"
in
session
:
value
[
"email"
]
=
session
[
"id_info"
][
"email"
]
value
[
"email"
]
=
session
[
"id_info"
][
"email"
]
if
"user_name"
not
in
value
or
not
value
[
"user_name"
]:
if
not
request
.
user
and
(
"user_name"
not
in
value
or
not
value
[
"user_name"
]):
value
[
"user_name"
]
=
value
[
"email"
]
value
[
"user_name"
]
=
value
[
"email"
]
if
'user_name'
in
value
:
if
'user_name'
in
value
:
...
@@ -228,15 +240,6 @@ class Registrasi(BaseView):
...
@@ -228,15 +240,6 @@ class Registrasi(BaseView):
if
user
.
id
!=
is_logged
.
id
:
if
user
.
id
!=
is_logged
.
id
:
err_user
()
err_user
()
email
=
value
[
"email"
]
user
=
user_found
(
email
)
if
user
and
not
is_logged
:
err_email
()
if
user
and
is_logged
:
if
user
.
id
!=
is_logged
.
id
:
err_email
()
# Check Data Partner
# Check Data Partner
if
request
.
user
:
if
request
.
user
:
q
=
DBSession
.
query
(
Partner
)
.
filter_by
(
email
=
request
.
user
.
email
)
q
=
DBSession
.
query
(
Partner
)
.
filter_by
(
email
=
request
.
user
.
email
)
...
@@ -244,12 +247,22 @@ class Registrasi(BaseView):
...
@@ -244,12 +247,22 @@ class Registrasi(BaseView):
else
:
else
:
partner
=
None
partner
=
None
found
=
email_found_partner
(
email
)
if
not
request
.
user
:
if
partner
:
email
=
value
[
"email"
]
if
found
and
found
.
id
!=
partner
.
id
:
user
=
user_found
(
email
)
if
user
and
not
is_logged
:
err_email
()
if
user
and
is_logged
:
if
user
.
id
!=
is_logged
.
id
:
err_email
()
found
=
email_found_partner
(
email
)
if
partner
:
if
found
and
found
.
id
!=
partner
.
id
:
err_email
()
elif
found
:
err_email
()
err_email
()
elif
found
:
err_email
()
if
"kode"
not
in
value
or
not
value
[
"kode"
]:
if
"kode"
not
in
value
or
not
value
[
"kode"
]:
value
[
"kode"
]
=
value
[
"mobile"
]
value
[
"kode"
]
=
value
[
"mobile"
]
...
@@ -278,7 +291,77 @@ class Registrasi(BaseView):
...
@@ -278,7 +291,77 @@ class Registrasi(BaseView):
result
.
update
(
dict
(
captcha
=
get_url_captcha
(
self
.
req
)))
result
.
update
(
dict
(
captcha
=
get_url_captcha
(
self
.
req
)))
return
result
return
result
def
after_save
(
self
,
row
,
values
):
# def after_save(self, row, values):
def
cancel_act
(
self
):
forget
(
self
.
req
)
self
.
ses
.
delete
()
@view_config
(
route_name
=
'register'
,
renderer
=
'templates/form.pt'
)
def
view_register
(
self
):
if
"g_state"
in
self
.
req
.
cookies
:
if
"id_info"
not
in
self
.
ses
or
not
self
.
ses
[
"id_info"
]:
return
HTTPFound
(
location
=
self
.
req
.
route_url
(
"login"
))
request
=
self
.
req
reg_form
=
get_params
(
"reg_form"
)
if
reg_form
:
return
HTTPFound
(
location
=
self
.
req
.
route_url
(
reg_form
))
self
.
bindings
=
dict
(
user
=
None
)
if
request
.
user
:
return
HTTPFound
(
location
=
request
.
route_url
(
"profile"
))
return
super
(
Registrasi
,
self
)
.
view_add
()
def
query_id
(
self
):
return
DBSession
.
query
(
User
)
.
\
filter
(
User
.
id
==
self
.
req
.
user
.
id
)
def
id_not_found
(
self
):
return
def
get_values
(
self
,
row
,
istime
=
False
):
d
=
super
()
.
get_values
(
row
,
istime
)
partner
=
DBSession
.
query
(
Partner
)
.
\
join
(
User
,
Partner
.
email
==
User
.
email
)
.
\
filter
(
User
.
id
==
self
.
req
.
user
.
id
)
.
first
()
if
partner
:
fields
=
[
"nama"
,
"alamat_1"
,
"alamat_2"
,
"mobile"
,
"email"
,
"kode"
,
"idcard"
]
for
f
in
fields
:
d
[
f
]
=
hasattr
(
partner
,
f
)
and
getattr
(
partner
,
f
)
or
""
if
"idcard"
in
d
and
d
[
"idcard"
]:
filename
=
d
[
"idcard"
]
preview_url
=
"/"
.
join
(
[
self
.
home
,
partner_idcard_folder
,
filename
])
d
[
"idcard"
]
=
{
"uid"
:
filename
.
split
(
"."
)[
0
],
"filename"
:
filename
,
"preview_url"
:
preview_url
}
return
d
@view_config
(
route_name
=
'profile'
,
renderer
=
'templates/form.pt'
,
permission
=
'view'
)
def
view_profile
(
self
):
self
.
buttons
=
(
btn_save
,
btn_cancel
)
reg_form
=
get_params
(
"reg_form"
)
if
reg_form
:
return
HTTPFound
(
location
=
self
.
req
.
route_url
(
reg_form
))
self
.
bindings
=
dict
(
user
=
self
.
req
.
user
)
return
super
(
Registrasi
,
self
)
.
view_edit
()
def
save_request
(
self
,
values
,
row
=
None
):
if
"idcard"
in
values
and
values
[
"idcard"
]:
if
self
.
req
.
POST
[
'upload'
]
!=
b
''
:
path
=
get_params
(
'idcard_folder'
,
'/tmp/idcard'
)
upload
=
Upload
(
path
)
values
[
"idcard"
]
=
upload
.
save
(
self
.
req
,
'upload'
)
else
:
values
.
pop
(
"idcard"
)
row
=
super
()
.
save_request
(
values
,
row
)
if
not
self
.
req
.
user
:
# User Baru
if
not
self
.
req
.
user
:
# User Baru
if
'groups'
in
values
and
values
[
'groups'
]:
if
'groups'
in
values
and
values
[
'groups'
]:
gr
=
Group
.
query_group_name
(
values
[
'groups'
])
.
first
()
gr
=
Group
.
query_group_name
(
values
[
'groups'
])
.
first
()
...
@@ -326,6 +409,7 @@ class Registrasi(BaseView):
...
@@ -326,6 +409,7 @@ class Registrasi(BaseView):
default
=
'${email} berhasil ditambahkan '
,
default
=
'${email} berhasil ditambahkan '
,
mapping
=
data
)
mapping
=
data
)
else
:
# Kirim email validasi
else
:
# Kirim email validasi
# todo validasi dan perubahan profile
remain
=
regenerate_security_code
(
row
)
remain
=
regenerate_security_code
(
row
)
send_email_security_code
(
send_email_security_code
(
self
.
req
,
row
,
remain
,
'Welcome new user'
,
'email-new-user'
,
self
.
req
,
row
,
remain
,
'Welcome new user'
,
'email-new-user'
,
...
@@ -349,65 +433,8 @@ class Registrasi(BaseView):
...
@@ -349,65 +433,8 @@ class Registrasi(BaseView):
partner
.
is_vendor
=
0
partner
.
is_vendor
=
0
partner
.
is_customer
=
1
partner
.
is_customer
=
1
partner
.
status
=
0
partner
.
status
=
0
partner
.
from_dict
(
values
)
partner
.
from_dict
(
values
)
DBSession
.
add
(
partner
)
DBSession
.
add
(
partner
)
DBSession
.
flush
()
DBSession
.
flush
()
return
row
self
.
req
.
session
.
flash
(
"Sukses update profile"
)
def
cancel_act
(
self
):
forget
(
self
.
req
)
self
.
ses
.
delete
()
@view_config
(
route_name
=
'register'
,
renderer
=
'templates/form.pt'
)
def
view_register
(
self
):
if
"g_state"
in
self
.
req
.
cookies
:
if
"id_info"
not
in
self
.
ses
or
not
self
.
ses
[
"id_info"
]:
return
HTTPFound
(
location
=
self
.
req
.
route_url
(
"login"
))
request
=
self
.
req
reg_form
=
get_params
(
"reg_form"
)
if
reg_form
:
return
HTTPFound
(
location
=
self
.
req
.
route_url
(
reg_form
))
self
.
bindings
=
dict
(
user
=
None
)
if
request
.
user
:
return
HTTPFound
(
location
=
request
.
route_url
(
"profile"
))
return
super
(
Registrasi
,
self
)
.
view_add
()
def
query_id
(
self
):
return
DBSession
.
query
(
User
)
.
\
filter
(
User
.
id
==
self
.
req
.
user
.
id
)
def
id_not_found
(
self
):
return
def
before_edit
(
self
,
form
):
partner
=
DBSession
.
query
(
Partner
)
.
\
join
(
User
,
Partner
.
email
==
User
.
email
)
.
\
filter
(
User
.
id
==
self
.
req
.
user
.
id
)
.
first
()
if
partner
:
values
=
{}
for
f
in
[
"nama"
,
"alamat_1"
,
"alamat_2"
,
"mobile"
,
"email"
]:
values
[
f
]
=
hasattr
(
partner
,
f
)
and
getattr
(
partner
,
f
)
or
""
form
.
set_appstruct
(
values
)
return
form
@view_config
(
route_name
=
'profile'
,
renderer
=
'templates/form.pt'
,
permission
=
'view'
)
def
view_profile
(
self
):
reg_form
=
get_params
(
"reg_form"
)
if
reg_form
:
return
HTTPFound
(
location
=
self
.
req
.
route_url
(
reg_form
))
self
.
bindings
=
dict
(
user
=
self
.
req
.
user
)
return
super
(
Registrasi
,
self
)
.
view_edit
()
def
save_request
(
self
,
values
,
row
=
None
):
if
"idcard"
in
values
and
values
[
"idcard"
]:
path
=
get_params
(
'idcard_folder'
,
'/tmp/idcard'
)
upload
=
Upload
(
path
)
values
[
"idcard"
]
=
upload
.
save
(
self
.
req
,
'upload'
)
row
=
super
()
.
save_request
(
values
,
row
)
self
.
after_save
(
row
,
values
)
return
row
return
row
opensipkd/models/users.py
View file @
89ac5da
from
datetime
import
datetime
from
datetime
import
datetime
import
pytz
import
pytz
from
ziggurat_foundations
import
ziggurat_model_init
import
sqlalchemy
as
sa
import
sqlalchemy
as
sa
from
pyramid.authorization
import
(
Allow
,
Authenticated
,
ALL_PERMISSIONS
)
from
pyramid.authorization
import
(
Allow
,
Authenticated
,
ALL_PERMISSIONS
)
from
sqlalchemy
import
(
from
sqlalchemy
import
(
Column
,
Integer
,
DateTime
,
ForeignKey
,
String
)
Column
,
Integer
,
DateTime
,
String
)
from
sqlalchemy.orm
import
(
relationship
,
backref
)
from
sqlalchemy.orm
import
(
relationship
,
backref
)
from
ziggurat_foundations
import
ziggurat_model_init
from
ziggurat_foundations.models.base
import
BaseModel
from
ziggurat_foundations.models.base
import
BaseModel
from
ziggurat_foundations.models.external_identity
import
ExternalIdentityMixin
from
ziggurat_foundations.models.external_identity
import
ExternalIdentityMixin
from
ziggurat_foundations.models.group
import
GroupMixin
from
ziggurat_foundations.models.group
import
GroupMixin
from
ziggurat_foundations.models.group_permission
import
GroupPermissionMixin
from
ziggurat_foundations.models.group_permission
import
GroupPermissionMixin
from
ziggurat_foundations.models.group_resource_permission
import
GroupResourcePermissionMixin
from
ziggurat_foundations.models.group_resource_permission
import
\
GroupResourcePermissionMixin
from
ziggurat_foundations.models.resource
import
ResourceMixin
from
ziggurat_foundations.models.resource
import
ResourceMixin
from
ziggurat_foundations.models.services.user
import
UserService
from
ziggurat_foundations.models.services.user
import
UserService
from
ziggurat_foundations.models.user
import
UserMixin
from
ziggurat_foundations.models.user
import
UserMixin
from
ziggurat_foundations.models.user_group
import
UserGroupMixin
from
ziggurat_foundations.models.user_group
import
UserGroupMixin
from
ziggurat_foundations.models.user_permission
import
UserPermissionMixin
from
ziggurat_foundations.models.user_permission
import
UserPermissionMixin
from
ziggurat_foundations.models.user_resource_permission
import
UserResourcePermissionMixin
from
ziggurat_foundations.models.user_resource_permission
import
\
from
ziggurat_foundations.models.services.external_identity
import
ExternalIdentityService
UserResourcePermissionMixin
from
opensipkd.tools
import
as_timezone
,
get_timezone
from
opensipkd.tools
import
as_timezone
from
.base
import
CommonModel
,
DBSession
,
DefaultModel
from
.base
import
CommonModel
,
DBSession
,
DefaultModel
from
.meta
import
Base
from
.meta
import
Base
# from .partner import Partner
class
GroupPermission
(
GroupPermissionMixin
,
Base
):
class
GroupPermission
(
GroupPermissionMixin
,
Base
):
...
@@ -74,13 +73,16 @@ class User(UserMixin, BaseModel, CommonModel, Base):
...
@@ -74,13 +73,16 @@ class User(UserMixin, BaseModel, CommonModel, Base):
nullable
=
False
,
nullable
=
False
,
default
=
datetime
.
utcnow
)
default
=
datetime
.
utcnow
)
security_code_date
=
Column
(
DateTime
(
timezone
=
True
),
security_code_date
=
Column
(
DateTime
(
timezone
=
True
),
default
=
datetime
(
2000
,
1
,
1
,
tzinfo
=
pytz
.
timezone
(
'Asia/Jakarta'
)),
default
=
datetime
(
2000
,
1
,
1
,
tzinfo
=
pytz
.
timezone
(
'Asia/Jakarta'
)),
server_default
=
"2000-01-01 01:01+7"
,
server_default
=
"2000-01-01 01:01+7"
,
)
)
api_key
=
Column
(
String
(
256
))
api_key
=
Column
(
String
(
256
))
partner_id
=
Column
(
Integer
)
#, ForeignKey(Partner.id))
partner_id
=
Column
(
Integer
)
# , ForeignKey(Partner.id))
company_id
=
Column
(
Integer
)
#, ForeignKey(Partner.id))
company_id
=
Column
(
Integer
)
# , ForeignKey(Partner.id))
#partners = relationship(Partner, backref=backref('users'))
# partners = relationship(Partner, backref=backref('users'))
def
_get_password
(
self
):
def
_get_password
(
self
):
return
self
.
_password
return
self
.
_password
...
@@ -127,6 +129,7 @@ class User(UserMixin, BaseModel, CommonModel, Base):
...
@@ -127,6 +129,7 @@ class User(UserMixin, BaseModel, CommonModel, Base):
def
get_by_token
(
cls
,
token
):
def
get_by_token
(
cls
,
token
):
return
DBSession
.
query
(
cls
)
.
filter_by
(
security_code
=
token
)
return
DBSession
.
query
(
cls
)
.
filter_by
(
security_code
=
token
)
# @classmethod
# @classmethod
# def get_departemen_id(cls, user_id):
# def get_departemen_id(cls, user_id):
# partner = Partner.query_user_id(user_id).first()
# partner = Partner.query_user_id(user_id).first()
...
@@ -160,6 +163,19 @@ class User(UserMixin, BaseModel, CommonModel, Base):
...
@@ -160,6 +163,19 @@ class User(UserMixin, BaseModel, CommonModel, Base):
class
ExternalIdentity
(
ExternalIdentityMixin
,
CommonModel
,
Base
):
class
ExternalIdentity
(
ExternalIdentityMixin
,
CommonModel
,
Base
):
user
=
relationship
(
User
,
backref
=
backref
(
"external"
))
user
=
relationship
(
User
,
backref
=
backref
(
"external"
))
@classmethod
def
query
(
cls
):
return
DBSession
.
query
(
cls
)
@classmethod
def
query_user
(
cls
,
user
):
return
cls
.
query
()
.
filter_by
(
local_user_id
=
user
.
id
)
@classmethod
def
external
(
cls
,
user
):
return
cls
.
query_user
(
user
)
.
count
()
>
0
# class GroupRoutePermission(Base, CommonModel):
# class GroupRoutePermission(Base, CommonModel):
# __tablename__ = 'groups_routes_permissions'
# __tablename__ = 'groups_routes_permissions'
...
@@ -194,7 +210,9 @@ class RootFactory:
...
@@ -194,7 +210,9 @@ class RootFactory:
acl_name
=
'group:{}'
.
format
(
gp
.
group_id
)
acl_name
=
'group:{}'
.
format
(
gp
.
group_id
)
self
.
__acl__
.
append
((
Allow
,
acl_name
,
gp
.
perm_name
))
self
.
__acl__
.
append
((
Allow
,
acl_name
,
gp
.
perm_name
))
def
init_model
():
def
init_model
():
ziggurat_model_init
(
User
,
Group
,
UserGroup
,
GroupPermission
,
UserPermission
,
ziggurat_model_init
(
User
,
Group
,
UserGroup
,
GroupPermission
,
UserPermission
,
UserResourcePermission
,
GroupResourcePermission
,
Resource
,
UserResourcePermission
,
GroupResourcePermission
,
Resource
,
ExternalIdentity
,
passwordmanager
=
None
)
ExternalIdentity
,
passwordmanager
=
None
)
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