feat: homepage

This commit is contained in:
Aravinth Manivannan 2022-05-21 00:17:14 +05:30
parent 0586f2e670
commit 428cb600a6
8 changed files with 245 additions and 0 deletions

131
src/pages/chart/home.rs Normal file
View file

@ -0,0 +1,131 @@
/*
* ForgeFlux StarChart - A federated software forge spider
* Copyright © 2022 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
use actix_web::http::{self, header::ContentType};
use actix_web::{HttpResponse, Responder};
use actix_web_codegen_const_routes::{get, post};
use log::info;
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use tera::Context;
use url::Url;
use db_core::prelude::*;
use crate::errors::ServiceResult;
use crate::pages::errors::*;
use crate::settings::Settings;
use crate::verify::TXTChallenge;
use crate::*;
pub use crate::pages::*;
pub const TITLE: &str = "Explore";
pub const HOME: TemplateFile = TemplateFile::new("home_page", "pages/chart/index.html");
pub const REPO_INFO: TemplateFile =
TemplateFile::new("repo_info", "pages/chart/components/repo_info.html");
pub struct HomePage {
ctx: RefCell<Context>,
}
impl CtxError for HomePage {
fn with_error(&self, e: &ReadableError) -> String {
self.ctx.borrow_mut().insert(ERROR_KEY, e);
self.render()
}
}
#[derive(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
pub struct HomePagePayload {
pub repos: Vec<Repository>,
pub next_page: String,
pub prev_page: String,
}
impl HomePage {
fn new(settings: &Settings, payload: &HomePagePayload) -> Self {
let ctx = RefCell::new(ctx(settings));
ctx.borrow_mut().insert(TITLE_KEY, TITLE);
ctx.borrow_mut().insert(PAYLOAD_KEY, payload);
Self { ctx }
}
pub fn render(&self) -> String {
TEMPLATES.render(HOME.name, &self.ctx.borrow()).unwrap()
}
pub fn page(s: &Settings, payload: &HomePagePayload) -> String {
let p = Self::new(s, payload);
p.render()
}
}
pub fn services(cfg: &mut web::ServiceConfig) {
cfg.service(home);
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Page {
pub page: u32,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OptionalPage {
pub page: Option<u32>,
}
impl From<OptionalPage> for Page {
fn from(o: OptionalPage) -> Self {
match o.page {
Some(page) => Self { page },
None => Page { page: 2 },
}
}
}
#[get(path = "PAGES.home")]
pub async fn home(
q: web::Query<OptionalPage>,
ctx: WebCtx,
db: WebDB,
) -> PageResult<impl Responder, HomePage> {
let q = q.into_inner();
async fn _home(ctx: &ArcCtx, db: &BoxDB, p: &Page) -> ServiceResult<Vec<db_core::Repository>> {
const LIMIT: u32 = 10;
let responses = db.get_all_repositories(p.page, LIMIT).await?;
Ok(responses)
}
let q: Page = q.into();
let repos = _home(&ctx, &db, &q).await.map_err(|e| {
let x = HomePagePayload::default();
PageError::new(HomePage::new(&ctx.settings, &x), e)
})?;
let prev = if q.page == 2 { 1 } else { q.page - 1 };
let payload = HomePagePayload {
repos,
next_page: PAGES.home_next(q.page + 1),
prev_page: PAGES.home_next(prev),
};
let page = HomePage::page(&ctx.settings, &payload);
let html = ContentType::html();
Ok(HttpResponse::Ok().content_type(html).body(page))
}

32
src/pages/chart/mod.rs Normal file
View file

@ -0,0 +1,32 @@
/*
* ForgeFlux StarChart - A federated software forge spider
* Copyright © 2022 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
pub mod home;
pub use home::HOME;
pub use home::REPO_INFO;
pub use super::{ctx, TemplateFile, ERROR_KEY, PAGES, PAYLOAD_KEY, TITLE_KEY};
pub fn register_templates(t: &mut tera::Tera) {
HOME.register(t).expect(HOME.name);
REPO_INFO.register(t).expect(REPO_INFO.name);
}
pub fn services(cfg: &mut actix_web::web::ServiceConfig) {
home::services(cfg);
}

View file

@ -26,6 +26,7 @@ use crate::static_assets::ASSETS;
use crate::{GIT_COMMIT_HASH, VERSION}; use crate::{GIT_COMMIT_HASH, VERSION};
pub mod auth; pub mod auth;
pub mod chart;
mod errors; mod errors;
pub mod routes; pub mod routes;
@ -70,6 +71,7 @@ lazy_static! {
} }
errors::register_templates(&mut tera); errors::register_templates(&mut tera);
auth::register_templates(&mut tera); auth::register_templates(&mut tera);
chart::register_templates(&mut tera);
tera.autoescape_on(vec![".html", ".sql"]); tera.autoescape_on(vec![".html", ".sql"]);
//auth::register_templates(&mut tera); //auth::register_templates(&mut tera);
//gists::register_templates(&mut tera); //gists::register_templates(&mut tera);
@ -122,6 +124,7 @@ impl<'a> Footer<'a> {
pub fn services(cfg: &mut web::ServiceConfig) { pub fn services(cfg: &mut web::ServiceConfig) {
auth::services(cfg); auth::services(cfg);
chart::services(cfg);
} }
#[cfg(test)] #[cfg(test)]
@ -140,6 +143,7 @@ mod tests {
PUB_NAV, PUB_NAV,
auth::AUTH_CHALLENGE, auth::AUTH_CHALLENGE,
auth::AUTH_ADD, auth::AUTH_ADD,
chart::HOME,
// auth::AUTH_BASE, // auth::AUTH_BASE,
// auth::login::LOGIN, // auth::login::LOGIN,
// auth::register::REGISTER, // auth::register::REGISTER,

View file

@ -36,6 +36,10 @@ impl Pages {
let auth = Auth::new(); let auth = Auth::new();
Pages { home, auth } Pages { home, auth }
} }
pub fn home_next(&self, page: u32) -> String {
format!("{}?page={page}", self.home)
}
} }
#[derive(Serialize)] #[derive(Serialize)]

View file

@ -253,3 +253,32 @@ button {
border-radius: none; border-radius: none;
border: none; border: none;
} }
/* Inline #1 | http://localhost:7000/ */
.repository__container {
width: 100%;
margin: 20px auto;
display: flex;
flex-direction: column;
justify-content: center;
border-bottom: 1px grey dotted;
}
.repository__tags {
}
.repository_tags > a {
background: lightgreen;
}
.repository__tags > a {
background: lightgreen;
margin: 15px 2px;
padding: 1px;
border-radius: 5px;
}

View file

@ -13,6 +13,10 @@
<div class="nav__spacer"></div> <div class="nav__spacer"></div>
<div class="nav__link-group"> <div class="nav__link-group">
<div class="nav__link-container">
<a class="nav__link" rel="noreferrer" href="/federate/">Download Data</a>
</div>
<div class="nav__link-container"> <div class="nav__link-container">
<a class="nav__link" rel="noreferrer" href="{{ page.auth.add }}">Spider Forge</a> <a class="nav__link" rel="noreferrer" href="{{ page.auth.add }}">Spider Forge</a>
</div> </div>

View file

@ -0,0 +1,22 @@
{% set name = repository.hostname ~ "/" ~ repository.username ~ "/" ~ repository.name %}
<div class="repository__container">
<h3><a href="/{{ name }}">{{ name }}</a></h3>
{% if repository.description %}
<p>{{ repository.description }}</p>
{% endif %}
<div class="repository__tags">
{% if repository.tags %}
{% for tag in repository.tags %}
<a class="repository__tag" href="/tag/{{ tag }}" >{{ tag }}</a>
{% endfor %}
{% endif %}
</div>
<a class="" href="{{ repository.html_url }}" target="_blank">On {{ repository.hostname }}</a>
{% if repository.website %}
<a href="{{ repository.website }}" target="_blank">Homeage</a>
{% endif %}
</div>

View file

@ -0,0 +1,19 @@
{% extends 'base' %}
{% block title %} {{ title }} {% endblock %}
{% block nav %} {% include "pub_nav" %} {% endblock %}
{% block main %}
<section class="main">
{% for repository in payload.repos %}
{% include "repo_info" %}
{% endfor %}
<div class="next_page">
<a href="{{ payload.prev_page }}">Back</a>
<a href="{{ payload.next_page }}">Next</a>
</div>
</section>
{% endblock %}