diff options
author | Katharina Fey <kookie@spacekookie.de> | 2020-06-22 01:48:59 +0200 |
---|---|---|
committer | Katharina Fey <kookie@spacekookie.de> | 2020-06-22 01:48:59 +0200 |
commit | 84a9a0ccee713e26a28ff5e54ea3776085d93b5f (patch) | |
tree | 9a0158ecc1668e8594881a4f9be7e54c8773d6a9 | |
parent | 67ad3b7a26ed0dc99f3324011fa8e5ed316a655a (diff) |
Updating just like... a bunch of shit
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/cli.rs | 79 | ||||
-rw-r--r-- | src/config.rs | 17 | ||||
-rw-r--r-- | src/main.rs | 20 | ||||
-rw-r--r-- | src/pages/mod.rs | 4 | ||||
-rw-r--r-- | src/pages/repo/about.rs | 44 | ||||
-rw-r--r-- | src/pages/repo/details.rs | 37 | ||||
-rw-r--r-- | src/pages/repo/mod.rs | 14 | ||||
-rw-r--r-- | src/state/mod.rs | 14 | ||||
-rw-r--r-- | src/types/mod.rs | 30 | ||||
-rw-r--r-- | static/main.css | 7 | ||||
-rw-r--r-- | templates/core.html | 18 | ||||
-rw-r--r-- | templates/repo/about.html | 133 | ||||
-rw-r--r-- | templates/repo/base.html | 37 | ||||
-rw-r--r-- | templates/repo/details.html | 258 |
15 files changed, 426 insertions, 288 deletions
@@ -7,8 +7,8 @@ edition = "2018" [dependencies] actix-files = "0.2" -actix-web = "2.0.0" actix-rt = "1.0.0" +actix-web = "2.0.0" askama = "0.8" env_logger = "0.6" git2 = "0.11" diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..500a901 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,79 @@ +use clap::{App, Arg}; +use colored::Colorize; +use std::{ + env, + fs::File, + path::{Path, PathBuf}, +}; + +pub struct Paths { + pub config: File, + pub data: PathBuf, +} + +/// Initialise the application by getting valid path options +pub fn init() -> Paths { + let app = App::new("webgit") + .about("The friendly and simple git web frontend") + .version("0.0.0") + .arg( + Arg::with_name("CONFIG") + .short("c") + .long("config") + .takes_value(true) + .help( + "Provide the path to the system configuration. Alternatively \ + set WEBGIT_CONFIG_PATH in your env", + ), + ) + .arg( + Arg::with_name("DATA_DIR") + .short("d") + .long("data-dir") + .takes_value(true) + .help( + "Specify where webgit should save git repositories. Alternatively \ + set WEBGIT_DATA_DIR in your env", + ), + ); + + let matches = app.get_matches(); + + Paths { + config: File::open( + env::var_os("WEBGIT_CONFIG_PATH") + .map(|os| match os.into_string() { + Ok(p) => p.to_owned(), + Err(_) => { + eprintln!("{}: Failed to parse provided config path!", "Error:".red()); + std::process::exit(2); + } + }) + .unwrap_or_else(|| match matches.value_of("CONFIG") { + Some(p) => p.to_owned(), + None => { + eprintln!("{}: No config provided!", "Error:".red()); + std::process::exit(2); + } + }), + ) + .expect(&format!("{}: Config file not found!", "Error:".red())), + data: Path::new( + &env::var_os("WEBGIT_DATA_DIR") + .map(|os| { + os.into_string().expect(&format!( + "{}: Failed to parse provided data-dir path!", + "Error".red() + )) + }) + .unwrap_or_else(|| match matches.value_of("CONFIG") { + Some(p) => p.to_owned(), + None => { + eprintln!("{}: No data dir provided!", "Error:".red()); + std::process::exit(2); + } + }), + ) + .into(), + } +} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..99e8cff --- /dev/null +++ b/src/config.rs @@ -0,0 +1,17 @@ +//! Configuration to run octopus + +pub struct Config { + app_path: String, + port: u16, + handle_ssl: bool, + cache_path: String, + repos_path: String, + repo_discovery: bool, + repos: Vec<RepoConfig> +} + +pub struct RepoConfig { + name: String, + description: String, + category: String, +} diff --git a/src/main.rs b/src/main.rs index d6a4b36..6d0ef79 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,25 @@ mod pages; mod repo; +// mod router; +mod types; use actix_files as fs; use actix_web::{web, App, HttpServer}; use std::io; +use std::path::PathBuf; #[actix_rt::main] async fn main() -> io::Result<()> { - HttpServer::new(|| { + std::env::set_var("RUST_LOG", "actix_web=info"); + env_logger::init(); + let root = PathBuf::new(); + + HttpServer::new(move || { App::new() - .service(fs::Files::new("/static", "static")) - .service(web::resource("/{repo}").route(web::get().to(pages::repo::about::render))) - // default - .default_service( - // 404 for GET request - web::resource("").route(web::get().to(pages::p404::render)), - ) + .service(fs::Files::new("/static", root.join("static"))) + .service(web::resource("/{repo}").route(web::get().to(pages::repo::about))) + .service(web::resource("/{repo}/details").route(web::get().to(pages::repo::details))) + .default_service(web::resource("").route(web::get().to(pages::p404))) }) .bind("127.0.0.1:8080")? .run() diff --git a/src/pages/mod.rs b/src/pages/mod.rs index d53561b..f838eee 100644 --- a/src/pages/mod.rs +++ b/src/pages/mod.rs @@ -4,4 +4,6 @@ //! which is exported from the module and then called by the router pub mod repo; -pub mod p404; + +mod p404; +pub use p404::render as p404; diff --git a/src/pages/repo/about.rs b/src/pages/repo/about.rs index 8797edd..fa88eb1 100644 --- a/src/pages/repo/about.rs +++ b/src/pages/repo/about.rs @@ -1,35 +1,35 @@ +use super::RepoWrapper; +use crate::types::RepoData; use actix_web::{web, HttpRequest, HttpResponse, Result}; use askama::Template; #[derive(Template)] -#[template(path = "repo.html")] -struct Repo<'a> { - project_owner: &'a str, - project_summary: &'a str, - project_name: &'a str, - project_logo: &'a str, - project_logo_alt_text: &'a str, - first_commit: &'a str, - num_commits: usize, - num_contributors: usize, +#[template(path = "repo/about.html")] +struct AboutRepo { + repo: RepoWrapper, + readme: String, } /// Renders the "repository/about" subpage pub async fn render(req: HttpRequest, path: web::Path<String>) -> Result<HttpResponse> { - println!("Rendering path: {:#?}", path); - dbg!(req); - - let repo = Repo { - project_owner: "spacekookie", - project_summary: "A lightweight web frontend for git repositories", - project_name: "webgit", - project_logo: "rust.png", - project_logo_alt_text: "Rust logo", - first_commit: "f6ca929", - num_commits: 123, - num_contributors: 3, + let repo = AboutRepo { + readme: include_str!("../../../README").to_string(), + repo: RepoWrapper { + data: RepoData { + owner: "spacekookie".into(), + name: "octopus".into(), + tagline: "A lightweight web frontend for git repositories".into(), + num_commit: 141, + num_branch: 1, + num_tag: 0, + num_contributor: 3, + size: "13.12M".into(), + }, + logo: "fakeavi.png".into(), + }, } .render() .unwrap(); + Ok(HttpResponse::Ok().content_type("text/html").body(repo)) } diff --git a/src/pages/repo/details.rs b/src/pages/repo/details.rs new file mode 100644 index 0000000..4745e96 --- /dev/null +++ b/src/pages/repo/details.rs @@ -0,0 +1,37 @@ +use super::RepoWrapper; +use crate::types::{BranchData, CommitData, RepoData}; +use actix_web::{web, HttpRequest, HttpResponse, Result}; +use askama::Template; + +#[derive(Template)] +#[template(path = "repo/details.html")] +struct AboutRepo { + repo: RepoWrapper, + branches: Vec<BranchData>, + commits: Vec<CommitData>, +} + +/// Renders the "repository/about" subpage +pub async fn render(req: HttpRequest, path: web::Path<String>) -> Result<HttpResponse> { + let repo = AboutRepo { + branches: vec![], + commits: vec![], + repo: RepoWrapper { + data: RepoData { + owner: "spacekookie".into(), + name: "octopus".into(), + tagline: "A lightweight web frontend for git repositories".into(), + num_commit: 141, + num_branch: 1, + num_tag: 0, + num_contributor: 3, + size: "13.12M".into(), + }, + logo: "fakeavi.png".into(), + }, + } + .render() + .unwrap(); + + Ok(HttpResponse::Ok().content_type("text/html").body(repo)) +} diff --git a/src/pages/repo/mod.rs b/src/pages/repo/mod.rs index c339350..7d90c97 100644 --- a/src/pages/repo/mod.rs +++ b/src/pages/repo/mod.rs @@ -1,3 +1,15 @@ //! The repository page subtree -pub mod about; +mod about; +mod details; + +pub use about::render as about; +pub use details::render as details; + +use crate::types::RepoData; + +/// A template wrapper for repository data +pub(self) struct RepoWrapper { + pub(self) data: RepoData, + pub(self) logo: String, +} diff --git a/src/state/mod.rs b/src/state/mod.rs new file mode 100644 index 0000000..5e7f927 --- /dev/null +++ b/src/state/mod.rs @@ -0,0 +1,14 @@ +//! Core octopus state handling + +use std::sync::Arc; + +pub(crate) type StateRef = Arc<OctoState>; + +/// Holds all state handles for the application +pub(crate) struct OctoState {} + +impl OctoState { + pub(crate) fn new() -> StateRef { + Arc::new(Self {}) + } +} diff --git a/src/types/mod.rs b/src/types/mod.rs new file mode 100644 index 0000000..d764b84 --- /dev/null +++ b/src/types/mod.rs @@ -0,0 +1,30 @@ +//! Octopus data types + +/// A simple overview of a repository +/// +/// This type can be generated by the octopus Repository state wrapper +pub(crate) struct RepoData { + pub owner: String, + pub name: String, + pub tagline: String, + pub num_commit: usize, + pub num_branch: usize, + pub num_tag: usize, + pub num_contributor: usize, + pub size: String, +} + +/// Data about an individual commit +pub(crate) struct CommitData { + pub hash: String, + pub message: String, + pub author: String, + pub date: String, + pub diff: (usize, usize), +} + +/// Data about a branch +pub(crate) struct BranchData { + pub name: String, + pub last_commit: CommitData, +} diff --git a/static/main.css b/static/main.css index b567240..cea0eb1 100644 --- a/static/main.css +++ b/static/main.css @@ -66,6 +66,7 @@ a:hover, a:active { grid-row-end: 3; max-width:230px; max-height:100px; + padding-right: 1em; } .subheader { @@ -99,6 +100,12 @@ a:hover, a:active { font-size: 1.25em; } +.details-table { + padding: 5ch 15ch; + font-size: 1.25em; + text-align: left; +} + .details-grid { display: grid; grid-template-columns: 2fr 4fr repeat(3, 1fr); diff --git a/templates/core.html b/templates/core.html new file mode 100644 index 0000000..808dc4c --- /dev/null +++ b/templates/core.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8" /> + <link href="/static/main.css" rel="stylesheet"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + {% block title %}{% endblock %} + </head> + <body> + <div class="container"> + {% block content %}{% endblock %} + + <hr/> + <pre>Generated by octopus v0.0.0</pre> + <div> + </body> +</html> diff --git a/templates/repo/about.html b/templates/repo/about.html index b98edbd..5c476aa 100644 --- a/templates/repo/about.html +++ b/templates/repo/about.html @@ -1,131 +1,6 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="utf-8" /> - <title>octopus | /spacekookie/octopus</title> - <link href="/static/main.css" rel="stylesheet"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - </head> - <body> - <div class="container"> - <div class="tagline-container"> - <img class="repo-logo" src="/static/fakeavi.png" /> - <h1><a href="">spacekookie</a> / <a href="">octopus</a></h1> - <p>š It's a water animal</p> - <div class="starbox"> - <a href="">Clone</a> - <a href="">Star</a> - <a href="">RSS</a> - </div> - </div> <!-- tagline container --> - <div class="subheader"> - - <a href="">141 commits</a> - <a href="">1 branch</a> - <a href="">0 tags</a> - <a href="">1 contributor</a> - <a href="">size: 13.12M</a> - <input id="repo-search" type="search" placeholder="Search repository" /> - <!-- <label for="repo-search">Search for files in the repository</label> --> - </div> <!-- subheader --> - <hr /> - <div class="repo-navigation"> - <a href="about.html" class="nav-item nav-active">about</a> - <a href="details.html " class="nav-item">details</a> - <a href="" class="nav-item">files</a> - <a href="" class="nav-item">log</a> - <a href="" class="nav-item"> patches</a> - <a href="" class="nav-item">contribute</a> - </div> +{% extends "base.html" %} - <pre class="readme"> - .'.' - .'-'. - . ( o O) - \_ ` _, _ --.___'.) ( ,-' - '-.O.'-..-.. octopus git web frontend - ./\/\/ | \_.-._ - ; - ._/ +{% block child_content %} +<pre class="readme">{{ readme }}</pre> +{% endblock %} - -A git web frontend that wants to hug your code. - - -Why? ----- - -This is a very good first question, and one that I think is important -to answer before getting more into the project. Whenever I brought up -this project during the creation of it, most people would react with -"have you tried...", followed by some git web software, such as -gitlab, gittea, and many many more. But there is a reason why I stuck -with octopus and the design ideas I had for it. - -Fundamentally it's about decentralisation. The internet is a pretty -big place (allegedly), but a lot of the services that people use are -very centralised by a single company or even server. If this company -or server goes away, so does valuable knowledge. There are many ways -to create more decentralised systems, and one aspect of this for me, -is code repos. - -Git is by it's nature decentralised, meaning that it doesn't require -an "upstream" or canonical server to function. Theoretically you -could use git to exchange code patches with people without the -internet. Yet, a lot of people's perception of git is one that is -dictated by the workflows on github and gitlab: centralised into a -single service. Many git web frontends mirror this workflow, because -after all, it is what people want and love. - -However, it has some flaws (which would take too long to elaborate -here), and for octopus I had something else in mind. Instead of -replicating the same mistakes, I took much more inspiration from cgit, -which is used and loved by many today. - -Octopus is a re-imagining of cgit, trying to improve the UX and -maintainability where possible, adding new features, but mostly -staying true to it's core: a simple git web service, that doesn't lock -you into a vendor, or server. - -Configuration -------------- - -octopus is easy to configure and run, even on systems that don't give -you priviledged system access. The main server binary is configured -primarily with a few environment variables, and an app config. - -+ OCTOPUS_CONFIG should contain the path of the main configuration - -+ OCTOPUS_SSL_KEY can optionally be set to the path of a certificate key - -+ OCTOPUS_SSL_CERT can optionally be set to the path of a certificate - - -The main configuration file is written in yaml, and outlines things -like the application domain, repo paths, and added modules. Because -octopus is vory modular, you can only depend on certain features. - - ---- -app_path: git.octopus.example -port: 8080 -handle_ssl: false -cache_path: /var/cache/octopus -repo_path: /var/lib/octopus/repos -repo_discovery: false # Disables automatic config loading from repo_path - # and instead let's you set a static set of repos - # in the section below -repos: - - octopus: - description: "š It's a water animal" - category: "/" - - libkookie: - description: "My personal nix expressions" - category: "/nix" - - - </pre> - </div> - </body> -</html> diff --git a/templates/repo/base.html b/templates/repo/base.html new file mode 100644 index 0000000..9927a4a --- /dev/null +++ b/templates/repo/base.html @@ -0,0 +1,37 @@ +{% extends "../core.html" %} +{% block title %}<title>octopus | /{{ repo.data.owner }}/{{ repo.data.name }}</title>{% endblock %} + +{% block content %} +<div class="tagline-container"> + <img class="repo-logo" src="/static/{{ repo.logo }}" /> + <h1><a href="">{{ repo.data.owner }}</a> / <a href="">{{ repo.data.name }}</a></h1> + <p>š It's a water animal</p> + <div class="starbox"> + <a href="">Clone</a> + <a href="">Star</a> + <a href="">RSS</a> + </div> +</div> <!-- tagline container --> +<div class="subheader"> + + <a href="">{{ repo.data.num_commit }} commits</a> + <a href="">{{ repo.data.num_branch}} branch</a> + <a href="">{{ repo.data.num_tag }} tags</a> + <a href="">{{ repo.data.num_contributor }} contributor</a> + <a href="">size: {{ repo.data.size }}</a> + <input id="repo-search" type="search" placeholder="Search repository" /> + <!-- <label for="repo-search">Search for files in the repository</label> --> +</div> <!-- subheader --> +<hr /> +<div class="repo-navigation"> + <a href="about.html" class="nav-item nav-active">about</a> + <a href="details.html " class="nav-item">details</a> + <a href="" class="nav-item">files</a> + <a href="" class="nav-item">log</a> + <a href="" class="nav-item">patches</a> + <a href="" class="nav-item">contribute</a> +</div> + +{% block child_content %}{% endblock %} + +{% endblock %} diff --git a/templates/repo/details.html b/templates/repo/details.html index ddcc761..6a13a77 100644 --- a/templates/repo/details.html +++ b/templates/repo/details.html @@ -1,126 +1,132 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="utf-8" /> - <title>octopus | /spacekookie/octopus</title> - <link href="/static/main.css" rel="stylesheet"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - </head> - <body> - <div class="container"> - <div class="tagline-container"> - <img class="repo-logo" src="/static/fakeavi.png" /> - <h1><a href="">spacekookie</a> / <a href="">octopus</a></h1> - <p>š It's a water animal</p> - <div class="starbox"> - <a href="">Clone</a> - <a href="">Star</a> - <a href="">RSS</a> - </div> - </div> <!-- tagline container --> - <div class="subheader"> - - <a href="">141 commits</a> - <a href="">1 branch</a> - <a href="">0 tags</a> - <a href="">1 contributor</a> - <a href="">size: 13.12M</a> - <input id="repo-search" type="search" placeholder="Search repository" /> - <!-- <label for="repo-search">Search for files in the repository</label> --> - </div> <!-- subheader --> - <hr /> - <div class="repo-navigation"> - <a href="about.html" class="nav-item">about</a> - <a href="details.html" class="nav-item nav-active">details</a> - <a href="" class="nav-item">files</a> - <a href="" class="nav-item">log</a> - <a href="" class="nav-item"> patches</a> - <a href="" class="nav-item">contribute</a> - </div> - - <div class="details-grid"> - <h3>Branch</h3> - <h3>Commit message</h3> - <h3>Author</h3> - <h3 class="details-span">Date</h3> - - <a href="">fn-verify-9324832</a> - <a href="">Updating to actix 2.0.0 and adding 404 handler</a> - <p>Katharina Fey</p> - <p class="details-span">5 months ago</p> - - <a href="">master</a> - <a href="">Rebuilding the entire htlm and css styles</a> - <p>Katharina Fey</p> - <p class="details-span">18 hours ago</p> - - <!-- Switch to last commits --> - <h3>Commit Hash</h3> - <h3>Commit message</h3> - <h3>Author</h3> - <h3>Date</h3> - <h3>Lines</h3> - - <a href="">270cb70</a> - <a href="">Rebuilding the entire htlm and css stiles</a> - <p>Katharina Fey</p> - <p>19 hours ago</p> - <p>-214/+75</p> - - <a href="">5db4c57</a> - <a href="">Updating to actix 2.0.0 and adding 404 handler</a> - <p>Katharina Fey</p> - <p>2020-01-23</p> - <p>-610/+455</p> - - <a href="">5e16c64</a> - <a href="">Adding project documentation and roadmap planning</a> - <p>Katharina Fey</p> - <p>2020-01-23</p> - <p>-3/+61</p> - - <a href="">8b38bdd</a> - <a href="">data: adding a small wrapper around libgit2</a> - <p>Katharina Fey</p> - <p>2019-12-29</p> - <p>-36/+32</p> - - <a href="">c896fcd</a> - <a href="">material-ish design with gitea-style tabs</a> - <p>Milan PƤssler</p> - <p>2019-12-29</p> - <p>-102/+169</p> - - <a href="">f2f49bb</a> - <a href="">material-ish design with gitea-style tabs</a> - <p>Milan PƤssler</p> - <p>2019-12-29</p> - <p>-1/+2</p> - - <a href="">4be56ee</a> - <a href="">Adding a small limgit2 example usage</a> - <p>Katharina Fey</p> - <p>2019-12-29</p> - <p>-2/+17</p> - - <a href="">81ae20b</a> - <a href="">Refactoring basic project structure</a> - <p>Katharina Fey</p> - <p>2019-12-28</p> - <p>-76/+209</p> - - <a href="">baf496a</a> - <a href="">initial styling</a> - <p>Milan PƤssler</p> - <p>2019-12-13</p> - <p>-38/+149</p> - - <a href="">d43a02e</a> - <a href="">Adding AGPL-3.0 license</a> - <p>Katharina Fey</p> - <p>2019-12-10</p> - <p>-0/+661</p> - </div> - </div> - </body> -</html> +{% extends "base.html" %} + +{% block child_content %} +<table class="details-table"> + <thead> + <tr> + <th>Branch</th> + <th>Commit message</th> + <th>Author</th> + <th>Date</th> + </tr> + </thead> + <tbody> + {% for b in branches %} + <tr> + <td>{{ b.name }}</td> + <td>{{ b.last_commit.message }}</td> + <td>{{ b.last_commit.author }}</td> + <td>{{ b.last_commit.date }}</td> + </tr> + {% endfor %} + </tbody> +</table> + +<table class="details-table"> + <thead> + <tr> + <th>Hash</th> + <th>Commit message</th> + <th>Author</th> + <th>Date</th> + <th>Lines</th> + </tr> + </thead> + <tbody> + {% for c in commits %} + <tr> + <td>{{ c.hash }}</td> + <td>{{ c.message }}</td> + <td>{{ c.author }}</td> + <td>{{ c.date }}</td> + </tr> + {% endfor %} + </tbody> +</table> + + +<div class="details-grid"> + <h3>Branch</h3> + <h3>Commit message</h3> + <h3>Author</h3> + <h3 class="details-span">Date</h3> + + <a href="">fn-verify-9324832</a> + <a href="">Updating to actix 2.0.0 and adding 404 handler</a> + <p>Katharina Fey</p> + <p class="details-span">5 months ago</p> + + <a href="">master</a> + <a href="">Rebuilding the entire htlm and css styles</a> + <p>Katharina Fey</p> + <p class="details-span">18 hours ago</p> + + <!-- Switch to last commits --> + <h3>Commit Hash</h3> + <h3>Commit message</h3> + <h3>Author</h3> + <h3>Date</h3> + <h3>Lines</h3> + + <a href="">270cb70</a> + <a href="">Rebuilding the entire htlm and css stiles</a> + <p>Katharina Fey</p> + <p>19 hours ago</p> + <p>-214/+75</p> + + <a href="">5db4c57</a> + <a href="">Updating to actix 2.0.0 and adding 404 handler</a> + <p>Katharina Fey</p> + <p>2020-01-23</p> + <p>-610/+455</p> + + <a href="">5e16c64</a> + <a href="">Adding project documentation and roadmap planning</a> + <p>Katharina Fey</p> + <p>2020-01-23</p> + <p>-3/+61</p> + + <a href="">8b38bdd</a> + <a href="">data: adding a small wrapper around libgit2</a> + <p>Katharina Fey</p> + <p>2019-12-29</p> + <p>-36/+32</p> + + <a href="">c896fcd</a> + <a href="">material-ish design with gitea-style tabs</a> + <p>Milan PƤssler</p> + <p>2019-12-29</p> + <p>-102/+169</p> + + <a href="">f2f49bb</a> + <a href="">material-ish design with gitea-style tabs</a> + <p>Milan PƤssler</p> + <p>2019-12-29</p> + <p>-1/+2</p> + + <a href="">4be56ee</a> + <a href="">Adding a small limgit2 example usage</a> + <p>Katharina Fey</p> + <p>2019-12-29</p> + <p>-2/+17</p> + + <a href="">81ae20b</a> + <a href="">Refactoring basic project structure</a> + <p>Katharina Fey</p> + <p>2019-12-28</p> + <p>-76/+209</p> + + <a href="">baf496a</a> + <a href="">initial styling</a> + <p>Milan PƤssler</p> + <p>2019-12-13</p> + <p>-38/+149</p> + + <a href="">d43a02e</a> + <a href="">Adding AGPL-3.0 license</a> + <p>Katharina Fey</p> + <p>2019-12-10</p> + <p>-0/+661</p> +</div> + +{% endblock %} |