From 70a0065b98967c0db2bbe03d9e6ca08d5b0257c1 Mon Sep 17 00:00:00 2001 From: Ske087 Date: Thu, 23 Jan 2025 16:31:57 +0200 Subject: [PATCH] updated to video upload --- Dockerfile | 21 +- __pycache__/app.cpython-311.pyc | Bin 29670 -> 30345 bytes app.py | 69 +++--- dashboard.db | Bin 0 -> 53248 bytes docker-compose.yml | 4 +- instance/dashboard.db | Bin 49152 -> 61440 bytes migrations/__pycache__/env.cpython-311.pyc | Bin 5101 -> 3337 bytes migrations/alembic.ini | 68 ++++-- migrations/env.py | 62 +----- .../0de18b4ddaa3_initial_migration.py | 34 --- ...74695298_add_theme_column_to_user_table.py | 28 +++ ...8b4ddaa3_initial_migration.cpython-311.pyc | Bin 1812 -> 0 bytes ...theme_column_to_user_table.cpython-311.pyc | Bin 0 -> 786 bytes ...theme_column_to_user_table.cpython-311.pyc | Bin 0 -> 786 bytes ...b0e3043c_initial_migration.cpython-311.pyc | Bin 0 -> 4395 bytes ...6e720021_add_theme_column_to_user_table.py | 28 +++ .../e341b0e3043c_initial_migration.py | 72 ++++++ requirements.txt | 3 +- templates/add_group.html | 15 +- templates/add_player.html | 21 +- templates/admin.html | 137 ++++++++---- templates/dashboard.html | 208 ++++++++++-------- templates/integrate_player.html | 23 +- templates/manage_group.html | 77 ++----- templates/player_auth.html | 15 +- templates/player_page.html | 81 ++----- templates/register.html | 15 +- templates/upload_content.html | 58 ++++- 28 files changed, 619 insertions(+), 420 deletions(-) create mode 100644 dashboard.db delete mode 100644 migrations/versions/0de18b4ddaa3_initial_migration.py create mode 100644 migrations/versions/173774695298_add_theme_column_to_user_table.py delete mode 100644 migrations/versions/__pycache__/0de18b4ddaa3_initial_migration.cpython-311.pyc create mode 100644 migrations/versions/__pycache__/173774695298_add_theme_column_to_user_table.cpython-311.pyc create mode 100644 migrations/versions/__pycache__/c07c6e720021_add_theme_column_to_user_table.cpython-311.pyc create mode 100644 migrations/versions/__pycache__/e341b0e3043c_initial_migration.cpython-311.pyc create mode 100644 migrations/versions/c07c6e720021_add_theme_column_to_user_table.py create mode 100644 migrations/versions/e341b0e3043c_initial_migration.py diff --git a/Dockerfile b/Dockerfile index 050df56..339302d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -# Use the official Python image from the Docker Hub +# Stage 1: Build stage FROM python:3.11-slim AS build # Set the working directory in the container @@ -11,6 +11,7 @@ RUN apt-get update && apt-get install -y \ libssl-dev \ python3-dev \ cargo \ + g++ \ curl \ && rm -rf /var/lib/apt/lists/* @@ -30,17 +31,25 @@ FROM python:3.11-slim # Set the working directory in the container WORKDIR /app -# Copy only the necessary files from the build stage -COPY --from=build /app /app -COPY --from=build /root/.cargo /root/.cargo - # Install runtime dependencies RUN apt-get update && apt-get install -y \ libffi-dev \ libssl-dev \ + g++ \ + curl \ && rm -rf /var/lib/apt/lists/* -# Install Gunicorn +# Install Rust +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" + +# Copy only the necessary files from the build stage +COPY --from=build /app /app +COPY --from=build /root/.cargo /root/.cargo + +# Install Gunicorn and other Python dependencies +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt RUN pip install gunicorn # Make port 5000 available to the world outside this container diff --git a/__pycache__/app.cpython-311.pyc b/__pycache__/app.cpython-311.pyc index 035afd5e9180104df2e9523b5f4f9141cde55cf4..72a25e64e7238537f9f1a65a47c91efbf7bbe566 100644 GIT binary patch delta 7881 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 LtT24IiU;`r*H81n delta 7524 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 diff --git a/app.py b/app.py index f57292e..54552c3 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,5 @@ import os -from flask import Flask, render_template, request, redirect, url_for +from flask import Flask, render_template, request, redirect, url_for, session from flask_sqlalchemy import SQLAlchemy from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user from flask_bcrypt import Bcrypt @@ -32,7 +32,7 @@ migrate = Migrate(app, db) @login_manager.user_loader def load_user(user_id): - return User.query.get(int(user_id)) + return db.session.get(User, int(user_id)) # Modele pentru baza de date class User(db.Model, UserMixin): @@ -40,22 +40,20 @@ class User(db.Model, UserMixin): username = db.Column(db.String(80), 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), nullable=False) - hostname = db.Column(db.String(120), nullable=False) - ip = db.Column(db.String(15), nullable=False) + 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) - user_id = db.Column(db.Integer, db.ForeignKey('user.id', name='fk_user_id'), nullable=True) 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_players', backref='groups') - content = db.relationship('Content', backref='group', lazy=True) + players = db.relationship('Player', secondary='group_player', backref='groups') -group_players = db.Table('group_players', +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) ) @@ -113,25 +111,18 @@ def logout(): @app.route('/upload_content', methods=['GET', 'POST']) @login_required +@admin_required def upload_content(): + if request.method == 'POST': + # Handle file upload logic here + pass + + target_type = request.args.get('target_type') + 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() - if request.method == 'POST': - target_type = request.form['target_type'] - target_id = request.form['target_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, player_id=target_id if target_type == 'player' else None, group_id=target_id if target_type == 'group' else None) - db.session.add(new_content) - - db.session.commit() - return redirect(url_for('dashboard')) - return render_template('upload_content.html', players=players, groups=groups) + return render_template('upload_content.html', target_type=target_type, target_id=target_id, players=players, groups=groups, return_url=return_url) @app.route('/admin') @login_required @@ -243,7 +234,7 @@ def delete_group_content(content_id): @login_required @admin_required def delete_group(group_id): - group = Group.query.get_or_404(group_id) + group = db.session.get(Group, group_id) db.session.delete(group) db.session.commit() return redirect(url_for('dashboard')) @@ -251,7 +242,7 @@ def delete_group(group_id): @app.route('/player/') @login_required def player_page(player_id): - player = Player.query.get_or_404(player_id) + player = db.session.get(Player, player_id) content = Content.query.filter_by(player_id=player_id).all() return render_template('player_page.html', player=player, content=content) @@ -339,10 +330,8 @@ def add_player(): if request.method == 'POST': username = request.form['username'] hostname = request.form['hostname'] - ip = request.form['ip'] - password = request.form['password'] - hashed_password = bcrypt.generate_password_hash(password).decode('utf-8') - new_player = Player(username=username, hostname=hostname, ip=ip, password=hashed_password) + password = bcrypt.generate_password_hash(request.form['password']).decode('utf-8') + new_player = Player(username=username, hostname=hostname, password=password) db.session.add(new_player) db.session.commit() return redirect(url_for('dashboard')) @@ -376,13 +365,29 @@ def edit_player(player_id): if request.method == 'POST': player.username = request.form['username'] player.hostname = request.form['hostname'] - player.ip = request.form['ip'] if request.form['password']: player.password = bcrypt.generate_password_hash(request.form['password']).decode('utf-8') db.session.commit() return redirect(url_for('player_page', player_id=player.id)) return render_template('edit_player.html', player=player) +@app.route('/change_theme', methods=['POST']) +@login_required +@admin_required +def change_theme(): + theme = request.form['theme'] + current_user.theme = theme + db.session.commit() + return redirect(url_for('admin')) + +@app.context_processor +def inject_theme(): + if current_user.is_authenticated: + theme = current_user.theme + else: + theme = 'light' + return dict(theme=theme) + if __name__ == '__main__': with app.app_context(): db.create_all() # Creează toate tabelele diff --git a/dashboard.db b/dashboard.db new file mode 100644 index 0000000000000000000000000000000000000000..40690eb73ed0314ebb651a6dff072318b0df7a51 GIT binary patch literal 53248 zcmeI(O;6iM7{GCx7YDlu>7mF%Tt<~p5(TvlbeEzP>SmGKMoYtDLM2XCN=%6w5;k#m zyT`zOg&y~V>^JGT*S+kqx7IIlh+Ry3=*j(CIQEP^lRUo}PZ-%b*xzkCwm9ka&zg?d zkZwz|Ed4BmBuT2f=G--06nAGXOt@QlYCmaLmF^wOx%>wytG<=;x%|J2M~m-scNW)j zAG0&r|Fn1NTkW5u!sH`>00IagfB*vDjljkHt&CnM$d@&z`Lbib>i34{)_JG-m)##k z64@Qos5T7IsQ$8Rh{z#P)YKrO-4eBW!+2_#qQ2J<^~2rWHKD0NeOAKJ-^|+cs(B=S zHI76vtY=M33YEMnp6r=M?P=XRX>v|Un8p*sH0nFXfw=3Jyeo?B)@KE-s+ukl^5u48wd@#a>9 zZJg)!cbjHH($?2c?K+YuIl(?Oylms6D(8H7w!fMbxh`3(I^< z$UwuLlnbLR? z`0kUi<1VMYffIrItYdvy?xyg=`u(f#8k2HH(H}1-nFR4!>%n%RtbE1EmEh#eNSV#( zx-O4iUyWgY_nnInPDY4C!w65@@21$jf^M^y<`jKfPYN-(qJqI=epHe(dbuoLsQzbe zcI>m4?PKc?ci43=?O1Xq5=ZQycdd+zS>55;r2RM6qr=9|Uj3k9R^9Pg#A>k4UmuG| zcvJPcVQtSS`hGbntaxRWSjMdTUAo|XpL!E~Isd=p{;?o{00IagfB*srAb$|E5I_I{1Q0*~0R#|00D<%iF#k_~ z8xtV{2q1s}0tg_000IagfB*tK|4$!4009ILKmY**5I_I{1Q0+V{Q}(oPk$Q|Ap!^> zfB*srAb4MF*seaoj}5-PoPcxd z8WT=it;oh;nh(Z>MOj)-&L`visvuuJQ?3a&H|1ugIOhX5a~V+}anQ8hR)^CT3$ke~ zv4o^VT1ccTfy^6q=SY>|2^h}h2C%+*j2^Knhx!JkKw(T-Yo5K#35j>0x@c-0y`~%* zS`k9|VfcvFV)SU+MWJ#|)ZfyOxpHC_GvYK&BiYzr8zshSB}gUF8jQY6S1Jjsj`~ok zijX*MHX|FhQdPN?@)uPcS^rxQ)6%Zd4Gq95MK_(!_!Rr%fhgqer3OHcUqZQDA1c373bPXlIod zlubE+{d#?I9!7QFzw$Nr3otj15-1?mI|S|mxSMB+k7;6uR$-<@vGHyd+_J&*XwK#1ew0|}=mkZ`bKi6G3& zv3+}$5kue(fIF(ja~Sp`80a!*QI8a7oIJxa=?o+CvY`GudA6eIjmCOYuJBy%kbTwd z9IFDvf1b~S z?;@`l_i3KX9G^H2Zx$4AJ zPHJ*~UP)?R36$d5EWr7lk%gC!;mE{^2bh~!1tw4BR%7ItyodWfqu}H@JQk{)e18}? zKt?s`^RtUfN;0-sf()fIR-gF%fC?HZ{871LA*a&>bJa`kg|4ORe& zDQIM-XmV*bvhhxSz$3=UI{7sl8T{`N||e^UvZUzv9Xt{e`01~aHNZKPKtk~ zNmNdumq(FHRghUuL};RONN#0tx?8rVp--`+S0&hhO$ICiObh}*qu=sR4B%zs0@{Ye W1zC=pi>i3j1P+DG!UC^B<^TYP%#jfQ diff --git a/migrations/__pycache__/env.cpython-311.pyc b/migrations/__pycache__/env.cpython-311.pyc index 0205ce49b23ce3627cac4fcd88f7dd4fa5396bea..9ced6a72a7270d7a11a80c40ea2b37cca351ba80 100644 GIT binary patch delta 1741 zcmZuxU1%It6ux(6cjssSl1Z{L|1pp>lhQxo{L#zI*>k>o&$s8^ z^WAxJ;p5iv@1ju=!7#_Z$b8Bp^g9h|BXs2KFJXkfMjFzvflQplnEH&tB$<`*M8C-; zxe5|AcvDCU80kW;!bEyTfkIrZ zb627b^+@CO_zB%=Jw;Wd31_p{7~q1pIv_uulWLJBw$xmdYpA)o#+sLG(!w91WI~I8 zZH97%+%v8kPPpSZSV*kFvh~_h1RG^$5v*x`8ZJlwq$_3Y$KKC6cNN=F9o^I|XBr?e zoi+69c`KdG$c!)PRwirdN}A+NB~?NFz(PK6z)B8cN5ALX53BQrZq8>@gSzz|OoUU5 zgaDnQE-W0z>~{^-NZr-V4+a;B;Wy9DOifH(f9=Mbca&ErZcR*1%-&FL-+bNY%xs20 zA*thCfJ2+h!nGN$WJRGCo90Xf;HI;eH;Lu3#r#n?Wdd z%&>%=V@V+Nh&?YEC+0}&IvH9ZdOCa07ijlV zhHBdYig03l}Lc8Ph(~E}j7LZm1 zLD>kL*DxY<8x>YU)l8_6;V;8Se@Qh%S^=}^edz8cO>SphTcI0*%M=}kzAdAFVyK~a zmyd1pty_HSH=|zL8y{iMeeB9$(R+GPU75SMGKjZN;;QSG7^rC&GXulWjFC#3tdv#iYgM>;}#Q=G* z7syXzC$s0ggM))}$hpuSh0Sd=3{75TH<`xCp5SI8Lj9h=WS_9v$AVwjlraqkXs~%T zFnNvp8Dp?=i!UlldeH%eD+-~)@;M`)fg76fV@J+lwNE5KXT=i@RQp=#7^haREA7)! ztLu)sOD}&xu~bv{1?c`1kn6+`QEvDRra?FF5UN!_Zi6^XHESvP1*#vPh4sD&-viyU zA+~)+oA-HBcT`Pv)T$8Z?IYcl^sKGq(`kc#T+F3{XK`+Oq b9|hW$U-a1465H;v?PcWt*f1D)9yakmhzhbd literal 5101 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 - return current_app.extensions['migrate'].db.engine - - -def get_engine_url(): - try: - return get_engine().url.render_as_string(hide_password=False).replace( - '%', '%%') - except AttributeError: - return str(get_engine().url).replace('%', '%%') - - # add your model's MetaData object here # for 'autogenerate' support # from myapp import mymodel # target_metadata = mymodel.Base.metadata -config.set_main_option('sqlalchemy.url', get_engine_url()) -target_db = current_app.extensions['migrate'].db +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: @@ -45,12 +28,6 @@ target_db = current_app.extensions['migrate'].db # ... etc. -def get_metadata(): - if hasattr(target_db, 'metadatas'): - return target_db.metadatas[None] - return target_db.metadata - - def run_migrations_offline(): """Run migrations in 'offline' mode. @@ -65,7 +42,7 @@ def run_migrations_offline(): """ url = config.get_main_option("sqlalchemy.url") context.configure( - url=url, target_metadata=get_metadata(), literal_binds=True + url=url, target_metadata=target_metadata, literal_binds=True ) with context.begin_transaction(): @@ -79,29 +56,14 @@ def run_migrations_online(): and associate a connection with the context. """ - - # this callback is used to prevent an auto-migration from being generated - # when there are no changes to the schema - # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html - def process_revision_directives(context, revision, directives): - if getattr(config.cmd_opts, 'autogenerate', False): - script = directives[0] - if script.upgrade_ops.is_empty(): - directives[:] = [] - logger.info('No changes in schema detected.') - - conf_args = current_app.extensions['migrate'].configure_args - if conf_args.get("process_revision_directives") is None: - conf_args["process_revision_directives"] = process_revision_directives - - connectable = get_engine() + 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=get_metadata(), - **conf_args - ) + context.configure(connection=connection, target_metadata=target_metadata) with context.begin_transaction(): context.run_migrations() diff --git a/migrations/versions/0de18b4ddaa3_initial_migration.py b/migrations/versions/0de18b4ddaa3_initial_migration.py deleted file mode 100644 index 0f61892..0000000 --- a/migrations/versions/0de18b4ddaa3_initial_migration.py +++ /dev/null @@ -1,34 +0,0 @@ -"""Initial migration - -Revision ID: 0de18b4ddaa3 -Revises: -Create Date: 2025-01-20 14:50:44.116314 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '0de18b4ddaa3' -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - with op.batch_alter_table('player', schema=None) as batch_op: - batch_op.add_column(sa.Column('user_id', sa.Integer(), nullable=True)) - batch_op.create_foreign_key('fk_user_id', 'user', ['user_id'], ['id']) - - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - with op.batch_alter_table('player', schema=None) as batch_op: - batch_op.drop_constraint('fk_user_id', type_='foreignkey') - batch_op.drop_column('user_id') - - # ### end Alembic commands ### diff --git a/migrations/versions/173774695298_add_theme_column_to_user_table.py b/migrations/versions/173774695298_add_theme_column_to_user_table.py new file mode 100644 index 0000000..4259dce --- /dev/null +++ b/migrations/versions/173774695298_add_theme_column_to_user_table.py @@ -0,0 +1,28 @@ +"""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__/0de18b4ddaa3_initial_migration.cpython-311.pyc b/migrations/versions/__pycache__/0de18b4ddaa3_initial_migration.cpython-311.pyc deleted file mode 100644 index 149862fb7e884217012d90e4325d15f36b086d0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1812 zcmb_cO>7%Q6rR~#d&iqP#G$09b)}UeHL*}?J9Q9Ps8Z4hDH1h;a*2hstUXg_oAvH8 zyGbwtDF@D+kkSK4IiNu09*R_?95@h8JvxyQ(OwY;Zbsn{^~9T9+i{B817ddf+c)pM z`FU@?H{Yex8iMxi+g~=mk`ek{bOuf83nyg|b`V8XL@||Y+?1*k7P4&1RfQ_m1eL2v z_*D1^O?-i>DVhY-sC)-+~z6?;-=L_=-bA{sEd_gak$_s^ZsdT+qeEmkTq-lSOt>$njxn3o_ zFgjbkA4K#cfDk1*8OI``0C3Rm4P}T6J(Tt!`t~3LXaRkWK0~|1{$P~&2kKexo-&ZB zd`_Pj==VTq4?2h{4-?crXqST#AYjs9tpLbe;2k_O&`Rolar;bfxc zd;~&!2Th|Q@|7*=6L}SFVT@K0hDTU(sY;miY_rAq0~{v(`WkDRp}OHSZdmjK$SrX; zY}>5aEY$9<8+}8l2qBa#np3$5BFxmxpuT39b^s%T*x#hosJr$?(+MTt43oEFSzU1g z)_~!Y_2{6DyDn!|!!g!b3pPRGnOx5o`Ou%fmtS+6Ebm$QW#+F3u9v4)!-C~E8P5-y z<>#R*h~?);d0<#E1&yKOb*}~Sc|b_Y_$653W%&GG0k+W}sj+VA>ixCvgHEb+m@0Ks zr5=(J@8W%OOeTIKSB}V)Z8{=Qm5`RZHs(-P3dV2a|huG>*LS#FOQ;TK!psXz3 zRDZ!3unyW`6HF6_c=8j#|5YDUj#z%Ko+4fkIX_$<1e$!d0{#=5)e0BEa8a9l3;;+Q zlMA>7WKIMvj~P4#mYfn1myZjtmne5V;Hu*X+_an^9P29tdHF?fiOI;Pgm;R%TTV=% ztI*F1vncTA5@@#1AN`2vyV*w{c8GpRmbzrALzW`8WRFPp{^}u_>5`canGqbB73UX& zAjquX$B6FC`i#`)#q(YL3~Y60ZZRVtWR%5M)Pq+sU~Vi_4THLM!w6N=X3d&ak1JdA zKekONv!mcfN_K`b8nu5GEzZk`+5h(V{^+6kI(dvXt1Wg(5&uFI_S;n}!myNZ3O47fMdyP9FLM zUHS+`-ln6$sX(W00 zH^fkY7-m|6Q!UW2()C0STC5f9vAv+p^uPcyS^EnLI?MpHn0|%&=I7-FW2Bn%l#?h= z7HLMRoGeN%NEJ>KZdvd7O07@0mG?- z+_eD|@hfzTFK>}Bl@kQrf3W9y%IzYyC%pVv<%P}SSqzMBxUkcBCc+Bnls1@(S84C2 zrXgdrX$Rf3gH}0J?VwFNPKu>876rs$TID3wN-@N^nSLN!BL<#iG!5lnF@wK9~Z*bYth zR6zP@PDPkSbDD%xo|MvJyxa7o-0rZ}%th%k?PK_R*`=CAgl-BV71B2ng AoB#j- literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..2cc478ff28b8d9ca0436f621c40ba1277118f5ad GIT binary patch literal 786 zcmah`y>8nu5GEzZk`+5h(V{^+6kI(d`m+;2D2f*K(j`N)31|sfBy6Gj3niy;CJ%jr zE`5X|Z`0A>RG?Eg0ogM3D7%T#r3CNe-I2Vz@9z6xU?Er^UVohh8bZI6@ppmUuG;{P zZ-}7~G0e0SXIiLXrR%94c33CeV|!tj>7fB)vhEiY_Lu=^G5rD!&FkeG#z;Nq87Fa( zF0!1|1zA*FkUE;C+_K*DtE5VboV=R^BzDf?Q-0<-j^}P}coh)tkKC!leP`sy)?2}& znv)4YKs?7AA3N@`=M#4vxPIWcCnMJ%`<`X}Rt$z%YDIZ2`@4~4e>Y;>GTj1(QwO>2 z0x04a=mwwPAYm#e2)g@d&x?%PWnxcw^{FmOnL_3hP0~7G)iNb;!RUEFDq yf&+w)exRqjdyT-e-HnO*&sXO9@WpDdK70Z&c(k&bu7-OJx`+O~_TW=m%l{8Gj>Av@ literal 0 HcmV?d00001 diff --git a/migrations/versions/__pycache__/e341b0e3043c_initial_migration.cpython-311.pyc b/migrations/versions/__pycache__/e341b0e3043c_initial_migration.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..82cb72bc43c2a866876ae9d295a705951a342891 GIT binary patch literal 4395 zcmd5<+fUn87`Kxz&IQtz7RX3CmD1awEeQcyNZEjay3zaARhrnOEabSstz)Nl(vCjy z&`EpjCaO`1N_)yOr4KyvS4_6#hsx5Prakm6i1npU`%WBU%oZ9tD$UCIAMPI-86Jrb1_Cdss=ch~ zl5^M0)~(#qH6yBjK}0vUjr%@oQJ%FI@6`K*&3m@YQ~K&dT#k9zoG)Uhyg6Wq`#BVG zPr1I&v8z5yJdXLgM8ZAy7Ezb7tSlAZtb9lne!2NHXF9#ZMY}+Nr-R8^NWx_#+wzgmPHWLmxq}X15`?s>)!STPI z%^gi~>umC*5A6ZB`a4WQ8J4`4VT*V>mp5-{#v#F`?LgYD9cde8RS~O!GPXCI9ASrK zJ71c!dFPwW=GI(1cIIY#LFAJbCsMG=G1G5JNebi((^pjwyAQ2i zKlWXh)xDHL!Bo64hUi_D+E zJ-Yt*li%@g=6mwwz>#&o$HV=_AXF&4YGpiL6!+Y*E%#9*J0d%aciqZFsOy2dN^u?qiZKLn9yOufQe=Z{;6<4hhqjDtEpcbt?&0y z^${u*ULCa5zxeLe-`U?7s>~B*X`$rOLZ|i6X(M!cmDgZQhcN@jsy1v7$j%ncyvd@w z&*Ceir70~E(<3n>5?jLrnbcv@fJtjB4M^Y9Gb?9SF;wSuIB&ptYlUu2JRMsZTRpyQ z#op7d!8sky8E~$q{Ot0TQlfN5hfxDYYja;MUoBlOefV!#x8CNbfkLQIc-3wN>U#6K zVg8KhFk-;SE;YDRYSCfHfT8skj_QC=ae{IJU$->2`a=&D+BSYeX#A<>EO#3gxZ6IB z8q&F&;!RC4yEdofO(Av{IlqMX$>`P6I@dbJk(19H)!aLCQ%4(@*3F zl66q^;dm08`Xz#OP+ff-)uG3L9u0bEXsN*q_|H?b-qRNO4f zR$Lqlm`Diw7&fFaom+n|7@Vp7Dn6z)yy$yzpnWlDL9lHxP~rMmOvE~T&2nsn^4kto G5Bv>vY(RSe literal 0 HcmV?d00001 diff --git a/migrations/versions/c07c6e720021_add_theme_column_to_user_table.py b/migrations/versions/c07c6e720021_add_theme_column_to_user_table.py new file mode 100644 index 0000000..c1cdff2 --- /dev/null +++ b/migrations/versions/c07c6e720021_add_theme_column_to_user_table.py @@ -0,0 +1,28 @@ +"""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 new file mode 100644 index 0000000..a991de2 --- /dev/null +++ b/migrations/versions/e341b0e3043c_initial_migration.py @@ -0,0 +1,72 @@ +"""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/requirements.txt b/requirements.txt index 87f0dab..665263c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ bcrypt==4.2.1 blinker==1.9.0 click==8.1.8 Flask==3.1.0 - +Flask-Bcrypt==1.0.1 Flask-Login==0.6.3 Flask-Migrate==4.1.0 Flask-SQLAlchemy==3.1.1 @@ -16,4 +16,3 @@ SQLAlchemy==2.0.37 typing_extensions==4.12.2 Werkzeug==3.1.3 gunicorn==20.1.0 -Flask-Bcrypt==1.0.1 \ No newline at end of file diff --git a/templates/add_group.html b/templates/add_group.html index a14e2e9..84410da 100644 --- a/templates/add_group.html +++ b/templates/add_group.html @@ -3,8 +3,21 @@ Add Group + - +

Add Group

diff --git a/templates/add_player.html b/templates/add_player.html index 85f3e96..446b9b4 100644 --- a/templates/add_player.html +++ b/templates/add_player.html @@ -3,11 +3,24 @@ Add Player + - +

Add Player

- +
@@ -16,10 +29,6 @@
-
- - -
diff --git a/templates/admin.html b/templates/admin.html index 7267c26..6de9995 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -3,60 +3,101 @@ Admin Panel + - +

Admin Panel

-

Manage Users

- - - - - - - - - - {% for user in users %} - - - - - - {% endfor %} - -
UsernameRoleActions
{{ user.username }}{{ user.role }} - - - - -
- -
-
+
+
+

Manage Users

+
+
+ +

Manage User Roles

+ + + + + + + + + + {% for user in users %} + + + + + + {% endfor %} + +
UsernameRoleActions
{{ user.username }}{{ user.role }} +
+ + +
+
+ +
+
-

Create New User

-
-
- - + +

Add New User

+ +
+ + +
+
+ + +
+
+ + +
+ +
-
- - +
+ + +
+
+

Change Theme

-
- - +
+
+
+ + +
+ +
- - +
Back to Dashboard @@ -65,4 +106,4 @@ - \ No newline at end of file + diff --git a/templates/dashboard.html b/templates/dashboard.html index e86e88f..8d9e5e6 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -5,8 +5,18 @@ Dashboard + - +

Dashboard

@@ -15,110 +25,116 @@ Sign Out
- - {% if current_user.role == 'admin' %} -
-
-

Users Management

-
- -
- {% endif %} +
+
+ +
+
+

Players

+
+
+
    + {% for player in players %} +
  • +
    + {{ player.username }} +
    +
    + Manage Player + Full Screen + {% if current_user.role == 'admin' %} +
    + +
    + {% endif %} +
    +
  • + {% endfor %} +
+ {% if current_user.role == 'admin' %} + + {% endif %} +
+
- -
-
-

Players

-
-
-
    - {% for player in players %} -
  • -
    - {{ player.username }} ({{ player.ip }}) -
    -
    - Manage Player - Full Screen - {% if current_user.role == 'admin' %} -
    - -
    - {% endif %} -
    -
  • - {% endfor %} -
+ +
+
+

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 %} +
+
+ + +
+
+

Content Upload

+
+ +
+ + {% if current_user.role == 'admin' %} -
- Add Player +
+
+

Integrate Player

+
+
{% endif %}
-
- -
-
-

Player Groups

-
-
-
    - {% for group in groups %} -
  • -
    - {{ group.name }} ({{ group.players | length }} players) -
      - {% for player in group.players %} -
    • - {{ player.username }} ({{ player.ip }}) -
    • - {% endfor %} -
    -
    -
    - Manage Group - Full Screen - {% if current_user.role == 'admin' %} -
    - -
    - {% endif %} -
    -
  • - {% endfor %} -
- {% if current_user.role == 'admin' %} -
- Add Group + + {% if current_user.role == 'admin' %} +
+
+
+

App Settings

+
+
- {% endif %}
+ {% endif %}
- - -
-
-

Content Upload

-
- -
- - - {% if current_user.role == 'admin' %} -
-
-

Integrate Player

-
- -
- {% endif %}
diff --git a/templates/integrate_player.html b/templates/integrate_player.html index b84871a..7ef9f41 100644 --- a/templates/integrate_player.html +++ b/templates/integrate_player.html @@ -3,13 +3,26 @@ Integrate Player + - +

Integrate Player

-
+

Players

@@ -17,7 +30,7 @@
{% for player in players %}
-
+
{{ player.username }}

{{ player.ip }}

@@ -35,7 +48,7 @@
-
+

Groups

@@ -43,7 +56,7 @@
{% for group in groups %}
-
+
{{ group.name }}

{{ group.players | length }} players

diff --git a/templates/manage_group.html b/templates/manage_group.html index eefcd82..e46ccfa 100644 --- a/templates/manage_group.html +++ b/templates/manage_group.html @@ -3,13 +3,26 @@ Manage Group + - +

Manage Group: {{ group.name }}

-
+

Add Players to Group

@@ -29,17 +42,17 @@
-
+

Players in Group

    {% for player in group.players %} -
  • -
    {{ player.username }} ({{ player.ip }})
    +
  • + {{ player.username }} ({{ player.ip }})
    - +
  • {% endfor %} @@ -47,57 +60,15 @@
- -
-
-

Upload Content for Group

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

Manage Group Content

-
-
-
    - {% for content in group.content %} -
  • -
    {{ content.file_name }} - {{ content.duration }} seconds
    -
    - -
    - - -
    - -
    - -
    -
    -
  • - {% endfor %} -
- Full Screen -
+ + {% if current_user.role == 'admin' %} + + {% endif %} Back to Dashboard
- \ No newline at end of file diff --git a/templates/player_auth.html b/templates/player_auth.html index 2ff29e6..754172c 100644 --- a/templates/player_auth.html +++ b/templates/player_auth.html @@ -3,8 +3,21 @@ Player Authentication + - +

Player Authentication

diff --git a/templates/player_page.html b/templates/player_page.html index ddbf382..496ae9b 100644 --- a/templates/player_page.html +++ b/templates/player_page.html @@ -3,13 +3,26 @@ Player Schedule + - +

Player Schedule for {{ player.username }}

-
+

Player Info

@@ -32,76 +45,24 @@

Member of Group(s):

    {% for group in player.groups %} -
  • -
    {{ group.name }}
    - - -
  • - +
  • {{ group.name }}
  • {% endfor %}
{% else %} -

Not a member of any group

+

This player is not a member of any groups.

{% endif %}
- -
-
-

Schedule

-
-
-
    - {% for item in content %} -
  • -
    - {{ item.file_name }} - {{ item.duration }} seconds -
    - {% if not player.groups %} -
    - -
    - - -
    - -
    - -
    -
    - {% endif %} -
  • - {% endfor %} -
-
-
- - - {% if not player.groups %} -
-
-

Upload Content

-
-
-
-
- - -
-
- - -
- -
-
+ + {% if current_user.role == 'admin' %} + {% endif %} Back to Dashboard Full Screen
- \ No newline at end of file diff --git a/templates/register.html b/templates/register.html index 982a6f0..f4d1d17 100644 --- a/templates/register.html +++ b/templates/register.html @@ -3,8 +3,21 @@ Register + - +

Register

diff --git a/templates/upload_content.html b/templates/upload_content.html index 87f85c6..a7d1aca 100644 --- a/templates/upload_content.html +++ b/templates/upload_content.html @@ -3,32 +3,58 @@ Upload Content + - +

Upload Content

- + + + {% if target_type %} + + {% endif %}
- {% for player in players %} - + {% endfor %} {% for group in groups %} - + {% endfor %} + {% if target_id %} + + {% endif %} +
+
+ +
@@ -40,8 +66,26 @@
+ Back Back to Dashboard
+