diff --git a/.test_api.py.swp b/.test_api.py.swp deleted file mode 100644 index 216387f..0000000 Binary files a/.test_api.py.swp and /dev/null differ diff --git a/__pycache__/app.cpython-311.pyc b/__pycache__/app.cpython-311.pyc index e40dc7a..57052dc 100644 Binary files a/__pycache__/app.cpython-311.pyc and b/__pycache__/app.cpython-311.pyc differ diff --git a/__pycache__/app.cpython-312.pyc b/__pycache__/app.cpython-312.pyc deleted file mode 100644 index db39331..0000000 Binary files a/__pycache__/app.cpython-312.pyc and /dev/null differ diff --git a/__pycache__/extensions.cpython-311.pyc b/__pycache__/extensions.cpython-311.pyc new file mode 100644 index 0000000..366fb2f Binary files /dev/null and b/__pycache__/extensions.cpython-311.pyc differ diff --git a/__pycache__/models.cpython-311.pyc b/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000..43158e0 Binary files /dev/null and b/__pycache__/models.cpython-311.pyc differ diff --git a/app.py b/app.py index 47e82f5..4b96350 100644 --- a/app.py +++ b/app.py @@ -1,13 +1,13 @@ import os from flask import Flask, render_template, request, redirect, url_for, session, flash, jsonify, send_from_directory -from flask_sqlalchemy import SQLAlchemy -from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user -from flask_bcrypt import Bcrypt -from werkzeug.utils import secure_filename -from functools import wraps from flask_migrate import Migrate from pdf2image import convert_from_path import subprocess +from werkzeug.utils import secure_filename +from functools import wraps +from extensions import db, bcrypt, login_manager +from models import User, Player, Content # Import the models from models.py +from flask_login import login_user, logout_user, login_required, current_user app = Flask(__name__, instance_relative_config=True) @@ -21,8 +21,9 @@ app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # Ensure the instance folder exists os.makedirs(app.instance_path, exist_ok=True) -db = SQLAlchemy(app) -bcrypt = Bcrypt(app) +db.init_app(app) +bcrypt.init_app(app) +login_manager.init_app(app) UPLOAD_FOLDER = 'static/uploads' app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER @@ -34,7 +35,6 @@ if not os.path.exists(UPLOAD_FOLDER): os.makedirs(UPLOAD_FOLDER) os.makedirs(UPLOAD_FOLDERLOGO) -login_manager = LoginManager(app) login_manager.login_view = 'login' migrate = Migrate(app, db) @@ -43,42 +43,6 @@ migrate = Migrate(app, db) def load_user(user_id): return User.query.get(int(user_id)) -# Modele pentru baza de date -class User(db.Model, UserMixin): - id = db.Column(db.Integer, primary_key=True) - username = db.Column(db.String(80), unique=True, nullable=False) - email = db.Column(db.String(120), unique=True, nullable=False) - password = db.Column(db.String(120), nullable=False) - role = db.Column(db.String(20), nullable=False, default='user') - theme = db.Column(db.String(10), nullable=False, default='light') - -class Player(db.Model): - id = db.Column(db.Integer, primary_key=True) - username = db.Column(db.String(80), unique=True, nullable=False) - hostname = db.Column(db.String(120), unique=True, nullable=False) - password = db.Column(db.String(120), nullable=False) - quickconnect_password = db.Column(db.String(120), nullable=False) - - def verify_quickconnect_code(self, code): - return bcrypt.check_password_hash(self.quickconnect_password, code) - -class Group(db.Model): - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(80), unique=True, nullable=False) - players = db.relationship('Player', secondary='group_player', backref='groups') - -group_player = db.Table('group_player', - db.Column('group_id', db.Integer, db.ForeignKey('group.id'), primary_key=True), - db.Column('player_id', db.Integer, db.ForeignKey('player.id'), primary_key=True) -) - -class Content(db.Model): - id = db.Column(db.Integer, primary_key=True) - file_name = db.Column(db.String(120), nullable=False) - duration = db.Column(db.Integer, nullable=False) - player_id = db.Column(db.Integer, db.ForeignKey('player.id'), nullable=True) - group_id = db.Column(db.Integer, db.ForeignKey('group.id'), nullable=True) - def admin_required(f): @wraps(f) def decorated_function(*args, **kwargs): @@ -95,18 +59,16 @@ def convert_ppt_to_pdf(input_file, output_file): @login_required def dashboard(): players = Player.query.all() - groups = Group.query.all() logo_exists = os.path.exists(os.path.join(app.config['UPLOAD_FOLDERLOGO'], 'logo.png')) - return render_template('dashboard.html', players=players, groups=groups, logo_exists=logo_exists) + return render_template('dashboard.html', players=players, logo_exists=logo_exists) @app.route('/register', methods=['GET', 'POST']) def register(): if request.method == 'POST': username = request.form['username'] - email = request.form['email'] password = request.form['password'] hashed_password = bcrypt.generate_password_hash(password).decode('utf-8') - new_user = User(username=username, email=email, password=hashed_password, role='user') + new_user = User(username=username, password=hashed_password, role='user') db.session.add(new_user) db.session.commit() return redirect(url_for('login')) @@ -157,7 +119,7 @@ def upload_content(): image_filename = f"{os.path.splitext(filename)[0]}_page_{i + 1}.png" image_path = os.path.join(app.config['UPLOAD_FOLDER'], image_filename) image.save(image_path, 'PNG') - new_content = Content(file_name=image_filename, duration=duration, player_id=target_id if target_type == 'player' else None, group_id=target_id if target_type == 'group' else None) + new_content = Content(file_name=image_filename, duration=duration, player_id=target_id if target_type == 'player' else None) db.session.add(new_content) os.remove(file_path) # Remove the original PDF file elif media_type == 'ppt': @@ -171,12 +133,12 @@ def upload_content(): image_filename = f"{os.path.splitext(filename)[0]}_page_{i + 1}.png" image_path = os.path.join(app.config['UPLOAD_FOLDER'], image_filename) image.save(image_path, 'PNG') - new_content = Content(file_name=image_filename, duration=duration, player_id=target_id if target_type == 'player' else None, group_id=target_id if target_type == 'group' else None) + new_content = Content(file_name=image_filename, duration=duration, player_id=target_id if target_type == 'player' else None) db.session.add(new_content) os.remove(file_path) # Remove the original PPT/PPTX file os.remove(pdf_path) # Remove the intermediate PDF file else: - new_content = Content(file_name=filename, duration=duration, player_id=target_id if target_type == 'player' else None, group_id=target_id if target_type == 'group' else None) + new_content = Content(file_name=filename, duration=duration, player_id=target_id if target_type == 'player' else None) db.session.add(new_content) db.session.commit() @@ -186,8 +148,7 @@ def upload_content(): target_id = request.args.get('target_id') return_url = request.args.get('return_url', url_for('dashboard')) players = Player.query.all() - groups = Group.query.all() - return render_template('upload_content.html', target_type=target_type, target_id=target_id, players=players, groups=groups, return_url=return_url) + return render_template('upload_content.html', target_type=target_type, target_id=target_id, players=players, return_url=return_url) @app.route('/admin') @login_required @@ -222,91 +183,14 @@ def delete_user(user_id): @admin_required def create_user(): username = request.form['username'] - email = request.form['email'] password = request.form['password'] role = request.form['role'] hashed_password = bcrypt.generate_password_hash(password).decode('utf-8') - new_user = User(username=username, email=email, password=hashed_password, role=role) + new_user = User(username=username, password=hashed_password, role=role) db.session.add(new_user) db.session.commit() return redirect(url_for('admin')) -@app.route('/group//manage') -@login_required -@admin_required -def manage_group(group_id): - group = Group.query.get_or_404(group_id) - available_players = Player.query.filter(~Player.groups.any(Group.id == group_id)).all() - return render_template('manage_group.html', group=group, available_players=available_players) - -@app.route('/group//add_player', methods=['POST']) -@login_required -@admin_required -def add_player_to_group(group_id): - group = Group.query.get_or_404(group_id) - player_id = request.form['player_id'] - player = Player.query.get_or_404(player_id) - group.players.append(player) - db.session.commit() - return redirect(url_for('manage_group', group_id=group_id)) - -@app.route('/group//remove_player/', methods=['POST']) -@login_required -@admin_required -def remove_player_from_group(group_id, player_id): - group = Group.query.get_or_404(group_id) - player = Player.query.get_or_404(player_id) - group.players.remove(player) - db.session.commit() - return redirect(url_for('manage_group', group_id=group_id)) - -@app.route('/group//upload', methods=['POST']) -@login_required -@admin_required -def upload_content_to_group(group_id): - group = Group.query.get_or_404(group_id) - files = request.files.getlist('files') - duration = int(request.form['duration']) - - for file in files: - filename = secure_filename(file.filename) - file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) - file.save(file_path) - new_content = Content(file_name=filename, duration=duration, group_id=group_id) - db.session.add(new_content) - - db.session.commit() - return redirect(url_for('manage_group', group_id=group_id)) - -@app.route('/group/content//edit', methods=['POST']) -@login_required -@admin_required -def edit_group_content(content_id): - content = Content.query.get_or_404(content_id) - new_duration = int(request.form['duration']) - content.duration = new_duration - db.session.commit() - return redirect(url_for('manage_group', group_id=content.group_id)) - -@app.route('/group/content//delete', methods=['POST']) -@login_required -@admin_required -def delete_group_content(content_id): - content = Content.query.get_or_404(content_id) - group_id = content.group_id - db.session.delete(content) - db.session.commit() - return redirect(url_for('manage_group', group_id=group_id)) - -@app.route('/group//delete', methods=['POST']) -@login_required -@admin_required -def delete_group(group_id): - group = db.session.get(Group, group_id) - db.session.delete(group) - db.session.commit() - return redirect(url_for('dashboard')) - @app.route('/player/') @login_required def player_page(player_id): @@ -372,24 +256,11 @@ def player_fullscreen(player_id): authenticated = False if authenticated or current_user.is_authenticated: - if player.groups: - # If the player is part of a group, get the group's content - group = player.groups[0] # Assuming a player can only be in one group - content = Content.query.filter_by(group_id=group.id).all() - else: - # If the player is not part of a group, get the player's content - content = Content.query.filter_by(player_id=player_id).all() + content = Content.query.filter_by(player_id=player_id).all() return render_template('player_fullscreen.html', player=player, content=content) else: return render_template('player_auth.html', player_id=player_id) -@app.route('/group//fullscreen') -@login_required -def group_fullscreen(group_id): - group = Group.query.get_or_404(group_id) - content = Content.query.filter_by(group_id=group.id).all() - return render_template('group_fullscreen.html', group=group, content=content) - @app.route('/player//delete', methods=['POST']) @login_required @admin_required @@ -422,25 +293,12 @@ def add_player(): return redirect(url_for('dashboard')) return render_template('add_player.html') -@app.route('/group/add', methods=['GET', 'POST']) -@login_required -@admin_required -def add_group(): - if request.method == 'POST': - name = request.form['name'] - new_group = Group(name=name) - db.session.add(new_group) - db.session.commit() - return redirect(url_for('dashboard')) - return render_template('add_group.html') - @app.route('/integrate_player') @login_required @admin_required def integrate_player(): players = Player.query.all() - groups = Group.query.all() - return render_template('integrate_player.html', players=players, groups=groups) + return render_template('integrate_player.html', players=players) @app.route('/edit_player/', methods=['GET', 'POST']) @login_required @@ -549,13 +407,7 @@ def get_playlist(): if not player or not player.verify_quickconnect_code(quickconnect_code): return jsonify({'error': 'Invalid hostname or quick connect code'}), 404 - if player.groups: - # If the player is part of a group, get the group's content - group = player.groups[0] # Assuming a player can only be in one group - content = Content.query.filter_by(group_id=group.id).all() - else: - # If the player is not part of a group, get the player's content - content = Content.query.filter_by(player_id=player.id).all() + content = Content.query.filter_by(player_id=player.id).all() playlist = [{'file_name': item.file_name, 'duration': item.duration, 'url': url_for('media', filename=item.file_name, _external=True)} for item in content] return jsonify({'playlist': playlist}) diff --git a/clear_db.py b/clear_db.py index 6988a70..7596a67 100644 --- a/clear_db.py +++ b/clear_db.py @@ -1,10 +1,7 @@ + +# drop_user_table.py from app import app, db -def clear_database(): - with app.app_context(): - db.drop_all() - db.create_all() - print("Database cleared and structure recreated.") - -if __name__ == '__main__': - clear_database() \ No newline at end of file +with app.app_context(): + db.drop_all() + print("Dropped all tables.") \ No newline at end of file diff --git a/extensions.py b/extensions.py new file mode 100644 index 0000000..4c449b7 --- /dev/null +++ b/extensions.py @@ -0,0 +1,8 @@ +# extensions.py +from flask_sqlalchemy import SQLAlchemy +from flask_bcrypt import Bcrypt +from flask_login import LoginManager + +db = SQLAlchemy() +bcrypt = Bcrypt() +login_manager = LoginManager() \ No newline at end of file diff --git a/import requests.py b/import requests.py deleted file mode 100644 index 5676f53..0000000 --- a/import requests.py +++ /dev/null @@ -1,19 +0,0 @@ -import requests - -# Replace with the actual server IP address or domain name and quick connect code -server_ip = 'http://192.168.0.115:5000' -quickconnect_code = 'Initial01!' - -# Construct the URL with the quick connect code as a query parameter -url = f'{server_ip}/api/playlists?quickconnect_code={quickconnect_code}' - -# Make the GET request to the API -response = requests.get(url) - -# Check if the request was successful -if response.status_code == 200: - # Parse the JSON response - playlist = response.json().get('playlist', []) - print('Playlist:', playlist) -else: - print('Failed to retrieve playlist:', response.json()) \ No newline at end of file diff --git a/init_db.py b/init_db.py index d05e9e9..bafea4f 100644 --- a/init_db.py +++ b/init_db.py @@ -17,4 +17,5 @@ def create_admin_user(): if __name__ == '__main__': with app.app_context(): db.create_all() - create_admin_user() \ No newline at end of file + create_admin_user() + diff --git a/instance/dashboard.db b/instance/dashboard.db index 791bf97..a72a3d4 100644 Binary files a/instance/dashboard.db and b/instance/dashboard.db differ diff --git a/migrations/README b/migrations/README deleted file mode 100644 index 0e04844..0000000 --- a/migrations/README +++ /dev/null @@ -1 +0,0 @@ -Single-database configuration for Flask. diff --git a/migrations/__pycache__/env.cpython-311.pyc b/migrations/__pycache__/env.cpython-311.pyc deleted file mode 100644 index 9ced6a7..0000000 Binary files a/migrations/__pycache__/env.cpython-311.pyc and /dev/null differ diff --git a/migrations/alembic.ini b/migrations/alembic.ini deleted file mode 100644 index 11a47f2..0000000 --- a/migrations/alembic.ini +++ /dev/null @@ -1,86 +0,0 @@ -[alembic] -# path to migration scripts -script_location = migrations - -# template used to generate migration files -file_template = %%(rev)s_%%(slug)s - -# timezone to use when rendering the date within the migration file as well as the filename. -# string value is passed to datetime.datetime.strftime(), default is to use UTC. -# output_timezone = UTC - -# max length of characters to apply to the "slug" field -# truncate_slug_length = 40 - -# set to 'true' to run the environment during the 'revision' command, regardless of autogenerate -# revision_environment = false - -# set to 'true' to allow .pyc and .pyo files without a source .py file to be detected as revisions -# sourceless = false - -# version location specification; this defaults -# to migrations/versions. When using multiple version -# directories, initial revisions must be specified with --version-path. -# The path separator used here should be the separator specified by "os.pathsep". -# version_locations = %(here)s/bar:%(here)s/bat:migrations/versions - -# the output encoding used when revision files -# are written from script.py.mako -# output_encoding = utf-8 - -sqlalchemy.url = sqlite:///dashboard.db - -[post_write_hooks] -# post_write_hooks defines scripts or Python functions that are run -# on newly generated revision scripts. See the documentation for further -# detail and examples -# hooks = - -# format the generated revision script to be PEP8 compliant -# hooks = pep8 - -# python -# hook_1.type = python -# hook_1.entrypoint = myproject.please_run_pep8 -# hook_1.options = {"treat-as-warning": "true"} - -# exec -# hook_2.type = exec -# hook_2.entrypoint = /usr/bin/pep8 -# hook_2.options = - -[loggers] -keys = root,sqlalchemy,alembic - -[handlers] -keys = console - -[formatters] -keys = generic - -[logger_root] -level = WARN -handlers = console -qualname = - -[logger_sqlalchemy] -level = WARN -handlers = console -qualname = sqlalchemy.engine -# propagate = 0 - -[logger_alembic] -level = INFO -handlers = console -qualname = alembic -# propagate = 0 - -[handler_console] -class = StreamHandler -args = (sys.stderr,) -level = NOTSET -formatter = generic - -[formatter_generic] -format = %(levelname)-5.5s [%(name)s] %(message)s -datefmt = %H:%M:%S \ No newline at end of file diff --git a/migrations/env.py b/migrations/env.py deleted file mode 100644 index 4c1a2cd..0000000 --- a/migrations/env.py +++ /dev/null @@ -1,75 +0,0 @@ -from __future__ import with_statement -import logging -from logging.config import fileConfig - -from sqlalchemy import engine_from_config, pool -from alembic import context - -# this is the Alembic Config object, which provides -# access to the values within the .ini file in use. -config = context.config - -# Interpret the config file for Python logging. -# This line sets up loggers basically. -fileConfig(config.config_file_name) -logger = logging.getLogger('alembic.env') - -# add your model's MetaData object here -# for 'autogenerate' support -# from myapp import mymodel -# target_metadata = mymodel.Base.metadata -from flask import current_app -config.set_main_option('sqlalchemy.url', current_app.config.get('SQLALCHEMY_DATABASE_URI')) -target_metadata = current_app.extensions['migrate'].db.metadata - -# other values from the config, defined by the needs of env.py, -# can be acquired: -# my_important_option = config.get_main_option("my_important_option") -# ... etc. - - -def run_migrations_offline(): - """Run migrations in 'offline' mode. - - This configures the context with just a URL - and not an Engine, though an Engine is acceptable - here as well. By skipping the Engine creation - we don't even need a DBAPI to be available. - - Calls to context.execute() here emit the given string to the - script output. - - """ - url = config.get_main_option("sqlalchemy.url") - context.configure( - url=url, target_metadata=target_metadata, literal_binds=True - ) - - with context.begin_transaction(): - context.run_migrations() - - -def run_migrations_online(): - """Run migrations in 'online' mode. - - In this scenario we need to create an Engine - and associate a connection with the context. - - """ - connectable = engine_from_config( - config.get_section(config.config_ini_section), - prefix="sqlalchemy.", - poolclass=pool.NullPool, - ) - - with connectable.connect() as connection: - context.configure(connection=connection, target_metadata=target_metadata) - - with context.begin_transaction(): - context.run_migrations() - - -if context.is_offline_mode(): - run_migrations_offline() -else: - run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako deleted file mode 100644 index 2c01563..0000000 --- a/migrations/script.py.mako +++ /dev/null @@ -1,24 +0,0 @@ -"""${message} - -Revision ID: ${up_revision} -Revises: ${down_revision | comma,n} -Create Date: ${create_date} - -""" -from alembic import op -import sqlalchemy as sa -${imports if imports else ""} - -# revision identifiers, used by Alembic. -revision = ${repr(up_revision)} -down_revision = ${repr(down_revision)} -branch_labels = ${repr(branch_labels)} -depends_on = ${repr(depends_on)} - - -def upgrade(): - ${upgrades if upgrades else "pass"} - - -def downgrade(): - ${downgrades if downgrades else "pass"} diff --git a/migrations/versions/173774695298_add_theme_column_to_user_table.py b/migrations/versions/173774695298_add_theme_column_to_user_table.py deleted file mode 100644 index 4259dce..0000000 --- a/migrations/versions/173774695298_add_theme_column_to_user_table.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Add theme column to user table - -Revision ID: 173774695298 -Revises: c07c6e720021 -Create Date: 2025-01-23 15:16:46.761912 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '173774695298' -down_revision = 'c07c6e720021' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### diff --git a/migrations/versions/__pycache__/173774695298_add_theme_column_to_user_table.cpython-311.pyc b/migrations/versions/__pycache__/173774695298_add_theme_column_to_user_table.cpython-311.pyc deleted file mode 100644 index e7fa50c..0000000 Binary files a/migrations/versions/__pycache__/173774695298_add_theme_column_to_user_table.cpython-311.pyc and /dev/null differ diff --git a/migrations/versions/__pycache__/c07c6e720021_add_theme_column_to_user_table.cpython-311.pyc b/migrations/versions/__pycache__/c07c6e720021_add_theme_column_to_user_table.cpython-311.pyc deleted file mode 100644 index 2cc478f..0000000 Binary files a/migrations/versions/__pycache__/c07c6e720021_add_theme_column_to_user_table.cpython-311.pyc and /dev/null differ diff --git a/migrations/versions/__pycache__/e341b0e3043c_initial_migration.cpython-311.pyc b/migrations/versions/__pycache__/e341b0e3043c_initial_migration.cpython-311.pyc deleted file mode 100644 index 82cb72b..0000000 Binary files a/migrations/versions/__pycache__/e341b0e3043c_initial_migration.cpython-311.pyc and /dev/null differ diff --git a/migrations/versions/c07c6e720021_add_theme_column_to_user_table.py b/migrations/versions/c07c6e720021_add_theme_column_to_user_table.py deleted file mode 100644 index c1cdff2..0000000 --- a/migrations/versions/c07c6e720021_add_theme_column_to_user_table.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Add theme column to user table - -Revision ID: c07c6e720021 -Revises: e341b0e3043c -Create Date: 2025-01-23 15:13:01.413532 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'c07c6e720021' -down_revision = 'e341b0e3043c' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### diff --git a/migrations/versions/e341b0e3043c_initial_migration.py b/migrations/versions/e341b0e3043c_initial_migration.py deleted file mode 100644 index a991de2..0000000 --- a/migrations/versions/e341b0e3043c_initial_migration.py +++ /dev/null @@ -1,72 +0,0 @@ -"""Initial migration - -Revision ID: e341b0e3043c -Revises: -Create Date: 2025-01-23 15:09:25.485823 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'e341b0e3043c' -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('group', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('name', sa.String(length=80), nullable=False), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('name') - ) - op.create_table('player', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('username', sa.String(length=80), nullable=False), - sa.Column('hostname', sa.String(length=120), nullable=False), - sa.Column('password', sa.String(length=120), nullable=False), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('hostname'), - sa.UniqueConstraint('username') - ) - op.create_table('user', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('username', sa.String(length=80), nullable=False), - sa.Column('password', sa.String(length=120), nullable=False), - sa.Column('role', sa.String(length=20), nullable=False), - sa.Column('theme', sa.String(length=10), nullable=False), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('username') - ) - op.create_table('content', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('file_name', sa.String(length=120), nullable=False), - sa.Column('duration', sa.Integer(), nullable=False), - sa.Column('player_id', sa.Integer(), nullable=True), - sa.Column('group_id', sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(['group_id'], ['group.id'], ), - sa.ForeignKeyConstraint(['player_id'], ['player.id'], ), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('group_players', - sa.Column('group_id', sa.Integer(), nullable=False), - sa.Column('player_id', sa.Integer(), nullable=False), - sa.ForeignKeyConstraint(['group_id'], ['group.id'], ), - sa.ForeignKeyConstraint(['player_id'], ['player.id'], ), - sa.PrimaryKeyConstraint('group_id', 'player_id') - ) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('group_players') - op.drop_table('content') - op.drop_table('user') - op.drop_table('player') - op.drop_table('group') - # ### end Alembic commands ### diff --git a/models.py b/models.py index 05ea8d0..823ccf4 100644 --- a/models.py +++ b/models.py @@ -1,5 +1,6 @@ -from app import db +from extensions import db from flask_bcrypt import Bcrypt +from flask_login import UserMixin bcrypt = Bcrypt() @@ -8,7 +9,6 @@ class Content(db.Model): file_name = db.Column(db.String(120), nullable=False) duration = db.Column(db.Integer, nullable=False) player_id = db.Column(db.Integer, db.ForeignKey('player.id'), nullable=True) - group_id = db.Column(db.Integer, db.ForeignKey('group.id'), nullable=True) class Player(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -20,4 +20,32 @@ class Player(db.Model): def verify_quickconnect_code(self, code): return bcrypt.check_password_hash(self.quickconnect_password, code) +class User(db.Model, UserMixin): + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String(80), unique=True, nullable=False) + password = db.Column(db.String(120), nullable=False) + role = db.Column(db.String(80), nullable=False) + theme = db.Column(db.String(80), default='light') + + def set_password(self, password): + self.password = bcrypt.generate_password_hash(password).decode('utf-8') + + def check_password(self, password): + return bcrypt.check_password_hash(self.password, password) + + @property + def is_active(self): + return True + + @property + def is_authenticated(self): + return True + + @property + def is_anonymous(self): + return False + + def get_id(self): + return str(self.id) + # other models... \ No newline at end of file diff --git a/static/uploads/SampleVideo_1280x720_30mb.mp4 b/static/uploads/SampleVideo_1280x720_30mb.mp4 new file mode 100644 index 0000000..f29424e Binary files /dev/null and b/static/uploads/SampleVideo_1280x720_30mb.mp4 differ diff --git a/static/uploads/harting_contactor.jpg b/static/uploads/harting_contactor.jpg new file mode 100644 index 0000000..d188777 Binary files /dev/null and b/static/uploads/harting_contactor.jpg differ diff --git a/templates/add_group.html b/templates/add_group.html deleted file mode 100644 index 84410da..0000000 --- a/templates/add_group.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - Add Group - - - - -
-

Add Group

-
-
- - -
-
-
- {% for player in players %} -
- - -
- {% endfor %} -
- -
- Back to Dashboard -
- - - diff --git a/templates/dashboard.html b/templates/dashboard.html index e845d72..1186acd 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -68,45 +68,6 @@ - -
-
-

Player Groups

-
-
-
    - {% for group in groups %} -
  • -
    - {{ group.name }} ({{ group.players | length }} players) -
      - {% for player in group.players %} -
    • - {{ player.username }} -
    • - {% endfor %} -
    -
    -
    - Manage Group - Full Screen - {% if current_user.role == 'admin' %} -
    - -
    - {% endif %} -
    -
  • - {% endfor %} -
- {% if current_user.role == 'admin' %} -
- Add Group -
- {% endif %} -
-
-
diff --git a/templates/group_fullscreen.html b/templates/group_fullscreen.html deleted file mode 100644 index 732def5..0000000 --- a/templates/group_fullscreen.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - Group Fullscreen Schedule - - - -
- {% for item in content %} - {% if item.file_name.endswith('.mp4') %} - - {% else %} - Content Image - {% endif %} - {% endfor %} -
- - - \ No newline at end of file diff --git a/templates/manage_group.html b/templates/manage_group.html deleted file mode 100644 index 5c0c262..0000000 --- a/templates/manage_group.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - Manage Group - - - - -
-
- {% if logo_exists %} - - {% endif %} -

Manage Group: {{ group.name }}

-
- - -
-
-

Add Players to Group

-
-
-
-
- - -
- -
-
-
- - -
-
-

Group Players

-
-
-
    - {% for player in group.players %} -
  • -
    - {{ player.username }} -
    -
    -
    - -
    -
    -
  • - {% endfor %} -
-
-
- - Back to Dashboard -
- - - \ No newline at end of file