Skip to content

ishant025/cms-image-gallery

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Content मंच

Content मंच

Content को दें नई पहचान

A modern, cloud-powered Image & GIF Gallery — built with Flask, AWS S3, Neon PostgreSQL, and Tailwind CSS.

Python Flask AWS S3 Neon Tailwind CSS Render Tests


✨ Features

Core Features

  • 🔐 Secure Authentication — Sign up, log in, and log out with hashed passwords (Werkzeug + Flask-Login)
  • ☁️ Cloud Storage — Images uploaded directly to AWS S3 with public-read URLs
  • 🏷️ Tag System — Add up to 20 tags per image for easy discovery
  • 🔍 Live Search — Dynamic, case-insensitive partial tag search without page reloads
  • 👍 Like / Dislike — One reaction per user per image with smart toggle logic
  • 🗑️ Owner-Only Deletion — Only the uploader can delete an image, with a confirmation modal
  • 👑 Admin Role — Admin can delete any user's image for moderation
  • 🌓 Dark / Light Mode — Persistent theme toggle via localStorage
  • 📱 Fully Responsive — Pinterest-style masonry grid that adapts from mobile to desktop
  • Fast — Search returns results in under 2 seconds for up to 10,000 records

🖼️ Screenshots

IMG-20260519-WA0024 IMG-20260519-WA0025 Screenshot 2026-05-20 201632 Screenshot 2026-05-20 201602

🛠️ Tech Stack

Layer Technology
Backend Python 3.11, Flask 3.0, SQLAlchemy 2.0
Database Neon PostgreSQL (production) / SQLite (local dev)
Storage Amazon AWS S3 (Boto3)
Auth Flask-Login + Werkzeug password hashing
Frontend HTML5, Tailwind CSS (CDN), Vanilla JavaScript
Hosting Render (Web Service)
Testing pytest, Hypothesis (property-based tests)
Production Server Gunicorn

📋 Prerequisites

  • Python 3.10 or higher
  • An AWS account with an S3 bucket (configured for public read access)
  • An IAM user with s3:PutObject, s3:DeleteObject, s3:GetObject permissions
  • pip3 (Python package manager)

🚀 Quick Start

1. Clone the repository

git clone https://github.com/YOUR_USERNAME/cms-image-gallery.git
cd cms-image-gallery

2. Install dependencies

pip3 install -r requirements.txt

3. Configure environment variables

Create a .env file in the project root with the following keys:

# Flask secret key — generate with: python3 -c "import secrets; print(secrets.token_hex(32))"
SECRET_KEY=your-secret-key

# AWS S3 credentials
AWS_ACCESS_KEY_ID=your-aws-access-key-id
AWS_SECRET_ACCESS_KEY=your-aws-secret-access-key
AWS_S3_BUCKET_NAME=your-bucket-name
AWS_S3_REGION=us-east-1
Variable Description
SECRET_KEY Flask session signing key — generate one with the command below
AWS_ACCESS_KEY_ID Your AWS IAM access key ID
AWS_SECRET_ACCESS_KEY Your AWS IAM secret access key
AWS_S3_BUCKET_NAME Name of your S3 bucket
AWS_S3_REGION AWS region (e.g. us-east-1)

Generate a secret key:

python3 -c "import secrets; print(secrets.token_hex(32))"

4. Run the application

python3 app.py

To enable debug mode:

FLASK_DEBUG=1 python3 app.py

☁️ AWS S3 Setup

Bucket configuration

Setting Value
Object Ownership ACLs enabled
Block Public Access Disabled (all 4 unchecked)
Versioning Disabled
Encryption SSE-S3 (default)

Bucket policy

Allow public read for uploaded images:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "PublicReadGetObject",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*"
  }]
}

CORS configuration

[{
  "AllowedHeaders": ["*"],
  "AllowedMethods": ["GET", "PUT", "POST", "DELETE"],
  "AllowedOrigins": ["*"],
  "ExposeHeaders": ["ETag"]
}]

IAM policy (for the app's access key)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:PutObjectAcl", "s3:GetObject", "s3:DeleteObject"],
      "Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*"
    },
    {
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::YOUR_BUCKET_NAME"
    }
  ]
}

🧪 Testing

Run the full test suite (174 tests covering services, routes, and edge cases):

python3 -m pytest -v

Run with coverage:

python3 -m pytest --cov=. --cov-report=html

Test Coverage

  • 174 passing tests with 100% pass rate
  • Unit tests: All backend services (bulk operations, filters, image processing, search, undo queue)
  • Integration tests: API routes, template integration, progressive loading
  • Property-based tests: Tag validation, upload handling, like/dislike logic
  • End-to-end tests: Complete user workflows and feature interactions

🌐 Deployment (Render + Neon)

This app is deployed on Render (hosting) + Neon (PostgreSQL database) + AWS S3 (image storage).

Production setup:

  1. Push this repo to GitHub
  2. Create a free Neon project at neon.tech → copy the pooled connection string
  3. Create a Render Web Service at render.com → connect this repo
  4. Configure Render:
    • Build Command: pip install -r requirements.txt
    • Start Command: gunicorn app:application --workers 1 --timeout 120
    • Instance Type: Free
  5. Add Environment Variables in Render:
    • DATABASE_URL = your Neon connection string
    • SECRET_KEY = a random 64-char hex string
    • AWS_ACCESS_KEY_ID = your AWS key
    • AWS_SECRET_ACCESS_KEY = your AWS secret
    • AWS_S3_BUCKET_NAME = your bucket name
    • AWS_S3_REGION = your bucket region
    • RENDER = 1
  6. Deploy — your app goes live in ~3 minutes

Other supported platforms: Railway, Fly.io, PythonAnywhere, AWS Elastic Beanstalk


📁 Project Structure

cms-image-gallery/
├── app.py                      # Flask app factory + entry point
├── models.py                   # SQLAlchemy models (User, Image, Tag, Likes)
├── routes.py                   # All HTTP routes + API endpoints
├── auth_service.py             # Registration + login
├── upload_service.py           # File validation + S3 upload + tag parsing
├── s3_service.py               # Boto3 S3 integration
├── search_service.py           # Tag-based search + query builder
├── like_service.py             # Like/dislike toggle logic
├── delete_service.py           # Authorized deletion with cascade
├── bulk_service.py             # Bulk delete and download operations
├── filter_service.py           # Real-time image filter processing
├── image_service.py            # Thumbnail generation and upload
├── query_builder.py            # Advanced search query construction
├── undo_queue.py               # Undo delete queue management
├── templates/                  # Jinja2 HTML templates
│   ├── base.html               # Base template with mobile navigation
│   ├── index.html              # Gallery homepage with all features
│   ├── login.html
│   ├── register.html
│   ├── upload.html
│   └── error.html
├── static/                     # Static assets
│   ├── js/
│   │   ├── gallery.js          # Core gallery functionality
│   │   ├── image-viewer.js     # Lightbox image viewer
│   │   └── progressive-loading.js  # Blur-up image loading
│   ├── css/
│   │   └── (Tailwind CSS via CDN)
│   └── logo.png
├── tests/                      # pytest test suite (174 tests)
│   ├── test_like.py            # Like/dislike tests
│   ├── test_search.py          # Search and query builder tests
│   ├── test_upload.py          # Upload validation tests
│   ├── test_bulk_service.py    # Bulk operations tests
│   ├── test_filter_service.py  # Image filter tests
│   ├── test_image_service.py   # Thumbnail generation tests
│   ├── test_undo_queue.py      # Undo queue tests
│   ├── test_query_builder.py   # Advanced search tests
│   └── test_progressive_loading*.py  # Progressive loading tests
├── requirements.txt            # Python dependencies (pinned)
├── Procfile                    # Production start command
└── README.md

🔒 Security Notes

  • ✅ Passwords are hashed using Werkzeug's generate_password_hash (PBKDF2-SHA256)
  • ✅ AWS credentials are loaded from environment variables only — never hardcoded
  • .env is excluded from version control via .gitignore
  • ✅ Owner-only authorization on all destructive operations
  • ✅ Generic error messages on login to prevent user enumeration
  • ✅ Unique S3 keys (UUID-based) prevent overwrite attacks

🤝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

👥 Contributors

Ishant Sahu
Ishant Sahu
Nitin Nirmalkar
Nitin Nirmalkar
Rakesh Parate
Rakesh Parate
Khushraj Varghat
Khushraj Varghat

🙏 Acknowledgements

  • Built as a Cloud Computing college project
  • Logo represents a lotus (creativity) opening into a book (content)
  • Color palette inspired by traditional Indian aesthetics

Made with ❤️ for the love of content

Star this repo if you found it useful!

About

Content मंच — Cloud-based CMS Image/GIF Gallery built with Flask, AWS S3, and Tailwind CSS

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors