bin/
__pycache__/
pyvenv.cfg
+google_auth.json
# computer_science_club
+
A website for Computer Science Club. It was made during a mini-hackathon.
## setup
-To setup the server environment, run ```python -m venv .``` in the root of the project. Then, execute ```. ./bin/activate``` and you should be in the virtual environment. Next, run ```pip install flask schoolopy``` to install all the dependencies. Now, exit using by running ```exit```.
+
+To setup the server environment, run `python -m venv .` in the root of the project. Then, execute `. ./bin/activate` and you should be in the virtual environment. Next, run `pip install flask schoolopy` to install all the dependencies. Now, exit using by running `exit`.
+
+To setup Google OAuth2, goto [get google api clientid](https://developers.google.com/identity/oauth2/web/guides/get-google-api-clientid) and follow the instructions. Copy the json file into `google_auth.json` in the root of the project. In the `config.py` file in the directory of the project, change `REDIRECT_URL` to the url you used when you set up the google project.
## running
-To run the server, you need an API key and its companioning secret. In your browser, go to ```schoology.(PUT DOMAIN HERE).org/api```. There, you can manage your API credentials. Get the key and secret and return.
-Now, you can execute ```SCHOOLOGY_API_KEY="PUT KEY HERE" SCHOOLOGY_API_SECRET="PUT SECRET HERE" ./run.sh```.
+To run the server, you need an API key and its companioning secret. In your browser, go to `schoology.(PUT DOMAIN HERE).org/api`. There, you can manage your API credentials. Get the key and secret and return.
+Now, you can execute `SCHOOLOGY_API_KEY="PUT KEY HERE" SCHOOLOGY_API_SECRET="PUT SECRET HERE" ./run.sh`.
DOMAIN = "https://schoology.d214.org"
GROUP_ID = 6454678062
+REDIRECT_URL = "127.0.0.1:5000"
-{"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://github.com/moncheeta/computer_science_club", "images": null}]}
+{
+ "py/object": "database.Data",
+ "projects": [
+ {
+ "py/object": "project.Project",
+ "name": "Computer Science Club Website",
+ "description": "(this website)",
+ "authors": ["Damian Myrda"],
+ "source": "https://github.com/moncheeta/computer_science_club.git",
+ "images": null
+ }
+ ]
+}
import os
from jsonpickle import decode, encode
+
class Data:
- projects = []
-
- def __init__(self, projects):
- self.projects = projects
+ 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))
+ def read(self):
+ if not os.path.isfile("database.json"):
+ 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))
+ def read(self):
+ projects = []
+ for project in Database().read().projects:
+ projects.append(project)
+ return projects
+
+ def write(self, projects):
+ Database().write(Data(projects))
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 config import REDIRECT_URL
+from models import Project
+from database import ProjectDatabase
from schoology import group
-from flask import Flask, render_template
+from flask import Flask, request, redirect, abort, render_template, session
+from cachecontrol import CacheControl
app = Flask(__name__)
app.secret_key = "https://computer-science-club.moncheeto.repl.co"
+
@app.route("/")
def index():
- return render_template("home.html", group=group)
+ return render_template("home.html", group=group, account=session.get("name"))
+
@app.route("/updates")
def updates():
- return render_template("updates.html", group=group)
+ return render_template("updates.html", group=group, account=session.get("name"))
+
@app.route("/discussions")
def discussions():
- return render_template("discussions.html", group=group)
+ return render_template("discussions.html", group=group, account=session.get("name"))
+
-@app.route("/projects", methods = ["GET", "POST"])
+@app.route("/projects", methods=["GET", "POST"])
def projects():
- return render_template("projects.html", group=group)
+ return render_template(
+ "projects.html", group=group, create=False, account=session.get("name")
+ )
+
+
+@app.route("/projects/add", methods=["GET", "POST"])
+def add_project():
+ if request.method == "POST":
+ if not session.get("name"):
+ return abort(401)
+ name = request.form["name"].rstrip()
+ description = request.form["description"].rstrip()
+ authors = request.form["authors"]
+ for author in authors:
+ author = author.rstrip()
+ source = request.form["source"].rstrip()
+ if source == "":
+ source = None
+ images = request.files.get("images")
+ group.projects.append(Project(name, description, [authors], source, images))
+ ProjectDatabase().write(group.projects)
+ return redirect("/projects")
+ return render_template(
+ "projects.html", group=group, create=True, account=session.get("name")
+ )
+
@app.route("/members")
def members():
- return render_template("members.html", group=group)
+ return render_template("members.html", group=group, account=session.get("name"))
+
+
+import requests
+import google.auth.transport.requests
+from google_auth_oauthlib.flow import Flow
+from google.oauth2 import id_token
+
+GOOGLE_CLIENT_ID = (
+ "861597772911-7k5ipk33tj84ubts3oulmqt6jp053hnr.apps.googleusercontent.com"
+)
+GOOGLE_CLIENT_SECRETS_FILE = os.path.join(PROJECT_DIR, "google_auth.json")
+GOOGLE_AUTH_SCOPES = [
+ "https://www.googleapis.com/auth/userinfo.profile",
+ "https://www.googleapis.com/auth/userinfo.email",
+ "openid",
+]
+os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
+flow = Flow.from_client_secrets_file(
+ client_secrets_file=GOOGLE_CLIENT_SECRETS_FILE,
+ scopes=GOOGLE_AUTH_SCOPES,
+ redirect_uri="http://" + REDIRECT_URL + "/login/callback",
+)
+
+
+@app.route("/login")
+def login():
+ auth_url, state = flow.authorization_url()
+ session["state"] = state
+ return redirect(auth_url)
+
+
+@app.route("/login/callback")
+def login_callback():
+ flow.fetch_token(authorization_response=request.url)
+ if not session["state"] == request.args["state"]:
+ abort(500)
+ credentials = flow.credentials
+ request_session = requests.session()
+ cached_session = CacheControl(request_session)
+ token_request = google.auth.transport.requests.Request(session=cached_session)
+ id_info = id_token.verify_oauth2_token(
+ id_token=credentials._id_token, request=token_request, audience=GOOGLE_CLIENT_ID
+ )
+ session["name"] = id_info.get("name")
+ return redirect("/")
+
+
+@app.route("/logout")
+def logout():
+ session.clear()
+ return redirect("/")
+
if __name__ == "__main__":
- app.run(host='0.0.0.0', port=8000)
+ app.run(host="0.0.0.0")
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
+ 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
+ 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
from datetime import datetime
from config import DOMAIN
+
class Event:
- name = ""
- description = ""
- start = datetime.now()
- end = None
- differentDay = False
- link = f"{DOMAIN}/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
+ 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
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 = []
+ 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
+ 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)
class Member:
- name = ""
- leader = False
+ name = ""
+ leader = False
- def __init__(self, name = "", leader = False):
- self.name = name
- self.leader = leader
+ def __init__(self, name="", leader=False):
+ self.name = name
+ self.leader = leader
class Project:
- name = ""
- description = ""
- authors = []
- source = None
- images = None
+ 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
+ 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
from datetime import datetime
from member import Member
+
class Update:
- member = Member()
- text = ""
- time = datetime.now()
+ member = Member()
+ text = ""
+ time = datetime.now()
- def __init__(self, member, text, time):
- self.member = member
- self.text = text
- self.time = time
+ def __init__(self, member, text, time):
+ self.member = member
+ self.text = text
+ self.time = time
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 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)))
-
+ def write(self, projects):
+ with open("database.json", "w") as file:
+ file.write(encode(Data(projects)))
import os
from datetime import datetime
from config import DOMAIN, GROUP_ID
-from models import Group, Event, Update, Discussion, Project, Member
+from models import Group, Event, Update, Discussion, Member
+from database import ProjectDatabase
from schoolopy import Schoology, Auth
+
class SchoologyAPI:
- api = None
- auth = Auth(os.environ["SCHOOLOGY_API_KEY"], os.environ["SCHOOLOGY_API_SECRET"], domain = DOMAIN)
+ 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 __init__(self):
- self.api = Schoology(self.auth)
- self.api.limit = 64
+ def name(self):
+ return self.api.get_group(GROUP_ID).title
- def name(self):
- return self.api.get_group(GROUP_ID).title
+ def description(self):
+ return self.api.get_group(GROUP_ID).description
- 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
+ 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 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 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 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 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 = ProjectDatabase().read()
+ members = self.members()
+ return Group(name, description, events, updates, discussions, projects, 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()
* {
- color: #FFFF82;
- text-align: center;
- background-color: black;
+ 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%;
+ 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;
+ position: absolute;
+ content: " ";
+ bottom: 60%;
+ left: 0;
+ right: 0;
+ top: 0;
}
#content {
- animation: scroll 128s;
- position: absolute;
- top: 100%;
+ animation: scroll 128s;
+ position: absolute;
+ top: 100%;
}
@keyframes scroll {
- 0% {
- top: 100%;
- }
- 100% {
- top: -350%;
- }
+ 0% {
+ top: 100%;
+ }
+ 100% {
+ top: -350%;
+ }
}
#back {
- color: white;
+ color: white;
}
#back.hidden {
- opacity: 0;
+ opacity: 0;
}
#back.shown {
- opacity: 1;
- transition: opacity 2000ms;
+ opacity: 1;
+ transition: opacity 2000ms;
}
* {
- color: white;
- font-family: monospace;
+ color: white;
+ font-family: monospace;
}
body {
- background-color: black;
+ background-color: black;
}
-input, textarea {
- color: black;
+input,
+textarea {
+ color: black;
}
center {
- top: 50%;
- left: 50%;
- transform: translate(-50%,-50%);
- position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ position: absolute;
}
<html>
-<head>
- {% import "elements/metadata.html" as metadata %}
- {{ metadata.head(group, "Discussions") }}
- <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
-</head>
+ <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>
+ <header>
+ {% import "elements/navigation.html" as navigation %} {{
+ navigation.bar(account) }}
+ </header>
-<body>
- {% import "elements/space.html" as space %}
- {{ space.stars(500) }}
+ <body>
+ {% import "elements/space.html" as space %} {{ space.stars(500) }}
- <h1>Discussions</h1>
- {% import "elements/discussions.html" as discussions %}
- {{ discussions.list(group.discussions) }}
-</body>
+ <h1>Discussions</h1>
+ {% import "elements/discussions.html" as discussions %} {{
+ discussions.list(group.discussions) }}
+ </body>
</html>
{% macro view(author) -%}
<a>{{ author }}</a>
-{%- endmacro %}
-
-{% macro list(authors) -%}
+{%- endmacro %} {% macro list(authors) -%}
<div>
- By: {{ view(authors[0]) }}{% for author in authors[1:] %}, {{ author }}{% endfor %}
+ By: {{ view(authors[0]) }}{% for author in authors[1:] %}, {{ author }}{%
+ endfor %}
</div>
{%- endmacro %}
-{% macro time(time) -%}
- {{ time.hour }}:{{ time.minute }}
-{%- endmacro %}
-
-{% macro date(date) -%}
- {{ date.year }}.{{ date.month }}.{{ date.day }}
-{%- endmacro %}
+{% macro time(time) -%} {{ time.hour }}:{{ time.minute }} {%- endmacro %} {%
+macro date(date) -%} {{ date.year }}.{{ date.month }}.{{ date.day }} {%-
+endmacro %}
{% 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 %}
+<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 %}
-{% import "elements/datetime.html" as datetime %}
-
-{% macro view(event) -%}
+{% 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 %}
+ {{ 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) -%}
+{%- 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 %}
+ 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 %}
+{%- endmacro %} {% macro upcoming(events) -%} {% for event in events %}
+<div>view(event)</div>
+{% endfor %} {%- endmacro %}
{% macro head(group, subsection) -%}
- <title>{{ group.name }}
- {% if subsection %}
- - {{ subsection }}
- {% endif %}
- </title>
- <link rel="icon" type="image/x-icon" href="{{ group.picture }}">
+<title>
+ {{ group.name }} {% if subsection %} - {{ subsection }} {% endif %}
+</title>
+<link rel="icon" type="image/x-icon" href="{{ group.picture }}" />
{%- endmacro %}
-{% macro bar() -%}
+{% macro bar(account) -%}
<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>
+ <a href="/">Home</a>
+ <a href="/updates">Updates</a>
+ <a href="/discussions">Discussions</a>
+ <a href="/projects">Projects</a>
+ <a href="/members">Members</a>
+ <div style="float: right">
+ {% if account %}
+ <a>{{ account }}</a>
+ <a href="/logout">Logout</a>
+ {% else %}
+ <a href="/login">Login</a>
+ {% endif %}
+ </div>
</nav>
{%- endmacro %}
-{% 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 %}
+{% 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>
+ {{ view(project) }}
+ <br />
</div>
-{% endfor %}
-{%- endmacro %}
-
-{% macro new() -%}
+{% 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>
+ <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 %}
{% macro stars(num) -%}
<style>
- #star {
- position: absolute;
- width: 1px;
- height: 1px;
- background-color: white;
- }
+ #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);
- }
+ 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];
- }
+ function randomPosition() {
+ var rw = Math.floor(Math.random() * window.innerWidth);
+ var rh = Math.floor(Math.random() * window.innerHeight);
+ return [rw, rh];
+ }
</script>
{%- endmacro %}
-{% 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 %}
+{% 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 %}
<html>
-<head>
- {% import "elements/metadata.html" as metadata %}
- {{ metadata.head(group)}}
- <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
-</head>
+ <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>
+ <header>
+ {% import "elements/navigation.html" as navigation %} {{
+ navigation.bar(account) }}
+ </header>
-<body>
- {% import "elements/space.html" as space %}
- {{ space.stars(500) }}
- <center>
- <h1>{{ group.name }}</h1>
- <p>{{ group.description }}</p>
+ <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>
+ {% 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>
<html>
-<head>
- {% import "elements/metadata.html" as metadata %}
- {{ metadata.head(group, "Members") }}
- <link rel="stylesheet" href="{{ url_for('static', filename='intro.css') }}">
-</head>
+ <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>
+ <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>
<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>
+ <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>
+ <header>
+ {% import "elements/navigation.html" as navigation %} {{
+ navigation.bar(account) }}
+ </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>
+ <body>
+ {% import "elements/space.html" as space %} {{ space.stars(500) }} {% import
+ "elements/projects.html" as projects %} {% if create %} {{ projects.new() }}
+ {% else %}
+ <h1>Projects</h1>
+ {{ projects.list(group.projects) }} {% if account %}
+ <a href="/projects/add">Add a Project</a>
+ {% endif %} {% endif %}
+ </body>
</html>
<html>
-<head>
- {% import "elements/metadata.html" as metadata %}
- {{ metadata.head(group, "Updates") }}
- <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
-</head>
+ <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>
+ <header>
+ {% import "elements/navigation.html" as navigation %} {{
+ navigation.bar(account) }}
+ </header>
-<body>
- {% import "elements/space.html" as space %}
- {{ space.stars(500) }}
+ <body>
+ {% import "elements/space.html" as space %} {{ space.stars(500) }}
- <h1>Updates</h1>
- {% import "elements/updates.html" as updates %}
- {{ updates.list(group.updates) }}
-</body>
+ <h1>Updates</h1>
+ {% import "elements/updates.html" as updates %} {{
+ updates.list(group.updates) }}
+ </body>
</html>