feat: homepage
This commit is contained in:
parent
0586f2e670
commit
428cb600a6
8 changed files with 245 additions and 0 deletions
131
src/pages/chart/home.rs
Normal file
131
src/pages/chart/home.rs
Normal 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
32
src/pages/chart/mod.rs
Normal 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);
|
||||
}
|
|
@ -26,6 +26,7 @@ use crate::static_assets::ASSETS;
|
|||
use crate::{GIT_COMMIT_HASH, VERSION};
|
||||
|
||||
pub mod auth;
|
||||
pub mod chart;
|
||||
mod errors;
|
||||
pub mod routes;
|
||||
|
||||
|
@ -70,6 +71,7 @@ lazy_static! {
|
|||
}
|
||||
errors::register_templates(&mut tera);
|
||||
auth::register_templates(&mut tera);
|
||||
chart::register_templates(&mut tera);
|
||||
tera.autoescape_on(vec![".html", ".sql"]);
|
||||
//auth::register_templates(&mut tera);
|
||||
//gists::register_templates(&mut tera);
|
||||
|
@ -122,6 +124,7 @@ impl<'a> Footer<'a> {
|
|||
|
||||
pub fn services(cfg: &mut web::ServiceConfig) {
|
||||
auth::services(cfg);
|
||||
chart::services(cfg);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -140,6 +143,7 @@ mod tests {
|
|||
PUB_NAV,
|
||||
auth::AUTH_CHALLENGE,
|
||||
auth::AUTH_ADD,
|
||||
chart::HOME,
|
||||
// auth::AUTH_BASE,
|
||||
// auth::login::LOGIN,
|
||||
// auth::register::REGISTER,
|
||||
|
|
|
@ -36,6 +36,10 @@ impl Pages {
|
|||
let auth = Auth::new();
|
||||
Pages { home, auth }
|
||||
}
|
||||
|
||||
pub fn home_next(&self, page: u32) -> String {
|
||||
format!("{}?page={page}", self.home)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
|
29
static/cache/css/main.css
vendored
29
static/cache/css/main.css
vendored
|
@ -253,3 +253,32 @@ button {
|
|||
border-radius: 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
<div class="nav__spacer"></div>
|
||||
|
||||
<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">
|
||||
<a class="nav__link" rel="noreferrer" href="{{ page.auth.add }}">Spider Forge</a>
|
||||
</div>
|
||||
|
|
22
templates/pages/chart/components/repo_info.html
Normal file
22
templates/pages/chart/components/repo_info.html
Normal 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>
|
19
templates/pages/chart/index.html
Normal file
19
templates/pages/chart/index.html
Normal 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 %}
|
Loading…
Reference in a new issue