Merge branch 'harvey-main'
This commit is contained in:
commit
85fe9558e9
5 files changed
+232
-2
No files matched your search
+80
-1
@@ -310,12 +310,91 @@ def init_programs_database():
|
|||||||
""")
|
""")
|
||||||
print("Programs database tables initialised.")
|
print("Programs database tables initialised.")
|
||||||
|
|
||||||
|
def init_activities_database():
|
||||||
|
activities_list = [
|
||||||
|
{
|
||||||
|
"title": "Build a Bird Feeder",
|
||||||
|
"description": "Create a bird feeder using recycled materials.",
|
||||||
|
"species": "Bird Conservation",
|
||||||
|
"due_date": "12/04/2026",
|
||||||
|
"difficulty": "Easy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Plant a Tree",
|
||||||
|
"description": "Plant a tree in your garden or local area to help restore natural habitats and support wildlife.",
|
||||||
|
"species": "Habitat Restoration",
|
||||||
|
"due_date": "13/04/2026",
|
||||||
|
"difficulty": "Medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Organise a Conservation Awareness Campaign",
|
||||||
|
"description": "Plan and deliver a campaign to raise awareness about endangered species.",
|
||||||
|
"species": "Education & Conservation",
|
||||||
|
"due_date": "3/05/2026",
|
||||||
|
"difficulty": "Hard"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
with get_db() as conn:
|
||||||
|
|
||||||
|
conn.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS activities (
|
||||||
|
activity_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
species TEXT,
|
||||||
|
due_date TEXT,
|
||||||
|
difficulty TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
print("Activities table created/found.")
|
||||||
|
|
||||||
|
for activity in activities_list:
|
||||||
|
exists = conn.execute(
|
||||||
|
"SELECT activity_id FROM activities WHERE title = ?",
|
||||||
|
(activity["title"],)
|
||||||
|
).fetchone()
|
||||||
|
if exists:
|
||||||
|
print(f" SKIP {activity['title']} (already exists)")
|
||||||
|
continue
|
||||||
|
|
||||||
|
conn.execute("""
|
||||||
|
INSERT INTO activities
|
||||||
|
(title, description, species, due_date, difficulty, created_at)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?)
|
||||||
|
""", (
|
||||||
|
activity["title"],
|
||||||
|
activity["description"],
|
||||||
|
activity["species"],
|
||||||
|
activity["due_date"],
|
||||||
|
activity["difficulty"],
|
||||||
|
datetime.now(),
|
||||||
|
))
|
||||||
|
|
||||||
|
with get_db() as conn:
|
||||||
|
conn.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS user_activities (
|
||||||
|
user_id INTEGER NOT NULL,
|
||||||
|
activity_id INTEGER NOT NULL,
|
||||||
|
status TEXT DEFAULT 'in_progress',
|
||||||
|
started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (user_id, activity_id),
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(user_id),
|
||||||
|
FOREIGN KEY (activity_id) REFERENCES activities(activity_id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
print(f" ADD {activity['title']}")
|
||||||
|
print("Activities seeding complete.")
|
||||||
|
|
||||||
|
|
||||||
init_database()
|
init_database()
|
||||||
init_accounts_database()
|
init_accounts_database()
|
||||||
init_classes_database()
|
init_classes_database()
|
||||||
init_programs_database()
|
init_programs_database()
|
||||||
init_articles()
|
init_articles()
|
||||||
|
init_activities_database()
|
||||||
register_user("admin", "admin@komodohub.org", "admin", "admin")
|
register_user("admin", "admin@komodohub.org", "admin", "admin")
|
||||||
register_user("private", "private@komodohub.org", "private_user", "private")
|
register_user("private", "private@komodohub.org", "private_user", "private")
|
||||||
register_user("teacher", "teacher@komodohub.org", "teacher", "teacher")
|
register_user("teacher", "teacher@komodohub.org", "teacher", "teacher")
|
||||||
register_user("student", "student@komodohub.org", "student", "student")
|
register_user("student", "student@komodohub.org", "student", "student")
|
||||||
@@ -68,4 +68,4 @@ def handle_bad_request(e):
|
|||||||
import_pages("routes", app)
|
import_pages("routes", app)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(host="0.0.0.0", port=3000, debug=True)
|
app.run(host="0.0.0.0", port=3001, debug=True)
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
from flask import render_template, Blueprint, g, request, redirect, url_for
|
||||||
|
from database.db_connection import get_db
|
||||||
|
|
||||||
|
page = Blueprint('activities', __name__, url_prefix='/activities')
|
||||||
|
|
||||||
|
@page.route('/', methods=['GET', 'POST'])
|
||||||
|
def home():
|
||||||
|
if request.method == 'POST':
|
||||||
|
if g.user and g.user["account_type"] == "admin":
|
||||||
|
with get_db() as conn:
|
||||||
|
conn.execute("""
|
||||||
|
INSERT INTO activities
|
||||||
|
(title, description, species, due_date, difficulty)
|
||||||
|
VALUES (?, ?, ?, ?, ?)
|
||||||
|
""", (
|
||||||
|
request.form['title'],
|
||||||
|
request.form['description'],
|
||||||
|
request.form['species'],
|
||||||
|
request.form['due_date'],
|
||||||
|
request.form['difficulty']
|
||||||
|
))
|
||||||
|
return redirect(url_for('activities.home'))
|
||||||
|
|
||||||
|
with get_db() as conn:
|
||||||
|
activities = conn.execute("SELECT * FROM activities").fetchall()
|
||||||
|
|
||||||
|
started_ids = []
|
||||||
|
if g.user:
|
||||||
|
started = conn.execute("""
|
||||||
|
SELECT activity_id FROM user_activities
|
||||||
|
WHERE user_id = ?
|
||||||
|
""", (g.user["user_id"],)).fetchall()
|
||||||
|
|
||||||
|
started_ids = [row["activity_id"] for row in started]
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
'activities/activities.jinja',
|
||||||
|
activities=activities,
|
||||||
|
started_ids=started_ids
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@page.route('/start/<int:activity_id>')
|
||||||
|
def start_activity(activity_id):
|
||||||
|
if not g.user:
|
||||||
|
return redirect(url_for('login.login'))
|
||||||
|
|
||||||
|
with get_db() as conn:
|
||||||
|
exists = conn.execute("""
|
||||||
|
SELECT * FROM user_activities
|
||||||
|
WHERE user_id = ? AND activity_id = ?
|
||||||
|
""", (g.user["user_id"], activity_id)).fetchone()
|
||||||
|
|
||||||
|
if not exists:
|
||||||
|
conn.execute("""
|
||||||
|
INSERT INTO user_activities (user_id, activity_id)
|
||||||
|
VALUES (?, ?)
|
||||||
|
""", (g.user["user_id"], activity_id))
|
||||||
|
|
||||||
|
return redirect(url_for('activities.home'))
|
||||||
|
|
||||||
|
|
||||||
|
@page.route('/my-activities')
|
||||||
|
def my_activities():
|
||||||
|
if not g.user:
|
||||||
|
return redirect(url_for('login.login'))
|
||||||
|
|
||||||
|
with get_db() as conn:
|
||||||
|
activities = conn.execute("""
|
||||||
|
SELECT a.*, ua.started_at, ua.completed
|
||||||
|
FROM user_activities ua
|
||||||
|
JOIN activities a ON ua.activity_id = a.activity_id
|
||||||
|
WHERE ua.user_id = ?
|
||||||
|
""", (g.user["user_id"],)).fetchall()
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
'activities/my_activities.jinja',
|
||||||
|
activities=activities
|
||||||
|
)
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
{% extends "base.jinja" %}
|
||||||
|
{% block title %}Activities{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
{% from 'button.jinja' import button %}
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
<style>
|
||||||
|
.activity-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 30px;
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-card {
|
||||||
|
background: #0b5d2a;
|
||||||
|
padding: 25px;
|
||||||
|
border-radius: 12px;
|
||||||
|
width: 300px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
<section style="padding: 50px 20px; text-align: center;">
|
||||||
|
<h1>Activities</h1>
|
||||||
|
|
||||||
|
<!-- Activities List -->
|
||||||
|
<div class="activity-container">
|
||||||
|
{% for activity in activities %}
|
||||||
|
<div class="activity-card">
|
||||||
|
<h3>{{ activity.title }}</h3>
|
||||||
|
<p>{{ activity.description }}</p>
|
||||||
|
<p><strong>Category:</strong> {{ activity.species }}</p>
|
||||||
|
<p><strong>Due date:</strong> {{ activity.due_date }}</p>
|
||||||
|
<p><strong>Difficulty:</strong> {{ activity.difficulty }}</p>
|
||||||
|
|
||||||
|
{% if activity.activity_id in started_ids %}
|
||||||
|
<p><strong>In Progress</strong></p>
|
||||||
|
{% else %}
|
||||||
|
{{ button(url=url_for('activities.start_activity', activity_id=activity.activity_id), button_text='Start Activity', extra_classes='homepage-btn') }}
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ADMIN ONLY SECTION -->
|
||||||
|
{% if g.user and g.user["account_type"] == "admin" %}
|
||||||
|
<section style="padding: 50px 20px; text-align: center; background-color: #eee;">
|
||||||
|
<h2>Create New Activity (Admin)</h2>
|
||||||
|
|
||||||
|
<form method="POST" class="activity-form">
|
||||||
|
<input type="text" name="title" placeholder="Activity Title" required><br><br>
|
||||||
|
|
||||||
|
<textarea name="description" placeholder="Description" required></textarea><br><br>
|
||||||
|
|
||||||
|
<input type="text" name="species" placeholder="Species / Program" required><br><br>
|
||||||
|
|
||||||
|
<input type="number" name="due_date" placeholder="due_date"><br><br>
|
||||||
|
|
||||||
|
<input type="text" name="difficulty" placeholder="difficulty"><br><br>
|
||||||
|
|
||||||
|
<button type="submit" class="homepage-btn">Publish Activity</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
{{ button(url='/donation', button_text='Donate Now', extra_classes='homepage-btn') }}
|
{{ button(url='/donation', button_text='Donate Now', extra_classes='homepage-btn') }}
|
||||||
{{ button(url='/species', button_text='Explore Species', extra_classes='homepage-btn') }}
|
{{ button(url='/species', button_text='Explore Species', extra_classes='homepage-btn') }}
|
||||||
{{ button(url='/register', button_text='Join the Movement', extra_classes='homepage-btn') }}
|
{{ button(url='/register', button_text='Join the Movement', extra_classes='homepage-btn') }}
|
||||||
|
{{ button(url='/activities', button_text ='Activities', extra_classes='homepage-btn')}}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<!-- About section -->
|
<!-- About section -->
|
||||||
|
|||||||
Reference in new issue
Block a user