mirror of
https://github.com/StefBuwalda/WebTech.git
synced 2025-11-01 12:19:58 +00:00
Merge branch 'development' into alternate-dashboard
This commit is contained in:
@@ -9,7 +9,7 @@ python -m venv venv
|
|||||||
### Installing required packages
|
### Installing required packages
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
## Setting up the database
|
## Setting up the database (in venv)
|
||||||
### Initialize database
|
### Initialize database
|
||||||
flask --app app.py db init
|
flask --app app.py db init
|
||||||
|
|
||||||
|
|||||||
BIN
__pycache__/app.cpython-312.pyc
Normal file
BIN
__pycache__/app.cpython-312.pyc
Normal file
Binary file not shown.
4
app.py
4
app.py
@@ -1,11 +1,9 @@
|
|||||||
from application import app
|
from application import app
|
||||||
from flask import redirect, url_for
|
from flask import redirect, url_for
|
||||||
from flask_login import login_required # type: ignore
|
|
||||||
|
|
||||||
|
|
||||||
# home route
|
# home route, place holder in case we want a home page
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
@login_required
|
|
||||||
def index():
|
def index():
|
||||||
return redirect(url_for("dash.index"))
|
return redirect(url_for("dash.index"))
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,6 @@ db.init_app(app)
|
|||||||
|
|
||||||
migrate = Migrate(app, db)
|
migrate = Migrate(app, db)
|
||||||
|
|
||||||
# bp import
|
|
||||||
from application.auth.views import auth_blueprint
|
|
||||||
from application.dash.views import dash_blueprint
|
|
||||||
|
|
||||||
# Login manager
|
# Login manager
|
||||||
from application.auth.models import User
|
from application.auth.models import User
|
||||||
@@ -32,6 +29,7 @@ login_manager.init_app(app) # type: ignore
|
|||||||
login_manager.login_view = "auth.login" # type: ignore
|
login_manager.login_view = "auth.login" # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
# Gets all the user data
|
||||||
@login_manager.user_loader # type: ignore
|
@login_manager.user_loader # type: ignore
|
||||||
def load_user(user_id): # type: ignore
|
def load_user(user_id): # type: ignore
|
||||||
return User.query.get(int(user_id)) # type: ignore
|
return User.query.get(int(user_id)) # type: ignore
|
||||||
@@ -39,5 +37,14 @@ def load_user(user_id): # type: ignore
|
|||||||
|
|
||||||
# Blueprint magic
|
# Blueprint magic
|
||||||
|
|
||||||
|
# bp import
|
||||||
|
# Would like to do this at the top of the file,
|
||||||
|
# but can't easily figure out how to do this.
|
||||||
|
# I think everything that the views depend on have to be moved
|
||||||
|
# into a seperate .py and imported.
|
||||||
|
from application.auth.views import auth_blueprint
|
||||||
|
from application.dash.views import dash_blueprint
|
||||||
|
|
||||||
|
# Register blueprints
|
||||||
app.register_blueprint(dash_blueprint, url_prefix="/dash")
|
app.register_blueprint(dash_blueprint, url_prefix="/dash")
|
||||||
app.register_blueprint(auth_blueprint, url_prefix="/auth")
|
app.register_blueprint(auth_blueprint, url_prefix="/auth")
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,16 +3,21 @@ from wtforms import StringField, SubmitField, PasswordField, BooleanField
|
|||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
|
|
||||||
|
|
||||||
|
# Default Form that inherits from FlaskForm and
|
||||||
|
# contains a username, password and submit button
|
||||||
class defaultForm(FlaskForm):
|
class defaultForm(FlaskForm):
|
||||||
username = StringField("Username", validators=[DataRequired()])
|
username = StringField("Username", validators=[DataRequired()])
|
||||||
password = PasswordField("Password", validators=[DataRequired()])
|
password = PasswordField("Password", validators=[DataRequired()])
|
||||||
submit = SubmitField("Submit")
|
submit = SubmitField("Submit")
|
||||||
|
|
||||||
|
|
||||||
|
# LoginForm, contains exactly the same as defaultForm
|
||||||
class LoginForm(defaultForm):
|
class LoginForm(defaultForm):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# RegisterForm that inherits from the default.
|
||||||
|
# Adds a password confirmation and if the user is an admin or not.
|
||||||
class RegisterForm(defaultForm):
|
class RegisterForm(defaultForm):
|
||||||
confirm_password = PasswordField(
|
confirm_password = PasswordField(
|
||||||
"Confirm Password", validators=[DataRequired()]
|
"Confirm Password", validators=[DataRequired()]
|
||||||
@@ -20,6 +25,8 @@ class RegisterForm(defaultForm):
|
|||||||
is_admin = BooleanField("Admin")
|
is_admin = BooleanField("Admin")
|
||||||
|
|
||||||
|
|
||||||
|
# Form to update password information.
|
||||||
|
# Needs a confirmation password and the current password
|
||||||
class UpdateForm(defaultForm):
|
class UpdateForm(defaultForm):
|
||||||
confirm_password = PasswordField(
|
confirm_password = PasswordField(
|
||||||
"Confirm Password", validators=[DataRequired()]
|
"Confirm Password", validators=[DataRequired()]
|
||||||
|
|||||||
@@ -2,14 +2,18 @@ from application import db
|
|||||||
from flask_login import UserMixin # type: ignore
|
from flask_login import UserMixin # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
# User model
|
||||||
class User(db.Model, UserMixin):
|
class User(db.Model, UserMixin):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
username = db.Column(db.String(150), unique=True, nullable=False)
|
username = db.Column(db.String(150), unique=True, nullable=False)
|
||||||
password = db.Column(db.String(150), nullable=False)
|
password = db.Column(db.String(150), nullable=False)
|
||||||
is_admin = db.Column(db.Boolean, default=False)
|
is_admin = db.Column(db.Boolean, default=False)
|
||||||
|
|
||||||
|
# Purely a relationship not a column,
|
||||||
|
# makes all the services accessible through User.services
|
||||||
services = db.relationship("Service", backref="user", lazy="joined")
|
services = db.relationship("Service", backref="user", lazy="joined")
|
||||||
|
|
||||||
|
# Initialize user, prevents red stuff
|
||||||
def __init__(self, username: str, password: str, is_admin: bool = False):
|
def __init__(self, username: str, password: str, is_admin: bool = False):
|
||||||
self.username = username
|
self.username = username
|
||||||
self.password = password
|
self.password = password
|
||||||
|
|||||||
@@ -1,23 +1,22 @@
|
|||||||
from flask import Blueprint, render_template, redirect, url_for
|
from flask import Blueprint, render_template, redirect, url_for, flash
|
||||||
|
|
||||||
from application import db
|
from application import db
|
||||||
from application.auth.models import User
|
from application.auth.models import User
|
||||||
from application.auth.forms import LoginForm
|
from application.auth.forms import LoginForm
|
||||||
from flask_login import ( # type: ignore
|
from flask_login import ( # type: ignore
|
||||||
login_required, # type: ignore
|
|
||||||
login_user, # type: ignore
|
login_user, # type: ignore
|
||||||
logout_user,
|
logout_user,
|
||||||
current_user,
|
current_user,
|
||||||
)
|
)
|
||||||
from werkzeug.security import check_password_hash, generate_password_hash
|
from werkzeug.security import check_password_hash, generate_password_hash
|
||||||
from application.decorators import admin_required
|
from application.decorators import admin_required, login_required
|
||||||
from application.auth.forms import RegisterForm, UpdateForm
|
from application.auth.forms import RegisterForm, UpdateForm
|
||||||
|
|
||||||
auth_blueprint = Blueprint("auth", __name__, template_folder="templates")
|
auth_blueprint = Blueprint("auth", __name__, template_folder="templates")
|
||||||
|
|
||||||
|
|
||||||
# Routes
|
# Add user
|
||||||
@auth_blueprint.route("/register", methods=["GET", "POST"])
|
@auth_blueprint.route("/register_user", methods=["GET", "POST"])
|
||||||
@admin_required
|
@admin_required
|
||||||
def register():
|
def register():
|
||||||
register_form = RegisterForm()
|
register_form = RegisterForm()
|
||||||
@@ -29,14 +28,14 @@ def register():
|
|||||||
is_admin = register_form.is_admin.data
|
is_admin = register_form.is_admin.data
|
||||||
if confirm_password != password:
|
if confirm_password != password:
|
||||||
return render_template(
|
return render_template(
|
||||||
"admin.html",
|
"register_user.html",
|
||||||
form=register_form,
|
form=register_form,
|
||||||
feedback="Passwords don't match, please try again",
|
feedback="Passwords don't match, please try again",
|
||||||
active_page="register",
|
active_page="register",
|
||||||
)
|
)
|
||||||
if User.query.filter_by(username=username).first():
|
if User.query.filter_by(username=username).first():
|
||||||
return render_template(
|
return render_template(
|
||||||
"admin.html",
|
"register_user.html",
|
||||||
form=register_form,
|
form=register_form,
|
||||||
feedback="Username is already taken",
|
feedback="Username is already taken",
|
||||||
active_page="register",
|
active_page="register",
|
||||||
@@ -49,16 +48,17 @@ def register():
|
|||||||
db.session.add(new_user)
|
db.session.add(new_user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return render_template(
|
return render_template(
|
||||||
"admin.html",
|
"register_user.html",
|
||||||
form=RegisterForm(formdata=None),
|
form=RegisterForm(formdata=None),
|
||||||
feedback="User succesfully added",
|
feedback="User succesfully added",
|
||||||
active_page="register",
|
active_page="register",
|
||||||
)
|
)
|
||||||
return render_template(
|
return render_template(
|
||||||
"admin.html", form=register_form, active_page="register"
|
"register_user.html", form=register_form, active_page="register"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Update user (specifically password)
|
||||||
@auth_blueprint.route("/update_user", methods=["GET", "POST"])
|
@auth_blueprint.route("/update_user", methods=["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def update():
|
def update():
|
||||||
@@ -85,10 +85,12 @@ def update():
|
|||||||
)
|
)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
logout_user()
|
logout_user()
|
||||||
|
flash("Password changed succesfully, please log back in")
|
||||||
return redirect(url_for("auth.login"))
|
return redirect(url_for("auth.login"))
|
||||||
return render_template("update_user.html", form=form, active_page="update")
|
return render_template("update_user.html", form=form, active_page="update")
|
||||||
|
|
||||||
|
|
||||||
|
# Login as user or admin
|
||||||
@auth_blueprint.route("/login", methods=["GET", "POST"])
|
@auth_blueprint.route("/login", methods=["GET", "POST"])
|
||||||
def login():
|
def login():
|
||||||
login_form = LoginForm()
|
login_form = LoginForm()
|
||||||
@@ -103,6 +105,7 @@ def login():
|
|||||||
user.password, password # type: ignore
|
user.password, password # type: ignore
|
||||||
):
|
):
|
||||||
login_user(user) # type: ignore
|
login_user(user) # type: ignore
|
||||||
|
flash("Logged in succesfully")
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
else:
|
else:
|
||||||
feedback = "Username or password is incorrect"
|
feedback = "Username or password is incorrect"
|
||||||
@@ -110,8 +113,10 @@ def login():
|
|||||||
return render_template("login.html", form=login_form, feedback=feedback)
|
return render_template("login.html", form=login_form, feedback=feedback)
|
||||||
|
|
||||||
|
|
||||||
|
# Logout
|
||||||
@auth_blueprint.route("/logout")
|
@auth_blueprint.route("/logout")
|
||||||
@login_required
|
@login_required
|
||||||
def logout():
|
def logout():
|
||||||
logout_user()
|
logout_user()
|
||||||
|
flash("Logged out succesfully")
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
|
|||||||
@@ -4,9 +4,19 @@ from wtforms.validators import DataRequired
|
|||||||
from flask_wtf.file import FileField, FileAllowed # type: ignore
|
from flask_wtf.file import FileField, FileAllowed # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
# Form for service on dashboard, connected to database through ORM
|
||||||
class ServiceForm(FlaskForm):
|
class ServiceForm(FlaskForm):
|
||||||
name = StringField("Service name:", validators=[DataRequired()])
|
name = StringField(
|
||||||
url = URLField("Service URL:", validators=[DataRequired()])
|
"Service name:",
|
||||||
|
validators=[DataRequired()],
|
||||||
|
render_kw={"placeholder": "Service Name"},
|
||||||
|
)
|
||||||
|
url = URLField(
|
||||||
|
"Service URL:",
|
||||||
|
validators=[DataRequired()],
|
||||||
|
render_kw={"placeholder": "https://example.com"},
|
||||||
|
)
|
||||||
|
# File field that only allows jpg, jpeg or png
|
||||||
image = FileField(
|
image = FileField(
|
||||||
"Icon:",
|
"Icon:",
|
||||||
validators=[
|
validators=[
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
from application import db
|
from application import db
|
||||||
|
|
||||||
|
|
||||||
|
# Service class for dashboard
|
||||||
class Service(db.Model):
|
class Service(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
name = db.Column(db.String, nullable=False)
|
name = db.Column(db.String, nullable=False)
|
||||||
url = db.Column(db.String, nullable=False)
|
url = db.Column(db.String, nullable=False)
|
||||||
icon = db.Column(db.String, default="google.png")
|
icon = db.Column(db.String, default="google.png")
|
||||||
|
|
||||||
|
# Foreign key to connect to User table
|
||||||
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
|
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
|
||||||
|
|
||||||
|
# Initialize the service (prevents ugly red lines)
|
||||||
def __init__(
|
def __init__(
|
||||||
self, name: str, url: str, user_id: int, icon: str = "google.png"
|
self, name: str, url: str, user_id: int, icon: str = "google.png"
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -22,13 +22,15 @@
|
|||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="threeDotDropdown">
|
<ul class="dropdown-menu" aria-labelledby="threeDotDropdown">
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" href="{{ url_for('dash.edit_service', service_id=service.id) }}">Edit</a>
|
<a class="dropdown-item"
|
||||||
|
href="{{ url_for('dash.edit_service', service_id=service.id) }}">Edit</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<hr class="dropdown-divider">
|
<hr class="dropdown-divider">
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<form action="{{ url_for('dash.delete_item', service_id=service.id) }}" method="POST" style="display:inline;">
|
<form action="{{ url_for('dash.delete_service', service_id=service.id) }}" method="POST"
|
||||||
|
style="display:inline;">
|
||||||
<button style="color: red;" type="submit" class="dropdown-item">Delete</button>
|
<button style="color: red;" type="submit" class="dropdown-item">Delete</button>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
from application import db
|
from application import db
|
||||||
from flask import Blueprint, render_template, redirect, url_for
|
from flask import Blueprint, render_template, redirect, url_for, flash
|
||||||
from application.dash.forms import ServiceForm
|
from application.dash.forms import ServiceForm
|
||||||
from flask_login import login_required, current_user # type: ignore
|
from flask_login import current_user # type: ignore
|
||||||
from application.dash.models import Service
|
from application.dash.models import Service
|
||||||
from application.utils import saveImage
|
from application.utils import saveImage
|
||||||
|
from application.decorators import login_required
|
||||||
|
|
||||||
|
# Dashboard blueprint
|
||||||
dash_blueprint = Blueprint("dash", __name__, template_folder="templates")
|
dash_blueprint = Blueprint("dash", __name__, template_folder="templates")
|
||||||
|
|
||||||
|
|
||||||
|
# index
|
||||||
@dash_blueprint.route("/", methods=["GET", "POST"])
|
@dash_blueprint.route("/", methods=["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def index():
|
def index():
|
||||||
@@ -17,23 +20,27 @@ def index():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dash_blueprint.route("/delete_item/<int:service_id>", methods=["POST"])
|
# Deleting a service
|
||||||
|
@dash_blueprint.route("/delete_service/<int:service_id>", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def delete_item(service_id: int):
|
def delete_service(service_id: int):
|
||||||
service = Service.query.get_or_404(service_id)
|
service = Service.query.get_or_404(service_id)
|
||||||
|
|
||||||
# Check ownership
|
# Check ownership
|
||||||
if service.user_id != current_user.id:
|
if service.user_id != current_user.id:
|
||||||
|
flash("This is not your service!")
|
||||||
return redirect(url_for("dash.index"))
|
return redirect(url_for("dash.index"))
|
||||||
|
|
||||||
db.session.delete(service)
|
db.session.delete(service)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
flash("Service deleted")
|
||||||
return redirect(url_for("dash.index"))
|
return redirect(url_for("dash.index"))
|
||||||
|
|
||||||
|
|
||||||
@dash_blueprint.route("/service", methods=["GET", "POST"])
|
# Add a service
|
||||||
|
@dash_blueprint.route("/add_service", methods=["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def service():
|
def add_service():
|
||||||
service_form = ServiceForm()
|
service_form = ServiceForm()
|
||||||
|
|
||||||
if service_form.validate_on_submit(): # type: ignore
|
if service_form.validate_on_submit(): # type: ignore
|
||||||
@@ -52,17 +59,14 @@ def service():
|
|||||||
) # type: ignore
|
) # type: ignore
|
||||||
db.session.add(new_service)
|
db.session.add(new_service)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return render_template(
|
flash("Service added")
|
||||||
"add_service.html",
|
return redirect(url_for("dash.index"))
|
||||||
form=ServiceForm(formdata=None),
|
|
||||||
feedback="Service succesfully added",
|
|
||||||
active_page="service",
|
|
||||||
)
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"add_service.html", form=service_form, active_page="service"
|
"add_service.html", form=service_form, active_page="service"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Edit service
|
||||||
@dash_blueprint.route(
|
@dash_blueprint.route(
|
||||||
"/edit_service/<int:service_id>", methods=["GET", "POST"]
|
"/edit_service/<int:service_id>", methods=["GET", "POST"]
|
||||||
)
|
)
|
||||||
@@ -88,22 +92,8 @@ def edit_service(service_id: int):
|
|||||||
commit = True
|
commit = True
|
||||||
if commit:
|
if commit:
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return redirect(url_for("dash.index"))
|
flash("Service edited")
|
||||||
|
return redirect(url_for("dash.index"))
|
||||||
# Fill in correct data
|
# Fill in correct data
|
||||||
form = ServiceForm(name=service.name, url=service.url)
|
form = ServiceForm(name=service.name, url=service.url)
|
||||||
return render_template("edit_service.html", form=form)
|
return render_template("edit_service.html", form=form)
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
def saveImage(image: ...):
|
|
||||||
filename = secure_filename(image.filename)
|
|
||||||
save_path = os.path.join(
|
|
||||||
app.config["UPLOAD_FOLDER"], # type: ignore
|
|
||||||
str(current_user.id),
|
|
||||||
filename,
|
|
||||||
)
|
|
||||||
os.makedirs(os.path.dirname(save_path), exist_ok=True)
|
|
||||||
image.save(save_path) # type: ignore
|
|
||||||
filename2 = str(current_user.id) + "/" + filename
|
|
||||||
return filename2
|
|
||||||
"""
|
|
||||||
|
|||||||
@@ -4,13 +4,26 @@ from functools import wraps
|
|||||||
from flask import redirect, url_for
|
from flask import redirect, url_for
|
||||||
|
|
||||||
|
|
||||||
|
# Decorator that checks if the current user is logged in and an admin
|
||||||
|
# Could be shortened by adding the login_required decorator
|
||||||
|
# and removing the logic here
|
||||||
def admin_required(f: Callable[..., Any]) -> Callable[..., Any]:
|
def admin_required(f: Callable[..., Any]) -> Callable[..., Any]:
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def decorated_function(*args: ..., **kwargs: ...):
|
def decorated_function(*args: ..., **kwargs: ...):
|
||||||
if not current_user.is_authenticated:
|
if not current_user.is_authenticated:
|
||||||
return redirect(url_for("login"))
|
return redirect(url_for("auth.login"))
|
||||||
if not current_user.is_admin:
|
if not current_user.is_admin:
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
return decorated_function
|
return decorated_function
|
||||||
|
|
||||||
|
|
||||||
|
def login_required(f: Callable[..., Any]) -> Callable[..., Any]:
|
||||||
|
@wraps(f)
|
||||||
|
def decorated_function(*args: ..., **kwargs: ...):
|
||||||
|
if not current_user.is_authenticated:
|
||||||
|
return redirect(url_for("auth.login"))
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
|
return decorated_function
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {% if active_page == 'service' %}active{% endif %}"
|
<a class="nav-link {% if active_page == 'service' %}active{% endif %}"
|
||||||
href="{{url_for('dash.service')}}">Add service</a>
|
href="{{url_for('dash.add_service')}}">Add service</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if current_user.is_admin %}
|
{% if current_user.is_admin %}
|
||||||
@@ -38,20 +38,46 @@
|
|||||||
</ul>
|
</ul>
|
||||||
{% if current_user.is_authenticated %}
|
{% if current_user.is_authenticated %}
|
||||||
<div class="dropstart">
|
<div class="dropstart">
|
||||||
<button class="btn btn-outline-info" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">
|
<button class="btn btn-outline-info" type="button" id="dropdownMenuButton1"
|
||||||
|
data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
Profile
|
Profile
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-lg-start" aria-labelledby="dropdownMenuButton1">
|
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-lg-start"
|
||||||
|
aria-labelledby="dropdownMenuButton1">
|
||||||
<li><a class="dropdown-item">Username: {{current_user.username}}</a></li>
|
<li><a class="dropdown-item">Username: {{current_user.username}}</a></li>
|
||||||
<li><a class="dropdown-item {% if active_page == 'update' %}active{% endif %}" href="{{url_for('auth.update')}}">Change password</a></li>
|
<li><a class="dropdown-item {% if active_page == 'update' %}active{% endif %}"
|
||||||
<li><hr class="dropdown-divider"></li>
|
href="{{url_for('auth.update')}}">Change password</a></li>
|
||||||
<li><a class="dropdown-item" style="color: tomato;" data-bs-theme="dark" href="{{url_for('auth.logout')}}">Logout</a></li>
|
<li>
|
||||||
|
<hr class="dropdown-divider">
|
||||||
|
</li>
|
||||||
|
<li><a class="dropdown-item" style="color: tomato;" data-bs-theme="dark"
|
||||||
|
href="{{url_for('auth.logout')}}">Logout</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="d-none">
|
||||||
|
<symbol id="check-circle-fill" viewBox="0 0 16 16">
|
||||||
|
<path
|
||||||
|
d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z" />
|
||||||
|
</symbol>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1050;">
|
||||||
|
{% for message in get_flashed_messages() %}
|
||||||
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||||
|
<svg class="bi flex-shrink-0 me-2" width="15" height="15" role="img" aria-label="Success:">
|
||||||
|
<use xlink:href="#check-circle-fill" />
|
||||||
|
</svg>
|
||||||
|
{{message}}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
from werkzeug.utils import secure_filename
|
|
||||||
import os
|
import os
|
||||||
|
from werkzeug.utils import secure_filename
|
||||||
from application import app
|
from application import app
|
||||||
from flask_login import current_user # type: ignore
|
from flask_login import current_user # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
# save image to static folder
|
||||||
def saveImage(image: ...):
|
def saveImage(image: ...):
|
||||||
filename = secure_filename(image.filename)
|
filename = secure_filename(image.filename)
|
||||||
|
# Path should be /application/static/[user_id]/[filename]
|
||||||
save_path = os.path.join(
|
save_path = os.path.join(
|
||||||
app.config["UPLOAD_FOLDER"], # type: ignore
|
app.config["UPLOAD_FOLDER"], # type: ignore
|
||||||
str(current_user.id),
|
str(current_user.id),
|
||||||
filename,
|
filename,
|
||||||
)
|
)
|
||||||
|
# Create path is it doesn't exist
|
||||||
os.makedirs(os.path.dirname(save_path), exist_ok=True)
|
os.makedirs(os.path.dirname(save_path), exist_ok=True)
|
||||||
|
# Save the image
|
||||||
image.save(save_path) # type: ignore
|
image.save(save_path) # type: ignore
|
||||||
filename2 = str(current_user.id) + "/" + filename
|
# Return the filename that is stored in database.
|
||||||
|
# Only done to keep a single default image, this should be done differently
|
||||||
|
filename2 = str(current_user.id) + "/" + filename # [user_id]/[filename]
|
||||||
return filename2
|
return filename2
|
||||||
|
|||||||
11
seed.py
11
seed.py
@@ -3,14 +3,7 @@ from application.dash.models import Service
|
|||||||
from application.auth.models import User
|
from application.auth.models import User
|
||||||
from werkzeug.security import generate_password_hash
|
from werkzeug.security import generate_password_hash
|
||||||
|
|
||||||
"""
|
# User acounts to add
|
||||||
new_strikers = [
|
|
||||||
se(name="Erik", strike="y", age=44),
|
|
||||||
Striker(name="Henk", strike="n", age=88),
|
|
||||||
]
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
new_users = [
|
new_users = [
|
||||||
User(
|
User(
|
||||||
username="admin",
|
username="admin",
|
||||||
@@ -29,6 +22,7 @@ new_users = [
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Services to add
|
||||||
new_services = [
|
new_services = [
|
||||||
Service(name="test123", url="http://google.com", user_id=1),
|
Service(name="test123", url="http://google.com", user_id=1),
|
||||||
# Daan services
|
# Daan services
|
||||||
@@ -51,4 +45,5 @@ with app.app_context():
|
|||||||
# Then add new
|
# Then add new
|
||||||
db.session.add_all(new_services)
|
db.session.add_all(new_services)
|
||||||
db.session.add_all(new_users)
|
db.session.add_all(new_users)
|
||||||
|
# Commit
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB |
Reference in New Issue
Block a user