Compare commits
No commits in common. "0352989083b4ad4fbdc7fe991d1da2d6e82b3f9a" and "df1babccd4d18486294a679327d36af0e2498164" have entirely different histories.
0352989083
...
df1babccd4
14 changed files with 5595 additions and 1851 deletions
|
@ -2,7 +2,7 @@
|
|||
|
||||
**static site management system**
|
||||
|
||||
[![CI status](https://ci.thetadev.de/api/badges/ThetaDev/Talon/status.svg)](https://ci.thetadev.de/ThetaDev/Talon)
|
||||
![CI status](https://ci.thetadev.de/api/badges/ThetaDev/Talon/status.svg)
|
||||
|
||||
---
|
||||
|
||||
|
|
89
src/api.rs
89
src/api.rs
|
@ -211,66 +211,58 @@ impl TalonApi {
|
|||
}
|
||||
|
||||
/// Get version
|
||||
#[oai(path = "/website/:subdomain/version/:version", method = "get")]
|
||||
#[oai(path = "/website/:subdomain/version/:id", method = "get")]
|
||||
async fn version_get(
|
||||
&self,
|
||||
talon: Data<&Talon>,
|
||||
subdomain: Path<String>,
|
||||
version: Path<u32>,
|
||||
id: Path<u32>,
|
||||
) -> Result<Json<Version>> {
|
||||
talon
|
||||
.db
|
||||
.get_version(&subdomain, *version)
|
||||
.map(|v| Json(Version::from((*version, v))))
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Get version files
|
||||
#[oai(path = "/website/:subdomain/version/:version/files", method = "get")]
|
||||
async fn version_files(
|
||||
&self,
|
||||
talon: Data<&Talon>,
|
||||
subdomain: Path<String>,
|
||||
version: Path<u32>,
|
||||
) -> Result<Json<Vec<String>>> {
|
||||
talon.db.version_exists(&subdomain, *version)?;
|
||||
talon
|
||||
.db
|
||||
.get_version_files(&subdomain, *version)
|
||||
.map(|r| r.map(|f| f.0))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map(Json)
|
||||
.get_version(&subdomain, *id)
|
||||
.map(|v| Json(Version::from((*id, v))))
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Delete version
|
||||
#[oai(path = "/website/:subdomain/version/:version", method = "delete")]
|
||||
#[oai(path = "/website/:subdomain/version/:id", method = "delete")]
|
||||
async fn version_delete(
|
||||
&self,
|
||||
auth: ApiKeyAuthorization,
|
||||
talon: Data<&Talon>,
|
||||
subdomain: Path<String>,
|
||||
version: Path<u32>,
|
||||
id: Path<u32>,
|
||||
) -> Result<()> {
|
||||
auth.check_subdomain(&subdomain, Access::Modify)?;
|
||||
|
||||
talon.db.delete_version(&subdomain, *version, true)?;
|
||||
talon.db.delete_version(&subdomain, *id, true)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Insert a new version into the database
|
||||
fn insert_version(
|
||||
talon: &Talon,
|
||||
subdomain: &str,
|
||||
id: u32,
|
||||
fallback: Option<String>,
|
||||
spa: bool,
|
||||
mut version_data: BTreeMap<String, String>,
|
||||
) -> Result<u32> {
|
||||
) -> Result<()> {
|
||||
version_data.remove("fallback");
|
||||
version_data.remove("spa");
|
||||
|
||||
let id = talon.db.insert_version(
|
||||
// Validata fallback path
|
||||
if let Some(fallback) = &fallback {
|
||||
if let Err(e) = talon.storage.get_file(id, fallback, &Default::default()) {
|
||||
// Remove the uploaded files of the bad version
|
||||
let _ = talon.db.delete_version(subdomain, id, false);
|
||||
return Err(ApiError::InvalidFallback(e.to_string()).into());
|
||||
}
|
||||
}
|
||||
|
||||
talon.db.insert_version(
|
||||
subdomain,
|
||||
id,
|
||||
&db::model::Version {
|
||||
data: version_data,
|
||||
fallback,
|
||||
|
@ -278,33 +270,10 @@ impl TalonApi {
|
|||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
/// Set the given version as the most recent one
|
||||
fn finalize_version(
|
||||
talon: &Talon,
|
||||
subdomain: &str,
|
||||
version: u32,
|
||||
fallback: Option<&str>,
|
||||
) -> Result<()> {
|
||||
// Validata fallback path
|
||||
if let Some(fallback) = fallback {
|
||||
if let Err(e) =
|
||||
talon
|
||||
.storage
|
||||
.get_file(subdomain, version, fallback, &Default::default())
|
||||
{
|
||||
// Remove the bad version
|
||||
let _ = talon.db.delete_version(subdomain, version, false);
|
||||
return Err(ApiError::InvalidFallback(e.to_string()).into());
|
||||
}
|
||||
}
|
||||
|
||||
talon.db.update_website(
|
||||
subdomain,
|
||||
db::model::WebsiteUpdate {
|
||||
latest_version: Some(Some(version)),
|
||||
latest_version: Some(Some(id)),
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
|
@ -334,12 +303,11 @@ impl TalonApi {
|
|||
data: Binary<Vec<u8>>,
|
||||
) -> Result<()> {
|
||||
auth.check_subdomain(&subdomain, Access::Upload)?;
|
||||
let version =
|
||||
Self::insert_version(&talon, &subdomain, fallback.clone(), spa.0, version_data.0)?;
|
||||
let vid = talon.db.new_version_id()?;
|
||||
talon
|
||||
.storage
|
||||
.insert_zip_archive(Cursor::new(data.as_slice()), &subdomain, version)?;
|
||||
Self::finalize_version(&talon, &subdomain, version, fallback.as_deref())
|
||||
.insert_zip_archive(Cursor::new(data.as_slice()), vid)?;
|
||||
Self::insert_version(&talon, &subdomain, vid, fallback.0, spa.0, version_data.0)
|
||||
}
|
||||
|
||||
/// Upload a new version (.tar.gz archive)
|
||||
|
@ -365,11 +333,8 @@ impl TalonApi {
|
|||
data: Binary<Vec<u8>>,
|
||||
) -> Result<()> {
|
||||
auth.check_subdomain(&subdomain, Access::Upload)?;
|
||||
let version =
|
||||
Self::insert_version(&talon, &subdomain, fallback.clone(), spa.0, version_data.0)?;
|
||||
talon
|
||||
.storage
|
||||
.insert_tgz_archive(data.as_slice(), &subdomain, version)?;
|
||||
Self::finalize_version(&talon, &subdomain, version, fallback.as_deref())
|
||||
let vid = talon.db.new_version_id()?;
|
||||
talon.storage.insert_tgz_archive(data.as_slice(), vid)?;
|
||||
Self::insert_version(&talon, &subdomain, vid, fallback.0, spa.0, version_data.0)
|
||||
}
|
||||
}
|
||||
|
|
131
src/db/mod.rs
131
src/db/mod.rs
|
@ -259,6 +259,14 @@ impl Db {
|
|||
String::from_utf8(key).map_err(|e| DbError::Other(format!("could not parse key: {e}")))
|
||||
}
|
||||
|
||||
fn split_key(key: Vec<u8>) -> Result<(String, String)> {
|
||||
let key_str = Self::key_to_string(key)?;
|
||||
key_str
|
||||
.split_once(':')
|
||||
.map(|(id, p)| (id.to_owned(), p.to_owned()))
|
||||
.ok_or_else(|| DbError::Other(format!("invalid key: {key_str}")))
|
||||
}
|
||||
|
||||
fn split_version_key(key: Vec<u8>) -> Result<(String, u32)> {
|
||||
let key_str = Self::key_to_string(key)?;
|
||||
key_str
|
||||
|
@ -267,68 +275,47 @@ impl Db {
|
|||
.ok_or_else(|| DbError::Other(format!("invalid key: {key_str}")))
|
||||
}
|
||||
|
||||
fn split_file_key(key: Vec<u8>) -> Result<(String, String)> {
|
||||
let key_str = Self::key_to_string(key)?;
|
||||
let mut parts = key_str.split(':');
|
||||
parts.next(); // Skip subdomain part
|
||||
|
||||
match (parts.next(), parts.next()) {
|
||||
(Some(id), Some(p)) => Ok((id.to_owned(), p.to_owned())),
|
||||
_ => Err(DbError::Other(format!("invalid key: {key_str}"))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an error if the website does not exist
|
||||
pub fn version_exists(&self, subdomain: &str, id: u32) -> Result<()> {
|
||||
let key = Self::version_key(subdomain, id);
|
||||
|
||||
if !self.i.versions.contains_key(&key)? {
|
||||
Err(DbError::NotExists("version", key))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
fn increment(old: Option<&[u8]>) -> Option<Vec<u8>> {
|
||||
let number = match old {
|
||||
Some(bytes) => {
|
||||
let array: [u8; 4] = bytes.try_into().unwrap();
|
||||
let number = u32::from_be_bytes(array);
|
||||
number + 1
|
||||
}
|
||||
None => 1,
|
||||
};
|
||||
Some(number.to_be_bytes().to_vec())
|
||||
}
|
||||
|
||||
/// Get a version from the database
|
||||
pub fn get_version(&self, subdomain: &str, id: u32) -> Result<Version> {
|
||||
let key = Self::version_key(subdomain, id);
|
||||
|
||||
let data = self.i.versions.get(&key)?;
|
||||
let data = self.i.versions.get(Self::version_key(subdomain, id))?;
|
||||
data.and_then(|data| rmp_serde::from_slice::<Version>(data.as_ref()).ok())
|
||||
.ok_or_else(|| DbError::NotExists("version", key))
|
||||
.ok_or_else(|| DbError::NotExists("version", subdomain.to_owned()))
|
||||
}
|
||||
|
||||
/// Get a new unique version id
|
||||
pub fn new_version_id(&self) -> Result<u32> {
|
||||
Ok(u32::from_be_bytes(
|
||||
self.i
|
||||
.db
|
||||
.update_and_fetch("vid_count", Self::increment)?
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Insert a new version into the database
|
||||
///
|
||||
/// Returns the ID of the new version
|
||||
pub fn insert_version(&self, subdomain: &str, version: &Version) -> Result<u32> {
|
||||
let ws = self
|
||||
.i
|
||||
.websites
|
||||
.update_and_fetch(subdomain, |data| match data {
|
||||
Some(data) => match rmp_serde::from_slice::<Website>(data) {
|
||||
Ok(mut w) => {
|
||||
w.vid_count += 1;
|
||||
rmp_serde::to_vec(&w).ok()
|
||||
}
|
||||
Err(_) => None,
|
||||
},
|
||||
None => todo!(),
|
||||
})?
|
||||
.and_then(|data| rmp_serde::from_slice::<Website>(&data).ok());
|
||||
|
||||
let id = match ws {
|
||||
Some(ws) => ws.vid_count,
|
||||
None => return Err(DbError::NotExists("website", subdomain.to_owned())),
|
||||
};
|
||||
|
||||
pub fn insert_version(&self, subdomain: &str, id: u32, version: &Version) -> Result<()> {
|
||||
let key = Self::version_key(subdomain, id);
|
||||
let data = rmp_serde::to_vec(version)?;
|
||||
self.i
|
||||
.versions
|
||||
.compare_and_swap(&key, None::<&[u8]>, Some(data))?
|
||||
.map_err(|_| DbError::Exists("version", key))?;
|
||||
Ok(id)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// internal method for deleting a version from the database
|
||||
|
@ -336,10 +323,10 @@ impl Db {
|
|||
/// this method does not lock the db or update the associated website
|
||||
fn _delete_version(&self, subdomain: &str, id: u32, should_exist: bool) -> Result<()> {
|
||||
// Remove all files associated with the version
|
||||
for f in self.get_version_files(subdomain, id) {
|
||||
for f in self.get_version_files(id) {
|
||||
match f {
|
||||
Ok((path, _)) => {
|
||||
self.delete_file(subdomain, id, &path, false)?;
|
||||
self.delete_file(id, &path, false)?;
|
||||
}
|
||||
Err(DbError::Sled(e)) => return Err(DbError::Sled(e)),
|
||||
Err(_) => {}
|
||||
|
@ -410,24 +397,19 @@ impl Db {
|
|||
})
|
||||
}
|
||||
|
||||
fn file_key(subdomain: &str, version: u32, path: &str) -> String {
|
||||
format!("{subdomain}:{version}:{path}")
|
||||
fn file_key(version: u32, path: &str) -> String {
|
||||
format!("{version}:{path}")
|
||||
}
|
||||
|
||||
/// Get the hash of a file in the database
|
||||
pub fn get_file_opt(
|
||||
&self,
|
||||
subdomain: &str,
|
||||
version: u32,
|
||||
path: &str,
|
||||
) -> Result<Option<Vec<u8>>> {
|
||||
let key = Self::file_key(subdomain, version, path);
|
||||
pub fn get_file_opt(&self, version: u32, path: &str) -> Result<Option<Vec<u8>>> {
|
||||
let key = Self::file_key(version, path);
|
||||
Ok(self.i.files.get(key)?.map(|hash| hash.to_vec()))
|
||||
}
|
||||
|
||||
/// Get the hash of a file in the database
|
||||
pub fn get_file(&self, subdomain: &str, version: u32, path: &str) -> Result<Vec<u8>> {
|
||||
let key = Self::file_key(subdomain, version, path);
|
||||
pub fn get_file(&self, version: u32, path: &str) -> Result<Vec<u8>> {
|
||||
let key = Self::file_key(version, path);
|
||||
match self.i.files.get(&key)? {
|
||||
Some(hash) => Ok(hash.to_vec()),
|
||||
None => Err(DbError::NotExists("file", key)),
|
||||
|
@ -435,14 +417,8 @@ impl Db {
|
|||
}
|
||||
|
||||
/// Insert a file into the database
|
||||
pub fn insert_file(
|
||||
&self,
|
||||
subdomain: &str,
|
||||
version: u32,
|
||||
path: &str,
|
||||
hash: &[u8],
|
||||
) -> Result<()> {
|
||||
let key = Self::file_key(subdomain, version, path);
|
||||
pub fn insert_file(&self, version: u32, path: &str, hash: &[u8]) -> Result<()> {
|
||||
let key = Self::file_key(version, path);
|
||||
self.i
|
||||
.files
|
||||
.compare_and_swap(&key, None::<&[u8]>, Some(hash))?
|
||||
|
@ -450,14 +426,8 @@ impl Db {
|
|||
}
|
||||
|
||||
/// Delete a file in the database
|
||||
pub fn delete_file(
|
||||
&self,
|
||||
subdomain: &str,
|
||||
version: u32,
|
||||
path: &str,
|
||||
should_exist: bool,
|
||||
) -> Result<()> {
|
||||
let key = Self::file_key(subdomain, version, path);
|
||||
pub fn delete_file(&self, version: u32, path: &str, should_exist: bool) -> Result<()> {
|
||||
let key = Self::file_key(version, path);
|
||||
let res = self.i.files.remove(&key)?;
|
||||
|
||||
if should_exist && res.is_none() {
|
||||
|
@ -472,14 +442,13 @@ impl Db {
|
|||
/// Result: Tuples of file path and hash
|
||||
pub fn get_version_files(
|
||||
&self,
|
||||
subdomain: &str,
|
||||
version: u32,
|
||||
id: u32,
|
||||
) -> impl DoubleEndedIterator<Item = Result<(String, Vec<u8>)>> {
|
||||
let key = Self::file_key(subdomain, version, "");
|
||||
let key = Self::file_key(id, "");
|
||||
|
||||
self.i.files.scan_prefix(key).map(|r| {
|
||||
r.map_err(DbError::from).and_then(|(k, v)| {
|
||||
let (_, path) = Self::split_file_key(k.to_vec())?;
|
||||
let (_, path) = Self::split_key(k.to_vec())?;
|
||||
Ok((path, v.to_vec()))
|
||||
})
|
||||
})
|
||||
|
|
|
@ -22,10 +22,6 @@ pub struct Website {
|
|||
pub source_url: Option<String>,
|
||||
/// Icon for the source link
|
||||
pub source_icon: Option<SourceIcon>,
|
||||
/// Version ID counter
|
||||
///
|
||||
/// value + 1 will be the next version ID
|
||||
pub vid_count: u32,
|
||||
}
|
||||
|
||||
impl Default for Website {
|
||||
|
@ -38,7 +34,6 @@ impl Default for Website {
|
|||
visibility: Default::default(),
|
||||
source_url: Default::default(),
|
||||
source_icon: Default::default(),
|
||||
vid_count: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
46
src/page.rs
46
src/page.rs
|
@ -36,34 +36,26 @@ pub async fn page(request: &Request, talon: Data<&Talon>) -> Result<Response> {
|
|||
|
||||
let ws = talon.db.get_website(subdomain)?;
|
||||
let vid = ws.latest_version.ok_or(PageError::NoVersion)?;
|
||||
let (file, ok) =
|
||||
match talon
|
||||
.storage
|
||||
.get_file(subdomain, vid, request.uri().path(), request.headers())
|
||||
{
|
||||
Ok(file) => (file, true),
|
||||
Err(StorageError::NotFound(f)) => {
|
||||
let version = talon.db.get_version(subdomain, vid)?;
|
||||
if let Some(fallback) = &version.fallback {
|
||||
(
|
||||
talon
|
||||
.storage
|
||||
.get_file(subdomain, vid, fallback, request.headers())?,
|
||||
version.spa,
|
||||
)
|
||||
} else if version.spa {
|
||||
(
|
||||
talon
|
||||
.storage
|
||||
.get_file(subdomain, vid, "", request.headers())?,
|
||||
true,
|
||||
)
|
||||
} else {
|
||||
return Err(StorageError::NotFound(f).into());
|
||||
}
|
||||
let (file, ok) = match talon
|
||||
.storage
|
||||
.get_file(vid, request.uri().path(), request.headers())
|
||||
{
|
||||
Ok(file) => (file, true),
|
||||
Err(StorageError::NotFound(f)) => {
|
||||
let version = talon.db.get_version(subdomain, vid)?;
|
||||
if let Some(fallback) = &version.fallback {
|
||||
(
|
||||
talon.storage.get_file(vid, fallback, request.headers())?,
|
||||
version.spa,
|
||||
)
|
||||
} else if version.spa {
|
||||
(talon.storage.get_file(vid, "", request.headers())?, true)
|
||||
} else {
|
||||
return Err(StorageError::NotFound(f).into());
|
||||
}
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
}
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
||||
Ok(match file.rd_path {
|
||||
Some(rd_path) => Redirect::moved_permanent(rd_path).into_response(),
|
||||
|
|
|
@ -114,7 +114,6 @@ impl Storage {
|
|||
pub fn insert_file<P: AsRef<Path>>(
|
||||
&self,
|
||||
file_path: P,
|
||||
subdomain: &str,
|
||||
version: u32,
|
||||
site_path: &str,
|
||||
) -> Result<()> {
|
||||
|
@ -154,7 +153,7 @@ impl Storage {
|
|||
}
|
||||
}
|
||||
|
||||
self.db.insert_file(subdomain, version, site_path, &hash)?;
|
||||
self.db.insert_file(version, site_path, &hash)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -211,40 +210,30 @@ impl Storage {
|
|||
}
|
||||
|
||||
/// Insert a directory of files into the store
|
||||
pub fn insert_dir<P: AsRef<Path>>(&self, dir: P, subdomain: &str, version: u32) -> Result<()> {
|
||||
pub fn insert_dir<P: AsRef<Path>>(&self, dir: P, version: u32) -> Result<()> {
|
||||
Self::visit_files(dir, "", &|file_path, site_path| {
|
||||
self.insert_file(file_path, subdomain, version, site_path)
|
||||
self.insert_file(file_path, version, site_path)
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Insert the contents of a zip archive into the store
|
||||
pub fn insert_zip_archive(
|
||||
&self,
|
||||
reader: impl Read + Seek,
|
||||
subdomain: &str,
|
||||
version: u32,
|
||||
) -> Result<()> {
|
||||
pub fn insert_zip_archive(&self, reader: impl Read + Seek, version: u32) -> Result<()> {
|
||||
let temp = TempDir::with_prefix(TMPDIR_PREFIX)?;
|
||||
let mut zip = ZipArchive::new(reader)?;
|
||||
zip.extract(temp.path())?;
|
||||
let import_path = Self::fix_archive_path(temp.path())?;
|
||||
self.insert_dir(import_path, subdomain, version)
|
||||
self.insert_dir(import_path, version)
|
||||
}
|
||||
|
||||
/// Insert the contents of a tar.gz archive into the store
|
||||
pub fn insert_tgz_archive(
|
||||
&self,
|
||||
reader: impl Read,
|
||||
subdomain: &str,
|
||||
version: u32,
|
||||
) -> Result<()> {
|
||||
pub fn insert_tgz_archive(&self, reader: impl Read, version: u32) -> Result<()> {
|
||||
let temp = TempDir::with_prefix(TMPDIR_PREFIX)?;
|
||||
let decoder = GzDecoder::new(reader);
|
||||
let mut archive = tar::Archive::new(decoder);
|
||||
archive.unpack(temp.path())?;
|
||||
let import_path = Self::fix_archive_path(temp.path())?;
|
||||
self.insert_dir(import_path, subdomain, version)
|
||||
self.insert_dir(import_path, version)
|
||||
}
|
||||
|
||||
/// Get the path of a file with the given hash while creating the subdirectory
|
||||
|
@ -313,13 +302,7 @@ impl Storage {
|
|||
/// Get a file using the raw site path and the website version
|
||||
///
|
||||
/// HTTP headers are used to determine if the compressed version of a file should be returned.
|
||||
pub fn get_file(
|
||||
&self,
|
||||
subdomain: &str,
|
||||
version: u32,
|
||||
site_path: &str,
|
||||
headers: &HeaderMap,
|
||||
) -> Result<GotFile> {
|
||||
pub fn get_file(&self, version: u32, site_path: &str, headers: &HeaderMap) -> Result<GotFile> {
|
||||
let sp = util::trim_site_path(site_path);
|
||||
let mut new_path: Cow<str> = sp.into();
|
||||
let mut rd_path = None;
|
||||
|
@ -332,7 +315,7 @@ impl Storage {
|
|||
// Attempt to access the following pages
|
||||
// 1. Site path directly
|
||||
// 2. Site path + `/index.html`
|
||||
match self.db.get_file_opt(subdomain, version, sp)? {
|
||||
match self.db.get_file_opt(version, sp)? {
|
||||
Some(h) => {
|
||||
hash = Some(h);
|
||||
}
|
||||
|
@ -351,7 +334,7 @@ impl Storage {
|
|||
Some(hash) => hash,
|
||||
None => self
|
||||
.db
|
||||
.get_file_opt(subdomain, version, &new_path)?
|
||||
.get_file_opt(version, &new_path)?
|
||||
.ok_or_else(|| StorageError::NotFound(sp.to_owned()))?,
|
||||
};
|
||||
|
||||
|
|
166
tests/fixtures/mod.rs
vendored
166
tests/fixtures/mod.rs
vendored
|
@ -19,6 +19,12 @@ pub const SUBDOMAIN_2: &str = "spotify-gender-ex";
|
|||
pub const SUBDOMAIN_3: &str = "rustypipe";
|
||||
pub const SUBDOMAIN_4: &str = "spa";
|
||||
|
||||
pub const VERSION_1_1: u32 = 1;
|
||||
pub const VERSION_1_2: u32 = 2;
|
||||
pub const VERSION_2_1: u32 = 3;
|
||||
pub const VERSION_3_1: u32 = 4;
|
||||
pub const VERSION_4_1: u32 = 5;
|
||||
|
||||
pub const HASH_1_1_INDEX: [u8; 32] =
|
||||
hex!("3b5f6bad5376897435def176d0fe77e5b9b4f0deafc7491fc27262650744ad68");
|
||||
pub const HASH_1_1_STYLE: [u8; 32] =
|
||||
|
@ -70,7 +76,7 @@ fn insert_websites(db: &Db) {
|
|||
&Website {
|
||||
name: "ThetaDev".to_owned(),
|
||||
created_at: datetime!(2023-02-18 16:30 +0),
|
||||
latest_version: Some(2),
|
||||
latest_version: Some(VERSION_1_2),
|
||||
color: Some(2068974),
|
||||
visibility: talon::model::Visibility::Featured,
|
||||
..Default::default()
|
||||
|
@ -82,7 +88,7 @@ fn insert_websites(db: &Db) {
|
|||
&Website {
|
||||
name: "Spotify-Gender-Ex".to_owned(),
|
||||
created_at: datetime!(2023-02-18 16:30 +0),
|
||||
latest_version: Some(1),
|
||||
latest_version: Some(VERSION_2_1),
|
||||
color: Some(1947988),
|
||||
visibility: talon::model::Visibility::Featured,
|
||||
source_url: Some("https://github.com/Theta-Dev/Spotify-Gender-Ex".to_owned()),
|
||||
|
@ -96,7 +102,7 @@ fn insert_websites(db: &Db) {
|
|||
&Website {
|
||||
name: "RustyPipe".to_owned(),
|
||||
created_at: datetime!(2023-02-20 18:30 +0),
|
||||
latest_version: Some(1),
|
||||
latest_version: Some(VERSION_3_1),
|
||||
color: Some(7943647),
|
||||
visibility: talon::model::Visibility::Featured,
|
||||
source_url: Some("https://code.thetadev.de/ThetaDev/rustypipe".to_owned()),
|
||||
|
@ -110,7 +116,7 @@ fn insert_websites(db: &Db) {
|
|||
&Website {
|
||||
name: "SvelteKit SPA".to_owned(),
|
||||
created_at: datetime!(2023-03-03 22:00 +0),
|
||||
latest_version: Some(1),
|
||||
latest_version: Some(VERSION_4_1),
|
||||
color: Some(16727552),
|
||||
visibility: talon::model::Visibility::Hidden,
|
||||
..Default::default()
|
||||
|
@ -124,18 +130,17 @@ fn insert_websites(db: &Db) {
|
|||
"Deployed by".to_owned(),
|
||||
"https://github.com/Theta-Dev/Talon/actions/runs/1352014628".to_owned(),
|
||||
);
|
||||
assert_eq!(
|
||||
db.insert_version(
|
||||
SUBDOMAIN_1,
|
||||
&Version {
|
||||
created_at: datetime!(2023-02-18 16:30 +0),
|
||||
data: v1_data,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
1
|
||||
);
|
||||
assert_eq!(db.new_version_id().unwrap(), VERSION_1_1);
|
||||
db.insert_version(
|
||||
SUBDOMAIN_1,
|
||||
VERSION_1_1,
|
||||
&Version {
|
||||
created_at: datetime!(2023-02-18 16:30 +0),
|
||||
data: v1_data,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut v2_data = BTreeMap::new();
|
||||
v2_data.insert("Version".to_owned(), "v0.1.1".to_owned());
|
||||
|
@ -143,54 +148,51 @@ fn insert_websites(db: &Db) {
|
|||
"Deployed by".to_owned(),
|
||||
"https://github.com/Theta-Dev/Talon/actions/runs/1354755231".to_owned(),
|
||||
);
|
||||
assert_eq!(
|
||||
db.insert_version(
|
||||
SUBDOMAIN_1,
|
||||
&Version {
|
||||
created_at: datetime!(2023-02-18 16:52 +0),
|
||||
data: v2_data,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
2
|
||||
);
|
||||
assert_eq!(db.new_version_id().unwrap(), VERSION_1_2);
|
||||
db.insert_version(
|
||||
SUBDOMAIN_1,
|
||||
VERSION_1_2,
|
||||
&Version {
|
||||
created_at: datetime!(2023-02-18 16:52 +0),
|
||||
data: v2_data,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
db.insert_version(
|
||||
SUBDOMAIN_2,
|
||||
&Version {
|
||||
created_at: datetime!(2023-02-18 16:30 +0),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
db.insert_version(
|
||||
SUBDOMAIN_3,
|
||||
&Version {
|
||||
created_at: datetime!(2023-02-20 18:30 +0),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
db.insert_version(
|
||||
SUBDOMAIN_4,
|
||||
&Version {
|
||||
created_at: datetime!(2023-03-03 22:00 +0),
|
||||
fallback: Some("200.html".to_owned()),
|
||||
spa: true,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
1
|
||||
);
|
||||
assert_eq!(db.new_version_id().unwrap(), VERSION_2_1);
|
||||
db.insert_version(
|
||||
SUBDOMAIN_2,
|
||||
VERSION_2_1,
|
||||
&Version {
|
||||
created_at: datetime!(2023-02-18 16:30 +0),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(db.new_version_id().unwrap(), VERSION_3_1);
|
||||
db.insert_version(
|
||||
SUBDOMAIN_3,
|
||||
VERSION_3_1,
|
||||
&Version {
|
||||
created_at: datetime!(2023-02-20 18:30 +0),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(db.new_version_id().unwrap(), VERSION_4_1);
|
||||
db.insert_version(
|
||||
SUBDOMAIN_4,
|
||||
VERSION_4_1,
|
||||
&Version {
|
||||
created_at: datetime!(2023-03-03 22:00 +0),
|
||||
fallback: Some("200.html".to_owned()),
|
||||
spa: true,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
|
@ -199,47 +201,44 @@ pub fn db() -> DbTest {
|
|||
let db = Db::new(&temp).unwrap();
|
||||
insert_websites(&db);
|
||||
|
||||
db.insert_file(SUBDOMAIN_1, 1, "index.html", &HASH_1_1_INDEX)
|
||||
db.insert_file(VERSION_1_1, "index.html", &HASH_1_1_INDEX)
|
||||
.unwrap();
|
||||
db.insert_file(SUBDOMAIN_1, 1, "style.css", &HASH_1_1_STYLE)
|
||||
db.insert_file(VERSION_1_1, "style.css", &HASH_1_1_STYLE)
|
||||
.unwrap();
|
||||
|
||||
db.insert_file(SUBDOMAIN_1, 2, "index.html", &HASH_1_2_INDEX)
|
||||
db.insert_file(VERSION_1_2, "index.html", &HASH_1_2_INDEX)
|
||||
.unwrap();
|
||||
db.insert_file(SUBDOMAIN_1, 2, "assets/style.css", &HASH_1_2_STYLE)
|
||||
db.insert_file(VERSION_1_2, "assets/style.css", &HASH_1_2_STYLE)
|
||||
.unwrap();
|
||||
db.insert_file(
|
||||
SUBDOMAIN_1,
|
||||
2,
|
||||
VERSION_1_2,
|
||||
"assets/image.jpg",
|
||||
&hex!("901d291a47a8a9b55c06f84e5e5f82fd2dcee65cac1406d6e878b805d45c1e93"),
|
||||
)
|
||||
.unwrap();
|
||||
db.insert_file(
|
||||
SUBDOMAIN_1,
|
||||
2,
|
||||
VERSION_1_2,
|
||||
"assets/test.js",
|
||||
&hex!("b6ed35f5ae339a35a8babb11a91ff90c1a62ef250d30fa98e59500e8dbb896fa"),
|
||||
)
|
||||
.unwrap();
|
||||
db.insert_file(
|
||||
SUBDOMAIN_1,
|
||||
2,
|
||||
VERSION_1_2,
|
||||
"data/example.txt",
|
||||
&hex!("bae6bdae8097c24f9a99028e04bfc8d5e0a0c318955316db0e7b955def9c1dbb"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
db.insert_file(SUBDOMAIN_2, 1, "index.html", &HASH_2_1_INDEX)
|
||||
db.insert_file(VERSION_2_1, "index.html", &HASH_2_1_INDEX)
|
||||
.unwrap();
|
||||
db.insert_file(SUBDOMAIN_2, 1, "gex_style.css", &HASH_2_1_STYLE)
|
||||
db.insert_file(VERSION_2_1, "gex_style.css", &HASH_2_1_STYLE)
|
||||
.unwrap();
|
||||
|
||||
db.insert_file(SUBDOMAIN_3, 1, "index.html", &HASH_3_1_INDEX)
|
||||
db.insert_file(VERSION_3_1, "index.html", &HASH_3_1_INDEX)
|
||||
.unwrap();
|
||||
db.insert_file(SUBDOMAIN_3, 1, "rp_style.css", &HASH_3_1_STYLE)
|
||||
db.insert_file(VERSION_3_1, "rp_style.css", &HASH_3_1_STYLE)
|
||||
.unwrap();
|
||||
db.insert_file(SUBDOMAIN_3, 1, "page2/index.html", &HASH_3_1_PAGE2)
|
||||
db.insert_file(VERSION_3_1, "page2/index.html", &HASH_3_1_PAGE2)
|
||||
.unwrap();
|
||||
|
||||
DbTest { db, _temp: temp }
|
||||
|
@ -267,26 +266,25 @@ pub fn tln() -> TalonTest {
|
|||
|
||||
talon
|
||||
.storage
|
||||
.insert_dir(path!("tests" / "testfiles" / "ThetaDev0"), SUBDOMAIN_1, 1)
|
||||
.insert_dir(path!("tests" / "testfiles" / "ThetaDev0"), VERSION_1_1)
|
||||
.unwrap();
|
||||
talon
|
||||
.storage
|
||||
.insert_dir(path!("tests" / "testfiles" / "ThetaDev1"), SUBDOMAIN_1, 2)
|
||||
.insert_dir(path!("tests" / "testfiles" / "ThetaDev1"), VERSION_1_2)
|
||||
.unwrap();
|
||||
talon
|
||||
.storage
|
||||
.insert_dir(path!("tests" / "testfiles" / "GenderEx"), SUBDOMAIN_2, 1)
|
||||
.insert_dir(path!("tests" / "testfiles" / "GenderEx"), VERSION_2_1)
|
||||
.unwrap();
|
||||
talon
|
||||
.storage
|
||||
.insert_dir(path!("tests" / "testfiles" / "RustyPipe"), SUBDOMAIN_3, 1)
|
||||
.insert_dir(path!("tests" / "testfiles" / "RustyPipe"), VERSION_3_1)
|
||||
.unwrap();
|
||||
talon
|
||||
.storage
|
||||
.insert_tgz_archive(
|
||||
File::open(path!("tests" / "testfiles" / "archive" / "spa.tar.gz")).unwrap(),
|
||||
SUBDOMAIN_4,
|
||||
1,
|
||||
VERSION_4_1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -2,14 +2,14 @@
|
|||
source: tests/tests.rs
|
||||
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}}
|
||||
{"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}}
|
||||
{"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}}
|
||||
{"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":"spotify-gender-ex:1","value":{"created_at":[2023,49,16,30,0,0,0,0,0],"data":{},"fallback":null,"spa":false}}
|
||||
{"type":"file","key":"rustypipe:1:index.html","value":"cc31423924cf1f124750825861ab1ccc675e755921fc2fa111c0a98e8c346a5e"}
|
||||
{"type":"file","key":"rustypipe:1:page2/index.html","value":"be4f409ca0adcb21cdc7130cde63031718406726f889ef97ac8870c90b330a75"}
|
||||
{"type":"file","key":"rustypipe:1:rp_style.css","value":"ee4fc4911a56e627c047a29ba3085131939d8d487759b9149d42aaab89ce8993"}
|
||||
{"type":"file","key":"spotify-gender-ex:1:gex_style.css","value":"fc825b409a49724af8f5b3c4ad15e175e68095ea746237a7b46152d3f383f541"}
|
||||
{"type":"file","key":"spotify-gender-ex:1:index.html","value":"6c5d37546616519e8973be51515b8a90898b4675f7b6d01f2d891edb686408a2"}
|
||||
{"type":"website","key":"rustypipe","value":{"name":"RustyPipe","created_at":[2023,51,18,30,0,0,0,0,0],"latest_version":4,"color":7943647,"visibility":"featured","source_url":"https://code.thetadev.de/ThetaDev/rustypipe","source_icon":"gitea"}}
|
||||
{"type":"website","key":"spa","value":{"name":"SvelteKit SPA","created_at":[2023,62,22,0,0,0,0,0,0],"latest_version":5,"color":16727552,"visibility":"hidden","source_url":null,"source_icon":null}}
|
||||
{"type":"website","key":"spotify-gender-ex","value":{"name":"Spotify-Gender-Ex","created_at":[2023,49,16,30,0,0,0,0,0],"latest_version":3,"color":1947988,"visibility":"featured","source_url":"https://github.com/Theta-Dev/Spotify-Gender-Ex","source_icon":"github"}}
|
||||
{"type":"version","key":"rustypipe:4","value":{"created_at":[2023,51,18,30,0,0,0,0,0],"data":{},"fallback":null,"spa":false}}
|
||||
{"type":"version","key":"spa:5","value":{"created_at":[2023,62,22,0,0,0,0,0,0],"data":{},"fallback":"200.html","spa":true}}
|
||||
{"type":"version","key":"spotify-gender-ex:3","value":{"created_at":[2023,49,16,30,0,0,0,0,0],"data":{},"fallback":null,"spa":false}}
|
||||
{"type":"file","key":"3:gex_style.css","value":"fc825b409a49724af8f5b3c4ad15e175e68095ea746237a7b46152d3f383f541"}
|
||||
{"type":"file","key":"3:index.html","value":"6c5d37546616519e8973be51515b8a90898b4675f7b6d01f2d891edb686408a2"}
|
||||
{"type":"file","key":"4:index.html","value":"cc31423924cf1f124750825861ab1ccc675e755921fc2fa111c0a98e8c346a5e"}
|
||||
{"type":"file","key":"4:page2/index.html","value":"be4f409ca0adcb21cdc7130cde63031718406726f889ef97ac8870c90b330a75"}
|
||||
{"type":"file","key":"4:rp_style.css","value":"ee4fc4911a56e627c047a29ba3085131939d8d487759b9149d42aaab89ce8993"}
|
||||
|
|
|
@ -2,24 +2,24 @@
|
|||
source: tests/tests.rs
|
||||
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}}
|
||||
{"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}}
|
||||
{"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}}
|
||||
{"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}}
|
||||
{"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}}
|
||||
{"type":"website","key":"rustypipe","value":{"name":"RustyPipe","created_at":[2023,51,18,30,0,0,0,0,0],"latest_version":4,"color":7943647,"visibility":"featured","source_url":"https://code.thetadev.de/ThetaDev/rustypipe","source_icon":"gitea"}}
|
||||
{"type":"website","key":"spa","value":{"name":"SvelteKit SPA","created_at":[2023,62,22,0,0,0,0,0,0],"latest_version":5,"color":16727552,"visibility":"hidden","source_url":null,"source_icon":null}}
|
||||
{"type":"website","key":"spotify-gender-ex","value":{"name":"Spotify-Gender-Ex","created_at":[2023,49,16,30,0,0,0,0,0],"latest_version":3,"color":1947988,"visibility":"featured","source_url":"https://github.com/Theta-Dev/Spotify-Gender-Ex","source_icon":"github"}}
|
||||
{"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":"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":"spotify-gender-ex:1","value":{"created_at":[2023,49,16,30,0,0,0,0,0],"data":{},"fallback":null,"spa":false}}
|
||||
{"type":"file","key":"-:1:index.html","value":"3b5f6bad5376897435def176d0fe77e5b9b4f0deafc7491fc27262650744ad68"}
|
||||
{"type":"file","key":"-:1:style.css","value":"356f131c825fbf604797c7e9c85352549d81db8af91fee834016d075110af026"}
|
||||
{"type":"file","key":"-:2:assets/image.jpg","value":"901d291a47a8a9b55c06f84e5e5f82fd2dcee65cac1406d6e878b805d45c1e93"}
|
||||
{"type":"file","key":"-:2:assets/style.css","value":"356f131c825fbf604797c7e9c85352549d81db8af91fee834016d075110af026"}
|
||||
{"type":"file","key":"-:2:assets/test.js","value":"b6ed35f5ae339a35a8babb11a91ff90c1a62ef250d30fa98e59500e8dbb896fa"}
|
||||
{"type":"file","key":"-:2:data/example.txt","value":"bae6bdae8097c24f9a99028e04bfc8d5e0a0c318955316db0e7b955def9c1dbb"}
|
||||
{"type":"file","key":"-:2:index.html","value":"a44816e6c3b650bdf88e6532659ba07ef187c2113ae311da9709e056aec8eadb"}
|
||||
{"type":"file","key":"rustypipe:1:index.html","value":"cc31423924cf1f124750825861ab1ccc675e755921fc2fa111c0a98e8c346a5e"}
|
||||
{"type":"file","key":"rustypipe:1:page2/index.html","value":"be4f409ca0adcb21cdc7130cde63031718406726f889ef97ac8870c90b330a75"}
|
||||
{"type":"file","key":"rustypipe:1:rp_style.css","value":"ee4fc4911a56e627c047a29ba3085131939d8d487759b9149d42aaab89ce8993"}
|
||||
{"type":"file","key":"spotify-gender-ex:1:gex_style.css","value":"fc825b409a49724af8f5b3c4ad15e175e68095ea746237a7b46152d3f383f541"}
|
||||
{"type":"file","key":"spotify-gender-ex:1:index.html","value":"6c5d37546616519e8973be51515b8a90898b4675f7b6d01f2d891edb686408a2"}
|
||||
{"type":"version","key":"rustypipe:4","value":{"created_at":[2023,51,18,30,0,0,0,0,0],"data":{},"fallback":null,"spa":false}}
|
||||
{"type":"version","key":"spa:5","value":{"created_at":[2023,62,22,0,0,0,0,0,0],"data":{},"fallback":"200.html","spa":true}}
|
||||
{"type":"version","key":"spotify-gender-ex:3","value":{"created_at":[2023,49,16,30,0,0,0,0,0],"data":{},"fallback":null,"spa":false}}
|
||||
{"type":"file","key":"1:index.html","value":"3b5f6bad5376897435def176d0fe77e5b9b4f0deafc7491fc27262650744ad68"}
|
||||
{"type":"file","key":"1:style.css","value":"356f131c825fbf604797c7e9c85352549d81db8af91fee834016d075110af026"}
|
||||
{"type":"file","key":"2:assets/image.jpg","value":"901d291a47a8a9b55c06f84e5e5f82fd2dcee65cac1406d6e878b805d45c1e93"}
|
||||
{"type":"file","key":"2:assets/style.css","value":"356f131c825fbf604797c7e9c85352549d81db8af91fee834016d075110af026"}
|
||||
{"type":"file","key":"2:assets/test.js","value":"b6ed35f5ae339a35a8babb11a91ff90c1a62ef250d30fa98e59500e8dbb896fa"}
|
||||
{"type":"file","key":"2:data/example.txt","value":"bae6bdae8097c24f9a99028e04bfc8d5e0a0c318955316db0e7b955def9c1dbb"}
|
||||
{"type":"file","key":"2:index.html","value":"a44816e6c3b650bdf88e6532659ba07ef187c2113ae311da9709e056aec8eadb"}
|
||||
{"type":"file","key":"3:gex_style.css","value":"fc825b409a49724af8f5b3c4ad15e175e68095ea746237a7b46152d3f383f541"}
|
||||
{"type":"file","key":"3:index.html","value":"6c5d37546616519e8973be51515b8a90898b4675f7b6d01f2d891edb686408a2"}
|
||||
{"type":"file","key":"4:index.html","value":"cc31423924cf1f124750825861ab1ccc675e755921fc2fa111c0a98e8c346a5e"}
|
||||
{"type":"file","key":"4:page2/index.html","value":"be4f409ca0adcb21cdc7130cde63031718406726f889ef97ac8870c90b330a75"}
|
||||
{"type":"file","key":"4:rp_style.css","value":"ee4fc4911a56e627c047a29ba3085131939d8d487759b9149d42aaab89ce8993"}
|
||||
|
|
|
@ -11,26 +11,23 @@ expression: "vec![ws1, ws2, ws3]"
|
|||
visibility: featured,
|
||||
source_url: None,
|
||||
source_icon: None,
|
||||
vid_count: 2,
|
||||
),
|
||||
Website(
|
||||
name: "Spotify-Gender-Ex",
|
||||
created_at: (2023, 49, 16, 30, 0, 0, 0, 0, 0),
|
||||
latest_version: Some(1),
|
||||
latest_version: Some(3),
|
||||
color: Some(1947988),
|
||||
visibility: featured,
|
||||
source_url: Some("https://github.com/Theta-Dev/Spotify-Gender-Ex"),
|
||||
source_icon: Some(github),
|
||||
vid_count: 1,
|
||||
),
|
||||
Website(
|
||||
name: "RustyPipe",
|
||||
created_at: (2023, 51, 18, 30, 0, 0, 0, 0, 0),
|
||||
latest_version: Some(1),
|
||||
latest_version: Some(4),
|
||||
color: Some(7943647),
|
||||
visibility: featured,
|
||||
source_url: Some("https://code.thetadev.de/ThetaDev/rustypipe"),
|
||||
source_icon: Some(gitea),
|
||||
vid_count: 1,
|
||||
),
|
||||
]
|
||||
|
|
|
@ -11,36 +11,32 @@ expression: websites
|
|||
visibility: featured,
|
||||
source_url: None,
|
||||
source_icon: None,
|
||||
vid_count: 2,
|
||||
)),
|
||||
("rustypipe", Website(
|
||||
name: "RustyPipe",
|
||||
created_at: (2023, 51, 18, 30, 0, 0, 0, 0, 0),
|
||||
latest_version: Some(1),
|
||||
latest_version: Some(4),
|
||||
color: Some(7943647),
|
||||
visibility: featured,
|
||||
source_url: Some("https://code.thetadev.de/ThetaDev/rustypipe"),
|
||||
source_icon: Some(gitea),
|
||||
vid_count: 1,
|
||||
)),
|
||||
("spa", Website(
|
||||
name: "SvelteKit SPA",
|
||||
created_at: (2023, 62, 22, 0, 0, 0, 0, 0, 0),
|
||||
latest_version: Some(1),
|
||||
latest_version: Some(5),
|
||||
color: Some(16727552),
|
||||
visibility: hidden,
|
||||
source_url: None,
|
||||
source_icon: None,
|
||||
vid_count: 1,
|
||||
)),
|
||||
("spotify-gender-ex", Website(
|
||||
name: "Spotify-Gender-Ex",
|
||||
created_at: (2023, 49, 16, 30, 0, 0, 0, 0, 0),
|
||||
latest_version: Some(1),
|
||||
latest_version: Some(3),
|
||||
color: Some(1947988),
|
||||
visibility: featured,
|
||||
source_url: Some("https://github.com/Theta-Dev/Spotify-Gender-Ex"),
|
||||
source_icon: Some(github),
|
||||
vid_count: 1,
|
||||
)),
|
||||
]
|
||||
|
|
|
@ -10,5 +10,4 @@ Website(
|
|||
visibility: hidden,
|
||||
source_url: Some("https://example.com"),
|
||||
source_icon: Some(link),
|
||||
vid_count: 2,
|
||||
)
|
||||
|
|
101
tests/tests.rs
101
tests/tests.rs
|
@ -94,29 +94,30 @@ mod database {
|
|||
|
||||
#[rstest]
|
||||
fn get_version(db: DbTest) {
|
||||
let version = db.get_version(SUBDOMAIN_1, 1).unwrap();
|
||||
let version = db.get_version(SUBDOMAIN_1, VERSION_1_1).unwrap();
|
||||
insta::assert_ron_snapshot!(version);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn delete_version(db: DbTest) {
|
||||
db.delete_version(SUBDOMAIN_1, 2, true).unwrap();
|
||||
db.delete_version(SUBDOMAIN_1, VERSION_1_2, true).unwrap();
|
||||
assert!(matches!(
|
||||
db.get_version(SUBDOMAIN_1, 2).unwrap_err(),
|
||||
db.get_version(SUBDOMAIN_1, VERSION_1_2).unwrap_err(),
|
||||
DbError::NotExists(_, _)
|
||||
));
|
||||
assert!(matches!(
|
||||
db.delete_version(SUBDOMAIN_1, 2, true).unwrap_err(),
|
||||
db.delete_version(SUBDOMAIN_1, VERSION_1_2, true)
|
||||
.unwrap_err(),
|
||||
DbError::NotExists(_, _)
|
||||
));
|
||||
db.delete_version(SUBDOMAIN_1, 2, false).unwrap();
|
||||
db.delete_version(SUBDOMAIN_1, VERSION_1_2, false).unwrap();
|
||||
|
||||
// Check if files were deleted
|
||||
assert!(db.get_version_files(SUBDOMAIN_1, 2).next().is_none());
|
||||
assert!(db.get_version_files(VERSION_1_2).next().is_none());
|
||||
|
||||
// Check if latest version was updated
|
||||
let ws = db.get_website(SUBDOMAIN_1).unwrap();
|
||||
assert_eq!(ws.latest_version, Some(1));
|
||||
assert_eq!(ws.latest_version, Some(VERSION_1_1));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
@ -134,34 +135,33 @@ mod database {
|
|||
.get_website_version_ids(SUBDOMAIN_1)
|
||||
.map(|v| v.unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(ids, vec![1, 2]);
|
||||
assert_eq!(ids, vec![VERSION_1_1, VERSION_1_2]);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn get_file(db: DbTest) {
|
||||
let hash = db.get_file(SUBDOMAIN_1, 1, "index.html").unwrap();
|
||||
let hash = db.get_file(VERSION_1_1, "index.html").unwrap();
|
||||
assert_eq!(hash, HASH_1_1_INDEX);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn delete_file(db: DbTest) {
|
||||
db.delete_file(SUBDOMAIN_1, 1, "index.html", true).unwrap();
|
||||
db.delete_file(VERSION_1_1, "index.html", true).unwrap();
|
||||
assert!(matches!(
|
||||
db.get_file(SUBDOMAIN_1, 1, "index.html").unwrap_err(),
|
||||
db.get_file(VERSION_1_1, "index.html").unwrap_err(),
|
||||
DbError::NotExists(_, _)
|
||||
));
|
||||
assert!(matches!(
|
||||
db.delete_file(SUBDOMAIN_1, 1, "index.html", true)
|
||||
.unwrap_err(),
|
||||
db.delete_file(VERSION_1_1, "index.html", true).unwrap_err(),
|
||||
DbError::NotExists(_, _)
|
||||
));
|
||||
db.delete_file(SUBDOMAIN_1, 1, "index.html", false).unwrap();
|
||||
db.delete_file(VERSION_1_1, "index.html", false).unwrap();
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn get_version_files(db: DbTest) {
|
||||
let files = db
|
||||
.get_version_files(SUBDOMAIN_1, 1)
|
||||
.get_version_files(VERSION_1_1)
|
||||
.map(|f| f.unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
|
@ -201,10 +201,10 @@ mod storage {
|
|||
let temp = temp_testdir::TempDir::default();
|
||||
let store = Storage::new(temp.to_path_buf(), db_empty.clone(), Default::default());
|
||||
|
||||
store.insert_dir(dir, SUBDOMAIN_1, 1).unwrap();
|
||||
store.insert_dir(dir, 1).unwrap();
|
||||
|
||||
let files = db_empty
|
||||
.get_version_files(SUBDOMAIN_1, 1)
|
||||
.get_version_files(1)
|
||||
.map(|f| f.unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
insta::assert_ron_snapshot!("insert_files", files);
|
||||
|
@ -223,11 +223,11 @@ mod storage {
|
|||
let store = Storage::new(temp.to_path_buf(), db_empty.clone(), Default::default());
|
||||
|
||||
store
|
||||
.insert_zip_archive(File::open(archive).unwrap(), SUBDOMAIN_1, 1)
|
||||
.insert_zip_archive(File::open(archive).unwrap(), 1)
|
||||
.unwrap();
|
||||
|
||||
let files = db_empty
|
||||
.get_version_files(SUBDOMAIN_1, 1)
|
||||
.get_version_files(1)
|
||||
.map(|f| f.unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
insta::assert_ron_snapshot!("insert_files", files);
|
||||
|
@ -246,11 +246,11 @@ mod storage {
|
|||
let store = Storage::new(temp.to_path_buf(), db_empty.clone(), Default::default());
|
||||
|
||||
store
|
||||
.insert_tgz_archive(File::open(archive).unwrap(), SUBDOMAIN_1, 1)
|
||||
.insert_tgz_archive(File::open(archive).unwrap(), 1)
|
||||
.unwrap();
|
||||
|
||||
let files = db_empty
|
||||
.get_version_files(SUBDOMAIN_1, 1)
|
||||
.get_version_files(1)
|
||||
.map(|f| f.unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
insta::assert_ron_snapshot!("insert_files", files);
|
||||
|
@ -278,9 +278,9 @@ mod storage {
|
|||
});
|
||||
|
||||
let store = Storage::new(temp.to_path_buf(), db_empty.clone(), cfg);
|
||||
store.insert_dir(dir, SUBDOMAIN_1, 1).unwrap();
|
||||
store.insert_dir(dir, 1).unwrap();
|
||||
|
||||
for f in db_empty.get_version_files(SUBDOMAIN_1, 1) {
|
||||
for f in db_empty.get_version_files(1) {
|
||||
let hash = f.unwrap().1;
|
||||
let hash_str = hash.encode_hex::<String>();
|
||||
let path = temp.join(&hash_str[..2]).join(&hash_str);
|
||||
|
@ -297,16 +297,15 @@ mod storage {
|
|||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::index("br", SUBDOMAIN_1, 2, "", false, "text/html", None)]
|
||||
#[case::nocmp("", SUBDOMAIN_1, 2, "assets/style.css", true, "text/css", None)]
|
||||
#[case::gzip("gzip", SUBDOMAIN_1, 2, "assets/style.css", true, "text/css", None)]
|
||||
#[case::br("br", SUBDOMAIN_1, 2, "assets/style.css", true, "text/css", None)]
|
||||
#[case::image("br", SUBDOMAIN_1, 2, "assets/image.jpg", false, "image/jpeg", None)]
|
||||
#[case::subdir("br", SUBDOMAIN_3, 1, "page2", false, "text/html", Some("/page2/"))]
|
||||
#[case::index("br", VERSION_1_2, "", false, "text/html", None)]
|
||||
#[case::nocmp("", VERSION_1_2, "assets/style.css", true, "text/css", None)]
|
||||
#[case::gzip("gzip", VERSION_1_2, "assets/style.css", true, "text/css", None)]
|
||||
#[case::br("br", VERSION_1_2, "assets/style.css", true, "text/css", None)]
|
||||
#[case::image("br", VERSION_1_2, "assets/image.jpg", false, "image/jpeg", None)]
|
||||
#[case::subdir("br", VERSION_3_1, "page2", false, "text/html", Some("/page2/"))]
|
||||
fn get_file(
|
||||
tln: TalonTest,
|
||||
#[case] encoding: &str,
|
||||
#[case] subdomain: &str,
|
||||
#[case] version: u32,
|
||||
#[case] path: &str,
|
||||
#[case] compressible: bool,
|
||||
|
@ -326,10 +325,7 @@ mod storage {
|
|||
None
|
||||
};
|
||||
|
||||
let index_file = tln
|
||||
.storage
|
||||
.get_file(subdomain, version, path, &headers)
|
||||
.unwrap();
|
||||
let index_file = tln.storage.get_file(version, path, &headers).unwrap();
|
||||
dbg!(&index_file);
|
||||
assert!(index_file.file_path.is_file());
|
||||
assert_eq!(
|
||||
|
@ -624,43 +620,38 @@ mod page {
|
|||
#[case] ok: bool,
|
||||
#[case] hash: &[u8],
|
||||
) {
|
||||
const SUBDOMAIN: &str = "fallback";
|
||||
|
||||
let vid = tln.db.new_version_id().unwrap();
|
||||
tln.db
|
||||
.insert_website(
|
||||
SUBDOMAIN,
|
||||
"fallback",
|
||||
&talon::db::model::Website {
|
||||
latest_version: Some(1),
|
||||
latest_version: Some(vid),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
tln.db
|
||||
.insert_version(
|
||||
"fallback",
|
||||
vid,
|
||||
&talon::db::model::Version {
|
||||
fallback,
|
||||
spa,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
tln.db
|
||||
.insert_version(
|
||||
SUBDOMAIN,
|
||||
&talon::db::model::Version {
|
||||
fallback,
|
||||
spa,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
1
|
||||
);
|
||||
tln.storage
|
||||
.insert_file(
|
||||
path!("tests" / "testfiles" / "ThetaDev0" / "index.html"),
|
||||
SUBDOMAIN,
|
||||
1,
|
||||
vid,
|
||||
"index.html",
|
||||
)
|
||||
.unwrap();
|
||||
tln.storage
|
||||
.insert_file(
|
||||
path!("tests" / "testfiles" / "ThetaDev1" / "index.html"),
|
||||
SUBDOMAIN,
|
||||
1,
|
||||
vid,
|
||||
"fallback.html",
|
||||
)
|
||||
.unwrap();
|
||||
|
|
6791
ui/menu/package-lock.json
generated
6791
ui/menu/package-lock.json
generated
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue