~saiko/modsite

ref: 18244534210ceb0b200b3a4a6317999c72693baf modsite/site/src/site/mod_page.rs -rw-r--r-- 3.6 KiB
182445342xsaiko Properly do inter page links 4 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use actix_web::{HttpRequest, HttpResponse, Responder, web};
use futures_util::TryStreamExt;
use handlebars::Handlebars;
use serde::Serialize;
use sqlx::{FromRow, PgConnection, Pool};
use url::Url;

use crate::db::types::Environment;
use crate::site::db_access::{Db, map_db_err};
use crate::site::geninfo::GenInfo;

use super::pagestates::ModPage as PageState;

pub async fn mod_page(req: HttpRequest, web::Query(PageState { id, v: version }): web::Query<PageState<'_>>, hb: web::Data<Handlebars<'_>>, db: Db) -> Result<impl Responder, actix_web::Error> {
    let from_db = if let Some(version) = version {
        FromDb::load_ver(&id, &version, &db).await.map_err(map_db_err)?
    } else {
        FromDb::load(&id, &db).await.map_err(map_db_err)?
    };
    let all_versions = ModVersion::load_all(&id, &from_db.file_version, &db, &req).await.map_err(map_db_err)?;

    let body = hb.render("mod", &Data {
        id: &id,
        name: from_db.name.clone().unwrap_or_else(|| from_db.modid.clone()),
        from_db,
        mcversions: vec![],
        allmods: all_versions,
        geninfo: GenInfo::current(),
    }).unwrap();

    Ok(HttpResponse::Ok().body(body))
}

#[derive(Serialize)]
struct Data<'a> {
    id: &'a str,
    name: String,
    from_db: FromDb,
    mcversions: Vec<ByMcVersion>,
    allmods: Vec<ModVersion>,
    geninfo: GenInfo,
}

#[derive(Serialize)]
struct ByMcVersion {
    mojang_name: String,
    modversions: ModVersion,
}

#[derive(Serialize)]
struct ModVersion {
    link: Url,
    current: bool,
    dl_link: String,
    file_version: String,
    id: String,
}

impl ModVersion {
    async fn load_all(id: &str, current: &str, db: &Pool<PgConnection>, req: &HttpRequest) -> sqlx::Result<Vec<ModVersion>> {
        let db: Vec<_> = sqlx::query!(
                "SELECT v.download_link, v.file_version FROM mod_version v \
                 JOIN mod_base b ON b.uuid = v.mod_base \
                 WHERE b.id = $1", id)
            .fetch(db)
            .try_collect().await?;

        Ok(db.into_iter().map(|db| {
            ModVersion {
                link: PageState { id: id.into(), v: Some((&db.file_version).into()) }.link(req),
                current: db.file_version == current,
                dl_link: db.download_link,
                file_version: db.file_version,
                id: id.to_string(),
            }
        }).collect())
    }
}

#[derive(FromRow, Serialize)]
struct FromDb {
    modid: String,
    name: Option<String>,
    file_version: String,
    description: Option<String>,
    homepage: Option<String>,
    issues: Option<String>,
    source: Option<String>,
    license: Option<String>,
    download_link: String,
    environment: Environment,
}

impl FromDb {
    async fn load(id: &str, db: &Pool<PgConnection>) -> sqlx::Result<FromDb> {
        sqlx::query_as_unchecked!(FromDb,
            "SELECT v.id as modid, v.name, v.file_version, v.description, v.homepage, v.issues, v.source, v.license, v.download_link, v.environment \
             FROM mod_version v \
             INNER JOIN mod_base b ON b.uuid = v.mod_base \
             WHERE b.id = $1 AND v.file_version = b.display_version", id)
            .fetch_one(db).await
    }

    async fn load_ver(id: &str, v: &str, db: &Pool<PgConnection>) -> sqlx::Result<FromDb> {
        sqlx::query_as_unchecked!(FromDb,
            "SELECT v.id as modid, v.name, v.file_version, v.description, v.homepage, v.issues, v.source, v.license, v.download_link, v.environment \
             FROM mod_version v \
             INNER JOIN mod_base b ON b.uuid = v.mod_base \
             WHERE b.id = $1 AND v.file_version = $2", id, v)
            .fetch_one(db).await
    }
}