Compare commits

..

No commits in common. "c94915e35120850a0de59ab125a929fd0c066945" and "7758385b512b85d0042ffef9720a8d12eaeeeb55" have entirely different histories.

18 changed files with 57 additions and 187 deletions

2
.gitignore vendored
View file

@ -1,3 +1 @@
/target /target
*.snap.new
*.pending-snap

View file

@ -63,8 +63,6 @@ pub enum ApiError {
InvalidArchiveType, InvalidArchiveType,
#[error("invalid color")] #[error("invalid color")]
InvalidColor, InvalidColor,
#[error("join error: {0}")]
TokioJoin(#[from] tokio::task::JoinError),
} }
impl ResponseError for ApiError { impl ResponseError for ApiError {
@ -75,7 +73,6 @@ impl ResponseError for ApiError {
| ApiError::InvalidArchiveType | ApiError::InvalidArchiveType
| ApiError::InvalidColor => StatusCode::BAD_REQUEST, | ApiError::InvalidColor => StatusCode::BAD_REQUEST,
ApiError::NoAccess => StatusCode::FORBIDDEN, ApiError::NoAccess => StatusCode::FORBIDDEN,
ApiError::TokioJoin(_) => StatusCode::INTERNAL_SERVER_ERROR,
} }
} }
} }
@ -102,17 +99,11 @@ impl TalonApi {
&self, &self,
talon: Data<&Talon>, talon: Data<&Talon>,
subdomain: Path<String>, subdomain: Path<String>,
) -> Result<Response<Json<Website>>> { ) -> Result<Json<Website>> {
talon talon
.db .db
.get_website(&subdomain) .get_website(&subdomain)
.map(|website| { .map(|w| Json(Website::from((subdomain.0, w))))
let modified = website.updated_at();
Response::new(Json(Website::from((subdomain.0, website)))).header(
header::LAST_MODIFIED,
httpdate::fmt_http_date(modified.into()),
)
})
.map_err(Error::from) .map_err(Error::from)
} }
@ -172,14 +163,9 @@ impl TalonApi {
) -> Result<()> { ) -> Result<()> {
auth.check_subdomain(&subdomain, Access::Modify)?; auth.check_subdomain(&subdomain, Access::Modify)?;
let t2 = talon.clone(); talon
let sd = subdomain.clone(); .icons
tokio::task::spawn_blocking(move || { .insert_icon(Cursor::new(data.as_slice()), &subdomain)?;
t2.icons.insert_icon(Cursor::new(data.as_slice()), &sd)
})
.await
.map_err(ApiError::from)??;
talon.db.update_website( talon.db.update_website(
&subdomain, &subdomain,
db::model::WebsiteUpdate { db::model::WebsiteUpdate {
@ -266,8 +252,7 @@ impl TalonApi {
/// Mimimum visibility of the websites /// Mimimum visibility of the websites
#[oai(default)] #[oai(default)]
visibility: Query<Visibility>, visibility: Query<Visibility>,
) -> Result<Response<Json<Vec<Website>>>> { ) -> Result<Json<Vec<Website>>> {
let modified = talon.db.websites_last_update()?;
talon talon
.db .db
.get_websites() .get_websites()
@ -285,10 +270,7 @@ impl TalonApi {
Err(_) => true, Err(_) => true,
}) })
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
.map(|data| { .map(Json)
Response::new(Json(data))
.header(header::LAST_MODIFIED, httpdate::fmt_http_date(modified))
})
.map_err(Error::from) .map_err(Error::from)
} }
@ -298,19 +280,14 @@ impl TalonApi {
&self, &self,
talon: Data<&Talon>, talon: Data<&Talon>,
subdomain: Path<String>, subdomain: Path<String>,
) -> Result<Response<Json<Vec<Version>>>> { ) -> Result<Json<Vec<Version>>> {
let website = talon.db.get_website(&subdomain)?; talon.db.website_exists(&subdomain)?;
talon talon
.db .db
.get_website_versions(&subdomain) .get_website_versions(&subdomain)
.map(|r| r.map(Version::from)) .map(|r| r.map(Version::from))
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
.map(|data| { .map(Json)
Response::new(Json(data)).header(
header::LAST_MODIFIED,
httpdate::fmt_http_date(website.updated_at().into()),
)
})
.map_err(Error::from) .map_err(Error::from)
} }
@ -321,17 +298,11 @@ impl TalonApi {
talon: Data<&Talon>, talon: Data<&Talon>,
subdomain: Path<String>, subdomain: Path<String>,
version: Path<u32>, version: Path<u32>,
) -> Result<Response<Json<Version>>> { ) -> Result<Json<Version>> {
talon talon
.db .db
.get_version(&subdomain, *version) .get_version(&subdomain, *version)
.map(|v| { .map(|v| Json(Version::from((*version, v))))
let create_date = v.created_at;
Response::new(Json(Version::from((*version, v)))).header(
header::LAST_MODIFIED,
httpdate::fmt_http_date(create_date.into()),
)
})
.map_err(Error::from) .map_err(Error::from)
} }
@ -342,19 +313,14 @@ impl TalonApi {
talon: Data<&Talon>, talon: Data<&Talon>,
subdomain: Path<String>, subdomain: Path<String>,
version: Path<u32>, version: Path<u32>,
) -> Result<Response<Json<Vec<VersionFile>>>> { ) -> Result<Json<Vec<VersionFile>>> {
let v = talon.db.get_version(&subdomain, *version)?; talon.db.version_exists(&subdomain, *version)?;
talon talon
.db .db
.get_version_files(&subdomain, *version) .get_version_files(&subdomain, *version)
.map(|r| r.map(VersionFile::from)) .map(|r| r.map(VersionFile::from))
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
.map(|r| { .map(Json)
Response::new(Json(r)).header(
header::LAST_MODIFIED,
httpdate::fmt_http_date(v.created_at.into()),
)
})
.map_err(Error::from) .map_err(Error::from)
} }
@ -414,21 +380,15 @@ impl TalonApi {
// Try to store the uploaded website // Try to store the uploaded website
// If this fails, the new version needs to be deleted // If this fails, the new version needs to be deleted
fn try_insert( let try_insert = || {
talon: &Talon,
data: Binary<Vec<u8>>,
subdomain: &str,
version: u32,
fallback: Option<String>,
) -> Result<()> {
if data.starts_with(&hex!("1f8b")) { if data.starts_with(&hex!("1f8b")) {
talon talon
.storage .storage
.insert_tgz_archive(data.as_slice(), subdomain, version)?; .insert_tgz_archive(data.as_slice(), &subdomain, version)?;
} else if data.starts_with(&hex!("504b0304")) { } else if data.starts_with(&hex!("504b0304")) {
talon.storage.insert_zip_archive( talon.storage.insert_zip_archive(
Cursor::new(data.as_slice()), Cursor::new(data.as_slice()),
subdomain, &subdomain,
version, version,
)?; )?;
} else { } else {
@ -436,26 +396,20 @@ impl TalonApi {
} }
// Validata fallback path // Validata fallback path
if let Some(fallback) = &fallback { if let Some(fallback) = &fallback.0 {
if let Err(e) = if let Err(e) =
talon talon
.storage .storage
.get_file(subdomain, version, fallback, &Default::default()) .get_file(&subdomain, version, fallback, &Default::default())
{ {
return Err(Error::from(ApiError::InvalidFallback(e.to_string()))); return Err(Error::from(ApiError::InvalidFallback(e.to_string())));
} }
} }
Ok(()) Ok(())
} };
let t2 = talon.clone(); match try_insert() {
let sd = subdomain.clone(); Ok(()) => {
match tokio::task::spawn_blocking(move || try_insert(&t2, data, &sd, version, fallback.0))
.await
.map_err(|e| Error::from(ApiError::from(e)))
{
Ok(Ok(())) => {
talon.db.update_website( talon.db.update_website(
&subdomain, &subdomain,
db::model::WebsiteUpdate { db::model::WebsiteUpdate {
@ -465,7 +419,7 @@ impl TalonApi {
)?; )?;
Ok(()) Ok(())
} }
Err(e) | Ok(Err(e)) => { Err(e) => {
// Remove the bad version and decrement the id counter // Remove the bad version and decrement the id counter
let _ = talon.db.delete_version(&subdomain, version, false); let _ = talon.db.delete_version(&subdomain, version, false);
let _ = talon.db.decrement_vid(&subdomain, version); let _ = talon.db.decrement_vid(&subdomain, version);

View file

@ -208,7 +208,6 @@ impl Db {
w.source_url = website.source_url.unwrap_or(w.source_url); w.source_url = website.source_url.unwrap_or(w.source_url);
w.source_icon = website.source_icon.unwrap_or(w.source_icon); w.source_icon = website.source_icon.unwrap_or(w.source_icon);
w.has_icon = website.has_icon.unwrap_or(w.has_icon); w.has_icon = website.has_icon.unwrap_or(w.has_icon);
w.updated_at = Some(OffsetDateTime::now_utc());
rmp_serde::to_vec(&w).ok() rmp_serde::to_vec(&w).ok()
} }

View file

@ -29,19 +29,13 @@ pub struct Website {
/// Does the website have an icon? /// Does the website have an icon?
#[serde(default)] #[serde(default)]
pub has_icon: bool, pub has_icon: bool,
/// Website update date
#[serde(default)]
pub updated_at: Option<OffsetDateTime>,
} }
impl Default for Website { impl Default for Website {
fn default() -> Self { fn default() -> Self {
let created_at = OffsetDateTime::now_utc();
Self { Self {
name: Default::default(), name: Default::default(),
created_at, created_at: OffsetDateTime::now_utc(),
updated_at: Some(created_at),
latest_version: Default::default(), latest_version: Default::default(),
color: Default::default(), color: Default::default(),
visibility: Default::default(), visibility: Default::default(),
@ -53,12 +47,6 @@ impl Default for Website {
} }
} }
impl Website {
pub fn updated_at(&self) -> OffsetDateTime {
self.updated_at.unwrap_or(self.created_at)
}
}
/// Update a website in the database with the contained values /// Update a website in the database with the contained values
/// ///
/// Values set to `None` remain unchanged. /// Values set to `None` remain unchanged.

View file

@ -37,7 +37,7 @@ impl ResponseError for ImagesError {
} }
} }
const IMAGE_SIZE: u32 = 48; const IMAGE_SIZE: u32 = 32;
const MAX_IMAGE_SIZE: u32 = 4000; const MAX_IMAGE_SIZE: u32 = 4000;
type Result<T> = std::result::Result<T, ImagesError>; type Result<T> = std::result::Result<T, ImagesError>;

View file

@ -75,7 +75,6 @@ fn insert_websites(db: &Db) {
&Website { &Website {
name: "ThetaDev".to_owned(), name: "ThetaDev".to_owned(),
created_at: datetime!(2023-02-18 16:30 +0), created_at: datetime!(2023-02-18 16:30 +0),
updated_at: Some(datetime!(2023-02-18 16:30 +0)),
latest_version: Some(2), latest_version: Some(2),
color: Some(2068974), color: Some(2068974),
visibility: talon::model::Visibility::Featured, visibility: talon::model::Visibility::Featured,
@ -88,7 +87,6 @@ fn insert_websites(db: &Db) {
&Website { &Website {
name: "Spotify-Gender-Ex".to_owned(), name: "Spotify-Gender-Ex".to_owned(),
created_at: datetime!(2023-02-18 16:30 +0), created_at: datetime!(2023-02-18 16:30 +0),
updated_at: Some(datetime!(2023-02-18 16:30 +0)),
latest_version: Some(1), latest_version: Some(1),
color: Some(1947988), color: Some(1947988),
visibility: talon::model::Visibility::Featured, visibility: talon::model::Visibility::Featured,
@ -103,7 +101,6 @@ fn insert_websites(db: &Db) {
&Website { &Website {
name: "RustyPipe".to_owned(), name: "RustyPipe".to_owned(),
created_at: datetime!(2023-02-20 18:30 +0), created_at: datetime!(2023-02-20 18:30 +0),
updated_at: Some(datetime!(2023-02-20 18:30 +0)),
latest_version: Some(1), latest_version: Some(1),
color: Some(7943647), color: Some(7943647),
visibility: talon::model::Visibility::Featured, visibility: talon::model::Visibility::Featured,
@ -118,7 +115,6 @@ fn insert_websites(db: &Db) {
&Website { &Website {
name: "SvelteKit SPA".to_owned(), name: "SvelteKit SPA".to_owned(),
created_at: datetime!(2023-03-03 22:00 +0), created_at: datetime!(2023-03-03 22:00 +0),
updated_at: Some(datetime!(2023-03-03 22:00 +0)),
latest_version: Some(1), latest_version: Some(1),
color: Some(16727552), color: Some(16727552),
visibility: talon::model::Visibility::Hidden, visibility: talon::model::Visibility::Hidden,

View file

@ -2,9 +2,9 @@
source: tests/tests.rs source: tests/tests.rs
expression: data expression: data
--- ---
{"type":"website","key":"rustypipe","value":{"name":"RustyPipe","created_at":[2023,51,18,30,0,0,0,0,0],"latest_version":1,"color":7943647,"visibility":"featured","source_url":"https://code.thetadev.de/ThetaDev/rustypipe","source_icon":"gitea","vid_count":1,"has_icon":false,"updated_at":[2023,51,18,30,0,0,0,0,0]}} {"type":"website","key":"rustypipe","value":{"name":"RustyPipe","created_at":[2023,51,18,30,0,0,0,0,0],"latest_version":1,"color":7943647,"visibility":"featured","source_url":"https://code.thetadev.de/ThetaDev/rustypipe","source_icon":"gitea","vid_count":1,"has_icon":false}}
{"type":"website","key":"spa","value":{"name":"SvelteKit SPA","created_at":[2023,62,22,0,0,0,0,0,0],"latest_version":1,"color":16727552,"visibility":"hidden","source_url":null,"source_icon":null,"vid_count":1,"has_icon":false,"updated_at":[2023,62,22,0,0,0,0,0,0]}} {"type":"website","key":"spa","value":{"name":"SvelteKit SPA","created_at":[2023,62,22,0,0,0,0,0,0],"latest_version":1,"color":16727552,"visibility":"hidden","source_url":null,"source_icon":null,"vid_count":1,"has_icon":false}}
{"type":"website","key":"spotify-gender-ex","value":{"name":"Spotify-Gender-Ex","created_at":[2023,49,16,30,0,0,0,0,0],"latest_version":1,"color":1947988,"visibility":"featured","source_url":"https://github.com/Theta-Dev/Spotify-Gender-Ex","source_icon":"github","vid_count":1,"has_icon":false,"updated_at":[2023,49,16,30,0,0,0,0,0]}} {"type":"website","key":"spotify-gender-ex","value":{"name":"Spotify-Gender-Ex","created_at":[2023,49,16,30,0,0,0,0,0],"latest_version":1,"color":1947988,"visibility":"featured","source_url":"https://github.com/Theta-Dev/Spotify-Gender-Ex","source_icon":"github","vid_count":1,"has_icon":false}}
{"type":"version","key":"rustypipe:1","value":{"created_at":[2023,51,18,30,0,0,0,0,0],"data":{},"fallback":null,"spa":false}} {"type":"version","key":"rustypipe:1","value":{"created_at":[2023,51,18,30,0,0,0,0,0],"data":{},"fallback":null,"spa":false}}
{"type":"version","key":"spa:1","value":{"created_at":[2023,62,22,0,0,0,0,0,0],"data":{},"fallback":"200.html","spa":true}} {"type":"version","key":"spa:1","value":{"created_at":[2023,62,22,0,0,0,0,0,0],"data":{},"fallback":"200.html","spa":true}}
{"type":"version","key":"spotify-gender-ex:1","value":{"created_at":[2023,49,16,30,0,0,0,0,0],"data":{},"fallback":null,"spa":false}} {"type":"version","key":"spotify-gender-ex:1","value":{"created_at":[2023,49,16,30,0,0,0,0,0],"data":{},"fallback":null,"spa":false}}

View file

@ -2,10 +2,10 @@
source: tests/tests.rs source: tests/tests.rs
expression: data expression: data
--- ---
{"type":"website","key":"-","value":{"name":"ThetaDev","created_at":[2023,49,16,30,0,0,0,0,0],"latest_version":2,"color":2068974,"visibility":"featured","source_url":null,"source_icon":null,"vid_count":2,"has_icon":false,"updated_at":[2023,49,16,30,0,0,0,0,0]}} {"type":"website","key":"-","value":{"name":"ThetaDev","created_at":[2023,49,16,30,0,0,0,0,0],"latest_version":2,"color":2068974,"visibility":"featured","source_url":null,"source_icon":null,"vid_count":2,"has_icon":false}}
{"type":"website","key":"rustypipe","value":{"name":"RustyPipe","created_at":[2023,51,18,30,0,0,0,0,0],"latest_version":1,"color":7943647,"visibility":"featured","source_url":"https://code.thetadev.de/ThetaDev/rustypipe","source_icon":"gitea","vid_count":1,"has_icon":false,"updated_at":[2023,51,18,30,0,0,0,0,0]}} {"type":"website","key":"rustypipe","value":{"name":"RustyPipe","created_at":[2023,51,18,30,0,0,0,0,0],"latest_version":1,"color":7943647,"visibility":"featured","source_url":"https://code.thetadev.de/ThetaDev/rustypipe","source_icon":"gitea","vid_count":1,"has_icon":false}}
{"type":"website","key":"spa","value":{"name":"SvelteKit SPA","created_at":[2023,62,22,0,0,0,0,0,0],"latest_version":1,"color":16727552,"visibility":"hidden","source_url":null,"source_icon":null,"vid_count":1,"has_icon":false,"updated_at":[2023,62,22,0,0,0,0,0,0]}} {"type":"website","key":"spa","value":{"name":"SvelteKit SPA","created_at":[2023,62,22,0,0,0,0,0,0],"latest_version":1,"color":16727552,"visibility":"hidden","source_url":null,"source_icon":null,"vid_count":1,"has_icon":false}}
{"type":"website","key":"spotify-gender-ex","value":{"name":"Spotify-Gender-Ex","created_at":[2023,49,16,30,0,0,0,0,0],"latest_version":1,"color":1947988,"visibility":"featured","source_url":"https://github.com/Theta-Dev/Spotify-Gender-Ex","source_icon":"github","vid_count":1,"has_icon":false,"updated_at":[2023,49,16,30,0,0,0,0,0]}} {"type":"website","key":"spotify-gender-ex","value":{"name":"Spotify-Gender-Ex","created_at":[2023,49,16,30,0,0,0,0,0],"latest_version":1,"color":1947988,"visibility":"featured","source_url":"https://github.com/Theta-Dev/Spotify-Gender-Ex","source_icon":"github","vid_count":1,"has_icon":false}}
{"type":"version","key":"-:1","value":{"created_at":[2023,49,16,30,0,0,0,0,0],"data":{"Deployed by":"https://github.com/Theta-Dev/Talon/actions/runs/1352014628","Version":"v0.1.0"},"fallback":null,"spa":false}} {"type":"version","key":"-:1","value":{"created_at":[2023,49,16,30,0,0,0,0,0],"data":{"Deployed by":"https://github.com/Theta-Dev/Talon/actions/runs/1352014628","Version":"v0.1.0"},"fallback":null,"spa":false}}
{"type":"version","key":"-:2","value":{"created_at":[2023,49,16,52,0,0,0,0,0],"data":{"Deployed by":"https://github.com/Theta-Dev/Talon/actions/runs/1354755231","Version":"v0.1.1"},"fallback":null,"spa":false}} {"type":"version","key":"-:2","value":{"created_at":[2023,49,16,52,0,0,0,0,0],"data":{"Deployed by":"https://github.com/Theta-Dev/Talon/actions/runs/1354755231","Version":"v0.1.1"},"fallback":null,"spa":false}}
{"type":"version","key":"rustypipe:1","value":{"created_at":[2023,51,18,30,0,0,0,0,0],"data":{},"fallback":null,"spa":false}} {"type":"version","key":"rustypipe:1","value":{"created_at":[2023,51,18,30,0,0,0,0,0],"data":{},"fallback":null,"spa":false}}

View file

@ -13,7 +13,6 @@ expression: "vec![ws1, ws2, ws3]"
source_icon: None, source_icon: None,
vid_count: 2, vid_count: 2,
has_icon: false, has_icon: false,
updated_at: Some((2023, 49, 16, 30, 0, 0, 0, 0, 0)),
), ),
Website( Website(
name: "Spotify-Gender-Ex", name: "Spotify-Gender-Ex",
@ -25,7 +24,6 @@ expression: "vec![ws1, ws2, ws3]"
source_icon: Some(github), source_icon: Some(github),
vid_count: 1, vid_count: 1,
has_icon: false, has_icon: false,
updated_at: Some((2023, 49, 16, 30, 0, 0, 0, 0, 0)),
), ),
Website( Website(
name: "RustyPipe", name: "RustyPipe",
@ -37,6 +35,5 @@ expression: "vec![ws1, ws2, ws3]"
source_icon: Some(gitea), source_icon: Some(gitea),
vid_count: 1, vid_count: 1,
has_icon: false, has_icon: false,
updated_at: Some((2023, 51, 18, 30, 0, 0, 0, 0, 0)),
), ),
] ]

View file

@ -13,7 +13,6 @@ expression: websites
source_icon: None, source_icon: None,
vid_count: 2, vid_count: 2,
has_icon: false, has_icon: false,
updated_at: Some((2023, 49, 16, 30, 0, 0, 0, 0, 0)),
)), )),
("rustypipe", Website( ("rustypipe", Website(
name: "RustyPipe", name: "RustyPipe",
@ -25,7 +24,6 @@ expression: websites
source_icon: Some(gitea), source_icon: Some(gitea),
vid_count: 1, vid_count: 1,
has_icon: false, has_icon: false,
updated_at: Some((2023, 51, 18, 30, 0, 0, 0, 0, 0)),
)), )),
("spa", Website( ("spa", Website(
name: "SvelteKit SPA", name: "SvelteKit SPA",
@ -37,7 +35,6 @@ expression: websites
source_icon: None, source_icon: None,
vid_count: 1, vid_count: 1,
has_icon: false, has_icon: false,
updated_at: Some((2023, 62, 22, 0, 0, 0, 0, 0, 0)),
)), )),
("spotify-gender-ex", Website( ("spotify-gender-ex", Website(
name: "Spotify-Gender-Ex", name: "Spotify-Gender-Ex",
@ -49,6 +46,5 @@ expression: websites
source_icon: Some(github), source_icon: Some(github),
vid_count: 1, vid_count: 1,
has_icon: false, has_icon: false,
updated_at: Some((2023, 49, 16, 30, 0, 0, 0, 0, 0)),
)), )),
] ]

View file

@ -12,5 +12,4 @@ Website(
source_icon: Some(link), source_icon: Some(link),
vid_count: 2, vid_count: 2,
has_icon: false, has_icon: false,
updated_at: "[date]",
) )

View file

@ -8,8 +8,6 @@ use rstest::rstest;
use fixtures::*; use fixtures::*;
use talon::db::{Db, DbError}; use talon::db::{Db, DbError};
const ICON_SIZE: u32 = 48;
mod database { mod database {
use super::*; use super::*;
@ -85,7 +83,7 @@ mod database {
.unwrap(); .unwrap();
let website = db.get_website(SUBDOMAIN_1).unwrap(); let website = db.get_website(SUBDOMAIN_1).unwrap();
insta::assert_ron_snapshot!(website, {".updated_at" => "[date]"}); insta::assert_ron_snapshot!(website);
} }
#[rstest] #[rstest]
@ -615,8 +613,8 @@ mod icons {
assert!(stored_path.is_file()); assert!(stored_path.is_file());
let stored_img = ImageReader::open(&stored_path).unwrap().decode().unwrap(); let stored_img = ImageReader::open(&stored_path).unwrap().decode().unwrap();
assert_eq!(stored_img.height(), ICON_SIZE); assert_eq!(stored_img.height(), 32);
assert_eq!(stored_img.width(), ICON_SIZE); assert_eq!(stored_img.width(), 32);
} }
#[test] #[test]
@ -858,7 +856,7 @@ mod api {
resp.assert_status_is_ok(); resp.assert_status_is_ok();
let ws = tln.db.get_website("test").unwrap(); let ws = tln.db.get_website("test").unwrap();
insta::assert_ron_snapshot!(ws, {".created_at" => "[date]", ".updated_at" => "[date]"}, @r###" insta::assert_ron_snapshot!(ws, {".created_at" => "[date]"}, @r###"
Website( Website(
name: "Test", name: "Test",
created_at: "[date]", created_at: "[date]",
@ -869,7 +867,6 @@ mod api {
source_icon: Some(git), source_icon: Some(git),
vid_count: 0, vid_count: 0,
has_icon: false, has_icon: false,
updated_at: "[date]",
) )
"###); "###);
} }
@ -914,7 +911,7 @@ mod api {
resp.assert_status_is_ok(); resp.assert_status_is_ok();
let ws = tln.db.get_website("-").unwrap(); let ws = tln.db.get_website("-").unwrap();
insta::assert_ron_snapshot!(ws, {".updated_at" => "[date]"}, @r###" insta::assert_ron_snapshot!(ws, @r###"
Website( Website(
name: "Test", name: "Test",
created_at: (2023, 49, 16, 30, 0, 0, 0, 0, 0), created_at: (2023, 49, 16, 30, 0, 0, 0, 0, 0),
@ -925,7 +922,6 @@ mod api {
source_icon: Some(git), source_icon: Some(git),
vid_count: 2, vid_count: 2,
has_icon: false, has_icon: false,
updated_at: "[date]",
) )
"###); "###);
} }
@ -971,8 +967,8 @@ mod api {
.unwrap() .unwrap()
.decode() .decode()
.unwrap(); .unwrap();
assert_eq!(got_icon.height(), ICON_SIZE); assert_eq!(got_icon.height(), 32);
assert_eq!(got_icon.width(), ICON_SIZE); assert_eq!(got_icon.width(), 32);
} }
#[rstest] #[rstest]

View file

@ -9,6 +9,7 @@
let currentWebsite: Website; let currentWebsite: Website;
currentWebsiteStore.subscribe((ws) => { currentWebsiteStore.subscribe((ws) => {
console.log("current ws changed", ws);
currentWebsite = ws; currentWebsite = ws;
}); });

View file

@ -139,7 +139,7 @@
height: 100% height: 100%
z-index: 999999 z-index: 999999
padding: 3em 0.4em 0.4em padding: 1em 0.4em
display: flex display: flex
flex-direction: column flex-direction: column

View file

@ -2,7 +2,6 @@
import PageIcon from "./PageIcon.svelte"; import PageIcon from "./PageIcon.svelte";
import { import {
formatDate, formatDate,
getSubdomainAndVersion,
getWebsiteVersionUrl, getWebsiteVersionUrl,
isUrl, isUrl,
trimCommit, trimCommit,
@ -15,37 +14,28 @@
import Modal from "./Modal.svelte"; import Modal from "./Modal.svelte";
import { openModal } from "svelte-modals"; import { openModal } from "svelte-modals";
import InstanceInfoModal from "./InstanceInfoModal.svelte"; import InstanceInfoModal from "./InstanceInfoModal.svelte";
import { onMount } from "svelte";
let currentWebsite: Website; let currentWebsite: Website;
currentWebsiteStore.subscribe((ws) => { currentWebsiteStore.subscribe((ws) => {
currentWebsite = ws; currentWebsite = ws;
}); });
const currentVid: number | null = getSubdomainAndVersion()[1];
export let isOpen: boolean; export let isOpen: boolean;
$: {
onMount(async () => { if (isOpen && currentWebsite) {
const v = await client.websiteSubdomainVersionsGet({ client
subdomain: currentWebsite.subdomain, .websiteSubdomainVersionsGet({ subdomain: currentWebsite.subdomain })
}); .then((v) => {
versions = v; versions = v;
if (v && v.length > 0) { if (v && v.length > 0) {
latestVersion = v[v.length - 1]; currentVersion = v[v.length - 1];
if (currentVid !== null) {
currentVersion = v.find((v) => v.id == currentVid);
} else {
currentVersion = latestVersion;
}
} }
}); });
}
}
let versions: Version[] = []; let versions: Version[] = [];
let currentVersion: Version | undefined; let currentVersion: Version = null;
let latestVersion: Version | undefined;
function getVersionAttr(version: Version): string | null { function getVersionAttr(version: Version): string | null {
return ( return (
@ -73,14 +63,6 @@
<p class="divider"> <p class="divider">
<InlineIcon iconName="question" /> <InlineIcon iconName="question" />
Current version #{currentVersion.id} Current version #{currentVersion.id}
{#if latestVersion && latestVersion !== currentVersion}
<a
class="latest-tag"
href={getWebsiteVersionUrl(currentWebsite.subdomain, latestVersion.id)}
>Latest: #{latestVersion.id}</a
>
{/if}
</p> </p>
<Tag key="Upload date" value={formatDate(currentVersion.createdAt)} /> <Tag key="Upload date" value={formatDate(currentVersion.createdAt)} />
@ -113,9 +95,7 @@
<div> <div>
Powered by Powered by
<button class="link" on:click={openInstanceInfo} <button on:click={openInstanceInfo}>Talon {talonConfig.version}</button>
>Talon {talonConfig.version}</button
>
</div> </div>
{/if} {/if}
</Modal> </Modal>
@ -131,13 +111,4 @@
font-size: 2em font-size: 2em
margin-left: 0.25em margin-left: 0.25em
.latest-tag
background-color: lime
color: values.$color-text-d1
margin: 0 1em
overflow: hidden
white-space: nowrap
padding: 0 0.4em
border-radius: 1em
</style> </style>

View file

@ -6,16 +6,15 @@
font-family: sans-serif font-family: sans-serif
color: values.$color-text color: values.$color-text
a, .link a, button
display: inline display: inline
text-decoration: none text-decoration: none
cursor: pointer cursor: pointer
background: none background: none
border: none border: none
box-shadow: none box-shadow: none
padding: 0
.link a
color: var(--talon-color) color: var(--talon-color)
filter: brightness(150%) filter: brightness(150%)

View file

@ -13,4 +13,3 @@ $color-base-2: color.scale($color-base, $lightness: 20%)
$color-primary-light: color.scale($color-primary, $lightness: 15%) $color-primary-light: color.scale($color-primary, $lightness: 15%)
$color-primary-dark: color.scale($color-primary, $lightness: -15%) $color-primary-dark: color.scale($color-primary, $lightness: -15%)
$color-text-1: color.scale($color-text, $lightness: -15%) $color-text-1: color.scale($color-text, $lightness: -15%)
$color-text-d1: color.scale($color-base, $lightness: -20%)

View file

@ -21,29 +21,6 @@ export function getSubdomain(): string {
return "-"; return "-";
} }
export function getSubdomainAndVersion(): [string, number | null] {
const hn = window.location.hostname;
const rd_noport = talonConfig.root_domain.split(":", 1)[0];
if (hn.endsWith("." + rd_noport)) {
const subdomainSplit = hn
.substring(0, hn.length - rd_noport.length - 1)
.split("--", 2);
const subdomain = subdomainSplit[0];
let version =
subdomainSplit.length > 1 ? parseInt(subdomainSplit[1].replace(/^v/, "")) : null;
if (Number.isNaN(version)) version = null;
if (subdomain === "x") {
return ["-", version];
} else {
return [subdomain, version];
}
}
return ["-", null];
}
export function getWebsiteUrl(subdomain: string): string { export function getWebsiteUrl(subdomain: string): string {
const proto = window.location.protocol; const proto = window.location.protocol;