shopyo-appadmin 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- shopyo_appadmin-1.0.0/PKG-INFO +13 -0
- shopyo_appadmin-1.0.0/pyproject.toml +36 -0
- shopyo_appadmin-1.0.0/setup.cfg +4 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin/__init__.py +20 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin/admin.py +26 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin/info.json +12 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin/models.py +0 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin/templates/shopyo_appadmin/add.html +86 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin/templates/shopyo_appadmin/blocks/sidebar.html +25 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin/templates/shopyo_appadmin/edit.html +69 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin/templates/shopyo_appadmin/index.html +81 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin/templates/shopyo_appadmin/roles.html +40 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin/view.py +236 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin.egg-info/PKG-INFO +13 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin.egg-info/SOURCES.txt +18 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin.egg-info/dependency_links.txt +1 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin.egg-info/requires.txt +1 -0
- shopyo_appadmin-1.0.0/shopyo_appadmin.egg-info/top_level.txt +2 -0
- shopyo_appadmin-1.0.0/tests/test_admin.py +406 -0
- shopyo_appadmin-1.0.0/tests/test_models.py +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: shopyo_appadmin
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Base module containing jinja macros and templates
|
|
5
|
+
Author-email: Abdur-Rahmaan Janhangeer <arj.python@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/shopyo/shopyo
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/shopyo/shopyo/issues
|
|
8
|
+
Keywords: shopyo
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
|
+
Requires-Dist: shopyo
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "shopyo_appadmin"
|
|
3
|
+
authors = [{ name = "Abdur-Rahmaan Janhangeer", email = "arj.python@gmail.com" }]
|
|
4
|
+
description = "Base module containing jinja macros and templates"
|
|
5
|
+
# readme = "README.md"
|
|
6
|
+
requires-python = ">=3.8"
|
|
7
|
+
# license = { file = "LICENSE.txt" }
|
|
8
|
+
keywords = ["shopyo"]
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Programming Language :: Python :: 3",
|
|
11
|
+
"License :: OSI Approved :: BSD License",
|
|
12
|
+
"Operating System :: OS Independent",
|
|
13
|
+
]
|
|
14
|
+
dependencies = ["shopyo"]
|
|
15
|
+
dynamic = ["version"]
|
|
16
|
+
|
|
17
|
+
[tool.setuptools.dynamic]
|
|
18
|
+
version = { attr = "shopyo_appadmin.__version__" }
|
|
19
|
+
|
|
20
|
+
[project.urls]
|
|
21
|
+
"Homepage" = "https://github.com/shopyo/shopyo"
|
|
22
|
+
"Bug Tracker" = "https://github.com/shopyo/shopyo/issues"
|
|
23
|
+
|
|
24
|
+
[build-system]
|
|
25
|
+
requires = ["setuptools>=61.0"]
|
|
26
|
+
build-backend = "setuptools.build_meta"
|
|
27
|
+
|
|
28
|
+
[tool.setuptools]
|
|
29
|
+
include-package-data = true
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.packages.find]
|
|
32
|
+
where = ["."]
|
|
33
|
+
exclude = ["tests*", "docs*", "examples*"]
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.package-data]
|
|
36
|
+
shopyo_appadmin = ["static/**", "templates/**", "*.json"]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from flask import Flask
|
|
4
|
+
from shopyo_appadmin.view import module_blueprint
|
|
5
|
+
|
|
6
|
+
__version__ = "1.0.0"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ShopyoAppAdmin:
|
|
10
|
+
def __init__(self, app: Any = None) -> None:
|
|
11
|
+
if app is not None:
|
|
12
|
+
self.init_app(app)
|
|
13
|
+
|
|
14
|
+
def init_app(self, app: Flask) -> None:
|
|
15
|
+
if not hasattr(app, "extensions"):
|
|
16
|
+
app.extensions = {}
|
|
17
|
+
|
|
18
|
+
app.extensions["shopyo_appadmin"] = self
|
|
19
|
+
bp = module_blueprint
|
|
20
|
+
app.register_blueprint(bp)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
|
|
3
|
+
from flask import redirect
|
|
4
|
+
from flask_login import current_user
|
|
5
|
+
from init import login_manager
|
|
6
|
+
from shopyo_auth.models import User
|
|
7
|
+
|
|
8
|
+
from shopyo.api.html import notify_warning
|
|
9
|
+
|
|
10
|
+
login_manager.login_message = notify_warning("Please login for access")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@login_manager.user_loader
|
|
14
|
+
def load_user(id):
|
|
15
|
+
return User.query.get(id)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def admin_required(f):
|
|
19
|
+
@wraps(f)
|
|
20
|
+
def wrap(*args, **kwargs):
|
|
21
|
+
if current_user.is_admin:
|
|
22
|
+
return f(*args, **kwargs)
|
|
23
|
+
else:
|
|
24
|
+
return redirect("/")
|
|
25
|
+
|
|
26
|
+
return wrap
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"display_string": "Admin",
|
|
3
|
+
"type": "show",
|
|
4
|
+
"fa-icon": "fas fa-user-lock",
|
|
5
|
+
"url_prefix": "/appadmin",
|
|
6
|
+
"module_name": "appadmin",
|
|
7
|
+
"author": {
|
|
8
|
+
"name":"Abdur-Rahmaan Janhangeer",
|
|
9
|
+
"website":"https://www.pythonkitchen.com/about-me/",
|
|
10
|
+
"mail":"arj.python@gmail.com"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{% extends "shopyo_base/module_base.html" %}
|
|
2
|
+
{% set active_page = "admin" %}
|
|
3
|
+
{% block pagehead %}
|
|
4
|
+
<title>{{active_page.capitalize()}}</title>
|
|
5
|
+
<style>
|
|
6
|
+
.hidden {
|
|
7
|
+
display: none;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.show {
|
|
11
|
+
display: inline-block;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.active {
|
|
15
|
+
width: 6rem;
|
|
16
|
+
color: white;
|
|
17
|
+
background-color: #34ce57;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.inactive {
|
|
21
|
+
width: 6rem;
|
|
22
|
+
color: white;
|
|
23
|
+
background-color: #ff253a;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.all_inactive {
|
|
27
|
+
display: none;
|
|
28
|
+
}
|
|
29
|
+
</style>
|
|
30
|
+
{% endblock %}
|
|
31
|
+
{% block sidebar %}
|
|
32
|
+
{%include 'appadmin/blocks/sidebar.html'%}
|
|
33
|
+
{%endblock%}
|
|
34
|
+
{% block content %}
|
|
35
|
+
<br>
|
|
36
|
+
<div class="container col-md-6 off-set-3">
|
|
37
|
+
<div class="card">
|
|
38
|
+
<div class="card-body">
|
|
39
|
+
<form action="/appadmin/add" method="post">
|
|
40
|
+
<div class="input-group mb-3">
|
|
41
|
+
<div class="input-group-prepend">
|
|
42
|
+
<span class="input-group-text"><i class="fa fa-user"></i></span>
|
|
43
|
+
</div>
|
|
44
|
+
<input type="email" name="email" class="form-control" id="email" placeholder="Email" required autocomplete="off">
|
|
45
|
+
</div>
|
|
46
|
+
<div class="input-group mb-3">
|
|
47
|
+
<div class="input-group-prepend">
|
|
48
|
+
<span class="input-group-text"><i class="fa fa-key"></i></span>
|
|
49
|
+
</div>
|
|
50
|
+
<input type="password" name="password" class="form-control" id="user_password" placeholder="Password" required autocomplete="off">
|
|
51
|
+
</div>
|
|
52
|
+
<div class="input-group mb-3">
|
|
53
|
+
<div class="input-group-prepend">
|
|
54
|
+
<span class="input-group-text"><i class="fa fa-key"></i></span>
|
|
55
|
+
</div>
|
|
56
|
+
<input type="text" name="first_name" class="form-control" placeholder="First Name" autocomplete="off">
|
|
57
|
+
</div>
|
|
58
|
+
<div class="input-group mb-3">
|
|
59
|
+
<div class="input-group-prepend">
|
|
60
|
+
<span class="input-group-text"><i class="fa fa-key"></i></span>
|
|
61
|
+
</div>
|
|
62
|
+
<input type="text" name="last_name" class="form-control" placeholder="Last Name" autocomplete="off">
|
|
63
|
+
</div>
|
|
64
|
+
<div class="input-group mb-3">
|
|
65
|
+
<div class="custom-control custom-checkbox">
|
|
66
|
+
<input type="checkbox" name="is_admin" class="custom-control-input" id="is_admin" value="True" checked>
|
|
67
|
+
<label for="is_admin" class="custom-control-label">Admin User</label>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
<table class="table">
|
|
71
|
+
<tbody>
|
|
72
|
+
{%for role in roles%}
|
|
73
|
+
<tr>
|
|
74
|
+
<td><input type="checkbox" name="role_{{role.id}}"></td>
|
|
75
|
+
<td>{{role.name}}</td>
|
|
76
|
+
</tr>
|
|
77
|
+
{%endfor%}
|
|
78
|
+
</tbody>
|
|
79
|
+
</table>
|
|
80
|
+
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
|
81
|
+
<input type="submit" class="btn btn-info" value="add" required>
|
|
82
|
+
</form>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
{% endblock %}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{{
|
|
2
|
+
sidebar_item(
|
|
3
|
+
'Home',
|
|
4
|
+
icon='fas fa-user-lock',
|
|
5
|
+
url=url_for('appadmin.user_list')
|
|
6
|
+
)
|
|
7
|
+
}}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
{{
|
|
11
|
+
sidebar_item(
|
|
12
|
+
'Add',
|
|
13
|
+
icon='fas fa-plus-circle',
|
|
14
|
+
url=url_for('appadmin.user_add')
|
|
15
|
+
)
|
|
16
|
+
}}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
{{
|
|
20
|
+
sidebar_item(
|
|
21
|
+
'Roles',
|
|
22
|
+
icon='fa fa-shield-alt',
|
|
23
|
+
url=url_for('appadmin.roles')
|
|
24
|
+
)
|
|
25
|
+
}}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{% extends "shopyo_base/module_base.html" %}
|
|
2
|
+
{% set active_page = "admin" %}
|
|
3
|
+
{% block pagehead %}
|
|
4
|
+
<title>edit</title>
|
|
5
|
+
{% endblock %}
|
|
6
|
+
{% block sidebar %}
|
|
7
|
+
{%include 'appadmin/blocks/sidebar.html'%}
|
|
8
|
+
{%endblock%}
|
|
9
|
+
{% block content %}
|
|
10
|
+
<br>
|
|
11
|
+
<div class="card">
|
|
12
|
+
<div class="card-body">
|
|
13
|
+
<h2>Edit User</h2>
|
|
14
|
+
<form action='/appadmin/update' method="post">
|
|
15
|
+
<label>Edit User:<span> {{ user.email }} </span></label>
|
|
16
|
+
<div class="input-group mb-3">
|
|
17
|
+
</div>
|
|
18
|
+
<div class="input-group mb-3">
|
|
19
|
+
<div class="input-group-prepend">
|
|
20
|
+
<span class="input-group-text"><i class="fa fa-key"></i></span>
|
|
21
|
+
</div>
|
|
22
|
+
<input type="text" name="email" class="form-control" id="user_email" value="{{ user.email }}" required autocomplete="off">
|
|
23
|
+
</div>
|
|
24
|
+
<div class="input-group mb-3">
|
|
25
|
+
<div class="input-group-prepend">
|
|
26
|
+
<span class="input-group-text"><i class="fa fa-key"></i></span>
|
|
27
|
+
</div>
|
|
28
|
+
<input type="password" name="password" class="form-control" id="user_password" value="" autocomplete="off">
|
|
29
|
+
</div>
|
|
30
|
+
<div class="">
|
|
31
|
+
<div class="">
|
|
32
|
+
<input type="checkbox" name="is_admin" id="is_admin" class="" {{'checked' if user.is_admin}}>
|
|
33
|
+
<label for="is_admin" class="custom-control-label">Admin User</label>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="input-group mb-3">
|
|
37
|
+
<div class="input-group-prepend">
|
|
38
|
+
<span class="input-group-text"><i class="fa fa-key"></i></span>
|
|
39
|
+
</div>
|
|
40
|
+
<input type="text" name="first_name" class="form-control" placeholder="First Name" autocomplete="off" value="{{ user.first_name }}">
|
|
41
|
+
</div>
|
|
42
|
+
<div class="input-group mb-3">
|
|
43
|
+
<div class="input-group-prepend">
|
|
44
|
+
<span class="input-group-text"><i class="fa fa-key"></i></span>
|
|
45
|
+
</div>
|
|
46
|
+
<input type="text" name="last_name" class="form-control" placeholder="Last Name" autocomplete="off" value="{{ user.last_name }}">
|
|
47
|
+
</div>
|
|
48
|
+
<input required name="id" id="user_id" type="hidden" class="form-control" value="{{ user.id }}">
|
|
49
|
+
<div>
|
|
50
|
+
Roles<br>
|
|
51
|
+
<table class="table">
|
|
52
|
+
<tbody>
|
|
53
|
+
{%for role in roles%}
|
|
54
|
+
<tr>
|
|
55
|
+
<td><input type="checkbox" name="role_{{role.id}}" {%if role.name in user_roles%} checked {%endif%}></td>
|
|
56
|
+
<td>{{role.name}}</td>
|
|
57
|
+
</tr>
|
|
58
|
+
{%endfor%}
|
|
59
|
+
</tbody>
|
|
60
|
+
</table>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="input-group mb-3">
|
|
63
|
+
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
|
64
|
+
<input required type="submit" class="btn btn-info" value="edit">
|
|
65
|
+
</div>
|
|
66
|
+
</form>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
{% endblock %}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{% extends "shopyo_base/module_base.html" %}
|
|
2
|
+
{% set active_page ='admin' %}
|
|
3
|
+
{% block pagehead %}
|
|
4
|
+
<title>{{active_page.capitalize()}}</title>
|
|
5
|
+
<style>
|
|
6
|
+
.hidden{
|
|
7
|
+
display: none;
|
|
8
|
+
}
|
|
9
|
+
.show{
|
|
10
|
+
display: inline-block;
|
|
11
|
+
}
|
|
12
|
+
</style>
|
|
13
|
+
{% endblock %}
|
|
14
|
+
{% block sidebar %}
|
|
15
|
+
{%include 'appadmin/blocks/sidebar.html'%}
|
|
16
|
+
{%endblock%}
|
|
17
|
+
{% block content %}
|
|
18
|
+
<br>
|
|
19
|
+
<script type="text/javascript">
|
|
20
|
+
$(function() {
|
|
21
|
+
$('.delete_me').click(function() {
|
|
22
|
+
var id = $(this).data('id');
|
|
23
|
+
console.log(id);
|
|
24
|
+
var ask = confirm("Do you want to delete ?");
|
|
25
|
+
if (ask == true) {
|
|
26
|
+
window.open("/appadmin/delete/" + id, "_self")
|
|
27
|
+
} else {
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
</script>
|
|
33
|
+
<div class="container">
|
|
34
|
+
<div class="card">
|
|
35
|
+
<div class="card-body">
|
|
36
|
+
<h2>{{active_page.capitalize()}}</h2>
|
|
37
|
+
<table class="table table-responsive table-bordered">
|
|
38
|
+
<thead>
|
|
39
|
+
<tr>
|
|
40
|
+
<th>ID</th>
|
|
41
|
+
<th>Email</th>
|
|
42
|
+
<th>Password</th>
|
|
43
|
+
<th>Admin</th>
|
|
44
|
+
<th>Roles</th>
|
|
45
|
+
<th style="border: none;"></th>
|
|
46
|
+
</tr>
|
|
47
|
+
</thead>
|
|
48
|
+
<tbody>
|
|
49
|
+
{% for user in users %}
|
|
50
|
+
<tr>
|
|
51
|
+
<td>{{user.id}}</td>
|
|
52
|
+
<td>{{user.email}}</td>
|
|
53
|
+
<td>*******</td>
|
|
54
|
+
<td>{{user.is_admin}}</td>
|
|
55
|
+
<td>
|
|
56
|
+
{%for role in user.roles%}
|
|
57
|
+
<div class="badge badge-primary">
|
|
58
|
+
{{role.name}}
|
|
59
|
+
</div>
|
|
60
|
+
{%endfor%}
|
|
61
|
+
</td>
|
|
62
|
+
<td style="border: none;">
|
|
63
|
+
<div style='display: inline-block; '>
|
|
64
|
+
<a style="text-decoration: none;">
|
|
65
|
+
<button id='delete' data-id="{{ user.id }}" class="delete_me btn btn-dark" type="" name="{{ user.id }}"><i class="fas fa-trash-alt"></i></button>
|
|
66
|
+
</a>
|
|
67
|
+
|
|
68
|
+
<a href="/appadmin/edit/{{ user.id }}" style="text-decoration: none;">
|
|
69
|
+
<button data-name="{{ user.id }}" class="btn btn-warning"><i id="ico-{{user.id}}" class="fas fa-pencil-alt"></i>
|
|
70
|
+
</button>
|
|
71
|
+
</a>
|
|
72
|
+
</div>
|
|
73
|
+
</td>
|
|
74
|
+
</tr>
|
|
75
|
+
{% endfor %}
|
|
76
|
+
</tbody>
|
|
77
|
+
</table>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
{% endblock %}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{% extends "shopyo_base/module_base.html" %}
|
|
2
|
+
{% set active_page = "admin" %}
|
|
3
|
+
{% block pagehead %}
|
|
4
|
+
{% endblock %}
|
|
5
|
+
{% block sidebar %}
|
|
6
|
+
{%include 'appadmin/blocks/sidebar.html'%}
|
|
7
|
+
{%endblock%}
|
|
8
|
+
{% block content %}
|
|
9
|
+
<br>
|
|
10
|
+
<div class="card">
|
|
11
|
+
<div class="card-body">
|
|
12
|
+
<h2>Roles</h2>
|
|
13
|
+
<div class="">
|
|
14
|
+
<form class="" method="POST" action='{{url_for("appadmin.roles_add")}}'>
|
|
15
|
+
<div class="form-group">
|
|
16
|
+
<input name="csrf_token" value="{{csrf_token()}}" type="hidden">
|
|
17
|
+
<input class="form-control" type="" name="name"><br>
|
|
18
|
+
<button class="btn btn-info" type="submit">add</button>
|
|
19
|
+
</div>
|
|
20
|
+
</form>
|
|
21
|
+
<table>
|
|
22
|
+
<tbody>
|
|
23
|
+
{%for role in roles%}
|
|
24
|
+
<tr>
|
|
25
|
+
<form action="{{url_for('appadmin.roles_update')}}" method="POST">
|
|
26
|
+
<td>
|
|
27
|
+
<input value="{{role.name}}" class="form-control" type="" name="role_name"></td>
|
|
28
|
+
<input type="hidden" name="role_id" value="{{role.id}}">
|
|
29
|
+
<input type="hidden" name="csrf_token" value="{{csrf_token()}}">
|
|
30
|
+
<td><button class="btn btn-info form-control" type="submit">save</button></td>
|
|
31
|
+
<td><a class="btn btn-danger" href="{{url_for('appadmin.roles_delete', role_id=role.id)}}">delete</a></td>
|
|
32
|
+
</form>
|
|
33
|
+
</tr>
|
|
34
|
+
{%endfor%}
|
|
35
|
+
</tbody>
|
|
36
|
+
</table>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
{% endblock %}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"""
|
|
2
|
+
.. module:: AdminViews
|
|
3
|
+
:synopsis: All endpoints of the admin views are defined here.
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from flask import flash
|
|
8
|
+
from flask import redirect
|
|
9
|
+
from flask import render_template
|
|
10
|
+
from flask import request
|
|
11
|
+
from flask import url_for
|
|
12
|
+
from flask_login import login_required
|
|
13
|
+
from init import db
|
|
14
|
+
from shopyo_auth.models import Role
|
|
15
|
+
from shopyo_auth.models import User
|
|
16
|
+
from sqlalchemy import exists
|
|
17
|
+
|
|
18
|
+
from .admin import admin_required
|
|
19
|
+
from shopyo.api.html import notify_success
|
|
20
|
+
from shopyo.api.html import notify_warning
|
|
21
|
+
from shopyo.api.module import ModuleHelp
|
|
22
|
+
|
|
23
|
+
# from config import Config
|
|
24
|
+
|
|
25
|
+
mhelp = ModuleHelp(__file__, __name__)
|
|
26
|
+
globals()[mhelp.blueprint_str] = mhelp.blueprint
|
|
27
|
+
module_blueprint = globals()[mhelp.blueprint_str]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@module_blueprint.route("/")
|
|
31
|
+
@login_required
|
|
32
|
+
@admin_required
|
|
33
|
+
def user_list():
|
|
34
|
+
"""
|
|
35
|
+
**Get The List of User**
|
|
36
|
+
|
|
37
|
+
Lists all users in the database.
|
|
38
|
+
|
|
39
|
+
"""
|
|
40
|
+
context = {}
|
|
41
|
+
context["users"] = User.query.all()
|
|
42
|
+
return render_template("appadmin/index.html", **context)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@module_blueprint.route("/add", methods=["GET", "POST"])
|
|
46
|
+
@login_required
|
|
47
|
+
@admin_required
|
|
48
|
+
def user_add():
|
|
49
|
+
"""
|
|
50
|
+
**Adds a User**
|
|
51
|
+
|
|
52
|
+
adds a user to database.
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
context = {}
|
|
56
|
+
if request.method == "POST":
|
|
57
|
+
email = request.form["email"]
|
|
58
|
+
password = request.form["password"]
|
|
59
|
+
first_name = request.form["first_name"]
|
|
60
|
+
last_name = request.form["last_name"]
|
|
61
|
+
admin_user = request.form.get("is_admin")
|
|
62
|
+
if admin_user == "True":
|
|
63
|
+
is_admin = True
|
|
64
|
+
else:
|
|
65
|
+
is_admin = False
|
|
66
|
+
|
|
67
|
+
has_user = db.session.query(exists().where(User.email == email)).scalar()
|
|
68
|
+
|
|
69
|
+
if not has_user:
|
|
70
|
+
new_user = User()
|
|
71
|
+
new_user.email = email
|
|
72
|
+
new_user.is_admin = is_admin
|
|
73
|
+
new_user.first_name = first_name
|
|
74
|
+
new_user.last_name = last_name
|
|
75
|
+
new_user.password = password
|
|
76
|
+
|
|
77
|
+
for key in request.form:
|
|
78
|
+
if key.startswith("role_"):
|
|
79
|
+
role_id = key.split("_")[1]
|
|
80
|
+
role = Role.get_by_id(role_id)
|
|
81
|
+
new_user.roles.append(role)
|
|
82
|
+
new_user.save()
|
|
83
|
+
return redirect(url_for("appadmin.user_add"))
|
|
84
|
+
|
|
85
|
+
flash(notify_warning("User with same email already exists"))
|
|
86
|
+
|
|
87
|
+
context["roles"] = Role.query.all()
|
|
88
|
+
return render_template("appadmin/add.html", **context)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@module_blueprint.route("/delete/<id>", methods=["GET"])
|
|
92
|
+
@login_required
|
|
93
|
+
@admin_required
|
|
94
|
+
def admin_delete(id):
|
|
95
|
+
"""
|
|
96
|
+
**Delete a User**
|
|
97
|
+
|
|
98
|
+
:param id: id of the user
|
|
99
|
+
:type id: int
|
|
100
|
+
|
|
101
|
+
"""
|
|
102
|
+
user = User.query.get(id)
|
|
103
|
+
|
|
104
|
+
if user is None:
|
|
105
|
+
flash(notify_warning("Unable to delete. Invalid user id"))
|
|
106
|
+
return redirect("/appadmin")
|
|
107
|
+
|
|
108
|
+
user.delete()
|
|
109
|
+
flash(notify_success("User successfully deleted"))
|
|
110
|
+
return redirect("/appadmin")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@module_blueprint.route("/edit/<id>", methods=["GET"])
|
|
114
|
+
@login_required
|
|
115
|
+
@admin_required
|
|
116
|
+
def admin_edit(id):
|
|
117
|
+
"""
|
|
118
|
+
**Update information for a User**
|
|
119
|
+
|
|
120
|
+
:param id: id of the user
|
|
121
|
+
:type id: int
|
|
122
|
+
|
|
123
|
+
"""
|
|
124
|
+
context = {}
|
|
125
|
+
user = User.query.get(id)
|
|
126
|
+
|
|
127
|
+
if user is None:
|
|
128
|
+
flash(notify_warning("Unable to edit. Invalid user id"))
|
|
129
|
+
return redirect("/appadmin")
|
|
130
|
+
|
|
131
|
+
context["user"] = user
|
|
132
|
+
context["user_roles"] = [r.name for r in user.roles]
|
|
133
|
+
context["roles"] = Role.query.all()
|
|
134
|
+
return render_template("appadmin/edit.html", **context)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@module_blueprint.route("/update", methods=["POST"])
|
|
138
|
+
@login_required
|
|
139
|
+
@admin_required
|
|
140
|
+
def admin_update():
|
|
141
|
+
"""
|
|
142
|
+
**Update a User record**
|
|
143
|
+
|
|
144
|
+
"""
|
|
145
|
+
id = request.form["id"]
|
|
146
|
+
password = request.form["password"]
|
|
147
|
+
email = request.form["email"]
|
|
148
|
+
first_name = request.form["first_name"]
|
|
149
|
+
last_name = request.form["last_name"]
|
|
150
|
+
is_admin = request.form.get("is_admin")
|
|
151
|
+
|
|
152
|
+
if is_admin:
|
|
153
|
+
is_admin = True
|
|
154
|
+
else:
|
|
155
|
+
is_admin = False
|
|
156
|
+
|
|
157
|
+
user = User.query.get(id)
|
|
158
|
+
|
|
159
|
+
if user is None:
|
|
160
|
+
flash(notify_warning("Unable to update. User does not exist."))
|
|
161
|
+
return redirect("/admin")
|
|
162
|
+
|
|
163
|
+
user.is_admin = is_admin
|
|
164
|
+
user.email = email
|
|
165
|
+
user.first_name = first_name
|
|
166
|
+
user.last_name = last_name
|
|
167
|
+
user.roles[:] = []
|
|
168
|
+
|
|
169
|
+
if password.strip():
|
|
170
|
+
user.password = password
|
|
171
|
+
|
|
172
|
+
for key in request.form:
|
|
173
|
+
if key.startswith("role_"):
|
|
174
|
+
role_id = key.split("_")[1]
|
|
175
|
+
role = Role.get_by_id(role_id)
|
|
176
|
+
user.roles.append(role)
|
|
177
|
+
|
|
178
|
+
user.update()
|
|
179
|
+
flash(notify_success("User successfully updated"))
|
|
180
|
+
return redirect("/appadmin")
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@module_blueprint.route("/roles")
|
|
184
|
+
@login_required
|
|
185
|
+
@admin_required
|
|
186
|
+
def roles():
|
|
187
|
+
context = {}
|
|
188
|
+
context["roles"] = Role.query.all()
|
|
189
|
+
return render_template("appadmin/roles.html", **context)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
@module_blueprint.route("/roles/add", methods=["POST"])
|
|
193
|
+
@login_required
|
|
194
|
+
@admin_required
|
|
195
|
+
def roles_add():
|
|
196
|
+
if request.method == "POST":
|
|
197
|
+
if not Role.query.filter(Role.name == request.form["name"]).first():
|
|
198
|
+
role = Role(name=request.form["name"])
|
|
199
|
+
role.save()
|
|
200
|
+
flash(notify_success("Role successfully added"))
|
|
201
|
+
return redirect(url_for("appadmin.roles"))
|
|
202
|
+
flash(notify_warning("Role already exists"))
|
|
203
|
+
return redirect(url_for("appadmin.roles"))
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
@module_blueprint.route("/roles/<role_id>/delete", methods=["GET"])
|
|
207
|
+
@login_required
|
|
208
|
+
@admin_required
|
|
209
|
+
def roles_delete(role_id):
|
|
210
|
+
role = Role.get_by_id(role_id)
|
|
211
|
+
|
|
212
|
+
if role is None:
|
|
213
|
+
flash(notify_warning("Unable to delete. Invalid role id"))
|
|
214
|
+
return redirect(url_for("appadmin.roles"))
|
|
215
|
+
|
|
216
|
+
role.delete()
|
|
217
|
+
flash(notify_success("Role successfully deleted"))
|
|
218
|
+
return redirect(url_for("appadmin.roles"))
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
@module_blueprint.route("/roles/update", methods=["POST"])
|
|
222
|
+
@login_required
|
|
223
|
+
@admin_required
|
|
224
|
+
def roles_update():
|
|
225
|
+
if request.method == "POST":
|
|
226
|
+
role = Role.get_by_id(request.form["role_id"])
|
|
227
|
+
|
|
228
|
+
if role is None:
|
|
229
|
+
flash(notify_warning("Unable to update. Role does not exist"))
|
|
230
|
+
return redirect(url_for("appadmin.roles"))
|
|
231
|
+
|
|
232
|
+
role.name = request.form["role_name"]
|
|
233
|
+
role.update()
|
|
234
|
+
flash(notify_success("Role successfully updated"))
|
|
235
|
+
|
|
236
|
+
return redirect(url_for("appadmin.roles"))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: shopyo_appadmin
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Base module containing jinja macros and templates
|
|
5
|
+
Author-email: Abdur-Rahmaan Janhangeer <arj.python@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/shopyo/shopyo
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/shopyo/shopyo/issues
|
|
8
|
+
Keywords: shopyo
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
|
+
Requires-Dist: shopyo
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
pyproject.toml
|
|
2
|
+
shopyo_appadmin/__init__.py
|
|
3
|
+
shopyo_appadmin/admin.py
|
|
4
|
+
shopyo_appadmin/info.json
|
|
5
|
+
shopyo_appadmin/models.py
|
|
6
|
+
shopyo_appadmin/view.py
|
|
7
|
+
shopyo_appadmin.egg-info/PKG-INFO
|
|
8
|
+
shopyo_appadmin.egg-info/SOURCES.txt
|
|
9
|
+
shopyo_appadmin.egg-info/dependency_links.txt
|
|
10
|
+
shopyo_appadmin.egg-info/requires.txt
|
|
11
|
+
shopyo_appadmin.egg-info/top_level.txt
|
|
12
|
+
shopyo_appadmin/templates/shopyo_appadmin/add.html
|
|
13
|
+
shopyo_appadmin/templates/shopyo_appadmin/edit.html
|
|
14
|
+
shopyo_appadmin/templates/shopyo_appadmin/index.html
|
|
15
|
+
shopyo_appadmin/templates/shopyo_appadmin/roles.html
|
|
16
|
+
shopyo_appadmin/templates/shopyo_appadmin/blocks/sidebar.html
|
|
17
|
+
tests/test_admin.py
|
|
18
|
+
tests/test_models.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
shopyo
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This file (test_admin.py) contains the functional tests for
|
|
3
|
+
the `admin` blueprint.
|
|
4
|
+
|
|
5
|
+
These tests use GETs and POSTs to different endpoints to check
|
|
6
|
+
for the proper behavior of the `admin` blueprint.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
from flask import request
|
|
14
|
+
from flask import url_for
|
|
15
|
+
from modules.box__default.auth.models import Role
|
|
16
|
+
from modules.box__default.auth.models import role_user_bridge
|
|
17
|
+
from modules.box__default.auth.models import User
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
dirpath = os.path.dirname(os.path.abspath(__file__))
|
|
21
|
+
module_path = os.path.dirname(dirpath)
|
|
22
|
+
|
|
23
|
+
module_info = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# class TestAdminInvalidAccess:
|
|
27
|
+
# """
|
|
28
|
+
# Test all admin routes for correct user authentication
|
|
29
|
+
# """
|
|
30
|
+
|
|
31
|
+
# routes_get = [
|
|
32
|
+
# "/",
|
|
33
|
+
# "/add",
|
|
34
|
+
# "/delete/<id>",
|
|
35
|
+
# "/edit/<id>",
|
|
36
|
+
# "/roles",
|
|
37
|
+
# "/roles/<role_id>/delete",
|
|
38
|
+
# ]
|
|
39
|
+
|
|
40
|
+
# routes_post = ["/update", "/roles/update", "/roles/add", "/add"]
|
|
41
|
+
|
|
42
|
+
# @pytest.mark.parametrize("route", routes_get)
|
|
43
|
+
# def test_redirect_if_not_logged_in_get(self, test_client, route, auth):
|
|
44
|
+
# auth.logout()
|
|
45
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
46
|
+
# module_info = json.load(f)
|
|
47
|
+
# response = test_client.get(
|
|
48
|
+
# f"{module_info['url_prefix']}{route}", follow_redirects=True
|
|
49
|
+
# )
|
|
50
|
+
|
|
51
|
+
# assert response.status_code == 200
|
|
52
|
+
# assert request.path == url_for("shopyo_auth.login")
|
|
53
|
+
|
|
54
|
+
# @pytest.mark.parametrize("route", routes_post)
|
|
55
|
+
# def test_redirect_if_not_logged_in_post(self, test_client, route, auth):
|
|
56
|
+
# auth.logout()
|
|
57
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
58
|
+
# module_info = json.load(f)
|
|
59
|
+
# response = test_client.post(
|
|
60
|
+
# f"{module_info['url_prefix']}{route}", follow_redirects=True
|
|
61
|
+
# )
|
|
62
|
+
|
|
63
|
+
# assert response.status_code == 200
|
|
64
|
+
# assert request.path == url_for("shopyo_auth.login")
|
|
65
|
+
|
|
66
|
+
# @pytest.mark.usefixtures("login_non_admin_user")
|
|
67
|
+
# @pytest.mark.parametrize("route", routes_get)
|
|
68
|
+
# def test_no_admin_access_if_not_admin_get(self, test_client, route):
|
|
69
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
70
|
+
# module_info = json.load(f)
|
|
71
|
+
# response = test_client.get(
|
|
72
|
+
# f"{module_info['url_prefix']}{route}", follow_redirects=True
|
|
73
|
+
# )
|
|
74
|
+
|
|
75
|
+
# assert response.status_code == 200
|
|
76
|
+
# assert request.path == url_for("shopyo_dashboard.index")
|
|
77
|
+
# assert b"You need to be an admin to view this page" in response.data
|
|
78
|
+
|
|
79
|
+
# @pytest.mark.usefixtures("login_non_admin_user")
|
|
80
|
+
# @pytest.mark.parametrize("route", routes_post)
|
|
81
|
+
# def test_no_admin_access_if_not_admin_post(self, test_client, route):
|
|
82
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
83
|
+
# module_info = json.load(f)
|
|
84
|
+
# response = test_client.post(
|
|
85
|
+
# f"{module_info['url_prefix']}{route}", follow_redirects=True
|
|
86
|
+
# )
|
|
87
|
+
|
|
88
|
+
# assert response.status_code == 200
|
|
89
|
+
# assert request.path == url_for("shopyo_dashboard.index")
|
|
90
|
+
# assert b"You need to be an admin to view this page" in response.data
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@pytest.mark.usefixtures("login_admin_user")
|
|
94
|
+
class TestAdminEndpoints:
|
|
95
|
+
"""
|
|
96
|
+
Test all admin api post and get requests
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
# def test_admin_user_list_get(self, test_client):
|
|
100
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
101
|
+
# module_info = json.load(f)
|
|
102
|
+
# response = test_client.get(f"{module_info['url_prefix']}/")
|
|
103
|
+
|
|
104
|
+
# assert response.status_code == 200
|
|
105
|
+
# assert b"Admin" in response.data
|
|
106
|
+
# assert b"id" in response.data
|
|
107
|
+
# assert b"Email" in response.data
|
|
108
|
+
# assert b"Password" in response.data
|
|
109
|
+
# assert b"Roles" in response.data
|
|
110
|
+
|
|
111
|
+
# def test_admin_add_get(self, test_client):
|
|
112
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
113
|
+
# module_info = json.load(f)
|
|
114
|
+
# response = test_client.get(f"{module_info['url_prefix']}/add")
|
|
115
|
+
|
|
116
|
+
# assert response.status_code == 200
|
|
117
|
+
# assert b"Email" in response.data
|
|
118
|
+
# assert b"Password" in response.data
|
|
119
|
+
# assert b"First Name" in response.data
|
|
120
|
+
# assert b"Last Name" in response.data
|
|
121
|
+
# assert b"Admin User" in response.data
|
|
122
|
+
|
|
123
|
+
# def test_admin_add_unique_user_post(self, test_client):
|
|
124
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
125
|
+
# module_info = json.load(f)
|
|
126
|
+
# role1 = Role.create(name="test1-role")
|
|
127
|
+
# role2 = Role.create(name="test2-role")
|
|
128
|
+
# data = {
|
|
129
|
+
# "email": "test@gmail.com",
|
|
130
|
+
# "password": "pass",
|
|
131
|
+
# "first_name": "Test",
|
|
132
|
+
# "last_name": "User",
|
|
133
|
+
# "is_admin": "",
|
|
134
|
+
# f"role_{role1.id}": "",
|
|
135
|
+
# f"role_{role2.id}": "",
|
|
136
|
+
# }
|
|
137
|
+
|
|
138
|
+
# test_client.post(
|
|
139
|
+
# f"{module_info['url_prefix']}/add",
|
|
140
|
+
# data=data,
|
|
141
|
+
# follow_redirects=True,
|
|
142
|
+
# )
|
|
143
|
+
# test_user = User.query.filter(User.email == "test@gmail.com").scalar()
|
|
144
|
+
|
|
145
|
+
# assert test_user is not None
|
|
146
|
+
# assert test_user.first_name == "Test"
|
|
147
|
+
# assert test_user.last_name == "User"
|
|
148
|
+
# assert test_user.is_admin is False
|
|
149
|
+
# assert test_user.roles is not None
|
|
150
|
+
# assert len(test_user.roles) == 2
|
|
151
|
+
# assert role1.users[0].email == "test@gmail.com"
|
|
152
|
+
# assert role2.users[0].email == "test@gmail.com"
|
|
153
|
+
|
|
154
|
+
# def test_admin_add_existing_user_post(self, test_client):
|
|
155
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
156
|
+
# module_info = json.load(f)
|
|
157
|
+
# User.create(email="test@gmail.com", password="pass")
|
|
158
|
+
# data = {
|
|
159
|
+
# "email": "test@gmail.com",
|
|
160
|
+
# "password": "pass",
|
|
161
|
+
# "first_name": "Test",
|
|
162
|
+
# "last_name": "User",
|
|
163
|
+
# "is_admin": "",
|
|
164
|
+
# }
|
|
165
|
+
|
|
166
|
+
# response = test_client.post(
|
|
167
|
+
# f"{module_info['url_prefix']}/add",
|
|
168
|
+
# data=data,
|
|
169
|
+
# follow_redirects=True,
|
|
170
|
+
# )
|
|
171
|
+
# test_users = User.query.filter(User.email == "test@gmail.com").count()
|
|
172
|
+
|
|
173
|
+
# assert response.status_code == 200
|
|
174
|
+
# assert b"User with same email already exists" in response.data
|
|
175
|
+
# assert test_users == 1
|
|
176
|
+
|
|
177
|
+
# def test_admin_delete_existing_user_get(self, test_client):
|
|
178
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
179
|
+
# module_info = json.load(f)
|
|
180
|
+
# user = User(email="test@gmail.com", password="pass")
|
|
181
|
+
# role1 = Role(name="test1-role")
|
|
182
|
+
# role2 = Role(name="test2-role")
|
|
183
|
+
# user.roles = [role1, role2]
|
|
184
|
+
# user.save()
|
|
185
|
+
|
|
186
|
+
# response = test_client.get(
|
|
187
|
+
# f"{module_info['url_prefix']}/delete/{user.id}",
|
|
188
|
+
# follow_redirects=True,
|
|
189
|
+
# )
|
|
190
|
+
# test_user = User.query.filter(User.email == user.email).scalar()
|
|
191
|
+
# test_roles = Role.query.count()
|
|
192
|
+
# user_role = (
|
|
193
|
+
# User.query.join(role_user_bridge)
|
|
194
|
+
# .join(Role)
|
|
195
|
+
# .filter(User.id == user.id)
|
|
196
|
+
# .scalar()
|
|
197
|
+
# )
|
|
198
|
+
|
|
199
|
+
# assert response.status_code == 200
|
|
200
|
+
# assert test_user is None
|
|
201
|
+
# assert user_role is None
|
|
202
|
+
# assert test_roles == 2
|
|
203
|
+
|
|
204
|
+
# def test_admin_delete_nonexisting_user_get(self, test_client):
|
|
205
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
206
|
+
# module_info = json.load(f)
|
|
207
|
+
# response = test_client.get(
|
|
208
|
+
# f"{module_info['url_prefix']}/delete/some_id",
|
|
209
|
+
# follow_redirects=True,
|
|
210
|
+
# )
|
|
211
|
+
|
|
212
|
+
# assert response.status_code == 200
|
|
213
|
+
# assert b"Unable to delete. Invalid user id" in response.data
|
|
214
|
+
|
|
215
|
+
# def test_admin_edit_existing_user_get(self, test_client):
|
|
216
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
217
|
+
# module_info = json.load(f)
|
|
218
|
+
# user = User.create(email="test@gmail.com", password="pass")
|
|
219
|
+
|
|
220
|
+
# response = test_client.get(
|
|
221
|
+
# f"{module_info['url_prefix']}/edit/{user.id}",
|
|
222
|
+
# )
|
|
223
|
+
|
|
224
|
+
# assert response.status_code == 200
|
|
225
|
+
# assert b"test@gmail.com" in response.data
|
|
226
|
+
# assert b"Edit User" in response.data
|
|
227
|
+
|
|
228
|
+
# def test_admin_edit_nonexisting_user_get(self, test_client):
|
|
229
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
230
|
+
# module_info = json.load(f)
|
|
231
|
+
# response = test_client.get(
|
|
232
|
+
# f"{module_info['url_prefix']}/edit/some-id", follow_redirects=True
|
|
233
|
+
# )
|
|
234
|
+
|
|
235
|
+
# assert response.status_code == 200
|
|
236
|
+
# assert b"Invalid user id" in response.data
|
|
237
|
+
# assert request.path == f"{module_info['url_prefix']}/"
|
|
238
|
+
|
|
239
|
+
# def test_admin_update_user_adding_new_roles_to_user(self, test_client):
|
|
240
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
241
|
+
# module_info = json.load(f)
|
|
242
|
+
# user = User.create(email="foo@gmail.com", password="pass")
|
|
243
|
+
# role1 = Role.create(name="test1-role")
|
|
244
|
+
# role2 = Role.create(name="test2-role")
|
|
245
|
+
# data = {
|
|
246
|
+
# "id": str(user.id),
|
|
247
|
+
# "email": "bar@gmail.com",
|
|
248
|
+
# "password": "newpass",
|
|
249
|
+
# "first_name": "Test",
|
|
250
|
+
# "last_name": "User",
|
|
251
|
+
# "is_admin": "",
|
|
252
|
+
# f"role_{role1.id}": "",
|
|
253
|
+
# f"role_{role2.id}": "",
|
|
254
|
+
# }
|
|
255
|
+
|
|
256
|
+
# response = test_client.post(
|
|
257
|
+
# f"{module_info['url_prefix']}/update",
|
|
258
|
+
# data=data,
|
|
259
|
+
# follow_redirects=True,
|
|
260
|
+
# )
|
|
261
|
+
|
|
262
|
+
# assert response.status_code == 200
|
|
263
|
+
# assert user.email == "bar@gmail.com"
|
|
264
|
+
# assert user.check_password("newpass")
|
|
265
|
+
# assert user.first_name == "Test"
|
|
266
|
+
# assert user.last_name == "User"
|
|
267
|
+
# assert len(user.roles) == 2
|
|
268
|
+
# assert role1.users[0].email == "bar@gmail.com"
|
|
269
|
+
# assert role2.users[0].email == "bar@gmail.com"
|
|
270
|
+
|
|
271
|
+
# def test_admin_update_user_remove_old_roles_from_user(self, test_client):
|
|
272
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
273
|
+
# module_info = json.load(f)
|
|
274
|
+
# user = User(email="foo@gmail.com", password="pass", is_admin=True)
|
|
275
|
+
# user.is_admin = True
|
|
276
|
+
# role1 = Role(name="test1-role")
|
|
277
|
+
# role2 = Role(name="test2-role")
|
|
278
|
+
# user.roles = [role1, role2]
|
|
279
|
+
# user.save()
|
|
280
|
+
# data = {
|
|
281
|
+
# "id": str(user.id),
|
|
282
|
+
# "email": "bar@gmail.com",
|
|
283
|
+
# "first_name": "Test",
|
|
284
|
+
# "last_name": "User",
|
|
285
|
+
# "password": " ",
|
|
286
|
+
# "is_admin": None,
|
|
287
|
+
# }
|
|
288
|
+
|
|
289
|
+
# response = test_client.post(
|
|
290
|
+
# f"{module_info['url_prefix']}/update",
|
|
291
|
+
# data=data,
|
|
292
|
+
# follow_redirects=True,
|
|
293
|
+
# )
|
|
294
|
+
|
|
295
|
+
# assert response.status_code == 200
|
|
296
|
+
# assert user.email == "bar@gmail.com"
|
|
297
|
+
# assert user.check_password("pass")
|
|
298
|
+
# assert len(user.roles) == 0
|
|
299
|
+
# assert len(role1.users) == 0
|
|
300
|
+
# assert len(role2.users) == 0
|
|
301
|
+
|
|
302
|
+
# def test_admin_roles_get(self, test_client):
|
|
303
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
304
|
+
# module_info = json.load(f)
|
|
305
|
+
# response = test_client.get(f"{module_info['url_prefix']}/roles")
|
|
306
|
+
|
|
307
|
+
# assert response.status_code == 200
|
|
308
|
+
# assert b"Roles" in response.data
|
|
309
|
+
|
|
310
|
+
# def test_admin_roles_add_nonexisting_role_post(self, test_client):
|
|
311
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
312
|
+
# module_info = json.load(f)
|
|
313
|
+
# response = test_client.post(
|
|
314
|
+
# f"{module_info['url_prefix']}/roles/add",
|
|
315
|
+
# data=dict(name="new-role"),
|
|
316
|
+
# follow_redirects=True,
|
|
317
|
+
# )
|
|
318
|
+
|
|
319
|
+
# role = Role.query.filter(Role.name == "new-role").scalar()
|
|
320
|
+
# role_count = Role.query.count()
|
|
321
|
+
|
|
322
|
+
# assert response.status_code == 200
|
|
323
|
+
# assert role is not None
|
|
324
|
+
# assert role_count == 1
|
|
325
|
+
|
|
326
|
+
# def test_admin_roles_add_existing_role_post(self, test_client):
|
|
327
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
328
|
+
# module_info = json.load(f)
|
|
329
|
+
# Role.create(name="new-role")
|
|
330
|
+
|
|
331
|
+
# response = test_client.post(
|
|
332
|
+
# f"{module_info['url_prefix']}/roles/add",
|
|
333
|
+
# data=dict(name="new-role"),
|
|
334
|
+
# follow_redirects=True,
|
|
335
|
+
# )
|
|
336
|
+
# role_count = Role.query.count()
|
|
337
|
+
# role = Role.query.filter(Role.name == "new-role").scalar()
|
|
338
|
+
|
|
339
|
+
# assert response.status_code == 200
|
|
340
|
+
# assert b"Role already exists" in response.data
|
|
341
|
+
# assert role is not None
|
|
342
|
+
# assert role_count == 1
|
|
343
|
+
|
|
344
|
+
# def test_admin_roles_delete_nonexisting_role_get(self, test_client):
|
|
345
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
346
|
+
# module_info = json.load(f)
|
|
347
|
+
# response = test_client.get(
|
|
348
|
+
# f"{module_info['url_prefix']}/roles/some-id/delete",
|
|
349
|
+
# follow_redirects=True,
|
|
350
|
+
# )
|
|
351
|
+
|
|
352
|
+
# assert response.status_code == 200
|
|
353
|
+
# assert request.path == f"{module_info['url_prefix']}/roles"
|
|
354
|
+
# assert b"Unable to delete. Invalid role id" in response.data
|
|
355
|
+
|
|
356
|
+
# def test_admin_roles_delete_existing_role_get(self, test_client):
|
|
357
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
358
|
+
# module_info = json.load(f)
|
|
359
|
+
# role1 = Role.create(name="new-role1")
|
|
360
|
+
# role2 = Role.create(name="new-role2")
|
|
361
|
+
|
|
362
|
+
# response = test_client.get(
|
|
363
|
+
# f"{module_info['url_prefix']}/roles/{role1.id}/delete",
|
|
364
|
+
# follow_redirects=True,
|
|
365
|
+
# )
|
|
366
|
+
# roles = Role.query.all()
|
|
367
|
+
|
|
368
|
+
# assert response.status_code == 200
|
|
369
|
+
# assert request.path == f"{module_info['url_prefix']}/roles"
|
|
370
|
+
# assert b"Role successfully deleted" in response.data
|
|
371
|
+
# assert roles is not None
|
|
372
|
+
# assert roles[0].name == role2.name
|
|
373
|
+
# assert len(roles) == 1
|
|
374
|
+
|
|
375
|
+
# def test_admin_roles_update_nonexisting_role_post(self, test_client):
|
|
376
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
377
|
+
# module_info = json.load(f)
|
|
378
|
+
# response = test_client.post(
|
|
379
|
+
# f"{module_info['url_prefix']}/roles/update",
|
|
380
|
+
# data=dict(role_id="some-id"),
|
|
381
|
+
# follow_redirects=True,
|
|
382
|
+
# )
|
|
383
|
+
# roles = Role.query.count()
|
|
384
|
+
|
|
385
|
+
# assert response.status_code == 200
|
|
386
|
+
# assert request.path == f"{module_info['url_prefix']}/roles"
|
|
387
|
+
# assert b"Unable to update. Role does not exist" in response.data
|
|
388
|
+
# assert roles == 0
|
|
389
|
+
|
|
390
|
+
# def test_admin_roles_update_existing_role_post(self, test_client):
|
|
391
|
+
# with open(os.path.join(module_path, "info.json")) as f:
|
|
392
|
+
# module_info = json.load(f)
|
|
393
|
+
# new_role = Role.create(name="new-role1")
|
|
394
|
+
|
|
395
|
+
# response = test_client.post(
|
|
396
|
+
# f"{module_info['url_prefix']}/roles/update",
|
|
397
|
+
# data=dict(role_id=new_role.id, role_name="update-role"),
|
|
398
|
+
# follow_redirects=True,
|
|
399
|
+
# )
|
|
400
|
+
# role = Role.query.scalar()
|
|
401
|
+
|
|
402
|
+
# assert response.status_code == 200
|
|
403
|
+
# assert request.path == f"{module_info['url_prefix']}/roles"
|
|
404
|
+
# assert b"Role successfully updated" in response.data
|
|
405
|
+
# assert role is not None
|
|
406
|
+
# assert role.name == "update-role"
|
|
File without changes
|