aded table, pagination, edit, view pages, ad tested it with person roles. errors like 404 don't work correctly yet

master
Kerem Yollu 12 months ago
parent 86b4f16a8e
commit 1d3fd5086f

@ -0,0 +1,7 @@
from minibase.app import db, create_app, bcrypt
from minibase.blueprints.user.models import Users, User_Roles
from minibase.blueprints.geography.models import Countries
app = create_app()
app.app_context().push()

Binary file not shown.

@ -38,8 +38,11 @@ def create_app():
# import and register all blueprints. # import and register all blueprints.
from minibase.blueprints.main.routes import main from minibase.blueprints.main.routes import main
from minibase.blueprints.user.routes import user from minibase.blueprints.user.routes import user
from minibase.blueprints.errors.routes import errors
app.register_blueprint(main, url_prefix='/') app.register_blueprint(main, url_prefix='/')
app.register_blueprint(user, url_prefix='/user') app.register_blueprint(user, url_prefix='/user')
app.register_blueprint(errors, url_prefix='/errors')
return app return app

@ -0,0 +1,32 @@
from minibase.app import db
class table_printable:
def __init__(self, table, link_for_item, item_to_be_linked):
self.titles = table.__table__.columns.keys()
self.lines = table.query.all()
self.link_for_item = link_for_item
self.item_to_be_linked = item_to_be_linked
self.paginate = 0
# https://www.youtube.com/watch?v=PSWf2TjTGNY&list=PL-osiE80TeTs4UjLw5MM6OjgkjFeUxCYH&index=9
class table_printable_paginate:
def __init__(self, table, current_page, per_page, link_for_item, item_to_be_linked):
self.titles = table.__table__.columns.keys()
self.lines = table.query.paginate(page=current_page, per_page=per_page)
self.link_for_item = link_for_item
self.item_to_be_linked = item_to_be_linked
self.paginate = 1
def dbAdd(dbClass):
db.session.add(dbClass)
def dbCommit():
db.session.commit()
def dbAddAndCommit(dbClass):
db.session.add(dbClass)
db.session.commit()

@ -0,0 +1,8 @@
from flask import Blueprint, render_template
import minibase.theme as theme
errors = Blueprint('errors', __name__, template_folder='templates')
@errors.app_errorhandler(403)
def error_403(error):
return render_template('errors/403.html', theme=theme), 403

@ -0,0 +1,9 @@
{% extends "base.html" %}
{% block content %}
<div class="content-section">
<h1>Your dont have permission to do that (403)</h1>
<p>PLease Check your account and try again</p>
</div>
{% endblock content %}

@ -1,10 +1,11 @@
from flask import Flask, url_for, render_template, Blueprint from flask import render_template, Blueprint, request
from flask_login import current_user from flask_login import login_user, current_user, logout_user, login_required
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField from wtforms import StringField
import minibase.theme as theme import minibase.theme as theme
from minibase.blueprints.user.models import Users, User_Roles from minibase.blueprints.user.models import Users, User_Roles
from sqlalchemy import inspect from minibase.blueprints.geography.models import Countries
import minibase.blueprints.database.utils as dbUtils
main = Blueprint('main', __name__, template_folder='templates') main = Blueprint('main', __name__, template_folder='templates')
@ -15,9 +16,5 @@ class LoginForm(FlaskForm):
@main.route('/', methods=['GET', 'POST']) @main.route('/', methods=['GET', 'POST'])
def index(): def index():
titles = User_Roles.__table__.columns.keys() info = dir(current_user)
items = User_Roles.query.all() return render_template('/main/index.html', info=info, theme=theme)
item_link = "/user/link/"
return render_template('/main/index.html', theme=theme, table=items, titles=titles, item_link=item_link)

@ -4,5 +4,5 @@
{% block content %} {% block content %}
<h1>Hompage of Minibase</h1> <h1>Hompage of Minibase</h1>
{% include 'table.html' %} {{ info }}
{% endblock %} {% endblock %}

@ -1,6 +1,6 @@
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed from flask_wtf.file import FileField, FileAllowed
from wtforms import StringField, PasswordField, SubmitField, BooleanField from wtforms import StringField, PasswordField, SubmitField, BooleanField, URLField
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
from flask_login import current_user from flask_login import current_user
from minibase.blueprints.user.models import Users from minibase.blueprints.user.models import Users
@ -71,3 +71,11 @@ class resetPasswordForm(FlaskForm): # Defines the form class to be used for pas
password = PasswordField('Password', validators=[DataRequired()]) password = PasswordField('Password', validators=[DataRequired()])
password_confirm = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')]) password_confirm = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Reset Password') submit = SubmitField('Reset Password')
class updateRoleForm(FlaskForm):
id = StringField('ID', render_kw={'disabled':''})
role = StringField('Role', validators=[DataRequired(), Length(min=4, max=20)])
description = StringField('Description', validators=[DataRequired(), Length(min=4, max=200)])
submit = SubmitField()

@ -1,14 +1,15 @@
from flask import current_app from flask import current_app
from itsdangerous import URLSafeTimedSerializer as Serializer from itsdangerous import URLSafeTimedSerializer as Serializer
from datetime import datetime from minibase.app import db, login_manager
from minibase.app import db, login_manager, bcrypt
from flask_login import UserMixin from flask_login import UserMixin
# The Default User Loading proccess # The Default User Loading proccess
@login_manager.user_loader @login_manager.user_loader
def load_user(user_id): def load_user(user_id):
return Users.query.get(int(user_id)) return Users.query.get(int(user_id))
class Users(db.Model, UserMixin): class Users(db.Model, UserMixin):
__tablename__ = 'users' __tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -16,9 +17,9 @@ class Users(db.Model, UserMixin):
email_account = db.Column(db.String(120), unique=True, nullable=False) email_account = db.Column(db.String(120), unique=True, nullable=False)
email_comm = db.Column(db.String(120), unique=False, nullable=False) email_comm = db.Column(db.String(120), unique=False, nullable=False)
role = db.Column(db.String(120), unique=False, nullable=False, default='user') role = db.Column(db.String(120), unique=False, nullable=False, default='user')
image_file = db.Column(db.String(20), nullable=False, default='default.jpg') image_file = db.Column(db.String(20), nullable=False, default='def_avatar.png')
password = db.Column(db.String(60), nullable=False) password = db.Column(db.String(60), nullable=False)
role_id = db.Column(db.Integer, db.ForeignKey('user_roles.id'), nullable=False) role_id = db.Column(db.Integer, db.ForeignKey('user_roles.id'), nullable=False, default=2)
role = db.relationship('User_Roles', backref=db.backref('users', lazy=True)) role = db.relationship('User_Roles', backref=db.backref('users', lazy=True))
def get_reset_token(self, expires_sec=1800): def get_reset_token(self, expires_sec=1800):

@ -2,8 +2,10 @@ from flask import render_template, url_for, flash, redirect, request, Blueprint
from flask_login import login_user, current_user, logout_user, login_required from flask_login import login_user, current_user, logout_user, login_required
from minibase.app import db, bcrypt from minibase.app import db, bcrypt
import minibase.theme as theme import minibase.theme as theme
from minibase.blueprints.user.models import Users from minibase.blueprints.user.models import Users, User_Roles
from minibase.blueprints.user.forms import registrationForm, loginForm, updateAccountForm, resetPasswordForm, requestResetForm import minibase.blueprints.database.utils as dbUtils
import minibase.blueprints.user.utils as UserUtils
from minibase.blueprints.user.forms import registrationForm, loginForm, updateAccountForm, resetPasswordForm, requestResetForm, updateRoleForm
from minibase.blueprints.user.utils import save_picture, send_reset_email from minibase.blueprints.user.utils import save_picture, send_reset_email
# Declaring a blueprint # Declaring a blueprint
@ -18,9 +20,7 @@ def register():
form = registrationForm() form = registrationForm()
if form.validate_on_submit(): if form.validate_on_submit():
hashed_pw = bcrypt.generate_password_hash(form.password.data).decode('utf-8') hashed_pw = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
user = Users(username=form.username.data, email_account=form.email.data, email_comm=form.email.data, password=hashed_pw) dbUtils.dbAddAndCommit(Users(username=form.username.data, email_account=form.email.data, email_comm=form.email.data, password=hashed_pw))
db.session.add(user)
db.session.commit()
flash(f'{"Your account has been created you can now log in!"}', 'success') flash(f'{"Your account has been created you can now log in!"}', 'success')
return redirect(url_for('user.login')) return redirect(url_for('user.login'))
@ -36,7 +36,7 @@ def login():
form = loginForm() form = loginForm()
if form.validate_on_submit(): if form.validate_on_submit():
user = Users.query.filter_by(email_account=form.email.data).first() user = UserUtils.dbGetMailFirst(form.email.data)
if user and bcrypt.check_password_hash(user.password, form.password.data): if user and bcrypt.check_password_hash(user.password, form.password.data):
login_user(user, remember=form.remember.data) login_user(user, remember=form.remember.data)
next_page = request.args.get('next') next_page = request.args.get('next')
@ -86,7 +86,7 @@ def reset_request():
return redirect(url_for('main.index')) return redirect(url_for('main.index'))
form = requestResetForm() form = requestResetForm()
if form.validate_on_submit(): if form.validate_on_submit():
user = Users.query.filter_by(email_account=form.email.data).first() user = UserUtils.dbGetMailFirst(form.email.data)
send_reset_email(user) send_reset_email(user)
flash('An Email has been sent with instruction to reset your password', 'warning') flash('An Email has been sent with instruction to reset your password', 'warning')
return render_template('user/reset_request.html', return render_template('user/reset_request.html',
@ -112,3 +112,42 @@ def reset_token(token):
return render_template('user/reset_token.html', return render_template('user/reset_token.html',
theme=theme, theme=theme,
form=form) form=form)
@user.route("/roles", methods=['GET', 'POST'])
@login_required
def roles():
page=request.args.get('page', 1, type=int)
table=dbUtils.table_printable_paginate(User_Roles, page, 20, 'role/edit/', 'id')
return(render_template('view.html', theme=theme, table=table, title="User Roles"))
class bottons:
def __init__(self, name, link):
self.name = name
self.link = link
@user.route("/role/edit/<int:id>", methods=['GET', 'POST'])
@login_required
def updateRole(id):
if current_user.role.id == 1:
extraButton=[]
extraButton.append(bottons('Back To Roles', url_for('user.roles')))
role = UserUtils.queryRoleById(id)
form = updateRoleForm()
if form.validate_on_submit():
role.title = form.role.data
role.description = form.description.data
dbUtils.dbCommit()
flash('The role has been updated', 'success')
return redirect(url_for('user.updateRole', id=role.id))
elif request.method == 'GET':
form.id.data = role.id
form.role.data = role.name
form.description.data = role.description
return(render_template('edit.html', theme=theme, form=form, title=current_user.role.name, extraButtons=extraButton))
else:
flash('You have no permission to do that', 'danger')
return redirect(url_for('main.index'))

@ -1,20 +1,26 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<div class="container rounded-5 mt-5 mb-5" style="{{ theme.form.div_style }};"> <div class="container-fluid rounded-5 mt-5 mb-5" style="{{ theme.form.div_style }};">
<div class="row"> <div class="row">
<div class="col-md-3 border-right"> <div class="col-md-3 border-right">
<div class="d-flex flex-column align-items-center text-center p-3 py-5"> <div class="d-flex flex-column align-items-center text-center p-3 py-5">
<img class="rounded-circle mt-4 border-info" width="150px" src="{{ image_file }}"> <img class="rounded-circle mt-4 border-info" width="150px" src="{{ image_file }}">
<h2 class="account-heading" style="color: {{ theme.orange }};">{{ current_user.username }}</h2> <h2 class="account-heading" style="color: {{ theme.orange }};">{{ current_user.username }}</h2>
<h5 class="account-heading" style="color: {{ theme.light_blue }};">{{ current_user.email_account }}</h5> <h5 class="account-heading" style="color: {{ theme.light_blue }};">{{ current_user.email_account }}</h5>
<div class="p-3 py-5">
<h4 class="account-heading" style="color: {{ theme.yellow }};">Permission</h4>
<h5 class="account-heading" style="color: {{ theme.yellow }};">{{ current_user.role.name }}</h5>
</div>
</div> </div>
</div> </div>
<div class="col-md-5 border-right"> <div class="col-md-5 border-right">
<div class="p-3 py-5"> <div class="p-3 py-5">
{% include 'form.html' %} {% include 'form.html' %}
</div> </div>
</div> </div>
<div class="col-md-4 rounded"> <div class="col-md-4 rounded">
<div class="p-3 py-5"> <div class="p-3 py-5">
{% include 'form.html' %} {% include 'form.html' %}

@ -4,7 +4,10 @@ from PIL import Image
from flask import url_for, current_app from flask import url_for, current_app
from flask_mail import Message from flask_mail import Message
from minibase.app import mail from minibase.app import mail
from minibase.blueprints.user.models import Users, User_Roles
def dbGetMailFirst(mail):
return Users.query.filter_by(email_account=mail).first()
def save_picture(form_picture): def save_picture(form_picture):
random_hex = secrets.token_hex(8) random_hex = secrets.token_hex(8)
@ -28,3 +31,7 @@ def send_reset_email(user):
If you didn't make this request, then simply ingnore this email and no chancges will be made. If you didn't make this request, then simply ingnore this email and no chancges will be made.
''' '''
mail.send(msg) mail.send(msg)
def queryRoleById(id):
return User_Roles.query.get_or_404(id)

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 KiB

@ -14,7 +14,6 @@
<body style="{{ theme.maineTheme.div_style}}"> <body style="{{ theme.maineTheme.div_style}}">
{% include 'navbar.html' %} {% include 'navbar.html' %}
<main> <main>
<!-- This part will catch anny messages that we whant to send when something has been updated --> <!-- This part will catch anny messages that we whant to send when something has been updated -->
{% with messages = get_flashed_messages(with_categories=true) %} {% with messages = get_flashed_messages(with_categories=true) %}
@ -33,5 +32,8 @@
{% block content %}{% endblock %} {% block content %}{% endblock %}
</main> </main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.25/js/jquery.dataTables.js"></script>
<script type="text/javascript" charset="utf8" src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
{% block scripts %}{% endblock %}
</body> </body>
</html> </html>

@ -0,0 +1,22 @@
{% extends "base.html" %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<div class="container-fluid text-center rounded-3 mt-2 mb-2" style="{{ theme.form.div_style }};">
<h1 class="account-heading" style="color: {{ theme.orange }};">{{ title }}</h1>
</div>
<div class="container-fluid rounded-3 " style="{{ theme.form.div_style }};">
{% include 'form.html' %}
{% if extraButtons %}
</div>
<div class="container-fluid rounded-3 mt-2 mb-2" style="{{ theme.form.div_style }};">
<div class="btn-group">
<br>
{% for button in extraButtons %}
<li><a href ="{{ button.link }}" class="{{ theme.form.submit_class }}" style="{{ theme.form.submit_style }}">{{ button.name }}<a>
{% endfor %}
<br>
</div>
{% endif %}
</div>
{% endblock content %}

@ -29,8 +29,9 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</fieldset> </fieldset>
<div class="form-group"> <div class="form-groupe">
<br> <br>
{{ form.submit(class=theme.form.submit_class, style=theme.form.submit_style) }} {{ form.submit(class=theme.form.submit_class, style=theme.form.submit_style) }}
<br>
</div> </div>
</form> </form>

@ -0,0 +1,14 @@
<ul class="pagination">
{# https://www.youtube.com/watch?v=PSWf2TjTGNY&list=PL-osiE80TeTs4UjLw5MM6OjgkjFeUxCYH&index=9 #}
{% for page_num in table.lines.iter_pages(left_edge=1, right_edge=1, left_current=1, right_current=2) %}
{% if page_num %}
{% if table.lines.page == page_num %}
<li class="page-item"><a class="btn btn-info mt-1" href="{{ url_for( request.endpoint , page=page_num) }}">{{ page_num }}</a></li>
{% else %}
<li class="page-item"><a class="btn btn-outline-info mt-1" href="{{ url_for( request.endpoint , page=page_num) }}">{{ page_num }}</a></li>
{% endif %}
{% else %}
<h4 class="account-heading " style="color: {{ theme.orange }};">...</h4>
{% endif %}
{% endfor %}
</ul>

@ -1,25 +1,59 @@
<div class="table-responsive"> <div class="table-responsive rounded " style="background-color: {{ theme.black }};">
<table class="table table-dark table-striped-columns table-hover"> <table id="data" class="table table-dark table-striped-columns table-hover mt-3 mb-3 mr-3 ml-3">
<thead> <thead>
{{ info }} {{ info }}
<tr> <tr>
{% for title in titles %} {% for title in table.titles %}
<th scope="col">{{ title }}</th> <th scope="col">{{ title }}</th>
{% endfor %} {% endfor %}
</tr> </tr>
</thead> </thead>
<tbody class="table-group-divider"> <tbody class="table-group-divider">
{% for item in table %} {% if table.paginate == 1 %}
{% for line in table.lines.items %}
<tr> <tr>
{% for title in titles %} {% for title in table.titles %}
{% if title == 'id' %} {% if title == table.item_to_be_linked %}
<th scope="col"><a href="{{ item_link }}{{ item|attr(title) }}">{{ item|attr(title) }}</a></th> <th scope="col" style="white-space: nowrap;"><a href="{{ table.link_for_item }}{{ line|attr(title) }}">{{ line|attr(title) }}</a></th>
{% else %} {% else %}
<th scope="col">{{ item|attr(title) }}</th> <th scope="col" style="white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">{{ line|attr(title) }}</th>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</tr> </tr>
{% endfor %} {% endfor %}
{% else %}
{% for line in table.lines %}
<tr>
{% for title in table.titles %}
{% if title == table.item_to_be_linked %}
<th scope="col"><a href="{{ table.link_for_item }}{{ line|attr(title) }}">{{ line|attr(title) }}</a></th>
{% else %}
<th scope="col">{{ line|attr(title) }}</th>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
{% endif %}
</tbody> </tbody>
</table> </table>
{% if table.paginate == 1 %}
{% if table.lines.pages < 2 %}
{% else %}
{% include 'pagination.html' %}
{% endif %}
{% endif %}
</div> </div>
{% block scripts %}
<script>
$(document).ready(function () {
$('#data').DataTable({
columns: [
null,
{searchable: false},
{orderable: false, searchable: false},
{orderable: false, searchable: false},
null],
});
});
</script>
{% endblock %}

@ -0,0 +1,10 @@
{% extends "base.html" %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<div class="container-fluid text-center rounded-3 mt-2 mb-2" style="{{ theme.form.div_style }};">
<h1 class="account-heading" style="color: {{ theme.orange }};">{{ title }}</h1>
</div>
<div class="container-fluid rounded-3 mt-2 mb-2" style="{{ theme.form.div_style }};">
{% include 'table.html' %}
</div>
{% endblock content %}

@ -12,7 +12,7 @@ class maineTheme:
div_style = "background-color:" + yellow div_style = "background-color:" + yellow
class form: class form:
div_style = "background-color:" + black div_style = "background-color:" + black + "; " +" width:98%;"
div_class = "container rounded p-4 py-4" div_class = "container rounded p-4 py-4"
div_error_class = "invalid-feedback" div_error_class = "invalid-feedback"
input_label_class = "col-form-label" input_label_class = "col-form-label"
@ -20,7 +20,7 @@ class form:
check_label_class = "form-check-label" check_label_class = "form-check-label"
check_label_style = input_label_style check_label_style = input_label_style
check_class = "form-check-input" check_class = "form-check-input"
submit_class = "btn btn-outline-info" submit_class = "btn btn-outline-info mb-2 mt-2"
submit_style = "" submit_style = ""
input_error_class = "form-control form-control-lg is-invalid" input_error_class = "form-control form-control-lg is-invalid"
input_class = "form-control form-control-lg" input_class = "form-control form-control-lg"

Loading…
Cancel
Save