167 lines
5.5 KiB
Rust
167 lines
5.5 KiB
Rust
use axum::extract::{Path, State};
|
|
use axum::http::StatusCode;
|
|
use axum::response::{Html, IntoResponse, Response};
|
|
use axum::routing::get;
|
|
use axum::Router;
|
|
use forage_core::platform::validate_slug;
|
|
use forage_core::session::CachedOrg;
|
|
use minijinja::context;
|
|
|
|
use super::error_page;
|
|
use crate::auth::Session;
|
|
use crate::state::AppState;
|
|
|
|
pub fn router() -> Router<AppState> {
|
|
Router::new()
|
|
.route("/orgs/{org}/projects", get(projects_list))
|
|
.route("/orgs/{org}/projects/{project}", get(project_detail))
|
|
.route("/orgs/{org}/usage", get(usage))
|
|
}
|
|
|
|
fn orgs_context(orgs: &[CachedOrg]) -> Vec<minijinja::Value> {
|
|
orgs.iter()
|
|
.map(|o| context! { name => o.name, role => o.role })
|
|
.collect()
|
|
}
|
|
|
|
async fn projects_list(
|
|
State(state): State<AppState>,
|
|
session: Session,
|
|
Path(org): Path<String>,
|
|
) -> Result<Response, Response> {
|
|
if !validate_slug(&org) {
|
|
return Err(error_page(&state, StatusCode::BAD_REQUEST, "Invalid request", "Invalid organisation name."));
|
|
}
|
|
|
|
let orgs = &session.user.orgs;
|
|
|
|
if !orgs.iter().any(|o| o.name == org) {
|
|
return Err(error_page(&state, StatusCode::FORBIDDEN, "Access denied", "You don't have access to this organisation."));
|
|
}
|
|
|
|
let projects = state
|
|
.platform_client
|
|
.list_projects(&session.access_token, &org)
|
|
.await
|
|
.unwrap_or_default();
|
|
|
|
let html = state
|
|
.templates
|
|
.render(
|
|
"pages/projects.html.jinja",
|
|
context! {
|
|
title => format!("{org} - Projects - Forage"),
|
|
description => format!("Projects in {org}"),
|
|
user => context! { username => session.user.username },
|
|
csrf_token => &session.csrf_token,
|
|
current_org => &org,
|
|
orgs => orgs_context(orgs),
|
|
org_name => &org,
|
|
projects => projects,
|
|
},
|
|
)
|
|
.map_err(|e| {
|
|
tracing::error!("template error: {e:#}");
|
|
error_page(&state, StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong", "Please try again.")
|
|
})?;
|
|
|
|
Ok(Html(html).into_response())
|
|
}
|
|
|
|
async fn project_detail(
|
|
State(state): State<AppState>,
|
|
session: Session,
|
|
Path((org, project)): Path<(String, String)>,
|
|
) -> Result<Response, Response> {
|
|
if !validate_slug(&org) || !validate_slug(&project) {
|
|
return Err(error_page(&state, StatusCode::BAD_REQUEST, "Invalid request", "Invalid organisation or project name."));
|
|
}
|
|
|
|
let orgs = &session.user.orgs;
|
|
|
|
if !orgs.iter().any(|o| o.name == org) {
|
|
return Err(error_page(&state, StatusCode::FORBIDDEN, "Access denied", "You don't have access to this organisation."));
|
|
}
|
|
|
|
let artifacts = state
|
|
.platform_client
|
|
.list_artifacts(&session.access_token, &org, &project)
|
|
.await
|
|
.unwrap_or_default();
|
|
|
|
let html = state
|
|
.templates
|
|
.render(
|
|
"pages/project_detail.html.jinja",
|
|
context! {
|
|
title => format!("{project} - {org} - Forage"),
|
|
description => format!("Project {project} in {org}"),
|
|
user => context! { username => session.user.username },
|
|
csrf_token => &session.csrf_token,
|
|
current_org => &org,
|
|
orgs => orgs_context(orgs),
|
|
org_name => &org,
|
|
project_name => &project,
|
|
artifacts => artifacts.iter().map(|a| context! {
|
|
slug => a.slug,
|
|
title => a.context.title,
|
|
description => a.context.description,
|
|
created_at => a.created_at,
|
|
}).collect::<Vec<_>>(),
|
|
},
|
|
)
|
|
.map_err(|e| {
|
|
tracing::error!("template error: {e:#}");
|
|
error_page(&state, StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong", "Please try again.")
|
|
})?;
|
|
|
|
Ok(Html(html).into_response())
|
|
}
|
|
|
|
async fn usage(
|
|
State(state): State<AppState>,
|
|
session: Session,
|
|
Path(org): Path<String>,
|
|
) -> Result<Response, Response> {
|
|
if !validate_slug(&org) {
|
|
return Err(error_page(&state, StatusCode::BAD_REQUEST, "Invalid request", "Invalid organisation name."));
|
|
}
|
|
|
|
let orgs = &session.user.orgs;
|
|
|
|
let current_org_data = orgs.iter().find(|o| o.name == org);
|
|
let current_org_data = match current_org_data {
|
|
Some(o) => o,
|
|
None => return Err(error_page(&state, StatusCode::FORBIDDEN, "Access denied", "You don't have access to this organisation.")),
|
|
};
|
|
|
|
let projects = state
|
|
.platform_client
|
|
.list_projects(&session.access_token, &org)
|
|
.await
|
|
.unwrap_or_default();
|
|
|
|
let html = state
|
|
.templates
|
|
.render(
|
|
"pages/usage.html.jinja",
|
|
context! {
|
|
title => format!("Usage - {org} - Forage"),
|
|
description => format!("Usage and plan for {org}"),
|
|
user => context! { username => session.user.username },
|
|
csrf_token => &session.csrf_token,
|
|
current_org => &org,
|
|
orgs => orgs_context(orgs),
|
|
org_name => &org,
|
|
role => ¤t_org_data.role,
|
|
project_count => projects.len(),
|
|
},
|
|
)
|
|
.map_err(|e| {
|
|
tracing::error!("template error: {e:#}");
|
|
error_page(&state, StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong", "Please try again.")
|
|
})?;
|
|
|
|
Ok(Html(html).into_response())
|
|
}
|