computer-science-club

computer-science-club
git clone https://git.prime8.dev/computer-science-club.git
Log | Files | Refs | README | LICENSE

commit 0c4b83d3346e4f13e782bbd175f7831bde15043a
parent 6c0ff50e848afa01101cae4218763c92b1236e79
Author: Damian Myrda <damian@prime8.dev>
Date:   Wed, 24 Apr 2024 14:44:36 -0500

Add all source files

Diffstat:
A.gitignore | 5+++++
Aconfig.py | 2++
Adatabase.json | 2++
Adatabase.py | 31+++++++++++++++++++++++++++++++
Amain.py | 34++++++++++++++++++++++++++++++++++
Amodels/__init__.py | 6++++++
Amodels/discussion.py | 30++++++++++++++++++++++++++++++
Amodels/event.py | 19+++++++++++++++++++
Amodels/group.py | 25+++++++++++++++++++++++++
Amodels/member.py | 7+++++++
Amodels/project.py | 13+++++++++++++
Amodels/update.py | 12++++++++++++
Aprojects.py | 19+++++++++++++++++++
Aschoology.py | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astatic/intro.css | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astatic/style.css | 19+++++++++++++++++++
Atemplates/discussions.html | 21+++++++++++++++++++++
Atemplates/elements/authors.html | 9+++++++++
Atemplates/elements/datetime.html | 7+++++++
Atemplates/elements/discussions.html | 14++++++++++++++
Atemplates/elements/events.html | 46++++++++++++++++++++++++++++++++++++++++++++++
Atemplates/elements/metadata.html | 8++++++++
Atemplates/elements/navigation.html | 9+++++++++
Atemplates/elements/projects.html | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Atemplates/elements/space.html | 26++++++++++++++++++++++++++
Atemplates/elements/updates.html | 17+++++++++++++++++
Atemplates/home.html | 27+++++++++++++++++++++++++++
Atemplates/members.html | 39+++++++++++++++++++++++++++++++++++++++
Atemplates/projects.html | 25+++++++++++++++++++++++++
Atemplates/updates.html | 21+++++++++++++++++++++
30 files changed, 671 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,5 @@ +lib/ +lib64 +bin/ +__pycache__/ +pyvenv.cfg diff --git a/config.py b/config.py @@ -0,0 +1,2 @@ +DOMAIN = "https://schoology.d214.org" +GROUP_ID = 6454678062 diff --git a/database.json b/database.json @@ -0,0 +1 @@ +{"py/object": "database.Data", "projects": [{"py/object": "project.Project", "name": "Computer Science Club Website", "description": "Made for Computer Science Club's Mini-Hackathon.", "authors": ["Damian Myrda"], "source": "https://replit.com/@Moncheeto/Computer-Science-Club?v=1", "images": null}]} +\ No newline at end of file diff --git a/database.py b/database.py @@ -0,0 +1,31 @@ +import os +from jsonpickle import decode, encode + +class Data: + projects = [] + + def __init__(self, projects): + self.projects = projects + +class Database: + def read(self): + if not os.path.isfile("database.json"): + data = Data([]) + self.write(data) + return data + with open("database.json", "r") as file: + return decode(file.read()) + + def write(self, data): + with open("database.json", "w") as file: + file.write(encode(data)) + +class ProjectDatabase: + def read(self): + projects = [] + for project in Database().read().projects: + projects.append(project) + return projects + + def write(self, projects): + Database().write(Data(projects)) diff --git a/main.py b/main.py @@ -0,0 +1,34 @@ +import os, sys, pathlib +PROJECT_DIR = os.path.join(pathlib.Path(__file__).parent) +sys.path.append(os.path.join(PROJECT_DIR, "config.py")) +sys.path.append(os.path.join(PROJECT_DIR, "models")) +sys.path.append(os.path.join(PROJECT_DIR, "projects.py")) +sys.path.append(os.path.join(PROJECT_DIR, "schoology.py")) +from schoology import group +from flask import Flask, render_template + +app = Flask(__name__) +app.secret_key = "https://computer-science-club.moncheeto.repl.co" + +@app.route("/") +def index(): + return render_template("home.html", group=group) + +@app.route("/updates") +def updates(): + return render_template("updates.html", group=group) + +@app.route("/discussions") +def discussions(): + return render_template("discussions.html", group=group) + +@app.route("/projects", methods = ["GET", "POST"]) +def projects(): + return render_template("projects.html", group=group) + +@app.route("/members") +def members(): + return render_template("members.html", group=group) + +if __name__ == "__main__": + app.run(host='0.0.0.0', port=8000) diff --git a/models/__init__.py b/models/__init__.py @@ -0,0 +1,6 @@ +from discussion import Discussion +from event import Event +from group import Group +from member import Member +from project import Project +from update import Update diff --git a/models/discussion.py b/models/discussion.py @@ -0,0 +1,30 @@ +from config import DOMAIN + +class Discussion: + name = "" + description = "" + link = f"{DOMAIN}/discussion/" + + def __init__(self, id, name, description): + self.link += str(id) + self.name = name + self.description = description +from datetime import datetime +from config import DOMAIN + +class Event: + name = "" + description = "" + start = datetime.now() + end = None + differentDay = False + link = f"{DOMAIN}/event/" + + def __init__(self, id, name, description, start, end): + self.link += str(id) + self.name = name + self.description = description + self.start = start + self.end = end + if end and self.end.year >= self.start.year and self.end.month >= self.start.month and self.end.day > start.day: + differentDay = True diff --git a/models/event.py b/models/event.py @@ -0,0 +1,19 @@ +from datetime import datetime +from config import DOMAIN + +class Event: + name = "" + description = "" + start = datetime.now() + end = None + differentDay = False + link = f"{DOMAIN}/event/" + + def __init__(self, id, name, description, start, end): + self.link += str(id) + self.name = name + self.description = description + self.start = start + self.end = end + if end and self.end.year >= self.start.year and self.end.month >= self.start.month and self.end.day > start.day: + differentDay = True diff --git a/models/group.py b/models/group.py @@ -0,0 +1,24 @@ +class Group: + name = "" + description = "" + picture = "https://www.shutterstock.com/image-vector/computer-science-icon-outline-thin-600nw-1613513884.jpg" + leaders = [] + members = [] + events = [] + updates = [] + discussions = [] + projects = [] + + def __init__(self, name, description, events, updates, discussions, projects, members): + self.name = name + self.description = description + self.events = events + self.updates = updates + self.discussions = discussions + self.projects = projects + for member in members: + if member.leader: + self.leaders.append(member) + continue + self.members.append(member) + +\ No newline at end of file diff --git a/models/member.py b/models/member.py @@ -0,0 +1,7 @@ +class Member: + name = "" + leader = False + + def __init__(self, name = "", leader = False): + self.name = name + self.leader = leader diff --git a/models/project.py b/models/project.py @@ -0,0 +1,13 @@ +class Project: + name = "" + description = "" + authors = [] + source = None + images = None + + def __init__(self, name, description, authors, source = None, images = None): + self.name = name + self.description = description + self.authors = authors + self.source = source + self.images = images diff --git a/models/update.py b/models/update.py @@ -0,0 +1,12 @@ +from datetime import datetime +from member import Member + +class Update: + member = Member() + text = "" + time = datetime.now() + + def __init__(self, member, text, time): + self.member = member + self.text = text + self.time = time diff --git a/projects.py b/projects.py @@ -0,0 +1,19 @@ +from models import Project +from database import Database, Data + +class ProjectDatabase: + def read(self): + projects = [] + for project in Database().read()["projects"]: + name = project.get("name") + description = project.get("description") + authors = project.get("authors") + source = project.get("source") + images = project.get("images") + projects.append(Project(name, description, authors, source, images)) + return projects + + def write(self, projects): + with open("database.json", "w") as file: + file.write(encode(Data(projects))) + diff --git a/schoology.py b/schoology.py @@ -0,0 +1,71 @@ +import os +from datetime import datetime +from config import DOMAIN, GROUP_ID +from models import Group, Event, Update, Discussion, Project, Member +from schoolopy import Schoology, Auth + +class SchoologyAPI: + api = None + auth = Auth(os.environ["SCHOOLOGY_API_KEY"], os.environ["SCHOOLOGY_API_SECRET"], domain = DOMAIN) + + def __init__(self): + self.api = Schoology(self.auth) + self.api.limit = 64 + + def name(self): + return self.api.get_group(GROUP_ID).title + + def description(self): + return self.api.get_group(GROUP_ID).description + + def events(self): + events = [] + for event in self.api.get_group_events(GROUP_ID): + start = datetime.strptime(event.start, "%Y-%m-%d %H:%M:%S") + end = None + differentDay = False + if event.has_end: + end = datetime.strptime(event.end, "%Y-%m-%d %H:%M:%S") + event = Event(event.id, event.title, event.description, start, end) + events.append(event) + return events + + def updates(self): + updates = [] + for update in self.api.get_group_updates(GROUP_ID): + user = self.api.get_user(update.uid) + member = Member(user.name_display) + #time = datetime.utcfromtimestamp(int(update.created)) + time = datetime.utcfromtimestamp(int(update.last_updated)) + updates.append(Update(member, update.body, time)) + return updates + + def discussions(self): + discussions = [] + for discussion in self.api.get_group_discussions(GROUP_ID): + discussions.append(Discussion(discussion.id, discussion.title, discussion.body)) + return discussions + + def members(self): + members = [] + for enrolled in self.api.get_group_enrollments(GROUP_ID): + member = Member(enrolled.name_display) + if enrolled.admin == 1: + member.leader = True + members.append(member) + return members + + def group(self): + name = self.name() + description = self.description() + events = self.events() + updates = self.updates() + discussions = self.discussions() + projects = [ + Project("Computer Science Club Website", "(this website)", ["Damian Myrda"], "https://replit.com/@Moncheeto/Computer-Science-Club?v=1") + ] + members = self.members() + return Group(name, description, events, updates, discussions, projects, members) + +api = SchoologyAPI() +group = api.group() diff --git a/static/intro.css b/static/intro.css @@ -0,0 +1,58 @@ +* { + color: #FFFF82; + text-align: center; + background-color: black; +} + +#board { + font-family: sans-serif; + transform: perspective(300px) rotateX(25deg); + transform-origin: 50% 100%; + text-align: justify; + position: absolute; + margin-left: -9em; + font-weight: bold; + overflow: hidden; + font-size: 350%; + height: 50em; + width: 18em; + bottom: 0; + left: 50%; +} + +#board:after { + position: absolute; + content: ' '; + bottom: 60%; + left: 0; + right: 0; + top: 0; +} + +#content { + animation: scroll 128s; + position: absolute; + top: 100%; +} + +@keyframes scroll { + 0% { + top: 100%; + } + 100% { + top: -350%; + } +} + +#back { + color: white; +} + +#back.hidden { + opacity: 0; +} + +#back.shown { + opacity: 1; + transition: opacity 2000ms; +} diff --git a/static/style.css b/static/style.css @@ -0,0 +1,19 @@ +* { + color: white; + font-family: monospace; +} + +body { + background-color: black; +} + +input, textarea { + color: black; +} + +center { + top: 50%; + left: 50%; + transform: translate(-50%,-50%); + position: absolute; +} diff --git a/templates/discussions.html b/templates/discussions.html @@ -0,0 +1,21 @@ +<html> +<head> + {% import "elements/metadata.html" as metadata %} + {{ metadata.head(group, "Discussions") }} + <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> +</head> + +<header> + {% import "elements/navigation.html" as navigation %} + {{ navigation.bar() }} +</header> + +<body> + {% import "elements/space.html" as space %} + {{ space.stars(500) }} + + <h1>Discussions</h1> + {% import "elements/discussions.html" as discussions %} + {{ discussions.list(group.discussions) }} +</body> +</html> diff --git a/templates/elements/authors.html b/templates/elements/authors.html @@ -0,0 +1,9 @@ +{% macro view(author) -%} +<a>{{ author }}</a> +{%- endmacro %} + +{% macro list(authors) -%} +<div> + By: {{ view(authors[0]) }}{% for author in authors[1:] %}, {{ author }}{% endfor %} +</div> +{%- endmacro %} diff --git a/templates/elements/datetime.html b/templates/elements/datetime.html @@ -0,0 +1,7 @@ +{% macro time(time) -%} + {{ time.hour }}:{{ time.minute }} +{%- endmacro %} + +{% macro date(date) -%} + {{ date.year }}.{{ date.month }}.{{ date.day }} +{%- endmacro %} diff --git a/templates/elements/discussions.html b/templates/elements/discussions.html @@ -0,0 +1,14 @@ +{% macro view(discussion) -%} + <a target="_blank" href="{{ discussion.link }}"> + {{ discussion.name }} + {{ discussion.description }} + </a> +{%- endmacro %} + +{% macro list(discussions) -%} +{% for discussion in discussions %} +<div> + {{ view(discussion) }} +</div> +{% endfor %} +{%- endmacro %} diff --git a/templates/elements/events.html b/templates/elements/events.html @@ -0,0 +1,46 @@ +{% import "elements/datetime.html" as datetime %} + +{% macro view(event) -%} +<a target="_blank" href="{{ event.link }}"> + {{ event.name }} + + at {{ datetime.time(event.start) }} + {% if event.end %} + to {{ datetime.time(event.end) }} + {% endif %} + + on {{ datetime.date(event.start) }} + {% if event.end %} + {% if event.differentDay %} + to {{ datetime.date(event.end) }} + {% endif %} + {% endif %} +</a> +{%- endmacro %} + +{% macro next(event) -%} +<a target="_blank" href="{{ event.link }}"> + Upcoming: + {{ event.name }} + + at {{ datetime.time(event.start) }} + {% if event.end %} + to {{ datetime.time(event.end) }} + {% endif %} + + on {{ datetime.date(event.start) }} + {% if event.end %} + {% if event.differentDay %} + to {{ datetime.date(event.end) }} + {% endif %} + {% endif %} +</a> +{%- endmacro %} + +{% macro upcoming(events) -%} +{% for event in events %} +<div> + view(event) +</div> +{% endfor %} +{%- endmacro %} diff --git a/templates/elements/metadata.html b/templates/elements/metadata.html @@ -0,0 +1,8 @@ +{% macro head(group, subsection) -%} + <title>{{ group.name }} + {% if subsection %} + - {{ subsection }} + {% endif %} + </title> + <link rel="icon" type="image/x-icon" href="{{ group.picture }}"> +{%- endmacro %} diff --git a/templates/elements/navigation.html b/templates/elements/navigation.html @@ -0,0 +1,9 @@ +{% macro bar() -%} +<nav> + <a href="/">Home</a> + <a href="/updates">Updates</a> + <a href="/discussions">Discussions</a> + <a href="/projects">Projects</a> + <a href="/members">Members</a> +</nav> +{%- endmacro %} diff --git a/templates/elements/projects.html b/templates/elements/projects.html @@ -0,0 +1,49 @@ +{% import "elements/authors.html" as authors %} + +{% macro view(project) -%} + <h2>{{ project.name }}</h2> + <p>{{ project.description }}</p> + {% if project.source %} + <a target="_blank" href="{{ project.source }}">Source Code</a> + <br> + {% endif %} + {{ authors.list(project.authors) }} + {% if project.images %} + {% for image in project.images %} + <img src="{{ image }}"> + {% endfor %} + {% endif %} +{%- endmacro %} + +{% macro list(projects) -%} +{% for project in projects %} +<div> + {{ view(project) }} + <br> +</div> +{% endfor %} +{%- endmacro %} + +{% macro new() -%} +<center> + <h1>Add New Project</h1> + <form method="post" enctype="multipart/form-data"> + <label for="name">Name:</label> + <input name="name" id="name" required> + <br> + <label for="description">Description:</label> + <textarea name="description" id="description" required></textarea> + <br> + <label for="authors">Authors:</label> + <input name="authors" id="authors" required> + <br> + <label for="source">Source:</label> + <input name="source" id="source"> + <br> + <label for="images">Images:</label> + <input name="images" id="images" type="file" accept="image/*" multiple> + <br> + <input type="submit" value="Add"> + </form> +</center> +{%- endmacro %} diff --git a/templates/elements/space.html b/templates/elements/space.html @@ -0,0 +1,26 @@ +{% macro stars(num) -%} +<style> + #star { + position: absolute; + width: 1px; + height: 1px; + background-color: white; + } +</style> +<script> + for (let i = 0; i < {{ num }}; i++) { + let star = document.createElement("div"); + star.id = "star"; + var [w, h] = randomPosition(); + star.style.top = h + "px"; + star.style.left = w + "px"; + document.body.append(star); + } + + function randomPosition() { + var rw = Math.floor(Math.random() * window.innerWidth); + var rh = Math.floor(Math.random() * window.innerHeight); + return [rw, rh]; + } +</script> +{%- endmacro %} diff --git a/templates/elements/updates.html b/templates/elements/updates.html @@ -0,0 +1,17 @@ +{% import "elements/datetime.html" as datetime %} + +{% macro view(update) -%} + <p>{{ update.member.name }} on {{ datetime.date(update.time) }} at {{ datetime.time(update.time) }}: {{ update.text }}</p> +{%- endmacro %} + +{% macro recent(update) -%} + <p>Annocement from {{ update.member.name }} on {{ datetime.date(update.time) }} at {{ datetime.time(update.time) }}: {{ update.text }}</p> +{%- endmacro %} + +{% macro list(updates) -%} +{% for update in updates %} +<div> + {{ view(update) }} +</div> +{% endfor %} +{%- endmacro %} diff --git a/templates/home.html b/templates/home.html @@ -0,0 +1,27 @@ +<html> +<head> + {% import "elements/metadata.html" as metadata %} + {{ metadata.head(group)}} + <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> +</head> + +<header> + {% import "elements/navigation.html" as navigation %} + {{ navigation.bar() }} +</header> + +<body> + {% import "elements/space.html" as space %} + {{ space.stars(500) }} + <center> + <h1>{{ group.name }}</h1> + <p>{{ group.description }}</p> + + {% import "elements/events.html" as events %} + {{ events.next(group.events[0]) }} + + {% import "elements/updates.html" as updates %} + {{ updates.recent(group.updates[0]) }} + </center> +</body> +</html> diff --git a/templates/members.html b/templates/members.html @@ -0,0 +1,39 @@ +<html> +<head> + {% import "elements/metadata.html" as metadata %} + {{ metadata.head(group, "Members") }} + <link rel="stylesheet" href="{{ url_for('static', filename='intro.css') }}"> +</head> + +<body> + {% import "elements/space.html" as space %} + {{ space.stars(200) }} + <div id="board"> + <div id="content"> + <center> + <h1>COMPUTER</h1> + <h1>SCIENCE</h1> + <h1>CLUB</h1> + <h2>LEADERS</h2> + {% for leader in group.leaders %} + <p>{{ leader.name }}</p> + {% endfor %} + <br> + <h2>MEMBERS</h2> + {% for member in group.members %} + <p>{{ member.name }}</p> + {% endfor %} + <br> + <h2>CREATED BY</h2> + <p>Damian Myrda</p> + </center> + </div> + </div> + <a id="back" class="hidden" href="/">Back</a> + <script> + setTimeout(function() { + document.getElementById("back").className = "shown"; + }, 8000); + </script> +</body> +</html> diff --git a/templates/projects.html b/templates/projects.html @@ -0,0 +1,25 @@ +<html> +<head> + {% import "elements/metadata.html" as metadata %} + {% if create %} + {{ metadata.head(group, "New Project") }} + {% else %} + {{ metadata.head(group, "Projects") }} + {% endif %} + <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> +</head> + +<header> + {% import "elements/navigation.html" as navigation %} + {{ navigation.bar() }} +</header> + +<body> + {% import "elements/space.html" as space %} + {{ space.stars(500) }} + + {% import "elements/projects.html" as projects %} + <h1>Projects</h1> + {{ projects.list(group.projects) }} +</body> +</html> diff --git a/templates/updates.html b/templates/updates.html @@ -0,0 +1,21 @@ +<html> +<head> + {% import "elements/metadata.html" as metadata %} + {{ metadata.head(group, "Updates") }} + <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> +</head> + +<header> + {% import "elements/navigation.html" as navigation %} + {{ navigation.bar() }} +</header> + +<body> + {% import "elements/space.html" as space %} + {{ space.stars(500) }} + + <h1>Updates</h1> + {% import "elements/updates.html" as updates %} + {{ updates.list(group.updates) }} +</body> +</html>