update api to comply with REST
add delete build endpoint parse some info to new build view
This commit is contained in:
parent
05448a6217
commit
a4f1179c94
@ -1,19 +1,7 @@
|
|||||||
use crate::api::list::build_output;
|
use crate::api::build::*;
|
||||||
use crate::api::list::okapi_add_operation_for_get_build_;
|
use crate::api::list::*;
|
||||||
use crate::api::list::okapi_add_operation_for_stats_;
|
use crate::api::package::*;
|
||||||
use crate::api::list::search;
|
use crate::api::version::*;
|
||||||
use crate::api::list::{get_build, okapi_add_operation_for_list_builds_};
|
|
||||||
use crate::api::list::{list_builds, okapi_add_operation_for_search_};
|
|
||||||
use crate::api::list::{okapi_add_operation_for_build_output_, stats};
|
|
||||||
use crate::api::package::okapi_add_operation_for_package_add_endpoint_;
|
|
||||||
use crate::api::package::okapi_add_operation_for_package_del_;
|
|
||||||
use crate::api::package::okapi_add_operation_for_package_list_;
|
|
||||||
use crate::api::package::okapi_add_operation_for_package_update_endpoint_;
|
|
||||||
use crate::api::package::package_add_endpoint;
|
|
||||||
use crate::api::package::{get_package, package_del, package_list};
|
|
||||||
use crate::api::package::{okapi_add_operation_for_get_package_, package_update_endpoint};
|
|
||||||
use crate::api::remove::okapi_add_operation_for_version_del_;
|
|
||||||
use crate::api::remove::version_del;
|
|
||||||
use rocket::Route;
|
use rocket::Route;
|
||||||
use rocket_okapi::openapi_get_routes;
|
use rocket_okapi::openapi_get_routes;
|
||||||
|
|
||||||
@ -25,6 +13,7 @@ pub fn build_api() -> Vec<Route> {
|
|||||||
package_del,
|
package_del,
|
||||||
version_del,
|
version_del,
|
||||||
build_output,
|
build_output,
|
||||||
|
delete_build,
|
||||||
list_builds,
|
list_builds,
|
||||||
stats,
|
stats,
|
||||||
get_build,
|
get_build,
|
||||||
|
169
backend/src/api/build.rs
Normal file
169
backend/src/api/build.rs
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
use crate::db::migration::{JoinType, Order};
|
||||||
|
use crate::db::prelude::Builds;
|
||||||
|
use crate::db::{builds, packages, versions};
|
||||||
|
use rocket::response::status::NotFound;
|
||||||
|
use rocket::serde::json::Json;
|
||||||
|
use rocket::serde::{Deserialize, Serialize};
|
||||||
|
use rocket::{delete, get, State};
|
||||||
|
use rocket_okapi::okapi::schemars;
|
||||||
|
use rocket_okapi::{openapi, JsonSchema};
|
||||||
|
use sea_orm::ColumnTrait;
|
||||||
|
use sea_orm::QueryFilter;
|
||||||
|
use sea_orm::{
|
||||||
|
DatabaseConnection, EntityTrait, FromQueryResult, ModelTrait, QueryOrder, QuerySelect,
|
||||||
|
RelationTrait,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
pub struct ListPackageModel {
|
||||||
|
id: i32,
|
||||||
|
name: String,
|
||||||
|
status: i32,
|
||||||
|
outofdate: bool,
|
||||||
|
latest_version: Option<String>,
|
||||||
|
latest_version_id: Option<i32>,
|
||||||
|
latest_aur_version: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[openapi(tag = "build")]
|
||||||
|
#[get("/build/<buildid>/output?<startline>")]
|
||||||
|
pub async fn build_output(
|
||||||
|
db: &State<DatabaseConnection>,
|
||||||
|
buildid: i32,
|
||||||
|
startline: Option<i32>,
|
||||||
|
) -> Result<String, NotFound<String>> {
|
||||||
|
let db = db as &DatabaseConnection;
|
||||||
|
|
||||||
|
let build = Builds::find_by_id(buildid)
|
||||||
|
.one(db)
|
||||||
|
.await
|
||||||
|
.map_err(|e| NotFound(e.to_string()))?
|
||||||
|
.ok_or(NotFound("couldn't find id".to_string()))?;
|
||||||
|
|
||||||
|
return match build.ouput {
|
||||||
|
None => Err(NotFound("No Output".to_string())),
|
||||||
|
Some(v) => match startline {
|
||||||
|
None => Ok(v),
|
||||||
|
Some(startline) => {
|
||||||
|
let output: Vec<String> = v.split("\n").map(|x| x.to_string()).collect();
|
||||||
|
let len = output.len();
|
||||||
|
let len_missing = len as i32 - startline;
|
||||||
|
|
||||||
|
let output = output
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.take(if len_missing > 0 {
|
||||||
|
len_missing as usize
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
})
|
||||||
|
.rev()
|
||||||
|
.map(|x1| x1.clone())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let output = output.join("\n");
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
pub struct ListBuildsModel {
|
||||||
|
id: i32,
|
||||||
|
pkg_id: i32,
|
||||||
|
pkg_name: String,
|
||||||
|
version: String,
|
||||||
|
status: i32,
|
||||||
|
start_time: Option<u32>,
|
||||||
|
end_time: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[openapi(tag = "build")]
|
||||||
|
#[get("/builds?<pkgid>&<limit>")]
|
||||||
|
pub async fn list_builds(
|
||||||
|
db: &State<DatabaseConnection>,
|
||||||
|
pkgid: Option<i32>,
|
||||||
|
limit: Option<u64>,
|
||||||
|
) -> Result<Json<Vec<ListBuildsModel>>, NotFound<String>> {
|
||||||
|
let db = db as &DatabaseConnection;
|
||||||
|
|
||||||
|
let basequery = Builds::find()
|
||||||
|
.join_rev(JoinType::InnerJoin, packages::Relation::Builds.def())
|
||||||
|
.join_rev(JoinType::InnerJoin, versions::Relation::Builds.def())
|
||||||
|
.select_only()
|
||||||
|
.column_as(builds::Column::Id, "id")
|
||||||
|
.column(builds::Column::Status)
|
||||||
|
.column_as(packages::Column::Name, "pkg_name")
|
||||||
|
.column_as(packages::Column::Id, "pkg_id")
|
||||||
|
.column(versions::Column::Version)
|
||||||
|
.column(builds::Column::EndTime)
|
||||||
|
.column(builds::Column::StartTime)
|
||||||
|
.order_by(builds::Column::StartTime, Order::Desc)
|
||||||
|
.limit(limit);
|
||||||
|
|
||||||
|
let build = match pkgid {
|
||||||
|
None => basequery.into_model::<ListBuildsModel>().all(db),
|
||||||
|
Some(pkgid) => basequery
|
||||||
|
.filter(builds::Column::PkgId.eq(pkgid))
|
||||||
|
.into_model::<ListBuildsModel>()
|
||||||
|
.all(db),
|
||||||
|
}
|
||||||
|
.await
|
||||||
|
.map_err(|e| NotFound(e.to_string()))?;
|
||||||
|
|
||||||
|
Ok(Json(build))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[openapi(tag = "build")]
|
||||||
|
#[get("/build/<buildid>")]
|
||||||
|
pub async fn get_build(
|
||||||
|
db: &State<DatabaseConnection>,
|
||||||
|
buildid: i32,
|
||||||
|
) -> Result<Json<ListBuildsModel>, NotFound<String>> {
|
||||||
|
let db = db as &DatabaseConnection;
|
||||||
|
|
||||||
|
let result = Builds::find()
|
||||||
|
.join_rev(JoinType::InnerJoin, packages::Relation::Builds.def())
|
||||||
|
.join_rev(JoinType::InnerJoin, versions::Relation::Builds.def())
|
||||||
|
.filter(builds::Column::Id.eq(buildid))
|
||||||
|
.select_only()
|
||||||
|
.column_as(builds::Column::Id, "id")
|
||||||
|
.column(builds::Column::Status)
|
||||||
|
.column_as(packages::Column::Name, "pkg_name")
|
||||||
|
.column_as(packages::Column::Id, "pkg_id")
|
||||||
|
.column(versions::Column::Version)
|
||||||
|
.column(builds::Column::EndTime)
|
||||||
|
.column(builds::Column::StartTime)
|
||||||
|
.into_model::<ListBuildsModel>()
|
||||||
|
.one(db)
|
||||||
|
.await
|
||||||
|
.map_err(|e| NotFound(e.to_string()))?
|
||||||
|
.ok_or(NotFound("no item with id found".to_string()))?;
|
||||||
|
|
||||||
|
Ok(Json(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[openapi(tag = "build")]
|
||||||
|
#[delete("/build/<buildid>")]
|
||||||
|
pub async fn delete_build(
|
||||||
|
db: &State<DatabaseConnection>,
|
||||||
|
buildid: i32,
|
||||||
|
) -> Result<(), NotFound<String>> {
|
||||||
|
let db = db as &DatabaseConnection;
|
||||||
|
|
||||||
|
let build = Builds::find_by_id(buildid)
|
||||||
|
.one(db)
|
||||||
|
.await
|
||||||
|
.map_err(|e| NotFound(e.to_string()))?
|
||||||
|
.ok_or(NotFound("Id not found".to_string()))?;
|
||||||
|
|
||||||
|
build
|
||||||
|
.delete(db)
|
||||||
|
.await
|
||||||
|
.map_err(|e| NotFound(e.to_string()))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
use crate::aur::aur::query_aur;
|
use crate::aur::aur::query_aur;
|
||||||
use crate::db::migration::JoinType;
|
|
||||||
use crate::db::prelude::{Builds, Packages};
|
use crate::db::prelude::{Builds, Packages};
|
||||||
use crate::db::{builds, packages, versions};
|
use crate::db::{builds};
|
||||||
use crate::utils::dir_size::dir_size;
|
use crate::utils::dir_size::dir_size;
|
||||||
use rocket::response::status::NotFound;
|
use rocket::response::status::NotFound;
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
@ -10,8 +9,8 @@ use rocket::{get, State};
|
|||||||
use rocket_okapi::okapi::schemars;
|
use rocket_okapi::okapi::schemars;
|
||||||
use rocket_okapi::{openapi, JsonSchema};
|
use rocket_okapi::{openapi, JsonSchema};
|
||||||
use sea_orm::{ColumnTrait, QueryFilter};
|
use sea_orm::{ColumnTrait, QueryFilter};
|
||||||
use sea_orm::{DatabaseConnection, EntityTrait, FromQueryResult, QuerySelect, RelationTrait};
|
use sea_orm::{DatabaseConnection, EntityTrait, FromQueryResult};
|
||||||
use sea_orm::{Order, PaginatorTrait, QueryOrder};
|
use sea_orm::{PaginatorTrait};
|
||||||
|
|
||||||
#[derive(Serialize, JsonSchema)]
|
#[derive(Serialize, JsonSchema)]
|
||||||
#[serde(crate = "rocket::serde")]
|
#[serde(crate = "rocket::serde")]
|
||||||
@ -20,7 +19,7 @@ pub struct ApiPackage {
|
|||||||
version: String,
|
version: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[openapi(tag = "test")]
|
#[openapi(tag = "aur")]
|
||||||
#[get("/search?<query>")]
|
#[get("/search?<query>")]
|
||||||
pub async fn search(query: &str) -> Result<Json<Vec<ApiPackage>>, String> {
|
pub async fn search(query: &str) -> Result<Json<Vec<ApiPackage>>, String> {
|
||||||
return match query_aur(query).await {
|
return match query_aur(query).await {
|
||||||
@ -38,135 +37,6 @@ pub async fn search(query: &str) -> Result<Json<Vec<ApiPackage>>, String> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)]
|
|
||||||
#[serde(crate = "rocket::serde")]
|
|
||||||
pub struct ListPackageModel {
|
|
||||||
id: i32,
|
|
||||||
name: String,
|
|
||||||
status: i32,
|
|
||||||
outofdate: bool,
|
|
||||||
latest_version: Option<String>,
|
|
||||||
latest_version_id: Option<i32>,
|
|
||||||
latest_aur_version: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[openapi(tag = "test")]
|
|
||||||
#[get("/builds/output?<buildid>&<startline>")]
|
|
||||||
pub async fn build_output(
|
|
||||||
db: &State<DatabaseConnection>,
|
|
||||||
buildid: i32,
|
|
||||||
startline: Option<i32>,
|
|
||||||
) -> Result<String, NotFound<String>> {
|
|
||||||
let db = db as &DatabaseConnection;
|
|
||||||
|
|
||||||
let build = Builds::find_by_id(buildid)
|
|
||||||
.one(db)
|
|
||||||
.await
|
|
||||||
.map_err(|e| NotFound(e.to_string()))?
|
|
||||||
.ok_or(NotFound("couldn't find id".to_string()))?;
|
|
||||||
|
|
||||||
return match build.ouput {
|
|
||||||
None => Err(NotFound("No Output".to_string())),
|
|
||||||
Some(v) => match startline {
|
|
||||||
None => Ok(v),
|
|
||||||
Some(startline) => {
|
|
||||||
let output: Vec<String> = v.split("\n").map(|x| x.to_string()).collect();
|
|
||||||
let len = output.len();
|
|
||||||
let len_missing = len as i32 - startline;
|
|
||||||
|
|
||||||
let output = output
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.take(if len_missing > 0 {
|
|
||||||
len_missing as usize
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
})
|
|
||||||
.rev()
|
|
||||||
.map(|x1| x1.clone())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let output = output.join("\n");
|
|
||||||
Ok(output)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)]
|
|
||||||
#[serde(crate = "rocket::serde")]
|
|
||||||
pub struct ListBuildsModel {
|
|
||||||
id: i32,
|
|
||||||
pkg_name: String,
|
|
||||||
version: String,
|
|
||||||
status: i32,
|
|
||||||
start_time: Option<u32>,
|
|
||||||
end_time: Option<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[openapi(tag = "test")]
|
|
||||||
#[get("/builds?<pkgid>&<limit>")]
|
|
||||||
pub async fn list_builds(
|
|
||||||
db: &State<DatabaseConnection>,
|
|
||||||
pkgid: Option<i32>,
|
|
||||||
limit: Option<u64>,
|
|
||||||
) -> Result<Json<Vec<ListBuildsModel>>, NotFound<String>> {
|
|
||||||
let db = db as &DatabaseConnection;
|
|
||||||
|
|
||||||
let basequery = Builds::find()
|
|
||||||
.join_rev(JoinType::InnerJoin, packages::Relation::Builds.def())
|
|
||||||
.join_rev(JoinType::InnerJoin, versions::Relation::Builds.def())
|
|
||||||
.select_only()
|
|
||||||
.column_as(builds::Column::Id, "id")
|
|
||||||
.column(builds::Column::Status)
|
|
||||||
.column_as(packages::Column::Name, "pkg_name")
|
|
||||||
.column(versions::Column::Version)
|
|
||||||
.column(builds::Column::EndTime)
|
|
||||||
.column(builds::Column::StartTime)
|
|
||||||
.order_by(builds::Column::StartTime, Order::Desc)
|
|
||||||
.limit(limit);
|
|
||||||
|
|
||||||
let build = match pkgid {
|
|
||||||
None => basequery.into_model::<ListBuildsModel>().all(db),
|
|
||||||
Some(pkgid) => basequery
|
|
||||||
.filter(builds::Column::PkgId.eq(pkgid))
|
|
||||||
.into_model::<ListBuildsModel>()
|
|
||||||
.all(db),
|
|
||||||
}
|
|
||||||
.await
|
|
||||||
.map_err(|e| NotFound(e.to_string()))?;
|
|
||||||
|
|
||||||
Ok(Json(build))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[openapi(tag = "test")]
|
|
||||||
#[get("/builds/<buildid>")]
|
|
||||||
pub async fn get_build(
|
|
||||||
db: &State<DatabaseConnection>,
|
|
||||||
buildid: i32,
|
|
||||||
) -> Result<Json<ListBuildsModel>, NotFound<String>> {
|
|
||||||
let db = db as &DatabaseConnection;
|
|
||||||
|
|
||||||
let result = Builds::find()
|
|
||||||
.join_rev(JoinType::InnerJoin, packages::Relation::Builds.def())
|
|
||||||
.join_rev(JoinType::InnerJoin, versions::Relation::Builds.def())
|
|
||||||
.filter(builds::Column::Id.eq(buildid))
|
|
||||||
.select_only()
|
|
||||||
.column_as(builds::Column::Id, "id")
|
|
||||||
.column(builds::Column::Status)
|
|
||||||
.column_as(packages::Column::Name, "pkg_name")
|
|
||||||
.column(versions::Column::Version)
|
|
||||||
.column(builds::Column::EndTime)
|
|
||||||
.column(builds::Column::StartTime)
|
|
||||||
.into_model::<ListBuildsModel>()
|
|
||||||
.one(db)
|
|
||||||
.await
|
|
||||||
.map_err(|e| NotFound(e.to_string()))?
|
|
||||||
.ok_or(NotFound("no item with id found".to_string()))?;
|
|
||||||
|
|
||||||
Ok(Json(result))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)]
|
#[derive(FromQueryResult, Deserialize, JsonSchema, Serialize)]
|
||||||
#[serde(crate = "rocket::serde")]
|
#[serde(crate = "rocket::serde")]
|
||||||
pub struct ListStats {
|
pub struct ListStats {
|
||||||
@ -179,15 +49,15 @@ pub struct ListStats {
|
|||||||
total_packages: u32,
|
total_packages: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[openapi(tag = "test")]
|
#[openapi(tag = "stats")]
|
||||||
#[get("/stats")]
|
#[get("/stats")]
|
||||||
pub async fn stats(db: &State<DatabaseConnection>) -> Result<Json<ListStats>, NotFound<String>> {
|
pub async fn stats(db: &State<DatabaseConnection>) -> Result<Json<ListStats>, NotFound<String>> {
|
||||||
let db = db as &DatabaseConnection;
|
let db = db as &DatabaseConnection;
|
||||||
|
|
||||||
return match get_stats(db).await {
|
get_stats(db)
|
||||||
Ok(v) => Ok(Json(v)),
|
.await
|
||||||
Err(e) => Err(NotFound(e.to_string())),
|
.map_err(|e| NotFound(e.to_string()))
|
||||||
};
|
.map(Json)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_stats(db: &DatabaseConnection) -> anyhow::Result<ListStats> {
|
async fn get_stats(db: &DatabaseConnection) -> anyhow::Result<ListStats> {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
pub mod backend;
|
pub mod backend;
|
||||||
|
mod build;
|
||||||
#[cfg(feature = "static")]
|
#[cfg(feature = "static")]
|
||||||
pub mod embed;
|
pub mod embed;
|
||||||
mod list;
|
mod list;
|
||||||
mod package;
|
mod package;
|
||||||
mod remove;
|
mod version;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::api::list::ListPackageModel;
|
use crate::api::build::ListPackageModel;
|
||||||
use crate::builder::types::Action;
|
use crate::builder::types::Action;
|
||||||
use crate::db::migration::{JoinType, Order};
|
use crate::db::migration::{JoinType, Order};
|
||||||
use crate::db::prelude::Packages;
|
use crate::db::prelude::Packages;
|
||||||
@ -9,7 +9,7 @@ use crate::package::update::package_update;
|
|||||||
use rocket::response::status::{BadRequest, NotFound};
|
use rocket::response::status::{BadRequest, NotFound};
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
use rocket::serde::Deserialize;
|
use rocket::serde::Deserialize;
|
||||||
use rocket::{get, post, State};
|
use rocket::{delete, get, post, State};
|
||||||
use rocket_okapi::okapi::schemars;
|
use rocket_okapi::okapi::schemars;
|
||||||
use rocket_okapi::{openapi, JsonSchema};
|
use rocket_okapi::{openapi, JsonSchema};
|
||||||
use sea_orm::DatabaseConnection;
|
use sea_orm::DatabaseConnection;
|
||||||
@ -23,7 +23,7 @@ pub struct AddBody {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[openapi(tag = "Packages")]
|
#[openapi(tag = "Packages")]
|
||||||
#[post("/packages/add", data = "<input>")]
|
#[post("/package", data = "<input>")]
|
||||||
pub async fn package_add_endpoint(
|
pub async fn package_add_endpoint(
|
||||||
db: &State<DatabaseConnection>,
|
db: &State<DatabaseConnection>,
|
||||||
input: Json<AddBody>,
|
input: Json<AddBody>,
|
||||||
@ -41,20 +41,21 @@ pub struct UpdateBody {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[openapi(tag = "Packages")]
|
#[openapi(tag = "Packages")]
|
||||||
#[post("/packages/<id>/update", data = "<input>")]
|
#[post("/package/<id>/update", data = "<input>")]
|
||||||
pub async fn package_update_endpoint(
|
pub async fn package_update_endpoint(
|
||||||
db: &State<DatabaseConnection>,
|
db: &State<DatabaseConnection>,
|
||||||
id: i32,
|
id: i32,
|
||||||
input: Json<UpdateBody>,
|
input: Json<UpdateBody>,
|
||||||
tx: &State<Sender<Action>>,
|
tx: &State<Sender<Action>>,
|
||||||
) -> Result<(), BadRequest<String>> {
|
) -> Result<Json<i32>, BadRequest<String>> {
|
||||||
package_update(db, id, input.force, tx)
|
package_update(db, id, input.force, tx)
|
||||||
.await
|
.await
|
||||||
|
.map(|e| Json(e))
|
||||||
.map_err(|e| BadRequest(Some(e.to_string())))
|
.map_err(|e| BadRequest(Some(e.to_string())))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[openapi(tag = "Packages")]
|
#[openapi(tag = "Packages")]
|
||||||
#[post("/package/delete/<id>")]
|
#[delete("/package/<id>")]
|
||||||
pub async fn package_del(db: &State<DatabaseConnection>, id: i32) -> Result<(), String> {
|
pub async fn package_del(db: &State<DatabaseConnection>, id: i32) -> Result<(), String> {
|
||||||
let db = db as &DatabaseConnection;
|
let db = db as &DatabaseConnection;
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use crate::repo::repo::remove_version;
|
use crate::repo::repo::remove_version;
|
||||||
use rocket::{post, State};
|
use rocket::{delete, State};
|
||||||
use rocket_okapi::openapi;
|
use rocket_okapi::openapi;
|
||||||
use sea_orm::DatabaseConnection;
|
use sea_orm::DatabaseConnection;
|
||||||
|
|
||||||
#[openapi(tag = "test")]
|
#[openapi(tag = "version")]
|
||||||
#[post("/versions/delete/<id>")]
|
#[delete("/version/<id>/delete")]
|
||||||
pub async fn version_del(db: &State<DatabaseConnection>, id: i32) -> Result<(), String> {
|
pub async fn version_del(db: &State<DatabaseConnection>, id: i32) -> Result<(), String> {
|
||||||
let db = db as &DatabaseConnection;
|
let db = db as &DatabaseConnection;
|
||||||
|
|
@ -19,12 +19,13 @@ pub async fn init(db: DatabaseConnection, tx: Sender<Action>) {
|
|||||||
if let Ok(_result) = tx.subscribe().recv().await {
|
if let Ok(_result) = tx.subscribe().recv().await {
|
||||||
match _result {
|
match _result {
|
||||||
// add a package to parallel build
|
// add a package to parallel build
|
||||||
Action::Build(name, version, url, version_model) => {
|
Action::Build(name, version, url, version_model, build_model) => {
|
||||||
let _ = queue_package(
|
let _ = queue_package(
|
||||||
name,
|
name,
|
||||||
version,
|
version,
|
||||||
url,
|
url,
|
||||||
version_model,
|
version_model,
|
||||||
|
build_model,
|
||||||
db.clone(),
|
db.clone(),
|
||||||
semaphore.clone(),
|
semaphore.clone(),
|
||||||
)
|
)
|
||||||
@ -40,25 +41,10 @@ async fn queue_package(
|
|||||||
version: String,
|
version: String,
|
||||||
url: String,
|
url: String,
|
||||||
version_model: versions::ActiveModel,
|
version_model: versions::ActiveModel,
|
||||||
|
mut build_model: builds::ActiveModel,
|
||||||
db: DatabaseConnection,
|
db: DatabaseConnection,
|
||||||
semaphore: Arc<Semaphore>,
|
semaphore: Arc<Semaphore>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
// set build status to pending
|
|
||||||
let build = builds::ActiveModel {
|
|
||||||
pkg_id: version_model.package_id.clone(),
|
|
||||||
version_id: version_model.id.clone(),
|
|
||||||
ouput: Set(None),
|
|
||||||
status: Set(Some(3)),
|
|
||||||
start_time: Set(Some(
|
|
||||||
SystemTime::now()
|
|
||||||
.duration_since(UNIX_EPOCH)
|
|
||||||
.unwrap()
|
|
||||||
.as_secs() as u32,
|
|
||||||
)),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let mut new_build = build.save(&db).await.unwrap();
|
|
||||||
|
|
||||||
let permits = Arc::clone(&semaphore);
|
let permits = Arc::clone(&semaphore);
|
||||||
|
|
||||||
// spawn new thread for each pkg build
|
// spawn new thread for each pkg build
|
||||||
@ -67,10 +53,10 @@ async fn queue_package(
|
|||||||
let _permit = permits.acquire().await.unwrap();
|
let _permit = permits.acquire().await.unwrap();
|
||||||
|
|
||||||
// set build status to building
|
// set build status to building
|
||||||
new_build.status = Set(Some(0));
|
build_model.status = Set(Some(0));
|
||||||
new_build = new_build.save(&db).await.unwrap();
|
build_model = build_model.save(&db).await.unwrap();
|
||||||
|
|
||||||
let _ = build_package(new_build, db, version_model, version, name, url).await;
|
let _ = build_package(build_model, db, version_model, version, name, url).await;
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
use crate::db::versions;
|
use crate::db::{builds, versions};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Build(String, String, String, versions::ActiveModel),
|
Build(
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
versions::ActiveModel,
|
||||||
|
builds::ActiveModel,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use crate::aur::aur::get_info_by_name;
|
use crate::aur::aur::get_info_by_name;
|
||||||
use crate::builder::types::Action;
|
use crate::builder::types::Action;
|
||||||
use crate::db::prelude::Packages;
|
use crate::db::prelude::Packages;
|
||||||
use crate::db::{packages, versions};
|
use crate::db::{builds, packages, versions};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use sea_orm::ColumnTrait;
|
use sea_orm::ColumnTrait;
|
||||||
use sea_orm::QueryFilter;
|
use sea_orm::QueryFilter;
|
||||||
use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityTrait, Set, TransactionTrait};
|
use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityTrait, Set, TransactionTrait};
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use tokio::sync::broadcast::Sender;
|
use tokio::sync::broadcast::Sender;
|
||||||
|
|
||||||
pub async fn package_add(
|
pub async fn package_add(
|
||||||
@ -49,11 +50,28 @@ pub async fn package_add(
|
|||||||
new_package.latest_version_id = Set(Some(new_version.id.clone().unwrap()));
|
new_package.latest_version_id = Set(Some(new_version.id.clone().unwrap()));
|
||||||
new_package.save(&txn).await?;
|
new_package.save(&txn).await?;
|
||||||
|
|
||||||
|
// set build status to pending
|
||||||
|
let build = builds::ActiveModel {
|
||||||
|
pkg_id: new_version.package_id.clone(),
|
||||||
|
version_id: new_version.id.clone(),
|
||||||
|
ouput: Set(None),
|
||||||
|
status: Set(Some(3)),
|
||||||
|
start_time: Set(Some(
|
||||||
|
SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_secs() as u32,
|
||||||
|
)),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let new_build = build.save(&txn).await?;
|
||||||
|
|
||||||
let _ = tx.send(Action::Build(
|
let _ = tx.send(Action::Build(
|
||||||
pkg.name,
|
pkg.name,
|
||||||
pkg.version,
|
pkg.version,
|
||||||
pkg.url_path.unwrap(),
|
pkg.url_path.unwrap(),
|
||||||
new_version,
|
new_version,
|
||||||
|
new_build,
|
||||||
));
|
));
|
||||||
|
|
||||||
txn.commit().await?;
|
txn.commit().await?;
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use crate::aur::aur::get_info_by_name;
|
use crate::aur::aur::get_info_by_name;
|
||||||
use crate::builder::types::Action;
|
use crate::builder::types::Action;
|
||||||
use crate::db::prelude::{Packages, Versions};
|
use crate::db::prelude::{Packages, Versions};
|
||||||
use crate::db::{packages, versions};
|
use crate::db::{builds, packages, versions};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use sea_orm::ColumnTrait;
|
use sea_orm::ColumnTrait;
|
||||||
use sea_orm::QueryFilter;
|
use sea_orm::QueryFilter;
|
||||||
use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityTrait, Set, TransactionTrait};
|
use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityTrait, Set, TransactionTrait};
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use tokio::sync::broadcast::Sender;
|
use tokio::sync::broadcast::Sender;
|
||||||
|
|
||||||
pub async fn package_update(
|
pub async fn package_update(
|
||||||
@ -13,7 +14,7 @@ pub async fn package_update(
|
|||||||
pkg_id: i32,
|
pkg_id: i32,
|
||||||
force: bool,
|
force: bool,
|
||||||
tx: &Sender<Action>,
|
tx: &Sender<Action>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<i32> {
|
||||||
let txn = db.begin().await?;
|
let txn = db.begin().await?;
|
||||||
|
|
||||||
let mut pkg_model: packages::ActiveModel = Packages::find_by_id(pkg_id)
|
let mut pkg_model: packages::ActiveModel = Packages::find_by_id(pkg_id)
|
||||||
@ -54,16 +55,34 @@ pub async fn package_update(
|
|||||||
|
|
||||||
pkg_model.status = Set(3);
|
pkg_model.status = Set(3);
|
||||||
pkg_model.latest_version_id = Set(Some(version_model.id.clone().unwrap()));
|
pkg_model.latest_version_id = Set(Some(version_model.id.clone().unwrap()));
|
||||||
pkg_model.save(&txn).await.expect("todo error message");
|
pkg_model.save(&txn).await?;
|
||||||
|
|
||||||
|
// set build status to pending
|
||||||
|
let build = builds::ActiveModel {
|
||||||
|
pkg_id: version_model.package_id.clone(),
|
||||||
|
version_id: version_model.id.clone(),
|
||||||
|
ouput: Set(None),
|
||||||
|
status: Set(Some(3)),
|
||||||
|
start_time: Set(Some(
|
||||||
|
SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_secs() as u32,
|
||||||
|
)),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let new_build = build.save(&txn).await?;
|
||||||
|
let build_id = new_build.id.clone().unwrap();
|
||||||
|
|
||||||
let _ = tx.send(Action::Build(
|
let _ = tx.send(Action::Build(
|
||||||
pkg.name,
|
pkg.name,
|
||||||
pkg.version,
|
pkg.version,
|
||||||
pkg.url_path.unwrap(),
|
pkg.url_path.unwrap(),
|
||||||
version_model,
|
version_model,
|
||||||
|
new_build,
|
||||||
));
|
));
|
||||||
|
|
||||||
txn.commit().await?;
|
txn.commit().await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(build_id)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import 'package:flutter/foundation.dart';
|
|||||||
|
|
||||||
class ApiClient {
|
class ApiClient {
|
||||||
static const String _apiBase =
|
static const String _apiBase =
|
||||||
kDebugMode ? "https://aurcache.heili.eu/api" : "api";
|
kDebugMode ? "http://localhost:8081/api" : "api";
|
||||||
final Dio _dio = Dio(BaseOptions(baseUrl: _apiBase));
|
final Dio _dio = Dio(BaseOptions(baseUrl: _apiBase));
|
||||||
|
|
||||||
String? token;
|
String? token;
|
||||||
|
@ -21,14 +21,19 @@ extension BuildsAPI on ApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<Build> getBuild(int id) async {
|
Future<Build> getBuild(int id) async {
|
||||||
final resp = await getRawClient().get("/builds/${id}");
|
final resp = await getRawClient().get("/build/${id}");
|
||||||
return Build.fromJson(resp.data);
|
return Build.fromJson(resp.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> deleteBuild(int id) async {
|
||||||
|
final resp = await getRawClient().delete("/build/${id}");
|
||||||
|
return resp.statusCode == 400;
|
||||||
|
}
|
||||||
|
|
||||||
Future<String> getOutput({int? line, required int buildID}) async {
|
Future<String> getOutput({int? line, required int buildID}) async {
|
||||||
String uri = "/builds/output?buildid=$buildID";
|
String uri = "/build/$buildID/output";
|
||||||
if (line != null) {
|
if (line != null) {
|
||||||
uri += "&startline=$line";
|
uri += "?startline=$line";
|
||||||
}
|
}
|
||||||
final resp = await getRawClient().get(uri);
|
final resp = await getRawClient().get(uri);
|
||||||
return resp.data.toString();
|
return resp.data.toString();
|
||||||
|
@ -20,19 +20,20 @@ extension PackagesAPI on ApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> addPackage({required String name}) async {
|
Future<void> addPackage({required String name}) async {
|
||||||
final resp =
|
final resp = await getRawClient().post("/package", data: {'name': name});
|
||||||
await getRawClient().post("/packages/add", data: {'name': name});
|
|
||||||
print(resp.data);
|
print(resp.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updatePackage({bool force = false, required int id}) async {
|
Future<int> updatePackage({bool force = false, required int id}) async {
|
||||||
final resp = await getRawClient()
|
final resp = await getRawClient()
|
||||||
.post("/packages/$id/update", data: {'force': force});
|
.post("/package/$id/update", data: {'force': force});
|
||||||
print(resp.data);
|
print(resp.data);
|
||||||
|
|
||||||
|
return resp.data as int;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> deletePackage(int id) async {
|
Future<bool> deletePackage(int id) async {
|
||||||
final resp = await getRawClient().post("/package/delete/$id");
|
final resp = await getRawClient().delete("/package/$id");
|
||||||
return resp.statusCode == 200;
|
return resp.statusCode == 200;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
class Build {
|
class Build {
|
||||||
final int id;
|
final int id;
|
||||||
final String pkg_name;
|
final String pkg_name;
|
||||||
|
final int pkg_id;
|
||||||
final String version;
|
final String version;
|
||||||
final int status;
|
final int status;
|
||||||
final int? start_time, end_time;
|
final int? start_time, end_time;
|
||||||
|
|
||||||
Build(
|
Build(
|
||||||
{required this.id,
|
{required this.id,
|
||||||
|
required this.pkg_id,
|
||||||
required this.pkg_name,
|
required this.pkg_name,
|
||||||
required this.version,
|
required this.version,
|
||||||
required this.start_time,
|
required this.start_time,
|
||||||
@ -16,6 +18,7 @@ class Build {
|
|||||||
factory Build.fromJson(Map<String, dynamic> json) {
|
factory Build.fromJson(Map<String, dynamic> json) {
|
||||||
return Build(
|
return Build(
|
||||||
id: json["id"] as int,
|
id: json["id"] as int,
|
||||||
|
pkg_id: json["pkg_id"] as int,
|
||||||
status: json["status"] as int,
|
status: json["status"] as int,
|
||||||
start_time: json["start_time"] as int?,
|
start_time: json["start_time"] as int?,
|
||||||
end_time: json["end_time"] as int?,
|
end_time: json["end_time"] as int?,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'package:aurcache/api/builds.dart';
|
||||||
|
import 'package:aurcache/api/packages.dart';
|
||||||
import 'package:aurcache/components/build_output.dart';
|
import 'package:aurcache/components/build_output.dart';
|
||||||
import 'package:aurcache/models/build.dart';
|
import 'package:aurcache/models/build.dart';
|
||||||
import 'package:aurcache/components/api/APIBuilder.dart';
|
import 'package:aurcache/components/api/APIBuilder.dart';
|
||||||
@ -7,6 +9,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../api/API.dart';
|
||||||
import '../components/confirm_popup.dart';
|
import '../components/confirm_popup.dart';
|
||||||
import '../components/dashboard/chart_card.dart';
|
import '../components/dashboard/chart_card.dart';
|
||||||
import '../components/dashboard/your_packages.dart';
|
import '../components/dashboard/your_packages.dart';
|
||||||
@ -57,7 +60,7 @@ class _BuildScreenState extends State<BuildScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
_buildSideBar(),
|
_buildSideBar(buildData),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -159,7 +162,7 @@ class _BuildScreenState extends State<BuildScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSideBar() {
|
Widget _buildSideBar(Build buildData) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 300,
|
width: 300,
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -190,8 +193,9 @@ class _BuildScreenState extends State<BuildScreen> {
|
|||||||
final confirmResult = await showConfirmationDialog(
|
final confirmResult = await showConfirmationDialog(
|
||||||
context,
|
context,
|
||||||
"Delete Build",
|
"Delete Build",
|
||||||
"Are you sure to delete this Package?", () async {
|
"Are you sure to delete this Package?", () {
|
||||||
// todo delete build
|
API.deleteBuild(widget.buildID);
|
||||||
|
context.pop();
|
||||||
}, null);
|
}, null);
|
||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text(
|
||||||
@ -204,7 +208,9 @@ class _BuildScreenState extends State<BuildScreen> {
|
|||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// todo api call and page redirect
|
final buildid =
|
||||||
|
await API.updatePackage(id: buildData.pkg_id);
|
||||||
|
context.pushReplacement("/build/$buildid");
|
||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text(
|
||||||
"Retry",
|
"Retry",
|
||||||
@ -220,21 +226,21 @@ class _BuildScreenState extends State<BuildScreen> {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 5,
|
height: 5,
|
||||||
),
|
),
|
||||||
Text(
|
const Text(
|
||||||
"Build Information:",
|
"Build Information:",
|
||||||
style: TextStyle(fontSize: 18),
|
style: TextStyle(fontSize: 18),
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
),
|
),
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
SideCard(
|
SideCard(
|
||||||
title: "Build Number",
|
title: "Build Number",
|
||||||
textRight: "7",
|
textRight: buildData.id.toString(),
|
||||||
),
|
),
|
||||||
SideCard(
|
SideCard(
|
||||||
title: "Finished",
|
title: "Finished",
|
||||||
textRight: "7",
|
textRight: buildData.end_time.toString(),
|
||||||
),
|
),
|
||||||
SideCard(
|
SideCard(
|
||||||
title: "Queued",
|
title: "Queued",
|
||||||
@ -242,7 +248,13 @@ class _BuildScreenState extends State<BuildScreen> {
|
|||||||
),
|
),
|
||||||
SideCard(
|
SideCard(
|
||||||
title: "Duration",
|
title: "Duration",
|
||||||
textRight: "7",
|
textRight: (buildData.end_time != null
|
||||||
|
? DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
buildData.end_time! * 1000)
|
||||||
|
: DateTime.now())
|
||||||
|
.difference(DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
buildData.start_time! * 1000))
|
||||||
|
.readableDuration(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -18,3 +18,21 @@ extension TimeFormatter on DateTime {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension DurationFormatter on Duration {
|
||||||
|
String readableDuration() {
|
||||||
|
if (inSeconds < 60) {
|
||||||
|
return '$inSeconds second${inSeconds != 1 ? 's' : ''}';
|
||||||
|
} else if (inMinutes < 60) {
|
||||||
|
return '$inMinutes minute${inMinutes != 1 ? 's' : ''}';
|
||||||
|
} else if (inHours < 24) {
|
||||||
|
return '$inHours hour${inHours != 1 ? 's' : ''}';
|
||||||
|
} else if (inDays < 30) {
|
||||||
|
return '$inDays day${inDays != 1 ? 's' : ''}';
|
||||||
|
} else if ((inDays / 30) < 12) {
|
||||||
|
return '${inDays ~/ 30} month${(inDays ~/ 30) != 1 ? 's' : ''}';
|
||||||
|
} else {
|
||||||
|
return '${inDays ~/ 365} year${(inDays ~/ 365) != 1 ? 's' : ''}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user