Conversation
Fixed code so the server can run and run on port 8000
This reverts commit e99f4e4.
allows running server or local
…r and recipient relationships established, blueprint
…istent users outlawed.
…tml updated to use her nav bar design, messages page style created to match what already exists, and style.css updated to address messing prompts.
There was a problem hiding this comment.
Pull request overview
This PR merges a broad set of “dev” changes into main, including a new UI/theme (“ZipChat”), a MySQL-based configuration path, and multiple new forum features (uploads/private posts, reactions, messages, admin subforum management) alongside significant refactoring of models/routes and expanded onboarding documentation.
Changes:
- Reworked app startup/config (new
run.sh, MySQL URI inconfig.py, schema-compat helper inforum/app.py). - Added/changed core features: file uploads + private posts + delete-post, reactions, and direct messages; plus admin-only create/delete subforums.
- Large UI refresh across templates and CSS, plus new “how the project works” documentation.
Reviewed changes
Copilot reviewed 26 out of 31 changed files in this pull request and generated 19 comments.
Show a summary per file
| File | Description |
|---|---|
| run.sh | New launcher that creates venv, installs deps, sets defaults, and runs Flask. |
| requirements.txt | Adds dependencies for MySQL/crypto and HTTP client. |
| README.md | Adds team guide + updated local startup instructions. |
| PROJECT_FLOW.md | New high-level runtime/data-flow documentation. |
| MYSQL_MIGRATION_GUIDE.md | New MySQL migration/startup guide. |
| CIRCUSCIRCUS_FULL_CODE_GUIDE.md | New extensive onboarding/codebase guide. |
| Procfile | Removed deployment entrypoint. |
| config.py | Switches SQLAlchemy DB URI to MySQL + adds upload config values. |
| forum/init.py | Registers new blueprints (posts/subforums/reactions/messages/auth). |
| forum/app.py | Updates site metadata, seeds protected subforums, adds schema-compat logic. |
| forum/models.py | Leaves shared db + helper validators; model classes moved to modules. |
| forum/routes.py | Old monolithic routes are commented out; blueprint remains. |
| forum/user.py | Introduces User model + auth blueprint + validation helpers. |
| forum/subforum.py | Introduces Subforum model + subforum browse/create/delete endpoints. |
| forum/post.py | Introduces Post model + uploads/private posts/comments/delete endpoints. |
| forum/Reactions.py | Adds Reaction model + react endpoint. |
| forum/messages.py | Adds Messages model + inbox/compose endpoints. |
| forum/templates/layout.html | New layout shell + new external assets + JS include. |
| forum/templates/header.html | New navbar + Messages link. |
| forum/templates/subforums.html | New “hero” top-level subforums UI. |
| forum/templates/subforum.html | Adds admin subforum actions + message links. |
| forum/templates/viewpost.html | Adds private badge, uploads rendering, delete button, reactions, message links. |
| forum/templates/createpost.html | Adds upload + “private post” option. |
| forum/templates/createsubforum.html | New subforum creation page. |
| forum/templates/messages.html | New messages UI. |
| forum/static/style.css | Large ZipChat-themed CSS refresh + compatibility styles. |
| forum/static/js.txt | Adds a small JS stub file. |
| forum/static/uploads/.gitkeep | Keeps uploads directory tracked while ignoring user uploads. |
| .gitignore | Ignores uploaded files under forum/static/uploads/*. |
| .DS_Store | Adds macOS Finder metadata file to repo. |
| forum/.DS_Store | Adds macOS Finder metadata file to repo under forum/. |
Comments suppressed due to low confidence (1)
Procfile:1
- Procfile was removed. If this app is deployed on a platform that relies on Procfile (e.g., Heroku), this will break the web process startup; either keep an updated Procfile (gunicorn entry) or update deployment docs/config accordingly.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| ## Team Guide | ||
|
|
||
| If you want the full explanation of the MySQL migration, startup flow, and schema changes, read [MYSQL_MIGRATION_GUIDE.md](/Users/ethan/Projects/CircusCircus/MYSQL_MIGRATION_GUIDE.md). |
There was a problem hiding this comment.
README links to MYSQL_MIGRATION_GUIDE.md using an absolute local filesystem path (/Users/...). This will be broken for everyone else and on GitHub; change it to a repository-relative link (e.g., ./MYSQL_MIGRATION_GUIDE.md).
| If you want the full explanation of the MySQL migration, startup flow, and schema changes, read [MYSQL_MIGRATION_GUIDE.md](/Users/ethan/Projects/CircusCircus/MYSQL_MIGRATION_GUIDE.md). | |
| If you want the full explanation of the MySQL migration, startup flow, and schema changes, read [MYSQL_MIGRATION_GUIDE.md](./MYSQL_MIGRATION_GUIDE.md). |
| ``` | ||
| $ python3.11 -m venv venv | ||
| $ source venv/bin/activate | ||
| $ pip install -r requirements.txt | ||
| $ ./run.sh | ||
| python3.11 -m venv venv | ||
| source venv/bin/activate | ||
| pip install -r requirements.txt | ||
| ./run.sh | ||
| ``` | ||
|
|
||
| and it should appear on port 5000 |
There was a problem hiding this comment.
README’s quickstart implies a fixed port, but run.sh now defaults PORT to 8000 (and can be overridden via env). Update this section to reflect the new default and/or mention using $PORT.
| # MySQL-only configuration. | ||
| export DB_USER="${DB_USER:-zipchat_app}" | ||
| export DB_HOST="${DB_HOST:-127.0.0.1}" | ||
| export DB_PORT="${DB_PORT:-3306}" | ||
| export DB_NAME="${DB_NAME:-ZipChat}" | ||
| export DB_PASSWORD="${DB_PASSWORD:-password}" | ||
|
|
There was a problem hiding this comment.
run.sh exports a hard-coded default DB_PASSWORD ("password"). Even if intended for local dev, this makes it easy to accidentally run with insecure credentials; consider requiring explicit DB_PASSWORD (or reading from a local .env) and/or printing a prominent warning when the default is used.
| """Configuration values consumed by Flask and Flask-SQLAlchemy.""" | ||
|
|
||
| SECRET_KEY = environ.get("SECRET_KEY", "kristofer") | ||
| FLASK_APP = "forum.app" | ||
| UPLOAD_FOLDER = path.join(basedir, "forum", "static", "uploads") | ||
| ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "gif", "mp4", "mov", "webm"} | ||
|
|
||
| DB_USER = environ.get("DB_USER", "zipchat_app") | ||
| DB_PASSWORD = environ.get("DB_PASSWORD", "password") | ||
| DB_HOST = environ.get("DB_HOST", "127.0.0.1") | ||
| DB_PORT = environ.get("DB_PORT", "3306") | ||
| DB_NAME = environ.get("DB_NAME", "ZipChat") |
There was a problem hiding this comment.
config.py hard-codes insecure default credentials (SECRET_KEY="kristofer", DB_PASSWORD="password"). Defaults are convenient for local dev, but they are dangerous if deployed as-is; consider failing fast in non-dev environments or requiring these values to be set explicitly.
| <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css" rel="stylesheet"> | ||
| <link rel="stylesheet" type="text/css" href="{{url_for('static', filename="bootstrap.min.css")}}"> | ||
| <link rel="stylesheet" type="text/css" href="{{url_for('static', filename="style.css")}}"> | ||
| <script src="{{url_for('static', filename="forum.js")}}"></script> |
There was a problem hiding this comment.
layout.html includes a static asset "forum.js", but there is no corresponding file under forum/static/. This will 404 in the browser; either add forum/static/forum.js (or rename the existing js.txt) or remove the script tag.
| <script src="{{url_for('static', filename="forum.js")}}"></script> |
| ### 4. Startup now tries to prepare MySQL automatically | ||
|
|
||
| `config.py` now includes startup helpers that: | ||
|
|
||
| - try to connect to MySQL as an admin user on the local machine | ||
| - create the `ZipChat` database if it is missing | ||
| - create the `zipchat_app` user if it is missing | ||
| - grant that user access to the database | ||
| - verify that the app credentials can connect | ||
|
|
||
| This is a best-effort bootstrap. If MySQL admin access is unavailable on a specific machine, the code prints clear instructions instead of failing silently. | ||
|
|
There was a problem hiding this comment.
MYSQL_MIGRATION_GUIDE.md claims config.py performs MySQL admin bootstrap (create DB/user/grants), but the current config.py only builds SQLALCHEMY_DATABASE_URI and contains no such helpers. Either implement the described bootstrap logic or adjust the guide to match actual behavior so onboarding instructions are accurate.
| function submitPost() { | ||
| const input = document.getElementById("composeInput"); | ||
| if (!input.value.trim()) return; | ||
|
|
||
| alert("Post submitted: " + input.value); | ||
| input.value = ""; | ||
| } No newline at end of file |
There was a problem hiding this comment.
forum/static/js.txt is not a recognized asset name for browsers and is not referenced by any template (layout.html tries to load forum.js). Rename this to a .js file under static/ (and reference it), or remove it if it’s leftover.
| def ensure_model_schema_compatibility(): | ||
| # Keep existing MySQL tables compatible with current and future model columns. | ||
| inspector = inspect(db.engine) | ||
| existing_tables = set(inspector.get_table_names()) | ||
|
|
||
| with db.engine.begin() as conn: | ||
| for mapper in db.Model.registry.mappers: | ||
| table = mapper.local_table | ||
| table_name = table.name | ||
| if table_name not in existing_tables: | ||
| continue | ||
|
|
||
| existing_columns = {col["name"] for col in inspector.get_columns(table_name)} | ||
| for column in table.columns: | ||
| if column.name in existing_columns: | ||
| continue | ||
| if column.primary_key: | ||
| continue | ||
|
|
||
| column_type = column.type.compile(dialect=db.engine.dialect) | ||
| nullability = "NULL" if column.nullable else "NOT NULL" | ||
|
|
||
| default_sql = "" | ||
| if column.default is not None and getattr(column.default, "is_scalar", False): | ||
| default_sql = f" DEFAULT {_sql_literal(column.default.arg)}" | ||
|
|
||
| sql = ( | ||
| f"ALTER TABLE `{table_name}` " | ||
| f"ADD COLUMN `{column.name}` {column_type} {nullability}{default_sql}" | ||
| ) | ||
| conn.execute(text(sql)) | ||
|
|
There was a problem hiding this comment.
ensure_model_schema_compatibility() runs ALTER TABLE statements automatically on app startup. This is operationally risky (startup DDL, potential locks, partial schema updates, missing indexes/constraints, and races with concurrent app instances). Prefer using a proper migration tool (Alembic/Flask-Migrate) and keeping startup read-only with respect to schema.
| @post_rt.route('/action_comment', methods=['POST', 'GET']) | ||
| @login_required | ||
| def comment(): | ||
| post_id = int(request.args.get("post")) | ||
| post = Post.query.filter(Post.id == post_id).first() | ||
| if not post: | ||
| return error("That post does not exist!") | ||
| content = request.form['content'] | ||
| reply = Post(content=content, postdate=datetime.datetime.now()) |
There was a problem hiding this comment.
action_comment declares methods=['POST','GET'] but the handler unconditionally reads request.form['content'], which will fail on GET. Restrict this endpoint to POST only (or handle GET explicitly).
| @post_rt.route('/action_delete_post', methods=['POST']) | ||
| @login_required | ||
| def action_delete_post(): | ||
| post_id = int(request.form['post_id']) | ||
| post = Post.query.filter(Post.id == post_id).first() | ||
| if not post: | ||
| return error("That post does not exist!") | ||
| if post.user_id != current_user.id and not current_user.admin: | ||
| return error("You do not have permission to delete this post.") | ||
| Post.query.filter(Post.parent_id == post_id).delete() | ||
| db.session.delete(post) | ||
| db.session.commit() | ||
| return redirect("/subforum?sub=" + str(post.subforum_id)) No newline at end of file |
There was a problem hiding this comment.
These POST endpoints (delete post, react, send message, delete subforum) are vulnerable to CSRF because the app does not include CSRF tokens in forms or server-side CSRF validation. Consider adding CSRF protection (e.g., Flask-WTF or a custom token) at least for state-changing/destructive actions.
Merging into main new front end look and name change as well as delete post option and implemented user class.