This repository has been archived by the owner on May 1, 2023. It is now read-only.
generated from cds-snc/project-template
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: bootstrapped basic web rendering using jinja2 (#102)
* feat: bootstrapped basic web rendering using jinja2 * Formatting and remove unused import * chore: removed reference to Form component * chore: ignore unreferenced objects since import is required * chore: api is now versioned and front end has been extracted to its own module * feat: i18n for en & fr added * chore: renamed pydantic organisation model to OrganisationFilter * chore: formatting * feat: add test * chore: formatting isnt my friend * chore: remove unused import after refactor * chore: another test * chore: remove unused imports from test * chore: test removal of db initialize * chore: remove import of disabled feature * chore: remove broken test and database reset debug code * chore: remove unused import * chore: cleaned up and new db session code * chore: less ugly page
- Loading branch information
Showing
24 changed files
with
420 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
from os import environ | ||
from fastapi import Depends, FastAPI, HTTPException | ||
from sqlalchemy.exc import SQLAlchemyError | ||
from sqlalchemy.orm import Session | ||
from fastapi.responses import RedirectResponse | ||
from database.db import db_session | ||
from logger import log | ||
|
||
from models.Organisation import Organisation | ||
from schemas.Organization import OrganizationCreate | ||
|
||
# from crawler.crawler import crawl | ||
# import uuid | ||
from pydantic import BaseModel | ||
|
||
app = FastAPI() | ||
|
||
|
||
# Dependency | ||
def get_db(): | ||
db = db_session() | ||
try: | ||
yield db | ||
finally: | ||
db.close() | ||
|
||
|
||
@app.get("/api/v1/version") | ||
def version(): | ||
return {"version": environ.get("GIT_SHA", "unknown")} | ||
|
||
|
||
def get_db_version(session): | ||
|
||
query = "SELECT version_num FROM alembic_version" | ||
full_name = session.execute(query).fetchone()[0] | ||
return full_name | ||
|
||
|
||
@app.get("/api/v1/healthcheck") | ||
def healthcheck(session: Session = Depends(get_db)): | ||
try: | ||
full_name = get_db_version(session) | ||
db_status = {"able_to_connect": True, "db_version": full_name} | ||
except SQLAlchemyError as err: | ||
log.error(err) | ||
db_status = {"able_to_connect": False} | ||
|
||
return {"database": db_status} | ||
|
||
|
||
# TODO Require auth and redirect to home | ||
# TODO Push errors to cloudwatch metric and response when debug enabled | ||
@app.post("/api/v1/organisation", response_class=RedirectResponse) | ||
def create_organisation( | ||
organisation: OrganizationCreate, session: Session = Depends(get_db) | ||
): | ||
|
||
try: | ||
new_organisation = Organisation(name=organisation.name) | ||
session.add(new_organisation) | ||
session.commit() | ||
return RedirectResponse("/dashboard") | ||
except Exception as e: | ||
log.error(e) | ||
raise HTTPException(status_code=500, detail=str(e)) | ||
|
||
|
||
class CrawlUrl(BaseModel): | ||
url: str | ||
|
||
|
||
# @app.post("/crawl") | ||
# def crawl_endpoint(crawl_url: CrawlUrl): | ||
# log.info(f"Crawling {crawl_url}") | ||
# crawl(uuid.uuid4(), crawl_url.url) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<!DOCTYPE html> | ||
<html lang="{{ lang }}"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<link rel="icon" href="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Ctext%20x='0'%20y='14'%3E🍁%3C/text%3E%3C/svg%3E" type="image/svg+xml" /> | ||
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet"> | ||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.1/css/all.css"> | ||
<title>{{ webpage_title }}</title> | ||
</head> | ||
<body class="bg-gray-100 font-sans leading-normal tracking-normal h-full"> | ||
<div class="min-h-screen flex flex-col"> | ||
<div class="flex-grow"> | ||
<nav class="bg-white w-full z-10 top-0 shadow" id="header"> | ||
<div class="w-full container mx-auto flex flex-wrap items-center mt-0 pt-3 pb-3 md:pb-0"> | ||
<div class="pl-2 pb-4 w-1/2 md:pl-0"> | ||
<a class="text-gray-900 text-base no-underline font-bold xl:text-xl hover:no-underline" href="/{{ lang }}" aria-label="{{ goc }}"> | ||
<img class="h-6 inline-block pr-10" src="{{ goc_banner }}" alt="{{ goc }}" /> | ||
</a> | ||
<span class="leading-none lg:ml-4 mr-5 lg:pl-5 font-semibold inline-block top-0 text-brand pb-0">{{ webpage_title }}</span> | ||
<span class="bg-blue-200 py-1 px-2 rounded-lg text-small">{{ alpha }}</span> | ||
</div> | ||
<div class="pl-2 pb-4 w-1/2 md:pl-0 text-right"> | ||
<a class="text-base no-underline hover:no-underline" href="/{{other_lang}}" aria-label="{{ goc }}"> | ||
{{ other_language }} | ||
</a> | ||
</div> | ||
</div> | ||
</nav> | ||
<div class="container w-full mx-auto h-full"> | ||
<div class="w-full px-4 mb-16 text-gray-800 leading-normal md:px-0 md:mt-8"> | ||
<div class="flex flex-col flex-1 max-h-full pl-2 pr-2 rounded-md xl:pr-4"> | ||
<main class="flex-1 pt-2"> | ||
{% block body %}{% endblock %} | ||
</main> | ||
</div> | ||
</div> | ||
<div class="footer"> | ||
{% block footer %} | ||
<br> | ||
<br> | ||
{% endblock %} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
{% extends "base.html" %} | ||
{% block body %} | ||
<center><h1>{{ organisations_locale }}</h1></center> | ||
<div class="flex flex-col"> | ||
<div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> | ||
<div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8"> | ||
<div class="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg"> | ||
<table class="min-w-full divide-y divide-gray-200"> | ||
<thead class="bg-gray-50"> | ||
<tr> | ||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||
Name | ||
</th> | ||
<th scope="col" class="relative px-6 py-3"> | ||
<span class="sr-only">Configure</span> | ||
</th> | ||
</tr> | ||
</thead> | ||
<tbody class="bg-white divide-y divide-gray-200"> | ||
{% for organisation in organisations %} | ||
<tr> | ||
<td class="px-6 py-4 whitespace-nowrap"> | ||
<div class="text-sm font-medium text-gray-900"> | ||
{{ organisation.name }} | ||
</div> | ||
</td> | ||
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | ||
<a href="{{lang}}/organisation/{{ organisation.id }}/edit" class="text-indigo-600 hover:text-indigo-900">Edit</a> | ||
</td> | ||
</tr> | ||
{% endfor %} | ||
</tbody> | ||
</table> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
|
||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{% extends "base.html" %} | ||
{% block content %} | ||
<div>{{ welcome }}</div> | ||
{% block footer %} | ||
{{super()}} | ||
{% endblock %} | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
from fastapi import Depends, FastAPI, Request, HTTPException | ||
from fastapi.responses import HTMLResponse, RedirectResponse | ||
from fastapi.templating import Jinja2Templates | ||
from babel.plural import PluralRule | ||
from database.db import db_session | ||
from logger import log | ||
from sqlalchemy.orm import Session | ||
|
||
from models.Organisation import Organisation | ||
|
||
import glob | ||
import json | ||
import os | ||
|
||
app = FastAPI() | ||
|
||
|
||
# Dependency | ||
def get_db(): | ||
db = db_session() | ||
try: | ||
yield db | ||
finally: | ||
db.close() | ||
|
||
|
||
templates = Jinja2Templates(directory="front_end/templates") | ||
default_fallback = "en" | ||
languages = {} | ||
|
||
|
||
def generate_languages(locale_files): | ||
language_list = glob.glob(locale_files) | ||
for lang in language_list: | ||
filename = lang.split(os.path.sep) | ||
lang_code = filename[1].split(".")[0] | ||
|
||
with open(lang, "r", encoding="utf8") as file: | ||
languages[lang_code] = json.load(file) | ||
|
||
|
||
generate_languages("i18n/*.json") | ||
|
||
|
||
# custom filters for Jinja2 | ||
def plural_formatting(key_value, input, locale): | ||
plural_rule = PluralRule({"one": "n in 0..1"}) | ||
key = "" | ||
for i in languages[locale]: | ||
if key_value == languages[locale][i]: | ||
key = i | ||
break | ||
|
||
if not key: | ||
return key_value | ||
|
||
plural_key = f"{key}_plural" | ||
|
||
if plural_rule(input) != "one" and plural_key in languages[locale]: | ||
key = plural_key | ||
|
||
return languages[locale][key] | ||
|
||
|
||
# assign filter to Jinja2 | ||
templates.env.filters["plural_formatting"] = plural_formatting | ||
|
||
|
||
@app.get("/", response_class=HTMLResponse) | ||
async def force_lang(): | ||
return RedirectResponse("/en") | ||
|
||
|
||
@app.get("/{locale}", response_class=HTMLResponse) | ||
async def home(request: Request, locale: str): | ||
try: | ||
if locale not in languages: | ||
locale = default_fallback | ||
|
||
result = {"request": request} | ||
result.update(languages[locale]) | ||
return templates.TemplateResponse("index.html", result) | ||
except Exception as e: | ||
log.error(e) | ||
raise HTTPException(status_code=500, detail=str(e)) | ||
|
||
|
||
# TODO Require auth & limit to users current organisation | ||
# TODO Push errors to cloudwatch metric and response when debug enabled | ||
# TODO Enable detailed error messages via debug flag | ||
@app.get("/{locale}/dashboard", response_class=HTMLResponse) | ||
async def dashboard(request: Request, locale: str, session: Session = Depends(get_db)): | ||
try: | ||
if locale not in languages: | ||
locale = default_fallback | ||
|
||
organisation_list = session.query(Organisation).all() | ||
result = {"request": request} | ||
result.update(languages[locale]) | ||
result.update({"organisations": organisation_list}) | ||
except Exception as e: | ||
log.error(e) | ||
raise HTTPException(status_code=500, detail=str(e)) | ||
return templates.TemplateResponse("dashboard.html", result) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"alpha": "Alpha", | ||
"goc": "Government of Canada", | ||
"goc_banner": "https://ssl-templates.services.gc.ca/app/cls/wet/gcintranet/v4_0_20/assets/sig-blk-en.svg", | ||
"lang": "en", | ||
"organisations_locale" : "Organisations", | ||
"other_lang": "fr", | ||
"other_language": "Français", | ||
"webpage_title": "Scan websites", | ||
"welcome": "Welcome to Scan websites" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"alpha": "Alpha", | ||
"goc": "Gouvernement du Canada", | ||
"goc_banner": "https://ssl-templates.services.gc.ca/app/cls/wet/gcintranet/v4_0_20/assets/sig-blk-fr.svg", | ||
"lang": "fr", | ||
"organisations_locale" : "Organisations", | ||
"other_lang": "en", | ||
"other_language": "English", | ||
"webpage_title": "Analyser les sites web", | ||
"welcome": "Bienvenue sur les sites Web de Scan" | ||
} |
Oops, something went wrong.