home.rs

  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}