Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
Owo Sugiana
/
web-starter
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit 20f4869a
authored
Jan 27, 2021
by
Owo Sugiana
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Bug fixed manifest
1 parent
1001ca9c
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
59 additions
and
28 deletions
MANIFEST.in
alembic/env.py
alembic/versions/074b33635316_alter_users_date_fields_with_time_zone.py
setup.py
web_starter/models/ziggurat.py
web_starter/scripts/initialize_db.py
web_starter/tools/waktu.py
web_starter/views/group.py
web_starter/views/login.py
web_starter/views/user.py
MANIFEST.in
View file @
20f4869
include *.txt *.ini *.cfg *.rst
include *.txt *.ini *.cfg *.rst
recursive-include web_starter *.
ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.jinja2
recursive-include web_starter *.
csv *.png *.css *.pt *.mako *.pot *.mo *.po
alembic/env.py
View file @
20f4869
...
@@ -64,6 +64,7 @@ def run_migrations_online():
...
@@ -64,6 +64,7 @@ def run_migrations_online():
with
context
.
begin_transaction
():
with
context
.
begin_transaction
():
context
.
run_migrations
()
context
.
run_migrations
()
if
context
.
is_offline_mode
():
if
context
.
is_offline_mode
():
run_migrations_offline
()
run_migrations_offline
()
else
:
else
:
...
...
alembic/versions/074b33635316_alter_users_date_fields_with_time_zone.py
View file @
20f4869
...
@@ -17,13 +17,16 @@ depends_on = None
...
@@ -17,13 +17,16 @@ depends_on = None
def
upgrade
():
def
upgrade
():
op
.
alter_column
(
'users'
,
'last_login_date'
,
op
.
alter_column
(
'users'
,
'last_login_date'
,
type_
=
sa
.
DateTime
(
timezone
=
True
),
type_
=
sa
.
DateTime
(
timezone
=
True
),
existing_type
=
sa
.
DateTime
(
timezone
=
False
))
existing_type
=
sa
.
DateTime
(
timezone
=
False
))
op
.
alter_column
(
'users'
,
'registered_date'
,
op
.
alter_column
(
'users'
,
'registered_date'
,
type_
=
sa
.
DateTime
(
timezone
=
True
),
type_
=
sa
.
DateTime
(
timezone
=
True
),
existing_type
=
sa
.
DateTime
(
timezone
=
False
))
existing_type
=
sa
.
DateTime
(
timezone
=
False
))
op
.
alter_column
(
'users'
,
'security_code_date'
,
op
.
alter_column
(
'users'
,
'security_code_date'
,
type_
=
sa
.
DateTime
(
timezone
=
True
),
type_
=
sa
.
DateTime
(
timezone
=
True
),
existing_type
=
sa
.
DateTime
(
timezone
=
False
))
existing_type
=
sa
.
DateTime
(
timezone
=
False
))
...
...
setup.py
View file @
20f4869
...
@@ -32,7 +32,6 @@ requires = [
...
@@ -32,7 +32,6 @@ requires = [
'deform'
,
'deform'
,
'pyramid_beaker'
,
'pyramid_beaker'
,
'pyramid_mailer'
,
'pyramid_mailer'
,
# 'opensipkd-jsonrpc @ git+https://git.opensipkd.com/sugiana/opensipkd-jsonrpc',
]
]
tests_require
=
[
tests_require
=
[
...
@@ -69,7 +68,8 @@ setup(
...
@@ -69,7 +68,8 @@ setup(
'main = web_starter:main'
,
'main = web_starter:main'
,
],
],
'console_scripts'
:
[
'console_scripts'
:
[
'initialize_web_starter_db = web_starter.scripts.initialize_db:main'
,
'initialize_web_starter_db = '
'web_starter.scripts.initialize_db:main'
,
'send_email = web_starter.scripts.send_email:main'
,
'send_email = web_starter.scripts.send_email:main'
,
]
]
},
},
...
...
web_starter/models/ziggurat.py
View file @
20f4869
...
@@ -9,12 +9,14 @@ from ziggurat_foundations.models.base import BaseModel
...
@@ -9,12 +9,14 @@ 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.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
\
UserResourcePermissionMixin
from
ziggurat_foundations
import
ziggurat_model_init
from
ziggurat_foundations
import
ziggurat_model_init
from
.
import
(
from
.
import
(
Base
,
Base
,
...
@@ -27,13 +29,16 @@ from . import (
...
@@ -27,13 +29,16 @@ from . import (
ziggurat_foundations
.
models
.
DBSession
=
DBSession
ziggurat_foundations
.
models
.
DBSession
=
DBSession
# optional for folks who pass request.db to model methods
# optional for folks who pass request.db to model methods
# Base is sqlalchemy's Base = declarative_base() from your project
# Base is sqlalchemy's Base = declarative_base() from your project
class
Group
(
GroupMixin
,
Base
,
CommonModel
):
class
Group
(
GroupMixin
,
Base
,
CommonModel
):
pass
pass
class
GroupPermission
(
GroupPermissionMixin
,
Base
):
class
GroupPermission
(
GroupPermissionMixin
,
Base
):
pass
pass
class
UserGroup
(
UserGroupMixin
,
Base
):
class
UserGroup
(
UserGroupMixin
,
Base
):
pass
pass
...
@@ -45,6 +50,7 @@ class GroupResourcePermission(GroupResourcePermissionMixin, Base):
...
@@ -45,6 +50,7 @@ class GroupResourcePermission(GroupResourcePermissionMixin, Base):
"resource_id"
,
"resource_id"
,
"perm_name"
),)
"perm_name"
),)
class
Resource
(
ResourceMixin
,
Base
):
class
Resource
(
ResourceMixin
,
Base
):
# ... your own properties....
# ... your own properties....
...
@@ -61,23 +67,27 @@ class Resource(ResourceMixin, Base):
...
@@ -61,23 +67,27 @@ class Resource(ResourceMixin, Base):
ALL_PERMISSIONS
,),
])
ALL_PERMISSIONS
,),
])
return
acls
return
acls
class
UserPermission
(
UserPermissionMixin
,
Base
):
class
UserPermission
(
UserPermissionMixin
,
Base
):
pass
pass
class
UserResourcePermission
(
UserResourcePermissionMixin
,
Base
):
class
UserResourcePermission
(
UserResourcePermissionMixin
,
Base
):
pass
pass
class
User
(
UserMixin
,
Base
,
CommonModel
):
class
User
(
UserMixin
,
Base
,
CommonModel
):
# ... your own properties....
# ... your own properties....
pass
pass
class
ExternalIdentity
(
ExternalIdentityMixin
,
Base
):
class
ExternalIdentity
(
ExternalIdentityMixin
,
Base
):
pass
pass
# you can define multiple resource derived models to build a complex
# you can define multiple resource derived models to build a complex
# application like CMS, forum or other permission based solution
# application like CMS, forum or other permission based solution
#class Entry(Resource):
#
class Entry(Resource):
# """
# """
# Resource of `entry` type
# Resource of `entry` type
# """
# """
...
@@ -105,7 +115,7 @@ class RootFactory:
...
@@ -105,7 +115,7 @@ class RootFactory:
self
.
__acl__
.
append
((
Allow
,
acl_name
,
gp
.
perm_name
))
self
.
__acl__
.
append
((
Allow
,
acl_name
,
gp
.
perm_name
))
#ziggurat_model_init(User, Group, UserGroup, GroupPermission, passwordmanager=None)
ziggurat_model_init
(
ziggurat_model_init
(
User
,
Group
,
UserGroup
,
GroupPermission
,
UserPermission
,
User
,
Group
,
UserGroup
,
GroupPermission
,
UserPermission
,
UserResourcePermission
,
GroupResourcePermission
,
Resource
,
UserResourcePermission
,
GroupResourcePermission
,
Resource
,
ExternalIdentity
,
passwordmanager
=
None
)
ExternalIdentity
,
passwordmanager
=
None
)
web_starter/scripts/initialize_db.py
View file @
20f4869
web_starter/tools/waktu.py
View file @
20f4869
...
@@ -12,15 +12,17 @@ def get_timezone():
...
@@ -12,15 +12,17 @@ def get_timezone():
return
pytz
.
timezone
(
settings
[
'timezone'
])
return
pytz
.
timezone
(
settings
[
'timezone'
])
def
create_datetime
(
year
,
month
,
day
,
hour
=
0
,
minute
=
7
,
second
=
0
,
def
create_datetime
(
microsecond
=
0
):
year
,
month
,
day
,
hour
=
0
,
minute
=
7
,
second
=
0
,
microsecond
=
0
):
tz
=
get_timezone
()
tz
=
get_timezone
()
return
datetime
(
year
,
month
,
day
,
hour
,
minute
,
second
,
return
datetime
(
microsecond
,
tzinfo
=
tz
)
year
,
month
,
day
,
hour
,
minute
,
second
,
microsecond
,
tzinfo
=
tz
)
def
create_date
(
year
,
month
,
day
):
def
create_date
(
year
,
month
,
day
):
return
create_datetime
(
year
,
month
,
day
)
return
create_datetime
(
year
,
month
,
day
)
def
as_timezone
(
tz_date
):
def
as_timezone
(
tz_date
):
localtz
=
get_timezone
()
localtz
=
get_timezone
()
if
not
tz_date
.
tzinfo
:
if
not
tz_date
.
tzinfo
:
...
@@ -34,6 +36,7 @@ def create_now():
...
@@ -34,6 +36,7 @@ def create_now():
tz
=
get_timezone
()
tz
=
get_timezone
()
return
datetime
.
now
(
tz
)
return
datetime
.
now
(
tz
)
def
date_from_str
(
value
):
def
date_from_str
(
value
):
separator
=
None
separator
=
None
value
=
value
.
split
()[
0
]
# dd-mm-yyyy HH:MM:SS
value
=
value
.
split
()[
0
]
# dd-mm-yyyy HH:MM:SS
...
@@ -50,12 +53,15 @@ def date_from_str(value):
...
@@ -50,12 +53,15 @@ def date_from_str(value):
y
,
m
,
d
=
int
(
value
[:
4
]),
int
(
value
[
4
:
6
]),
int
(
value
[
6
:])
y
,
m
,
d
=
int
(
value
[:
4
]),
int
(
value
[
4
:
6
]),
int
(
value
[
6
:])
return
date
(
y
,
m
,
d
)
return
date
(
y
,
m
,
d
)
def
dmy
(
tgl
):
def
dmy
(
tgl
):
return
tgl
.
strftime
(
'
%
d-
%
m-
%
Y'
)
return
tgl
.
strftime
(
'
%
d-
%
m-
%
Y'
)
def
dmyhms
(
t
):
def
dmyhms
(
t
):
return
t
.
strftime
(
'
%
d-
%
m-
%
Y
%
H:
%
M:
%
S'
)
return
t
.
strftime
(
'
%
d-
%
m-
%
Y
%
H:
%
M:
%
S'
)
def
next_month
(
year
,
month
):
def
next_month
(
year
,
month
):
if
month
==
12
:
if
month
==
12
:
month
=
1
month
=
1
...
@@ -64,6 +70,7 @@ def next_month(year, month):
...
@@ -64,6 +70,7 @@ def next_month(year, month):
month
+=
1
month
+=
1
return
year
,
month
return
year
,
month
def
best_date
(
year
,
month
,
day
):
def
best_date
(
year
,
month
,
day
):
try
:
try
:
return
date
(
year
,
month
,
day
)
return
date
(
year
,
month
,
day
)
...
@@ -71,6 +78,7 @@ def best_date(year, month, day):
...
@@ -71,6 +78,7 @@ def best_date(year, month, day):
last_day
=
calendar
.
monthrange
(
year
,
month
)[
1
]
last_day
=
calendar
.
monthrange
(
year
,
month
)[
1
]
return
date
(
year
,
month
,
last_day
)
return
date
(
year
,
month
,
last_day
)
def
next_month_day
(
year
,
month
,
day
):
def
next_month_day
(
year
,
month
,
day
):
year
,
month
=
next_month
(
year
,
month
)
year
,
month
=
next_month
(
year
,
month
)
return
best_date
(
year
,
month
,
day
)
return
best_date
(
year
,
month
,
day
)
web_starter/views/group.py
View file @
20f4869
...
@@ -51,8 +51,7 @@ class GroupNameValidator:
...
@@ -51,8 +51,7 @@ class GroupNameValidator:
group_name
=
clean_name
(
value
)
group_name
=
clean_name
(
value
)
if
self
.
group
and
self
.
group
.
group_name
.
lower
()
==
group_name
.
lower
():
if
self
.
group
and
self
.
group
.
group_name
.
lower
()
==
group_name
.
lower
():
return
return
q
=
DBSession
.
query
(
Group
)
.
\
q
=
DBSession
.
query
(
Group
)
.
filter
(
Group
.
group_name
.
ilike
(
group_name
))
filter
(
Group
.
group_name
.
ilike
(
group_name
))
found
=
q
.
first
()
found
=
q
.
first
()
if
not
found
:
if
not
found
:
return
return
...
@@ -98,6 +97,7 @@ PERMISSIONS = [
...
@@ -98,6 +97,7 @@ PERMISSIONS = [
(
'edit-user'
,
_
(
'User management'
))
(
'edit-user'
,
_
(
'User management'
))
]
]
def
get_form
(
request
,
class_form
,
group
=
None
):
def
get_form
(
request
,
class_form
,
group
=
None
):
schema
=
class_form
()
schema
=
class_form
()
schema
=
schema
.
bind
(
permission_list
=
PERMISSIONS
,
group
=
group
)
schema
=
schema
.
bind
(
permission_list
=
PERMISSIONS
,
group
=
group
)
...
@@ -147,6 +147,7 @@ def view_add(request):
...
@@ -147,6 +147,7 @@ def view_add(request):
request
.
session
.
flash
(
ts
)
request
.
session
.
flash
(
ts
)
return
HTTPFound
(
location
=
request
.
route_url
(
'group'
))
return
HTTPFound
(
location
=
request
.
route_url
(
'group'
))
########
########
# Edit #
# Edit #
########
########
...
@@ -202,7 +203,9 @@ def view_edit(request):
...
@@ -202,7 +203,9 @@ def view_edit(request):
return
resp
return
resp
update
(
group
,
dict
(
c
.
items
()))
update
(
group
,
dict
(
c
.
items
()))
data
=
dict
(
group_name
=
group
.
group_name
)
data
=
dict
(
group_name
=
group
.
group_name
)
ts
=
_
(
'group-updated'
,
default
=
'${group_name} group profile updated'
,
mapping
=
data
)
ts
=
_
(
'group-updated'
,
default
=
'${group_name} group profile updated'
,
mapping
=
data
)
request
.
session
.
flash
(
ts
)
request
.
session
.
flash
(
ts
)
return
HTTPFound
(
location
=
request
.
route_url
(
'group'
))
return
HTTPFound
(
location
=
request
.
route_url
(
'group'
))
...
...
web_starter/views/login.py
View file @
20f4869
...
@@ -119,11 +119,13 @@ def view_login(request):
...
@@ -119,11 +119,13 @@ def view_login(request):
@view_config
(
route_name
=
'logout'
)
@view_config
(
route_name
=
'logout'
)
def
view_logout
(
request
):
def
view_logout
(
request
):
headers
=
forget
(
request
)
headers
=
forget
(
request
)
return
HTTPFound
(
location
=
request
.
route_url
(
'home'
),
return
HTTPFound
(
headers
=
headers
)
location
=
request
.
route_url
(
'home'
),
headers
=
headers
)
@view_config
(
route_name
=
'login-by-code-failed'
,
renderer
=
'templates/login-by-code-failed.pt'
)
@view_config
(
route_name
=
'login-by-code-failed'
,
renderer
=
'templates/login-by-code-failed.pt'
)
def
view_login_by_code_failed
(
request
):
def
view_login_by_code_failed
(
request
):
return
dict
(
title
=
'Login by code failed'
)
return
dict
(
title
=
'Login by code failed'
)
...
@@ -170,6 +172,7 @@ def view_change_password(request):
...
@@ -170,6 +172,7 @@ def view_change_password(request):
DBSession
.
add
(
request
.
user
)
DBSession
.
add
(
request
.
user
)
return
HTTPFound
(
location
=
request
.
route_url
(
'change-password-done'
))
return
HTTPFound
(
location
=
request
.
route_url
(
'change-password-done'
))
@view_config
(
@view_config
(
route_name
=
'change-password-done'
,
route_name
=
'change-password-done'
,
renderer
=
'templates/change-password-done.pt'
,
permission
=
'view'
)
renderer
=
'templates/change-password-done.pt'
,
permission
=
'view'
)
...
@@ -185,7 +188,7 @@ class ResetPassword(colander.Schema):
...
@@ -185,7 +188,7 @@ class ResetPassword(colander.Schema):
colander
.
String
(),
title
=
_
(
'Email'
),
colander
.
String
(),
title
=
_
(
'Email'
),
description
=
_
(
description
=
_
(
'email-reset-password'
,
'email-reset-password'
,
default
=
'Enter your email address and we will send you '
\
default
=
'Enter your email address and we will send you '
'a link to reset your password.'
)
'a link to reset your password.'
)
)
)
...
@@ -234,7 +237,8 @@ def regenerate_security_code(user):
...
@@ -234,7 +237,8 @@ def regenerate_security_code(user):
return
one_hour
return
one_hour
@view_config
(
route_name
=
'reset-password'
,
renderer
=
'templates/reset-password.pt'
)
@view_config
(
route_name
=
'reset-password'
,
renderer
=
'templates/reset-password.pt'
)
def
view_reset_password
(
request
):
def
view_reset_password
(
request
):
if
authenticated_userid
(
request
):
if
authenticated_userid
(
request
):
return
HTTPFound
(
location
=
request
.
route_url
(
'home'
))
return
HTTPFound
(
location
=
request
.
route_url
(
'home'
))
...
@@ -262,7 +266,7 @@ def view_reset_password(request):
...
@@ -262,7 +266,7 @@ def view_reset_password(request):
@view_config
(
@view_config
(
route_name
=
'reset-password-sent'
,
renderer
=
'templates/reset-password-sent.pt'
)
route_name
=
'reset-password-sent'
,
renderer
=
'templates/reset-password-sent.pt'
)
def
view_reset_password_sent
(
request
):
def
view_reset_password_sent
(
request
):
return
dict
(
title
=
_
(
'Reset password'
))
return
dict
(
title
=
_
(
'Reset password'
))
web_starter/views/user.py
View file @
20f4869
...
@@ -85,8 +85,8 @@ def get_filter_form():
...
@@ -85,8 +85,8 @@ def get_filter_form():
def
query_filter
(
q
,
p
):
def
query_filter
(
q
,
p
):
if
'group'
in
p
:
if
'group'
in
p
:
q
=
q
.
filter
(
q
=
q
.
filter
(
User
.
id
==
UserGroup
.
user_id
,
User
.
id
==
UserGroup
.
user_id
,
UserGroup
.
group_id
==
p
[
'group'
])
UserGroup
.
group_id
==
p
[
'group'
])
if
'name'
in
p
:
if
'name'
in
p
:
pattern
=
'
%
{}
%
'
.
format
(
p
[
'name'
])
pattern
=
'
%
{}
%
'
.
format
(
p
[
'name'
])
q
=
q
.
filter
(
q
=
q
.
filter
(
...
@@ -184,6 +184,7 @@ class EmailValidator(colander.Email, Validator):
...
@@ -184,6 +184,7 @@ class EmailValidator(colander.Email, Validator):
REGEX_ONLY_CONTAIN
=
re
.
compile
(
'([a-z0-9-]*)'
)
REGEX_ONLY_CONTAIN
=
re
.
compile
(
'([a-z0-9-]*)'
)
REGEX_BEGIN_END_ALPHANUMERIC
=
re
.
compile
(
'^[a-z0-9]+(?:[-][a-z0-9]+)*$'
)
REGEX_BEGIN_END_ALPHANUMERIC
=
re
.
compile
(
'^[a-z0-9]+(?:[-][a-z0-9]+)*$'
)
class
UsernameValidator
(
Validator
):
class
UsernameValidator
(
Validator
):
def
__call__
(
self
,
node
,
value
):
def
__call__
(
self
,
node
,
value
):
username
=
value
.
lower
()
username
=
value
.
lower
()
...
@@ -227,7 +228,8 @@ class AddSchema(colander.Schema):
...
@@ -227,7 +228,8 @@ class AddSchema(colander.Schema):
email
=
colander
.
SchemaNode
(
email
=
colander
.
SchemaNode
(
colander
.
String
(),
title
=
_
(
'Email'
),
colander
.
String
(),
title
=
_
(
'Email'
),
validator
=
deferred_email_validator
)
validator
=
deferred_email_validator
)
user_name
=
colander
.
SchemaNode
(
colander
.
String
(),
title
=
_
(
'Username'
),
user_name
=
colander
.
SchemaNode
(
colander
.
String
(),
title
=
_
(
'Username'
),
validator
=
deferred_username_validator
)
validator
=
deferred_username_validator
)
groups
=
colander
.
SchemaNode
(
groups
=
colander
.
SchemaNode
(
colander
.
Set
(),
widget
=
deferred_group
,
title
=
_
(
'Group'
))
colander
.
Set
(),
widget
=
deferred_group
,
title
=
_
(
'Group'
))
...
...
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