1use crate::{
2 auth::RequestExt as _, github::Release, AppState, LayoutData, Request, RequestExt as _,
3};
4use comrak::ComrakOptions;
5use serde::{Deserialize, Serialize};
6use sqlx::Executor as _;
7use std::sync::Arc;
8use tide::{http::mime, log, Server};
9
10pub fn add_routes(app: &mut Server<Arc<AppState>>) {
11 app.at("/").get(get_home);
12 app.at("/signups").post(post_signup);
13 app.at("/releases/:tag_name/:name").get(get_release_asset);
14}
15
16async fn get_home(mut request: Request) -> tide::Result {
17 #[derive(Serialize)]
18 struct HomeData {
19 #[serde(flatten)]
20 layout: Arc<LayoutData>,
21 releases: Option<Vec<Release>>,
22 }
23
24 let mut data = HomeData {
25 layout: request.layout_data().await?,
26 releases: None,
27 };
28
29 if let Some(user) = request.current_user().await? {
30 if user.is_insider {
31 data.releases = Some(
32 request
33 .state()
34 .repo_client
35 .releases()
36 .await?
37 .into_iter()
38 .filter_map(|mut release| {
39 if release.draft {
40 None
41 } else {
42 let mut options = ComrakOptions::default();
43 options.render.unsafe_ = true; // Allow raw HTML in the markup. We control these release notes anyway.
44 release.body = comrak::markdown_to_html(&release.body, &options);
45 Some(release)
46 }
47 })
48 .collect(),
49 );
50 }
51 }
52
53 Ok(tide::Response::builder(200)
54 .body(request.state().render_template("home.hbs", &data)?)
55 .content_type(mime::HTML)
56 .build())
57}
58
59async fn post_signup(mut request: Request) -> tide::Result {
60 #[derive(Debug, Deserialize)]
61 struct Form {
62 github_login: String,
63 email_address: String,
64 about: String,
65 }
66
67 let mut form: Form = request.body_form().await?;
68 form.github_login = form
69 .github_login
70 .strip_prefix("@")
71 .map(str::to_string)
72 .unwrap_or(form.github_login);
73
74 log::info!("Signup submitted: {:?}", form);
75
76 // Save signup in the database
77 request
78 .db()
79 .execute(
80 sqlx::query(
81 "INSERT INTO signups (github_login, email_address, about) VALUES ($1, $2, $3);",
82 )
83 .bind(&form.github_login)
84 .bind(&form.email_address)
85 .bind(&form.about),
86 )
87 .await?;
88
89 let layout_data = request.layout_data().await?;
90 Ok(tide::Response::builder(200)
91 .body(
92 request
93 .state()
94 .render_template("signup.hbs", &layout_data)?,
95 )
96 .content_type(mime::HTML)
97 .build())
98}
99
100async fn get_release_asset(request: Request) -> tide::Result {
101 let body = request
102 .state()
103 .repo_client
104 .release_asset(request.param("tag_name")?, request.param("name")?)
105 .await?;
106
107 Ok(tide::Response::builder(200)
108 .header("Cache-Control", "no-transform")
109 .content_type(mime::BYTE_STREAM)
110 .body(body)
111 .build())
112}