Skip to content

Commit 8d66995

Browse files
committed
Add Photo Organizer App project (Issue #89)
1 parent 1bcbb73 commit 8d66995

File tree

4 files changed

+135
-0
lines changed

4 files changed

+135
-0
lines changed

Photo_Organizer_App/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Photo Organizer App
2+
3+
A simple application to help users organize their photos by date, location, or tags. Users can upload, sort, and search for images easily.
4+
5+
## Features
6+
- Upload photos with tags
7+
- Search photos by tag or date
8+
- View photo gallery
9+
10+
## Usage
11+
1. Install dependencies:
12+
```bash
13+
pip install flask werkzeug
14+
```
15+
2. Run the Flask app:
16+
```bash
17+
python app.py
18+
```
19+
3. Open your browser at `http://localhost:5000`.
20+
21+
## Requirements
22+
- Python 3.x
23+
- Flask
24+
- Werkzeug
25+
26+
## License
27+
MIT

Photo_Organizer_App/app.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""
2+
Photo Organizer App (Issue #89)
3+
Minimal Flask backend + HTML/JS frontend
4+
"""
5+
from flask import Flask, request, jsonify, send_from_directory, render_template_string
6+
import os
7+
from werkzeug.utils import secure_filename
8+
from datetime import datetime
9+
10+
app = Flask(__name__)
11+
UPLOAD_FOLDER = "photos"
12+
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
13+
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
14+
15+
PHOTOS = []
16+
17+
@app.route("/api/upload", methods=["POST"])
18+
def upload():
19+
file = request.files['photo']
20+
tags = request.form.get('tags', '')
21+
filename = secure_filename(file.filename)
22+
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
23+
file.save(filepath)
24+
meta = {
25+
"filename": filename,
26+
"date": datetime.now().strftime('%Y-%m-%d'),
27+
"tags": tags.split(',') if tags else []
28+
}
29+
PHOTOS.append(meta)
30+
return jsonify({"status": "uploaded"})
31+
32+
@app.route("/api/photos", methods=["GET"])
33+
def get_photos():
34+
tag = request.args.get('tag')
35+
date = request.args.get('date')
36+
results = PHOTOS
37+
if tag:
38+
results = [p for p in results if tag in p['tags']]
39+
if date:
40+
results = [p for p in results if p['date'] == date]
41+
return jsonify(results)
42+
43+
@app.route("/photos/<filename>")
44+
def serve_photo(filename):
45+
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
46+
47+
@app.route("/")
48+
def index():
49+
return send_from_directory(".", "organizer.html")
50+
51+
if __name__ == "__main__":
52+
app.run(debug=True)

Photo_Organizer_App/organizer.html

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Photo Organizer App</title>
6+
<style>
7+
body { font-family: Arial, sans-serif; margin: 40px; }
8+
.container { max-width: 700px; margin: auto; }
9+
input, button { margin: 5px; }
10+
img { max-width: 150px; margin: 5px; border: 1px solid #ccc; }
11+
</style>
12+
</head>
13+
<body>
14+
<div class="container">
15+
<h2>Photo Organizer App</h2>
16+
<form id="uploadForm" enctype="multipart/form-data">
17+
<input type="file" name="photo" required />
18+
<input type="text" name="tags" placeholder="Tags (comma separated)" />
19+
<button type="submit">Upload</button>
20+
</form>
21+
<div>
22+
<label>Search by Tag:</label>
23+
<input type="text" id="searchTag" />
24+
<label>Search by Date:</label>
25+
<input type="date" id="searchDate" />
26+
<button onclick="searchPhotos()">Search</button>
27+
</div>
28+
<div id="photoGallery"></div>
29+
</div>
30+
<script>
31+
document.getElementById('uploadForm').onsubmit = function(e) {
32+
e.preventDefault();
33+
const formData = new FormData(this);
34+
fetch('/api/upload', { method: 'POST', body: formData })
35+
.then(() => searchPhotos());
36+
};
37+
function searchPhotos() {
38+
const tag = document.getElementById('searchTag').value;
39+
const date = document.getElementById('searchDate').value;
40+
let url = '/api/photos?';
41+
if (tag) url += `tag=${tag}&`;
42+
if (date) url += `date=${date}`;
43+
fetch(url).then(r => r.json()).then(data => {
44+
const gallery = document.getElementById('photoGallery');
45+
gallery.innerHTML = '';
46+
data.forEach(p => {
47+
gallery.innerHTML += `<div><img src='/photos/${p.filename}' /><br/>Tags: ${p.tags.join(', ')}<br/>Date: ${p.date}</div>`;
48+
});
49+
});
50+
}
51+
searchPhotos();
52+
</script>
53+
</body>
54+
</html>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
flask
2+
werkzeug

0 commit comments

Comments
 (0)