Conversation
Fixed code so the server can run and run on port 8000
This reverts commit e99f4e4.
allows running server or local
Reactions.py temporary module created.
…reactions relationship added to post.py; blueprint registration added to __init__.py
There was a problem hiding this comment.
Pull request overview
This PR merges development work that adds reactions, private posts + file uploads, MySQL-oriented configuration/startup, and splits core functionality into additional blueprints/modules.
Changes:
- Reworked local startup and configuration to default to MySQL (plus added PyMySQL/cryptography dependencies).
- Added new post features: optional file upload, private posts, and reaction buttons on the post view.
- Introduced new modules/blueprints for posts, subforums, and reactions; added extensive project documentation.
Reviewed changes
Copilot reviewed 24 out of 25 changed files in this pull request and generated 18 comments.
Show a summary per file
| File | Description |
|---|---|
| run.sh | New bootstrap script (venv creation, dependency install, env defaults, server/dev modes). |
| requirements.txt | Adds MySQL driver and crypto dependency for authentication support. |
| README.md | Adds team startup guidance and MySQL migration link (currently with path issues). |
| PROJECT_FLOW.md | New high-level project/runtime flow documentation. |
| MYSQL_MIGRATION_GUIDE.md | New MySQL migration + startup guide (currently inconsistent with code). |
| CIRCUSCIRCUS_FULL_CODE_GUIDE.md | Large onboarding guide for codebase behavior (currently inconsistent with code). |
| Procfile | Removes old gunicorn Procfile entry. |
| config.py | Switches configuration to build a MySQL SQLAlchemy URI; adds upload config fields. |
| forum/init.py | Registers additional blueprints (posts/subforums/reactions) and adjusts imports. |
| forum/app.py | Adds seeding protections, schema-compat “ALTER TABLE add missing columns”, and startup tweaks. |
| forum/models.py | Updates User column types for MySQL compatibility; leaves other models modularized. |
| forum/routes.py | Keeps auth/login routes; comments out routes moved into other modules. |
| forum/post.py | New Post model + routes for posting, viewing, commenting (as replies), uploads, and privacy checks. |
| forum/subforum.py | New Subforum model + routes for browsing, creating, deleting subforums. |
| forum/Reactions.py | New Reaction model + route to toggle reactions. |
| forum/ignore.py | Adds MySQL bootstrap helper functions (currently incomplete/unimportable). |
| forum/templates/*.html | UI updates for private posts, uploads, reactions, admin controls, and minor HTML improvements. |
| forum/static/style.css | Adds CSS classes to replace repeated inline styles. |
Comments suppressed due to low confidence (1)
README.md:58
- README claims the app appears on port 5000, but
run.shdefaultsPORTto 8000 andforum/app.pyruns on 8000 when executed directly. Update the README to match the actual default port (or change the script default to 5000) to avoid confusion.
python3.11 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
./run.sh
and it should appear on port 5000
`http://0.0.0.0:5000`
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Shared SQLAlchemy object used by the app factory and all models. | ||
| from flask_sqlalchemy import SQLAlchemy | ||
|
|
||
| db = SQLAlchemy() | ||
|
|
||
| # Database models | ||
| class User(UserMixin, db.Model): | ||
| # Store account information and ownership of posts/comments. | ||
| id = db.Column(db.Integer, primary_key=True) | ||
| username = db.Column(db.String(80), unique=True, nullable=False) | ||
| password_hash = db.Column(db.String(255), nullable=False) | ||
| email = db.Column(db.String(255), unique=True, nullable=False) | ||
| admin = db.Column(db.Boolean, default=False) | ||
| posts = db.relationship("Post", backref="user") |
There was a problem hiding this comment.
This module defines a new db = SQLAlchemy() and an ORM User model, but the application’s shared db is already defined in forum/models.py. Having a second SQLAlchemy instance/model registry will cause tables/relationships and queries to bind to different metadata/engines. Remove the local db/ORM model from this file and import db/User from forum.models instead (keeping forum/user.py for validation/query helpers only).
| @@ -23,3 +52,63 @@ def username_taken(username): | |||
| return User.query.filter(User.username == username).first() | |||
| def email_taken(email): | |||
| return User.query.filter(User.email == email).first() | |||
|
|
|||
|
|
|||
| ########################################################################## | |||
| import hashlib | |||
| import hmac | |||
| import secrets | |||
|
|
|||
|
|
|||
| class User: | |||
| def __init__(self, id, username, password, email, | |||
| is_admin=False, permissions=None, privacy="public"): | |||
|
|
|||
| # --- Core Fields --- | |||
| self.id = id # Primary Key | |||
| self.username = username | |||
| self.password_hash = self._hash_password(password) | |||
There was a problem hiding this comment.
User is imported from .models (line 31) and then later redefined as a plain Python class (line 63). This overwrites the ORM model, so username_taken()/email_taken() will start referencing the non-ORM User at runtime and crash (User has no .query). Rename/remove the second User class (or move it to a different module/name) so the ORM User stays in scope.
| @login_required | ||
| @subforum_rt.route('/createsubforum', methods=['GET', 'POST']) | ||
| def create_subforum_page(): |
There was a problem hiding this comment.
Decorator order is reversed here: @login_required is applied after @subforum_rt.route, which means the blueprint registers the unprotected function and the login check won’t run. Swap the decorator order so @subforum_rt.route(...) is outermost and @login_required is directly above the function.
| @login_required | ||
| @subforum_rt.route('/deletesubforum', methods=['POST']) | ||
| def delete_subforum(): |
There was a problem hiding this comment.
Same decorator-order issue as above: with @login_required above @subforum_rt.route, the route is registered without authentication. Swap the decorators so the registered view function is the login_required wrapper.
| # Only admins can delete subforums. | ||
| if not current_user.admin: | ||
| return Subforum.error("Only administrators can delete subforums!") | ||
|
|
There was a problem hiding this comment.
Subforum.error(...) does not exist (there is no error method on the model), so these branches will raise AttributeError. Use the imported error(...) helper (or return a proper Flask response) instead.
| file = request.files.get('upload_file') | ||
| filename = None | ||
| if file and file.filename: | ||
| filename = secure_filename(file.filename) | ||
| file.save(os.path.join(current_app.config['UPLOAD_FOLDER'], filename)) | ||
| post = Post(title=title, content=content, postdate=datetime.datetime.now(), upload_file=filename, private=private) |
There was a problem hiding this comment.
file.save(os.path.join(current_app.config['UPLOAD_FOLDER'], filename)) will fail if the upload directory doesn’t exist. Config.UPLOAD_FOLDER points to forum/static/uploads, but that directory is not present in the repo. Ensure the directory is created on startup (e.g., os.makedirs(..., exist_ok=True)) before saving uploads.
| {% if post.upload_file %} | ||
| {% if post.upload_file.endswith(('.mp4', 'mov', '.webm')) %} | ||
| <video controls> | ||
| <source src="/uploads/{{ post.upload_file }}"> | ||
| </video> | ||
| {% else %} | ||
| <img src="/uploads/{{ post.upload_file }}"> | ||
| {% endif %} |
There was a problem hiding this comment.
The new image rendering <img src="/uploads/{{ post.upload_file }}"> is missing an alt attribute, which is important for accessibility/screen readers. Add a meaningful alt text (even a generic one like the filename) when rendering uploaded images.
| - Python imports modules. | ||
| - config.py executes top-level code. | ||
| - check_mysql_and_setup() runs during import. | ||
|
|
There was a problem hiding this comment.
This guide states that config.py contains and runs MySQL bootstrap helpers (and that check_mysql_and_setup() runs during config import), but in this PR config.py only defines Config and the bootstrap code appears in forum/ignore.py (which currently isn’t imported and is missing required imports). Please update the guide to match the actual bootstrap location/behavior, or move the bootstrap into config.py as described.
| ### 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.
This guide claims config.py includes startup helpers and runs MySQL setup checks, but config.py in this PR only builds the DB URI. Either implement the described bootstrap (DB/user creation + connectivity checks) where documented, or update this guide to reflect the current behavior/location (e.g., forum/ignore.py).
| We changed the model fields that need uniqueness or fixed sizes: | ||
|
|
||
| - `User.username` became a bounded string | ||
| - `User.email` became a bounded string | ||
| - `User.password_hash` became a bounded string | ||
| - `Post.title` became a bounded string | ||
| - `Subforum.title` became a bounded string | ||
|
|
There was a problem hiding this comment.
The guide says Post.title became a bounded string for MySQL compatibility, but forum/post.py still defines Post.title as db.Text (line 16). Update the guide or the model so they match (especially if you expect schema compatibility across environments).
merging in reactions, post updates, and simplified config file