shopyo-auth 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_auth-1.0.0/PKG-INFO +13 -0
- shopyo_auth-1.0.0/pyproject.toml +36 -0
- shopyo_auth-1.0.0/setup.cfg +4 -0
- shopyo_auth-1.0.0/shopyo_auth/__init__.py +20 -0
- shopyo_auth-1.0.0/shopyo_auth/decorators.py +15 -0
- shopyo_auth-1.0.0/shopyo_auth/forms.py +71 -0
- shopyo_auth-1.0.0/shopyo_auth/info.json +7 -0
- shopyo_auth-1.0.0/shopyo_auth/models.py +150 -0
- shopyo_auth-1.0.0/shopyo_auth/static/style.css +7 -0
- shopyo_auth-1.0.0/shopyo_auth/templates/shopyo_auth/blocks/login_form.html +36 -0
- shopyo_auth-1.0.0/shopyo_auth/templates/shopyo_auth/blocks/register_form.html +44 -0
- shopyo_auth-1.0.0/shopyo_auth/templates/shopyo_auth/emails/activate_user.html +16 -0
- shopyo_auth-1.0.0/shopyo_auth/templates/shopyo_auth/emails/activate_user.txt +13 -0
- shopyo_auth-1.0.0/shopyo_auth/templates/shopyo_auth/login.html +46 -0
- shopyo_auth-1.0.0/shopyo_auth/templates/shopyo_auth/register.html +26 -0
- shopyo_auth-1.0.0/shopyo_auth/templates/shopyo_auth/shop_login.html +19 -0
- shopyo_auth-1.0.0/shopyo_auth/templates/shopyo_auth/unconfirmed.html +19 -0
- shopyo_auth-1.0.0/shopyo_auth/upload.py +23 -0
- shopyo_auth-1.0.0/shopyo_auth/view.py +142 -0
- shopyo_auth-1.0.0/shopyo_auth.egg-info/PKG-INFO +13 -0
- shopyo_auth-1.0.0/shopyo_auth.egg-info/SOURCES.txt +25 -0
- shopyo_auth-1.0.0/shopyo_auth.egg-info/dependency_links.txt +1 -0
- shopyo_auth-1.0.0/shopyo_auth.egg-info/requires.txt +1 -0
- shopyo_auth-1.0.0/shopyo_auth.egg-info/top_level.txt +2 -0
- shopyo_auth-1.0.0/tests/test_auth_forms.py +1 -0
- shopyo_auth-1.0.0/tests/test_auth_functional.py +289 -0
- shopyo_auth-1.0.0/tests/test_auth_models.py +276 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: shopyo_auth
|
|
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_auth"
|
|
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_auth.__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_auth = ["static/**", "templates/**", "*.json"]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from flask import Flask
|
|
4
|
+
from .view import module_blueprint
|
|
5
|
+
|
|
6
|
+
__version__ = "1.0.0"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ShopyoAuth:
|
|
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_auth"] = self
|
|
19
|
+
bp = module_blueprint
|
|
20
|
+
app.register_blueprint(bp)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
|
|
3
|
+
from flask import redirect
|
|
4
|
+
from flask import url_for
|
|
5
|
+
from flask_login import current_user
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def check_confirmed(func):
|
|
9
|
+
@wraps(func)
|
|
10
|
+
def decorated_function(*args, **kwargs):
|
|
11
|
+
if current_user.is_email_confirmed:
|
|
12
|
+
return func(*args, **kwargs)
|
|
13
|
+
return redirect(url_for("auth.unconfirmed"))
|
|
14
|
+
|
|
15
|
+
return decorated_function
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from flask_wtf import FlaskForm
|
|
2
|
+
from sqlalchemy import func
|
|
3
|
+
from wtforms import PasswordField
|
|
4
|
+
from wtforms.fields import EmailField
|
|
5
|
+
from wtforms.validators import DataRequired
|
|
6
|
+
from wtforms.validators import Email
|
|
7
|
+
from wtforms.validators import EqualTo
|
|
8
|
+
from wtforms.validators import InputRequired
|
|
9
|
+
from wtforms.validators import Length
|
|
10
|
+
from wtforms.validators import ValidationError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LoginForm(FlaskForm):
|
|
14
|
+
email = EmailField(
|
|
15
|
+
"email",
|
|
16
|
+
[DataRequired(), Email(message="Not a valid email address.")],
|
|
17
|
+
render_kw={"class": "form-control", "autocomplete": "off"},
|
|
18
|
+
)
|
|
19
|
+
password = PasswordField(
|
|
20
|
+
"Password",
|
|
21
|
+
[DataRequired()],
|
|
22
|
+
render_kw={"class": "form-control", "autocomplete": "off"},
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class RegistrationForm(FlaskForm):
|
|
27
|
+
"""Registration Form"""
|
|
28
|
+
|
|
29
|
+
email = EmailField(
|
|
30
|
+
"email_label",
|
|
31
|
+
[DataRequired(), Email(message="Not a valid email address.")],
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
password = PasswordField(
|
|
35
|
+
"New Password",
|
|
36
|
+
validators=[
|
|
37
|
+
InputRequired("Password is required"),
|
|
38
|
+
Length(
|
|
39
|
+
min=6,
|
|
40
|
+
max=25,
|
|
41
|
+
message="Password must be between 6 and 25 characters",
|
|
42
|
+
),
|
|
43
|
+
EqualTo("confirm", message="Passwords must match"),
|
|
44
|
+
],
|
|
45
|
+
)
|
|
46
|
+
confirm = PasswordField(
|
|
47
|
+
"Repeat Password",
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
def validate_email(self, field):
|
|
51
|
+
"""
|
|
52
|
+
Inline validator for email. Checks to see if a user object with
|
|
53
|
+
entered email already present in the database
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
field : The form field that contains email data.
|
|
57
|
+
|
|
58
|
+
Raises:
|
|
59
|
+
ValidationError: if the username entered in the field is already
|
|
60
|
+
in the database
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
from .models import User
|
|
64
|
+
except Exception as e:
|
|
65
|
+
raise e
|
|
66
|
+
user = User.query.filter(
|
|
67
|
+
func.lower(User.email) == func.lower(field.data)
|
|
68
|
+
).scalar()
|
|
69
|
+
|
|
70
|
+
if user is not None:
|
|
71
|
+
raise ValidationError(f"email '{field.data}' is already in use.")
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""
|
|
2
|
+
.. module:: AdminModels
|
|
3
|
+
:synopsis: Contains model of a user Record
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import datetime
|
|
8
|
+
|
|
9
|
+
from flask import current_app
|
|
10
|
+
from flask_login import AnonymousUserMixin
|
|
11
|
+
from flask_login import UserMixin
|
|
12
|
+
|
|
13
|
+
from init import db
|
|
14
|
+
from init import login_manager
|
|
15
|
+
|
|
16
|
+
from itsdangerous import URLSafeTimedSerializer
|
|
17
|
+
from sqlalchemy.ext.hybrid import hybrid_property
|
|
18
|
+
from werkzeug.security import check_password_hash
|
|
19
|
+
from werkzeug.security import generate_password_hash
|
|
20
|
+
|
|
21
|
+
from shopyo.api.models import PkModel
|
|
22
|
+
|
|
23
|
+
role_user_bridge = db.Table(
|
|
24
|
+
"role_user_bridge",
|
|
25
|
+
db.Column(
|
|
26
|
+
"user_id",
|
|
27
|
+
db.Integer(),
|
|
28
|
+
db.ForeignKey("users.id", ondelete="CASCADE"),
|
|
29
|
+
primary_key=True,
|
|
30
|
+
),
|
|
31
|
+
db.Column(
|
|
32
|
+
"role_id",
|
|
33
|
+
db.Integer(),
|
|
34
|
+
db.ForeignKey("roles.id", ondelete="CASCADE"),
|
|
35
|
+
primary_key=True,
|
|
36
|
+
),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class AnonymousUser(AnonymousUserMixin):
|
|
41
|
+
"""Anonymous user class"""
|
|
42
|
+
|
|
43
|
+
def __init__(self):
|
|
44
|
+
self.username = "guest"
|
|
45
|
+
self.email = "<anonymous-user-no-email>"
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def is_email_confirmed(self):
|
|
49
|
+
is_disabled = False
|
|
50
|
+
|
|
51
|
+
if "EMAIL_CONFIRMATION_DISABLED" in current_app.config:
|
|
52
|
+
is_disabled = current_app.config["EMAIL_CONFIRMATION_DISABLED"]
|
|
53
|
+
|
|
54
|
+
if is_disabled is not True:
|
|
55
|
+
is_disabled = False
|
|
56
|
+
|
|
57
|
+
return is_disabled
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def is_admin(self):
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
def __repr__(self):
|
|
64
|
+
return f"<AnonymousUser {self.username}>"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
login_manager.anonymous_user = AnonymousUser
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class User(UserMixin, PkModel):
|
|
71
|
+
"""The user of the app"""
|
|
72
|
+
|
|
73
|
+
__tablename__ = "users"
|
|
74
|
+
|
|
75
|
+
username = db.Column(db.String(100), unique=True)
|
|
76
|
+
_password = db.Column(db.String(128), nullable=False)
|
|
77
|
+
first_name = db.Column(db.String(128))
|
|
78
|
+
last_name = db.Column(db.String(128))
|
|
79
|
+
is_admin = db.Column(db.Boolean, default=False)
|
|
80
|
+
email = db.Column(db.String(120), unique=True, nullable=False)
|
|
81
|
+
date_registered = db.Column(
|
|
82
|
+
db.DateTime, nullable=False, default=datetime.datetime.now()
|
|
83
|
+
)
|
|
84
|
+
is_email_confirmed = db.Column(db.Boolean(), nullable=False, default=False)
|
|
85
|
+
email_confirm_date = db.Column(db.DateTime)
|
|
86
|
+
|
|
87
|
+
# A user can have many roles and a role can have many users
|
|
88
|
+
roles = db.relationship(
|
|
89
|
+
"Role",
|
|
90
|
+
secondary=role_user_bridge,
|
|
91
|
+
backref="users",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def __repr__(self):
|
|
95
|
+
return f"<User-id: {self.id}, User-email: {self.email}>"
|
|
96
|
+
|
|
97
|
+
@hybrid_property
|
|
98
|
+
def password(self):
|
|
99
|
+
return self._password
|
|
100
|
+
|
|
101
|
+
@password.setter
|
|
102
|
+
def password(self, plaintext):
|
|
103
|
+
# the default hashing method is pbkdf2:sha256
|
|
104
|
+
self._password = generate_password_hash(plaintext)
|
|
105
|
+
|
|
106
|
+
def check_password(self, password):
|
|
107
|
+
return check_password_hash(self._password, password)
|
|
108
|
+
|
|
109
|
+
def generate_confirmation_token(self):
|
|
110
|
+
serializer = URLSafeTimedSerializer(current_app.config["SECRET_KEY"])
|
|
111
|
+
return serializer.dumps(self.email, salt=current_app.config["PASSWORD_SALT"])
|
|
112
|
+
|
|
113
|
+
def confirm_token(self, token, expiration=3600):
|
|
114
|
+
serializer = URLSafeTimedSerializer(current_app.config["SECRET_KEY"])
|
|
115
|
+
email = False
|
|
116
|
+
try:
|
|
117
|
+
email = serializer.loads(
|
|
118
|
+
token,
|
|
119
|
+
salt=current_app.config["PASSWORD_SALT"],
|
|
120
|
+
max_age=expiration,
|
|
121
|
+
)
|
|
122
|
+
except Exception as e:
|
|
123
|
+
print(f"\nShopyo-LOG, Error at confirm_token: {e}")
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
if email != self.email:
|
|
127
|
+
return False
|
|
128
|
+
|
|
129
|
+
self.is_email_confirmed = True
|
|
130
|
+
self.email_confirm_date = datetime.datetime.now()
|
|
131
|
+
self.update()
|
|
132
|
+
return True
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@login_manager.user_loader
|
|
136
|
+
def load_user(user_id):
|
|
137
|
+
return User.query.get(user_id)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
login_manager.login_view = "shopyo_auth.login"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class Role(PkModel):
|
|
144
|
+
"""A role for a user."""
|
|
145
|
+
|
|
146
|
+
__tablename__ = "roles"
|
|
147
|
+
name = db.Column(db.String(100), nullable=False)
|
|
148
|
+
|
|
149
|
+
def __repr__(self):
|
|
150
|
+
return f"<Role-id: {self.id}, Role-name: {self.name}>"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
|
|
2
|
+
<p class="h2">Login</p>
|
|
3
|
+
<div class="input-group mb-3">
|
|
4
|
+
<div class="input-group-prepend">
|
|
5
|
+
<span class="input-group-text"><i class="fa fa-id-card"></i></span>
|
|
6
|
+
</div>
|
|
7
|
+
{{ form.email() }}
|
|
8
|
+
{% if form.email.errors %}
|
|
9
|
+
<ul class="errors">
|
|
10
|
+
{% for error in form.user_id.errors %}
|
|
11
|
+
<li>{{ error }}</li>
|
|
12
|
+
{% endfor %}
|
|
13
|
+
</ul>
|
|
14
|
+
{% endif %}
|
|
15
|
+
</div>
|
|
16
|
+
<div class="input-group mb-3">
|
|
17
|
+
<div class="input-group-prepend">
|
|
18
|
+
<span class="input-group-text"><i class="fa fa-key"></i></span>
|
|
19
|
+
</div>
|
|
20
|
+
{{ form.password() }}
|
|
21
|
+
{% if form.password.errors %}
|
|
22
|
+
<ul class="errors">
|
|
23
|
+
{% for error in form.password.errors %}
|
|
24
|
+
<li>{{ error }}</li>
|
|
25
|
+
{% endfor %}
|
|
26
|
+
</ul>
|
|
27
|
+
{% endif %}
|
|
28
|
+
</div>
|
|
29
|
+
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
|
30
|
+
|
|
31
|
+
<input
|
|
32
|
+
type="hidden"
|
|
33
|
+
name="next"
|
|
34
|
+
value="{{ request.args.get('next', '') }}"
|
|
35
|
+
/>
|
|
36
|
+
<input type="submit" name="" value="submit" class="btn btn-info">
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<p class="h2">Register</p>
|
|
2
|
+
|
|
3
|
+
<div class="form-group">
|
|
4
|
+
<div class="input-group mb-3">
|
|
5
|
+
<div class="input-group-prepend">
|
|
6
|
+
<span class="input-group-text"><i class="fa fa-id-card"></i></span>
|
|
7
|
+
</div>
|
|
8
|
+
{{ form.email(class_="form-control", placeholder="Email", autocomplete="off", autofocus=true) }}
|
|
9
|
+
</div>
|
|
10
|
+
<ul class="form-errors">
|
|
11
|
+
{% for error in form.email.errors %}
|
|
12
|
+
<li>{{ error }}</li>
|
|
13
|
+
{% endfor %}
|
|
14
|
+
</ul>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="form-group">
|
|
17
|
+
<div class="input-group mb-3">
|
|
18
|
+
<div class="input-group-prepend">
|
|
19
|
+
<span class="input-group-text"><i class="fa fa-key"></i></span>
|
|
20
|
+
</div>
|
|
21
|
+
{{ form.password(class_="form-control", placeholder="Password") }}
|
|
22
|
+
</div>
|
|
23
|
+
<ul class="form-errors">
|
|
24
|
+
{% for error in form.password.errors %}
|
|
25
|
+
<li>{{ error }}</li>
|
|
26
|
+
{% endfor %}
|
|
27
|
+
</ul>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="form-group">
|
|
30
|
+
<div class="input-group mb-3">
|
|
31
|
+
<div class="input-group-prepend">
|
|
32
|
+
<span class="input-group-text"><i class="fa fa-key"></i></span>
|
|
33
|
+
</div>
|
|
34
|
+
{{ form.confirm(class_="form-control", placeholder="Confirm Password") }}
|
|
35
|
+
</div>
|
|
36
|
+
<ul class="form-errors">
|
|
37
|
+
{% for error in form.confirm.errors %}
|
|
38
|
+
<li>{{ error }}</li>
|
|
39
|
+
{% endfor %}
|
|
40
|
+
</ul>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
|
44
|
+
<input type="submit" name="" value="register" class="btn btn-info">
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<p>Dear {{ user.email }},</p>
|
|
2
|
+
|
|
3
|
+
<p>Welcome to <b>Shopyo</b>!</p>
|
|
4
|
+
|
|
5
|
+
<p>
|
|
6
|
+
To confirm your account please <a href="{{ url_for('auth.confirm', token=token, _external=True) }}">click here</a>.
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p>Alternatively, you can paste the following link in your browser's address bar:</p>
|
|
10
|
+
<p>{{ url_for('auth.confirm', token=token, _external=True) }}</p>
|
|
11
|
+
|
|
12
|
+
<p>Sincerely,</p>
|
|
13
|
+
|
|
14
|
+
<p>The Shopyo Team</p>
|
|
15
|
+
|
|
16
|
+
<p><small>Note: replies to this email address are not monitored.</small></p>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Dear {{ user.email }},
|
|
2
|
+
|
|
3
|
+
Welcome to Shopyo!
|
|
4
|
+
|
|
5
|
+
To confirm your account please click on the following link:
|
|
6
|
+
|
|
7
|
+
{{ url_for('auth.confirm', token=token, _external=True) }}
|
|
8
|
+
|
|
9
|
+
Sincerely,
|
|
10
|
+
|
|
11
|
+
The Shopyo Team
|
|
12
|
+
|
|
13
|
+
Note: replies to this email address are not monitored.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{% extends "shopyo_base/main_base.html" %}
|
|
2
|
+
|
|
3
|
+
{% set active_page = "login" %}
|
|
4
|
+
{% block pagehead %}
|
|
5
|
+
<title>{{active_page.capitalize()}}</title>
|
|
6
|
+
<style>
|
|
7
|
+
.hidden {
|
|
8
|
+
display: none;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.show {
|
|
12
|
+
display: inline-block;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.active {
|
|
16
|
+
width: 6rem;
|
|
17
|
+
color: white;
|
|
18
|
+
background-color: #34ce57;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.inactive {
|
|
22
|
+
width: 6rem;
|
|
23
|
+
color: white;
|
|
24
|
+
background-color: #ff253a;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.all_inactive {
|
|
28
|
+
display: none;
|
|
29
|
+
}
|
|
30
|
+
</style>
|
|
31
|
+
|
|
32
|
+
{% endblock %}
|
|
33
|
+
{% block content %}
|
|
34
|
+
|
|
35
|
+
<div class="container col-md-6 off-set-2 text-center test">
|
|
36
|
+
<div class="card">
|
|
37
|
+
<div class="card-body">
|
|
38
|
+
<img src="/static/shopyo.svg" width="175" height="150">
|
|
39
|
+
<form action="{{url_for('shopyo_auth.login')}}" method="POST">
|
|
40
|
+
{%include 'shopyo_auth/blocks/login_form.html'%}
|
|
41
|
+
</form>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
{% endblock %}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{% extends "shopyo_base/main_base.html" %}
|
|
2
|
+
|
|
3
|
+
{% set active_page = "register" %}
|
|
4
|
+
|
|
5
|
+
{% block pagehead %}
|
|
6
|
+
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='modules/box__default/auth/style.css') }}">
|
|
7
|
+
<title>{{ active_page.capitalize() }}</title>
|
|
8
|
+
{% endblock %}
|
|
9
|
+
|
|
10
|
+
{% block content %}
|
|
11
|
+
<div class="container col-md-6 mb-4 off-set-2 text-center">
|
|
12
|
+
<div class="card">
|
|
13
|
+
<div class="card-body">
|
|
14
|
+
<img src="/static/shopyo.svg" width="175" height="150">
|
|
15
|
+
<form action="{{url_for('shopyo_auth.register')}}" method="post">
|
|
16
|
+
{%include 'auth/blocks/register_form.html'%}
|
|
17
|
+
</form>
|
|
18
|
+
<hr>
|
|
19
|
+
<span class="text-muted">
|
|
20
|
+
Have already registered?
|
|
21
|
+
<a href="{{ url_for('shopyo_auth.login') }}">Sign in here</a>
|
|
22
|
+
</span>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
{% endblock %}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{%set active_page = 'shop.html'%}
|
|
2
|
+
{% extends "shop/base.html" %}
|
|
3
|
+
{% block pagehead %}
|
|
4
|
+
|
|
5
|
+
{% endblock %}
|
|
6
|
+
{% block content %}
|
|
7
|
+
<div class="shop-spacer-1">
|
|
8
|
+
</div>
|
|
9
|
+
<div class="container">
|
|
10
|
+
<div class="card">
|
|
11
|
+
<div class="card-body">
|
|
12
|
+
<form action="{{ url_for('auth.shop_login') }}" method="post">
|
|
13
|
+
{%include 'auth/blocks/login_form.html'%}
|
|
14
|
+
</form>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
</div>
|
|
19
|
+
{% endblock %}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{% extends "shopyo_base/main_base.html" %}
|
|
2
|
+
|
|
3
|
+
{% set active_page = "Email Confirmation" %}
|
|
4
|
+
|
|
5
|
+
{% block pagehead %}
|
|
6
|
+
<title>{{ active_page.capitalize() }}</title>
|
|
7
|
+
{% endblock %}
|
|
8
|
+
|
|
9
|
+
{% block content %}
|
|
10
|
+
<div class="container col-md-6 mb-4 off-set-2 text-center">
|
|
11
|
+
<div class="card">
|
|
12
|
+
<div class="card-body">
|
|
13
|
+
<img src="/static/shopyo.svg" width="175" height="150">
|
|
14
|
+
<p>You have not confirmed your account. Email confirmation link was sent to <span class="mark">{{ current_user.email }}</span>. Please check your inbox and your spam folder.</p>
|
|
15
|
+
<p>Didn't get the email?<a href="{{ url_for('auth.resend',_external=True) }}"> Resend</a></p>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
{% endblock %}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from .models import User
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def add_admin(email, password):
|
|
8
|
+
user = User()
|
|
9
|
+
user.email = email
|
|
10
|
+
user.password = password
|
|
11
|
+
user.is_admin = True
|
|
12
|
+
user.is_email_confirmed = True
|
|
13
|
+
user.email_confirm_date = datetime.datetime.now()
|
|
14
|
+
user.save()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def upload(verbose=False):
|
|
18
|
+
with open("config.json") as config:
|
|
19
|
+
config = json.load(config)
|
|
20
|
+
add_admin(config["admin_user"]["email"], config["admin_user"]["password"])
|
|
21
|
+
|
|
22
|
+
if verbose:
|
|
23
|
+
print("[x] Added Admin User")
|