from operator import pos import os from flask import Blueprint, current_app, flash, redirect, render_template, request, send_file, url_for import ulid import datetime from flask_login import current_user, login_required from io import BytesIO from PIL import Image import base64 from acmsite.models import Link, Officer, User, Event from acmsite import models from .forms import EventForm, LinkForm, OfficerForm from acmsite import db bp = Blueprint("admin", __name__, url_prefix="/admin") @bp.route("/") @login_required def home(): if not current_user.is_admin: flash("Unauthorized") return redirect(url_for('dashboard.home')) return render_template("admin/index.html") @bp.route("/users") @login_required def users(): if not current_user.is_admin: flash("Unauthorized") return redirect(url_for('dashboard.home')) user_list = User.query.all() position_form = OfficerForm(request.form) return render_template("admin/users.html", u_list=user_list, form=position_form) @bp.route("/users/toggle_admin/") @login_required def toggle_admin(user_id): if not current_user.is_admin: return error_json("Unauthorized") u = User.query.filter_by(id=user_id).first() if u is None: return error_json("Invalid user") u.is_admin = not u.is_admin db.session.commit() current_app.logger.info(f"{current_user.email} toggled admin status for {u.email}") return success_json() @bp.route("/users.csv") @login_required def users_csv(): if not current_user.is_admin: flash("Unauthorized") return redirect(url_for('dashboard.home')) user_list = User.query.all() models.create_acm_csv(user_list) return send_file('./tmp/members.csv') @bp.route("/events") @login_required def events(): if not current_user.is_admin: flash("Unauthorized") return redirect(url_for('dashboard.home')) event_list = Event.query.all() form = EventForm(request.form) return render_template("admin/events.html", e_list=event_list, form=form) @bp.route("/event/") @login_required def event(id): if not current_user.is_admin: return {"status": "error", "message": "Unauthorized"} event = Event.query.filter_by(id=id).first() if event is None: return {"status": "error", "message": "Invalid event ID"} return event.create_json() @bp.route("/event//delete") @login_required def delete_event(id): if not current_user.is_admin: return {"status": "error", "message": "Unauthorized"} event = Event.query.filter_by(id=id).first() if event is None: return {"status": "error", "message": "Invalid event ID"} db.session.delete(event) db.session.commit() return {"status": "success"} @bp.route("/event/", methods=["POST"]) @login_required def update_create_event(id): if not current_user.is_admin: flash("Unauthorized") return redirect(url_for("dashboard.home")) name = request.form.get('name') description = request.form.get('description') location = request.form.get('location') start_day = request.form.get('start_day') start_time = request.form.get('start_time') end_day = request.form.get('end_day') end_time = request.form.get('end_time') start = datetime.datetime.combine(datetime.date.fromisoformat(start_day), datetime.time.fromisoformat(start_time)) end = datetime.datetime.combine(datetime.date.fromisoformat(end_day), datetime.time.fromisoformat(end_time)) if id == '0': # new event e = Event( id=ulid.ulid(), name=name, description=description, location=location, start_time=start, end_time=end) db.session.add(e) db.session.commit() current_app.logger.info(f"{current_user} is creating a new event: {e.name}") else: e = Event.query.filter_by(id=id).first() if e is None: return {"status": "error", "message": "Invalid event ID"} e.name = name e.description = description e.location = location e.start_time = start e.end_time = end db.session.commit() current_app.logger.info(f"{current_user} is updating an existing event: {e.name}") return redirect(url_for("admin.events")) @bp.route("/links") @login_required def links(): if not current_user.is_admin: flash("Unauthorized") return redirect(url_for("dashboard.home")) links = Link.query.all() form = LinkForm(request.form) return render_template("admin/links.html", links=links, form=form) @bp.route("/link/") @login_required def link(id): if not current_user.is_admin: return {"status": "error", "message": "Unauthorized"} link = Link.query.filter_by(id=id).first() if link is None: return {"status": "error", "message": "Invalid ID"} return link.create_json() @bp.route("/link/", methods=["POST"]) @login_required def update_create_link(id): if not current_user.is_admin: flash("Unauthorized") return redirect(url_for("dashboard.home")) slug = request.form.get('slug') destination = request.form.get('destination') if id == '0': # new link l = Link( id=ulid.ulid(), slug=slug, destination=destination) db.session.add(l) db.session.commit() else: l = Link.query.filter_by(id=id).first() if l is None: flash("Invalid ID") return redirect(url_for("admin.links")) l.slug = slug l.destination = destination db.session.commit() return redirect(url_for("admin.links")) def error_json(message): return {"status": "error", "message": message} def success_json(): return {"status": "success"} @bp.route("/officer/") @login_required def officer_positions(user_id): if not current_user.is_admin: flash("Unauthorized") return redirect(url_for("dashboard.home")) form = OfficerForm(request.form) position_list = Officer.query.filter_by(user_id=user_id).order_by(Officer.term_end).all() return render_template("admin/officers.html", form=form, position_list=position_list, user_id=user_id) @bp.route("/officer/get/") @login_required def get_position(pos_id): if not current_user.is_admin: return error_json("Unauthorized") pos = Officer.query.filter_by(id=pos_id).first() if pos is None: return error_json("Invalid ID") return pos.create_json() @bp.route("/officer/new/", methods=["POST"]) @login_required def create_officer(user_id): if not current_user.is_admin: error_json("Unauthorized") form = OfficerForm(request.form) if form.validate_on_submit: position = request.form.get("position") term_end = request.form.get("term_end") term_start = request.form.get("term_start") position = Officer( id=ulid.ulid(), user_id=user_id, position=position, term_start=term_start, term_end=term_end) db.session.add(position) db.session.commit() return redirect(url_for("admin.officer_positions", user_id=user_id)) @bp.route("/officer/update//", methods=["POST"]) @login_required def update_officer(user_id, officer_id): if not current_user.is_admin: flash("Unauthorized") return redirect(url_for('dashboard.home')) form = OfficerForm(request.form) if form.validate_on_submit: officer = Officer.query.filter_by(id=officer_id).first() if officer is None: flash("Invalid ID") return redirect(url_for('admin.officer_positions', user_id=user_id)) officer.position = request.form.get("position") officer.term_start = request.form.get("term_start") officer.term_end = request.form.get("term_end") db.session.commit() return redirect(url_for('admin.officer_positions', user_id=user_id)) @bp.route("/officer/photo") @login_required def upload_photo(): if not current_user.is_admin: return error_json("Unauthorized") return render_template("admin/officer_photo.html") @bp.route("/officer/photo/upload", methods=["POST"]) @login_required def upload_photo_post(): if not current_user.is_admin: return error_json("Unauthorized") img_path = os.path.join("acmsite/" + current_app.config["UPLOAD_FOLDER"], f"{current_user.username()}.png") b64_string = request.data.decode() b64_string += '=' * (len(b64_string) % 4) im = Image.open(BytesIO(base64.b64decode(b64_string.split(',')[1]))) im.save(img_path, format="PNG") return success_json()