-
Notifications
You must be signed in to change notification settings - Fork 27
FastAPI-Based Multi-User Image Gallery with Admin Moderation #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
- Add admin router with user management endpoints - Create admin service for role-based access control - Add admin dashboard and user gallery templates - Implement admin authentication checks - Add unauthorized access template - Fix JWT configuration and improve token validation - Update gallery to show metadata JSON properly - Add admin navigation and styling - Update tests for new admin functionality
Summary of ChangesHello @safiya2610, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request delivers a comprehensive, full-stack image gallery application built with FastAPI. It establishes a secure environment for users to manage their image collections, complete with Google OAuth for authentication and a sophisticated admin panel for content oversight. The system also introduces an innovative image analysis component that detects and associates 'fuzzy emotions' with uploaded pictures, enriching the user's interaction with their visual content. The changes span across new routing, service layers, middleware, database schema, and front-end templates, creating a robust and feature-rich platform. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a significant amount of new functionality for a multi-user image gallery with admin moderation. The overall structure is well-organized, leveraging FastAPI's features like routers and dependencies. However, the review has identified several issues that need attention. These include a critical bug in the admin panel that leads to incorrect redirects, security vulnerabilities related to input sanitization and hardcoded credentials, and multiple areas where code can be refactored to improve maintainability, reduce duplication, and adhere to best practices. Addressing these points will significantly improve the quality and robustness of the application.
| ) | ||
| db.commit() | ||
|
|
||
| return RedirectResponse(f"/admin/user/{user_email}", status_code=303) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a critical bug in the redirect URL. You are redirecting to /admin/user/{user_email}, but the corresponding route /admin/user/{user_id} expects an integer user_id, not an email string. This will result in a 'Not Found' error.
To fix this, you need to query the database to get the user's ID from their email before creating the redirect response, similar to the pattern used in the admin_update_narrative endpoint.
| return RedirectResponse(f"/admin/user/{user_email}", status_code=303) | |
| cur.execute("SELECT id FROM users WHERE email = ?", (user_email,)) | |
| user_row = cur.fetchone() | |
| if not user_row: | |
| return RedirectResponse("/admin", status_code=303) | |
| user_id = user_row[0] | |
| return RedirectResponse(f"/admin/user/{user_id}", status_code=303) |
|
|
||
|
|
||
| def save_image(db, user, image, visibility): | ||
| ext = Path(image.filename).suffix or ".jpg" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The filename from the user upload (image.filename) is used to determine the file extension without proper sanitization. A malicious filename could potentially contain path traversal characters (../) or other exploits. It is a security best practice to sanitize all user-provided input, including filenames. Consider using a library function like werkzeug.utils.secure_filename or implementing a custom sanitization function that whitelists allowed characters.
|
|
||
| cur.execute("SELECT id FROM users WHERE email = ?", (user_email,)) | ||
| user_row = cur.fetchone() | ||
| user_id = user_row[0] if user_row else 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Defaulting to user_id = 1 when a user is not found is dangerous. It could lead to incorrect redirects or actions being performed on the wrong user account. It's much safer to handle the 'not found' case explicitly, for example, by redirecting to the admin dashboard.
| user_id = user_row[0] if user_row else 1 | |
| user_id = user_row[0] if user_row else None | |
| if not user_id: | |
| return RedirectResponse("/admin", status_code=303) |
| from fastapi import APIRouter, Request, Depends | ||
| from fastapi.responses import RedirectResponse | ||
| from db import get_db | ||
| from app.services.auth_service import * |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using wildcard imports (from ... import *) is discouraged by PEP 8 as it can pollute the namespace and make it unclear which names are being imported. It's better to explicitly import the functions you need.
| from app.services.auth_service import * | |
| from app.services.auth_service import google_login_redirect, google_callback_handler |
| try: | ||
| with open("cleaned_data.json", "r", encoding="utf-8") as f: | ||
| CLEANED = json.load(f) | ||
| except Exception as e: | ||
| CLEANED = {"colors": []} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This broad except Exception can hide various issues (e.g., file not found, permission error, invalid JSON). It's better to catch specific exceptions (like FileNotFoundError, json.JSONDecodeError) and use the logging module to report errors instead of silently failing. This will make debugging much easier.
| except ValueError as e: | ||
|
|
||
| print(f"KMeans clustering failed: {e}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| @app.exception_handler(Exception) | ||
| async def unhandled_exception_handler(request: Request, exc: Exception): | ||
| # Do not leak internals; optionally log exc to server logs here | ||
| return JSONResponse( | ||
| status_code=500, | ||
| content={"detail": "Internal server error"}, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unhandled exception handler correctly avoids leaking internal details to the client. However, it's crucial for debugging to log the actual exception on the server side. The traceback module is imported but not used. I suggest using a proper logger to capture the stack trace of unhandled exceptions, which will be invaluable for debugging production issues.
| <img src="/static/images/home3.jpg" alt="" class="img"> | ||
| </img> | ||
| </div> | ||
|
|
||
| <div class="card"> | ||
| <img src="/static/images/home4.jpg" alt="" class="img"> | ||
| </img> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| <img | ||
| src="https://talatyusuf.com/my-content/uploads/2025/02/99-Quotes-about-Change-in-People-Behaviour-Suddenly-4.jpg" | ||
| > | ||
| </img> | ||
|
|
||
| </div> | ||
| </section> | ||
|
|
||
|
|
||
| <section class="scene" data-speed="0.30"> | ||
| <div class="scene-bg" | ||
| style="background-image:url('https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRakOvNWFhYFkIwddm2a1O1BMJCZmR3QtHhyA&s')"> | ||
| </div> | ||
|
|
||
| <div class="scene-content"> | ||
|
|
||
| <img | ||
| src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSEgDJyE6Yw3Vd0jXOawqQSsTtkDg7GHK6i6w&s" | ||
| > | ||
| </img> | ||
| </div> | ||
|
|
||
| </section> | ||
|
|
||
|
|
||
| <section class="scene" data-speed="0.40"> | ||
| <div class="scene-bg" | ||
| style="background-image:url('https://images.template.net/358779/Memphis-Cute-Background-edit-online-3.jpg')"> | ||
| </div> | ||
|
|
||
| <div class="scene-content"> | ||
|
|
||
| <img | ||
| src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRbheh_eC-zLDcj8W76ksaBHyyEwjrtwZwM-A&s" | ||
| > | ||
| </img> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Description
Developed a FastAPI-based image gallery system supporting multi-user authentication and role-based authorization. Users can upload images with metadata and narratives, while admins can monitor all users through a centralized dashboard, view individual galleries, and perform moderation actions such as editing narratives and deleting images. The system uses SQLite as a shared database and Jinja2 for dynamic UI rendering.
Features
User Features
Google OAuth Login
Upload images
Add / edit narrative
Delete own images
View image metadata
Private / Public visibility support
Admin Features
Admin-only dashboard
View all users
Open any user’s gallery
Edit any user’s narrative
Delete any user’s images
View metadata of all images