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.
from minibase.blueprints.main.routes import main
from minibase.blueprints.user.routes import user
from minibase.blueprints.errors.routes import errors
app.register_blueprint(main, url_prefix='/')
app.register_blueprint(user, url_prefix='/user')
app.register_blueprint(errors, url_prefix='/errors')
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_login import current_user
from flask import render_template, Blueprint, request
from flask_login import login_user, current_user, logout_user, login_required
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms import StringField
import minibase.theme as theme
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')
@ -15,9 +16,5 @@ class LoginForm(FlaskForm):
@main.route('/', methods=['GET', 'POST'])
def index():
titles = User_Roles.__table__.columns.keys()
items = User_Roles.query.all()
item_link = "/user/link/"
return render_template('/main/index.html', theme=theme, table=items, titles=titles, item_link=item_link)
info = dir(current_user)
return render_template('/main/index.html', info=info, theme=theme)

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

@ -1,6 +1,6 @@
from flask_wtf import FlaskForm
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 flask_login import current_user
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_confirm = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('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 itsdangerous import URLSafeTimedSerializer as Serializer
from datetime import datetime
from minibase.app import db, login_manager, bcrypt
from minibase.app import db, login_manager
from flask_login import UserMixin
# The Default User Loading proccess
@login_manager.user_loader
def load_user(user_id):
return Users.query.get(int(user_id))
class Users(db.Model, UserMixin):
__tablename__ = 'users'
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_comm = db.Column(db.String(120), unique=False, nullable=False)
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)
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))
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 minibase.app import db, bcrypt
import minibase.theme as theme
from minibase.blueprints.user.models import Users
from minibase.blueprints.user.forms import registrationForm, loginForm, updateAccountForm, resetPasswordForm, requestResetForm
from minibase.blueprints.user.models import Users, User_Roles
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
# Declaring a blueprint
@ -18,9 +20,7 @@ def register():
form = registrationForm()
if form.validate_on_submit():
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)
db.session.add(user)
db.session.commit()
dbUtils.dbAddAndCommit(Users(username=form.username.data, email_account=form.email.data, email_comm=form.email.data, password=hashed_pw))
flash(f'{"Your account has been created you can now log in!"}', 'success')
return redirect(url_for('user.login'))
@ -36,7 +36,7 @@ def login():
form = loginForm()
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):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
@ -86,7 +86,7 @@ def reset_request():
return redirect(url_for('main.index'))
form = requestResetForm()
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)
flash('An Email has been sent with instruction to reset your password', 'warning')
return render_template('user/reset_request.html',
@ -112,3 +112,42 @@ def reset_token(token):
return render_template('user/reset_token.html',
theme=theme,
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" %}
{% 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="col-md-3 border-right">
<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 }}">
<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>
<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 class="col-md-5 border-right">
<div class="p-3 py-5">
{% include 'form.html' %}
</div>
</div>
<div class="col-md-4 rounded">
<div class="p-3 py-5">
{% include 'form.html' %}

@ -4,7 +4,10 @@ from PIL import Image
from flask import url_for, current_app
from flask_mail import Message
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):
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.
'''
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}}">
{% include 'navbar.html' %}
<main>
<!-- This part will catch anny messages that we whant to send when something has been updated -->
{% with messages = get_flashed_messages(with_categories=true) %}
@ -33,5 +32,8 @@
{% block content %}{% endblock %}
</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 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>
</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 %}
{% endfor %}
</fieldset>
<div class="form-group">
<div class="form-groupe">
<br>
{{ form.submit(class=theme.form.submit_class, style=theme.form.submit_style) }}
<br>
</div>
</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">
<table class="table table-dark table-striped-columns table-hover">
<div class="table-responsive rounded " style="background-color: {{ theme.black }};">
<table id="data" class="table table-dark table-striped-columns table-hover mt-3 mb-3 mr-3 ml-3">
<thead>
{{ info }}
<tr>
{% for title in titles %}
{% for title in table.titles %}
<th scope="col">{{ title }}</th>
{% endfor %}
</tr>
</thead>
<tbody class="table-group-divider">
{% for item in table %}
<tr>
{% for title in titles %}
{% if title == 'id' %}
<th scope="col"><a href="{{ item_link }}{{ item|attr(title) }}">{{ item|attr(title) }}</a></th>
{% else %}
<th scope="col">{{ item|attr(title) }}</th>
{% endif %}
{% if table.paginate == 1 %}
{% for line in table.lines.items %}
<tr>
{% for title in table.titles %}
{% if title == table.item_to_be_linked %}
<th scope="col" style="white-space: nowrap;"><a href="{{ table.link_for_item }}{{ line|attr(title) }}">{{ line|attr(title) }}</a></th>
{% else %}
<th scope="col" style="white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">{{ line|attr(title) }}</th>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tr>
{% 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>
</table>
{% if table.paginate == 1 %}
{% if table.lines.pages < 2 %}
{% else %}
{% include 'pagination.html' %}
{% endif %}
{% endif %}
</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
class form:
div_style = "background-color:" + black
div_style = "background-color:" + black + "; " +" width:98%;"
div_class = "container rounded p-4 py-4"
div_error_class = "invalid-feedback"
input_label_class = "col-form-label"
@ -20,7 +20,7 @@ class form:
check_label_class = "form-check-label"
check_label_style = input_label_style
check_class = "form-check-input"
submit_class = "btn btn-outline-info"
submit_class = "btn btn-outline-info mb-2 mt-2"
submit_style = ""
input_error_class = "form-control form-control-lg is-invalid"
input_class = "form-control form-control-lg"

Loading…
Cancel
Save