diff --git a/src/buybuilds/__init__.py b/src/buybuilds/__init__.py index 4b17992..2b5cec1 100644 --- a/src/buybuilds/__init__.py +++ b/src/buybuilds/__init__.py @@ -5,28 +5,13 @@ from dotenv import load_dotenv from flask import jsonify from werkzeug.middleware.proxy_fix import ProxyFix from argon2 import PasswordHasher + # Load environment variables from .env file load_dotenv() -DEFAULTS = { - 'SECRET_KEY': '', - 'BEHIND_PROXY': False -} - -def get(key, type: type = str): - value = os.environ.get(key) - - if value is None: - return DEFAULTS[key] - - if type == bool: - value = value.lower() == 'true' - - return value - app = Flask(__name__) -app.config['SECRET_KEY'] = get('SECRET_KEY') -app.config['BEHIND_PROXY'] = get('BEHIND_PROXY', bool) +app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY') +app.config['BEHIND_PROXY'] = os.environ.get('BEHIND_PROXY') == 'true' app.url_map.strict_slashes = False @@ -72,10 +57,6 @@ register_blueprints(app) from .scheduler import initialize_scheduler initialize_scheduler(app) -# TODO find a better way to do this -from .roles import Role -app.jinja_env.globals['Role'] = Role - # Flask CLI command to run migrations @app.cli.command("run-migrations") def run_migrations_command(): diff --git a/src/buybuilds/blueprints/admin/__init__.py b/src/buybuilds/blueprints/admin/__init__.py index f79a740..8211412 100644 --- a/src/buybuilds/blueprints/admin/__init__.py +++ b/src/buybuilds/blueprints/admin/__init__.py @@ -31,7 +31,7 @@ def index(): @login_required @require_role(Role.ADMIN) def dashboard(): - return render_template('dashboard.html') + return render_template('admin_dashboard.html') @blueprint.route('/manage_user/', methods=['GET', 'POST']) @login_required @@ -49,4 +49,4 @@ def manage_user(id: int): form.email.data = user.email form.username.data = user.username - return render_template('manage_user.html', user=user) \ No newline at end of file + return render_template('admin_manage_user.html', user=user) \ No newline at end of file diff --git a/src/buybuilds/blueprints/admin/templates/dashboard.html b/src/buybuilds/blueprints/admin/templates/admin_dashboard.html similarity index 100% rename from src/buybuilds/blueprints/admin/templates/dashboard.html rename to src/buybuilds/blueprints/admin/templates/admin_dashboard.html diff --git a/src/buybuilds/blueprints/admin/templates/manage_user.html b/src/buybuilds/blueprints/admin/templates/admin_manage_user.html similarity index 100% rename from src/buybuilds/blueprints/admin/templates/manage_user.html rename to src/buybuilds/blueprints/admin/templates/admin_manage_user.html diff --git a/src/buybuilds/blueprints/auth/__init__.py b/src/buybuilds/blueprints/auth/__init__.py index dd20ee5..fee16a1 100644 --- a/src/buybuilds/blueprints/auth/__init__.py +++ b/src/buybuilds/blueprints/auth/__init__.py @@ -67,11 +67,11 @@ def login(): if user and user.verify_password(password): login_user(user) - return redirect_to_next(default=url_for('.login_success')) + return redirect_to_next() else: flash('Invalid username or password', 'error') - return render_template('login.html', form=form) + return render_template('auth_login.html', form=form) @blueprint.route('/register', methods=['GET', 'POST']) def register(): @@ -92,15 +92,11 @@ def register(): return redirect(url_for('.register_success')) - return render_template('register.html', form=form) + return render_template('auth_register.html', form=form) @blueprint.route('/register_success') def register_success(): - return render_template('register_success.html') - -@blueprint.route('/login_success') -def login_success(): - return redirect_to_next() + return render_template('auth_register_success.html') @blueprint.route('/logout') def logout(): diff --git a/src/buybuilds/blueprints/auth/templates/login.html b/src/buybuilds/blueprints/auth/templates/auth_login.html similarity index 100% rename from src/buybuilds/blueprints/auth/templates/login.html rename to src/buybuilds/blueprints/auth/templates/auth_login.html diff --git a/src/buybuilds/blueprints/auth/templates/register.html b/src/buybuilds/blueprints/auth/templates/auth_register.html similarity index 100% rename from src/buybuilds/blueprints/auth/templates/register.html rename to src/buybuilds/blueprints/auth/templates/auth_register.html diff --git a/src/buybuilds/blueprints/auth/templates/register_success.html b/src/buybuilds/blueprints/auth/templates/auth_register_success.html similarity index 100% rename from src/buybuilds/blueprints/auth/templates/register_success.html rename to src/buybuilds/blueprints/auth/templates/auth_register_success.html diff --git a/src/buybuilds/blueprints/publisher/__init__.py b/src/buybuilds/blueprints/publisher/__init__.py index 38f5737..4da48a7 100644 --- a/src/buybuilds/blueprints/publisher/__init__.py +++ b/src/buybuilds/blueprints/publisher/__init__.py @@ -1,6 +1,7 @@ from flask import Blueprint, jsonify, Flask, request, render_template, redirect, url_for, flash -from wtforms import Form, StringField, IntegerField, validators -from flask_login import login_required +from wtforms import StringField, IntegerField, validators, SubmitField +from flask_wtf import FlaskForm +from flask_login import login_required, current_user from buybuilds.models.resource import Resource from buybuilds import db @@ -17,9 +18,11 @@ blueprint = Blueprint( def register_routes(app: Flask): app.register_blueprint(blueprint) -class CreateResourceForm(Form): +class CreateResourceForm(FlaskForm): name = StringField('Name', [validators.Length(min=2, max=30)]) price = IntegerField('Price', [validators.NumberRange(min=0, max=100)]) + description = StringField('Short description', [validators.Length(max=70)]) + submit = SubmitField('Submit') @blueprint.route('/', methods=['GET']) def index(): @@ -29,7 +32,7 @@ def index(): @login_required @require_role(Role.PUBLISHER) def dashboard(): - return render_template('dashboard.html') + return render_template('publisher_dashboard.html') @blueprint.route('/create_resource', methods=['GET', 'POST']) @login_required @@ -40,13 +43,17 @@ def create_resource(): if form.validate_on_submit(): name = form.name.data price = form.price.data + description = form.description.data - resource = Resource(name=name, price=price * 100) - db.session.add(resource) - db.session.commit() + resource = Resource.create( + name=name, + price=int(price * 100), + description=form.description.data, + user=current_user + ) flash("Resource created successfully", "success") return redirect(url_for('resource.resource', resource_id=resource.id)) - return render_template('create_resource.html', form=form) + return render_template('publisher_create_resource.html', form=form) diff --git a/src/buybuilds/blueprints/publisher/templates/dashboard.html b/src/buybuilds/blueprints/publisher/templates/dashboard.html deleted file mode 100644 index 06cd858..0000000 --- a/src/buybuilds/blueprints/publisher/templates/dashboard.html +++ /dev/null @@ -1,34 +0,0 @@ -{% extends 'base.html' %} - -{% block title %}Publisher Dashboard{% endblock %} - -{% block header %} -

Publisher Dashboard

-{% endblock %} - -{% block content %} -

All Resources

- - {% if resources %} - - - - - - - - - - {% for resource in resources %} - - - - - - {% endfor %} - -
IDNamePrice
{{ resource.id }}{{ resource.name }}{{ resource.price }}
- {% else %} -

No resources found. Create a new resource

- {% endif %} -{% endblock %} \ No newline at end of file diff --git a/src/buybuilds/blueprints/publisher/templates/create_resource.html b/src/buybuilds/blueprints/publisher/templates/publisher_create_resource.html similarity index 100% rename from src/buybuilds/blueprints/publisher/templates/create_resource.html rename to src/buybuilds/blueprints/publisher/templates/publisher_create_resource.html diff --git a/src/buybuilds/blueprints/publisher/templates/publisher_dashboard.html b/src/buybuilds/blueprints/publisher/templates/publisher_dashboard.html new file mode 100644 index 0000000..d310dc2 --- /dev/null +++ b/src/buybuilds/blueprints/publisher/templates/publisher_dashboard.html @@ -0,0 +1,33 @@ +{% extends 'base.html' %} + +{% block title %}Publisher Dashboard{% endblock %} + +{% block header %} +

Publisher Dashboard

+{% endblock %} + +{% block content %} +

Your Resources

+ + {% if current_user.resources %} +
+ {% for resource in current_user.resources %} +
+
+
+
{{ resource.name }}
+

+ {{ resource.description }} +
+ {{ render_icon('tag-fill') }} {{ resource.price / 100 }}$ +

+ View / Edit +
+
+
+ {% endfor %} +
+ {% else %} +

No resources found. Create a new resource

+ {% endif %} +{% endblock %} \ No newline at end of file diff --git a/src/buybuilds/blueprints/resource/__init__.py b/src/buybuilds/blueprints/resource/__init__.py index d32eee7..edff591 100644 --- a/src/buybuilds/blueprints/resource/__init__.py +++ b/src/buybuilds/blueprints/resource/__init__.py @@ -5,6 +5,7 @@ from buybuilds.models.resource import Resource blueprint = Blueprint( name='resource', import_name=__name__, + template_folder='templates', url_prefix='/resource' ) diff --git a/src/buybuilds/blueprints/resource/templates/resource.html b/src/buybuilds/blueprints/resource/templates/resource.html index e8fa1d3..dc9da3f 100644 --- a/src/buybuilds/blueprints/resource/templates/resource.html +++ b/src/buybuilds/blueprints/resource/templates/resource.html @@ -7,8 +7,38 @@ {% endblock %} {% block content %} -

ID: {{ resource.id }}

-

Name: {{ resource.name }}

-

Price: {{ resource.price }}

-

Publisher: {{ resource.user.username }}

+
+
+

Lorem ipsum

+

Lorem ipsum

+

Lorem ipsum

+
+
+
+
+

{{ resource.name }}

+
+
+

{{ resource.description }}

+
+ +
+
+ + +
+ +
+
{% endblock %} \ No newline at end of file diff --git a/src/buybuilds/database.py b/src/buybuilds/database.py index 845226a..d76d402 100644 --- a/src/buybuilds/database.py +++ b/src/buybuilds/database.py @@ -27,12 +27,12 @@ def create_database(app: Flask) -> SQLAlchemy: def initialize_database(app: Flask, db: SQLAlchemy): """Create database tables and initialize default data.""" - from .models import User + from .models import User, Resource from .roles import Role with app.app_context(): app.logger.info("Creating database tables...") - db.create_all() # Should now create all tables including Inquiry + db.create_all() # Run migrations after creating tables # This ensures any new columns added to existing tables are properly added diff --git a/src/buybuilds/login.py b/src/buybuilds/login.py index d2cd971..2ef5061 100644 --- a/src/buybuilds/login.py +++ b/src/buybuilds/login.py @@ -14,6 +14,10 @@ def create_login_manager(app): @login_manager.user_loader def user_loader(id): return User.query.get(id) + + + # TODO find a better way to do this + app.jinja_env.globals['Role'] = Role return login_manager diff --git a/src/buybuilds/models/resource.py b/src/buybuilds/models/resource.py index f94dfe2..faa221b 100644 --- a/src/buybuilds/models/resource.py +++ b/src/buybuilds/models/resource.py @@ -3,15 +3,20 @@ from .user import User class Resource(db.Model): id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(30), unique=True, nullable=False, index=True) price = db.Column(db.Integer, nullable=False) + description = db.Column(db.String(70)) + user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False, index=True) user = db.relationship('User', back_populates='resources') @classmethod - def create(cls, name: str, price: int, user: User) -> 'Resource': - resource = cls(name=name, price=price, user=user) - db.session.add(resource) + def create(cls, name: str, price: int, user: User, description: str = None) -> 'Resource': + resource = cls(name=name, price=price, description=description) + user.resources.append(resource) + db.session.commit() + return resource \ No newline at end of file diff --git a/src/buybuilds/templates/base.html b/src/buybuilds/templates/base.html index a170616..e5806bf 100644 --- a/src/buybuilds/templates/base.html +++ b/src/buybuilds/templates/base.html @@ -1,6 +1,6 @@ {% from 'bootstrap5/form.html' import render_form %} {% from 'bootstrap5/nav.html' import render_nav_item %} -{% from 'bootstrap5/utils.html' import render_messages %} +{% from 'bootstrap5/utils.html' import render_messages, render_icon %} @@ -23,7 +23,9 @@ {% if current_user.is_authenticated %} {% if current_user.role >= Role.ADMIN %} {{ render_nav_item('admin.dashboard', 'Admin Dashboard') }} - {% elif current_user.role >= Role.PUBLISHER %} + {% endif %} + + {% if current_user.role >= Role.PUBLISHER %} {{ render_nav_item('publisher.dashboard', 'Publisher Dashboard') }} {% endif %} {% endif %} @@ -32,17 +34,17 @@ {% if current_user.is_authenticated %} {% else %} - Login + {{ render_icon('door-open-fill') }} Login {% endif %}