IEEE.org     |     IEEE Xplore Digital Library     |     IEEE Standards     |     IEEE Spectrum     |     More Sites

Commit b1b2e51d authored by Bit Borealis's avatar Bit Borealis
Browse files

Merge branch 'main' into dev

parents 16eada80 d462f916
Pipeline #98 canceled with stage
......@@ -305,6 +305,7 @@ class User:
MalformedId.check_malformed(user_id)
self._user_id: int = user_id
self._username: Optional[str] = None
self._name: Optional[str] = None
self._projects: Optional[List[Project]] = None
self._c: Cursor = c
......@@ -333,6 +334,7 @@ class User:
except StopIteration:
raise NonexistantId('user', self._user_id)
self._username = record[1]
self._name = record[2]
def check_owns(self, project: Project) -> bool:
"""
......@@ -392,7 +394,7 @@ class User:
return self._c.rowcount > 0
@staticmethod
def create_user(c: Cursor, username: str) -> 'User':
def create_user(c: Cursor, uid: int, username: str, name: str) -> 'User':
"""
Creates a new user with a given username
......@@ -411,10 +413,37 @@ class User:
mystic.database.MalformedId: The provided ID was malformed, for
example because it was negative or because it was to large.
"""
c.execute('INSERT INTO users(username) VALUES (?);', (username,))
c.execute('INSERT INTO users(user_id, username, name) VALUES (?, ?, ?);', (uid, username, name))
user = User(c, c.lastrowid)
user._projects = []
user._username = username
user._name = name
return user
@staticmethod
def create_or_update(c: Cursor, uid: int, username: str, name: str) -> 'User':
"""
Update a user's information, creating one if not already in the db
This is effectively a User.create_user() with no chance of throwing an
error if the user already exists. Please read the documentation of
User.create_user() for more information.
One key difference between this user and a user created through the
create_user() method is that this user will not have a pre-populated
projects attribute, so certain properties will require a database
connection to access.
Raises:
sqlite3.OperationalError: The project was initialized with a
cursor that points to a database that was not properly set up
mystic.database.MalformedId: The provided ID was malformed, for
example because it was negative or because it was to large.
"""
c.execute('REPLACE INTO users(user_id, username, name) VALUES (?, ?, ?);', (uid, username, name))
user = User(c, c.lastrowid)
user._username = username
user._name = name
return user
@staticmethod
......@@ -461,6 +490,24 @@ class User:
self.load()
return self._username #type: ignore
@property
def name(self) -> str:
"""
Retrieves the user's first name (preferred, not legal)
This MAY require a database query if the field has not yet been fetched
Raises:
sqlite3.OperationalError: The user was initialized with a
cursor that points to a database that was not properly set up
mystic.database.NonexistantId: The user was initialized with an ID
that was not found
"""
if self._name is None:
self.load()
assert self._name is not None
return self._name
@property
def projects(self) -> List[Project]:
"""
......
import sqlite3
import json
from flask import render_template, request, session, Blueprint, current_app
from flask import render_template, request, Blueprint, current_app
from werkzeug.wrappers.response import Response
from typing import Tuple, Union
from typing import Tuple, Union, Optional
from mystic.database import User, Project
from mystic.projects import produce_project_report
from mystic.config import service_provider
......@@ -14,32 +14,31 @@ bp = Blueprint("main", __name__, url_prefix="/")
def landing() -> str:
return render_template("landing.html", login=_login_or_profile())
@bp.route("/login", methods=['POST'])
def login() -> Response:
service_provider.login_required()
return flask.redirect("projects")
@bp.route("/projects/")
def projects() -> str:
with sqlite3.connect(current_app.config['DATABASE']) as conn:
c = conn.cursor()
user = User(c, session['user'])
projects = list(user.projects)
projects_with_id = (
(p.alphaid, p)
for p
in projects
)
return render_template("projects.html", login=_login_or_profile(), projects=projects_with_id)
user = _current_user(c)
if user is not None:
projects = list(user.projects)
projects_with_id = (
(p.alphaid, p)
for p
in projects
)
return render_template("projects.html", login=_login_or_profile(), projects=projects_with_id)
else:
return "Viewing projects while logged out is not yet supported"
@bp.route("/projects/addsource", methods=['POST'])
def addsource() -> Response:
service_provider.login_required()
url = request.form['url'].strip()
if len(url) == 0:
return Response(status=400)
with sqlite3.connect(current_app.config['DATABASE']) as conn:
c = conn.cursor()
user = User(c, session['user'])
user = _current_user(c)
project = Project(c, int(request.form['project']))
if not user.check_owns(project):
return Response(status=401)
......@@ -49,9 +48,10 @@ def addsource() -> Response:
@bp.route("/projects/addowner", methods=['POST'])
def addowner() -> Response:
service_provider.login_required()
with sqlite3.connect(current_app.config['DATABASE']) as conn:
c = conn.cursor()
user = User(c, session['user'])
user = _current_user(c)
project = Project(c, int(request.form['project']))
if not user.check_owns(project):
return Response(status=401)
......@@ -64,10 +64,11 @@ def addowner() -> Response:
@bp.route("/projects/delsource")
def delsource() -> Response:
service_provider.login_required()
source_id = int(request.args['source'])
with sqlite3.connect(current_app.config['DATABASE']) as conn:
c = conn.cursor()
user = User(c, session['user'])
user = _current_user(c)
if user.delete_source_if_owned(source_id):
_save_projects_json_and_close_cursor(c, conn)
return _project_redir()
......@@ -76,9 +77,10 @@ def delsource() -> Response:
@bp.route("/projects/edit/<pid>")
def project_page(pid: str) -> Union[Response, str]:
service_provider.login_required()
with sqlite3.connect(current_app.config['DATABASE']) as conn:
c = conn.cursor()
user = User(c, session['user'])
user = _current_user(c)
project = Project.from_alphaid(c, pid)
if not user.check_owns(project):
return Response(status=401) # Public project pages aren't implemented yet
......@@ -90,10 +92,12 @@ def new() -> str:
@bp.route("/new/create", methods=['POST'])
def create() -> Response:
service_provider.login_required()
name = request.form['name']
with sqlite3.connect(current_app.config['DATABASE']) as conn:
c = conn.cursor()
user = User(c, session['user'])
user = _current_user(c)
assert user is not None
project = Project.create_project(c, name)
project.add_owner(user)
return flask.redirect("../projects")
......@@ -105,6 +109,13 @@ def _login_or_profile() -> Tuple[str, str]:
else:
return ('Login', service_provider.get_login_url())
def _current_user(c: sqlite3.Cursor) -> Optional[User]:
if service_provider.is_user_logged_in():
user_info = service_provider.get_auth_data_in_session().attributes
return User.create_or_update(c, int(user_info['uidNumber']), user_info['uid'], user_info['givenName'])
else:
return None
def _save_projects_json_and_close_cursor(c: sqlite3.Cursor, conn: sqlite3.Connection) -> None:
report = produce_project_report(c)
conn.commit()
......
......@@ -7,7 +7,8 @@ def setup_database(c: sqlite3.Cursor) -> None:
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
username TEXT UNIQUE NOT NULL
username TEXT UNIQUE NOT NULL,
name TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS projects (
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment