feat: log site deploy ,update and delete events in db
This commit is contained in:
parent
1e0fa7279f
commit
f89b3e6d4c
|
@ -1620,6 +1620,7 @@ dependencies = [
|
|||
"tracing-actix-web",
|
||||
"url",
|
||||
"urlencoding",
|
||||
"uuid 1.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2323,6 +2324,7 @@ dependencies = [
|
|||
"time",
|
||||
"tokio-stream",
|
||||
"url",
|
||||
"uuid 1.2.2",
|
||||
"webpki-roots",
|
||||
"whoami",
|
||||
]
|
||||
|
@ -2610,7 +2612,7 @@ dependencies = [
|
|||
"actix-web",
|
||||
"pin-project",
|
||||
"tracing",
|
||||
"uuid 1.2.1",
|
||||
"uuid 1.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2794,11 +2796,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.2.1"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "feb41e78f93363bb2df8b0e86a2ca30eed7806ea16ea0c790d757cf93f79be83"
|
||||
checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -19,7 +19,7 @@ actix-identity = "0.4.0"
|
|||
actix-rt = "2"
|
||||
actix-web-codegen-const-routes = { version = "0.1.0", tag = "0.1.0", git = "https://github.com/realaravinth/actix-web-codegen-const-routes" }
|
||||
argon2-creds = { branch = "master", git = "https://github.com/realaravinth/argon2-creds"}
|
||||
sqlx = { version = "0.6.1", features = [ "runtime-actix-rustls", "postgres", "time", "offline", "json"] }
|
||||
sqlx = { version = "0.6.1", features = ["runtime-actix-rustls", "postgres", "time", "offline", "json", "uuid"] }
|
||||
clap = { version = "3.2.20", features = ["derive"]}
|
||||
|
||||
config = "0.13"
|
||||
|
@ -50,6 +50,7 @@ tracing = { version = "0.1.37", features = ["log"]}
|
|||
tracing-actix-web = "0.6.2"
|
||||
toml = "0.5.9"
|
||||
serde_yaml = "0.9.14"
|
||||
uuid = { version = "1.2.2", features = ["serde"] }
|
||||
|
||||
[dependencies.cache-buster]
|
||||
git = "https://github.com/realaravinth/cache-buster"
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
CREATE TABLE IF NOT EXISTS librepages_deploy_event_type (
|
||||
name VARCHAR(30) NOT NULL UNIQUE,
|
||||
ID SERIAL PRIMARY KEY NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX librepages_deploy_event_name_index ON librepages_deploy_event_type(name);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS librepages_site_deploy_events (
|
||||
site INTEGER NOT NULL references librepages_sites(ID) ON DELETE CASCADE,
|
||||
event_type INTEGER NOT NULL references librepages_deploy_event_type(ID),
|
||||
time timestamptz NOT NULL,
|
||||
pub_id uuid NOT NULL UNIQUE,
|
||||
ID SERIAL PRIMARY KEY NOT NULL
|
||||
);
|
|
@ -347,6 +347,38 @@
|
|||
},
|
||||
"query": "SELECT email FROM librepages_users WHERE name = $1"
|
||||
},
|
||||
"e4adf1bc9175eeb9d61b495653bb452039cc38818c8792acdc6a1c732b6f4554": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "exists",
|
||||
"ordinal": 0,
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
null
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "SELECT EXISTS (SELECT 1 from librepages_deploy_event_type WHERE name = $1)"
|
||||
},
|
||||
"ed935cd75e805ddd7223ea8ba298ff94018cf305c519120279a5d1f7bb99e23e": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "INSERT INTO librepages_deploy_event_type\n (name) VALUES ($1);"
|
||||
},
|
||||
"faa4170a309f19a4abf1ca3f8dd3c0526945aa00f028ebf8bd7063825d448f5b": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
|
|
192
src/db.rs
192
src/db.rs
|
@ -19,10 +19,10 @@ use std::str::FromStr;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::postgres::PgPoolOptions;
|
||||
use sqlx::types::time::OffsetDateTime;
|
||||
//use sqlx::types::Json;
|
||||
use sqlx::ConnectOptions;
|
||||
use sqlx::PgPool;
|
||||
use tracing::error;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::errors::*;
|
||||
|
||||
|
@ -81,6 +81,7 @@ impl Database {
|
|||
.await
|
||||
.unwrap();
|
||||
//.map_err(|e| ServiceError::ServiceError(Box::new(e)))?;
|
||||
self.create_event_type().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -383,6 +384,139 @@ impl Database {
|
|||
|
||||
Ok(resp)
|
||||
}
|
||||
|
||||
/// check if event type exists
|
||||
async fn event_type_exists(&self, event: &Event) -> ServiceResult<bool> {
|
||||
let res = sqlx::query!(
|
||||
"SELECT EXISTS (SELECT 1 from librepages_deploy_event_type WHERE name = $1)",
|
||||
event.name,
|
||||
)
|
||||
.fetch_one(&self.pool)
|
||||
.await
|
||||
.map_err(map_register_err)?;
|
||||
|
||||
let mut resp = false;
|
||||
if let Some(x) = res.exists {
|
||||
resp = x;
|
||||
}
|
||||
|
||||
Ok(resp)
|
||||
}
|
||||
|
||||
async fn create_event_type(&self) -> ServiceResult<()> {
|
||||
for e in EVENTS {
|
||||
if !self.event_type_exists(&e).await? {
|
||||
sqlx::query!(
|
||||
"INSERT INTO librepages_deploy_event_type
|
||||
(name) VALUES ($1);",
|
||||
e.name
|
||||
)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
.map_err(map_register_err)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn log_event(&self, hostname: &str, event: &Event) -> ServiceResult<Uuid> {
|
||||
let now = now_unix_time_stamp();
|
||||
let uuid = Uuid::new_v4();
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO librepages_site_deploy_events
|
||||
(event_type, time, site, pub_id) VALUES (
|
||||
(SELECT iD from librepages_deploy_event_type WHERE name = $1),
|
||||
$2,
|
||||
(SELECT ID from librepages_sites WHERE hostname = $3),
|
||||
$4
|
||||
);
|
||||
",
|
||||
event.name,
|
||||
&now,
|
||||
hostname,
|
||||
uuid,
|
||||
)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
.map_err(map_register_err)?;
|
||||
Ok(uuid)
|
||||
}
|
||||
|
||||
pub async fn get_event(
|
||||
&self,
|
||||
hostname: &str,
|
||||
event_id: &Uuid,
|
||||
) -> ServiceResult<LibrePagesEvent> {
|
||||
let event = sqlx::query_as!(
|
||||
InnerLibrepagesEvent,
|
||||
"SELECT
|
||||
librepages_deploy_event_type.name,
|
||||
librepages_site_deploy_events.time,
|
||||
librepages_site_deploy_events.pub_id
|
||||
FROM
|
||||
librepages_site_deploy_events
|
||||
INNER JOIN librepages_deploy_event_type ON
|
||||
librepages_deploy_event_type.ID = librepages_site_deploy_events.event_type
|
||||
WHERE
|
||||
librepages_site_deploy_events.site = (
|
||||
SELECT ID FROM librepages_sites WHERE hostname = $1
|
||||
)
|
||||
AND
|
||||
librepages_site_deploy_events.pub_id = $2
|
||||
",
|
||||
hostname,
|
||||
event_id,
|
||||
)
|
||||
.fetch_one(&self.pool)
|
||||
.await
|
||||
.map_err(|e| map_row_not_found_err(e, ServiceError::AccountNotFound))?;
|
||||
|
||||
Ok(LibrePagesEvent {
|
||||
id: event.pub_id,
|
||||
time: event.time,
|
||||
event_type: Event::from_str(&event.name).unwrap(),
|
||||
site: hostname.to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn list_all_site_events(
|
||||
&self,
|
||||
hostname: &str,
|
||||
) -> ServiceResult<Vec<LibrePagesEvent>> {
|
||||
let mut inner_events = sqlx::query_as!(
|
||||
InnerLibrepagesEvent,
|
||||
"SELECT
|
||||
librepages_deploy_event_type.name,
|
||||
librepages_site_deploy_events.time,
|
||||
librepages_site_deploy_events.pub_id
|
||||
FROM
|
||||
librepages_site_deploy_events
|
||||
INNER JOIN librepages_deploy_event_type ON
|
||||
librepages_deploy_event_type.ID = librepages_site_deploy_events.event_type
|
||||
WHERE
|
||||
librepages_site_deploy_events.site = (
|
||||
SELECT ID FROM librepages_sites WHERE hostname = $1
|
||||
);
|
||||
",
|
||||
hostname,
|
||||
)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_err(|e| map_row_not_found_err(e, ServiceError::AccountNotFound))?;
|
||||
|
||||
let mut events = Vec::with_capacity(inner_events.len());
|
||||
|
||||
for e in inner_events.drain(0..) {
|
||||
events.push(LibrePagesEvent {
|
||||
id: e.pub_id,
|
||||
time: e.time,
|
||||
event_type: Event::from_str(&e.name).unwrap(),
|
||||
site: hostname.to_owned(),
|
||||
})
|
||||
}
|
||||
Ok(events)
|
||||
}
|
||||
}
|
||||
struct InnerSite {
|
||||
site_secret: String,
|
||||
|
@ -451,6 +585,40 @@ pub struct NameHash {
|
|||
pub hash: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Event {
|
||||
pub name: &'static str,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
const fn new(name: &'static str) -> Self {
|
||||
Self { name }
|
||||
}
|
||||
|
||||
pub fn from_str(name: &str) -> Option<Event> {
|
||||
EVENTS.into_iter().find(|e| e.name == name)
|
||||
}
|
||||
}
|
||||
pub const EVENT_TYPE_CREATE: Event = Event::new("site.event.create");
|
||||
pub const EVENT_TYPE_UPDATE: Event = Event::new("site.event.update");
|
||||
pub const EVENT_TYPE_DELETE: Event = Event::new("site.event.delete");
|
||||
|
||||
pub const EVENTS: [Event; 3] = [EVENT_TYPE_DELETE, EVENT_TYPE_DELETE, EVENT_TYPE_CREATE];
|
||||
|
||||
struct InnerLibrepagesEvent {
|
||||
name: String,
|
||||
time: OffsetDateTime,
|
||||
pub_id: Uuid,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct LibrePagesEvent {
|
||||
pub event_type: Event,
|
||||
pub time: OffsetDateTime,
|
||||
pub site: String,
|
||||
pub id: Uuid,
|
||||
}
|
||||
|
||||
fn now_unix_time_stamp() -> OffsetDateTime {
|
||||
OffsetDateTime::now_utc()
|
||||
}
|
||||
|
@ -637,6 +805,13 @@ mod tests {
|
|||
const PASSWORD: &str = "pasdfasdfasdfadf";
|
||||
|
||||
db.migrate().await.unwrap();
|
||||
|
||||
// check if events are created
|
||||
for e in EVENTS {
|
||||
println!("Testing event type exists {}", e.name);
|
||||
assert!(db.event_type_exists(&e).await.unwrap());
|
||||
}
|
||||
|
||||
let p = super::Register {
|
||||
username: NAME,
|
||||
email: EMAIL,
|
||||
|
@ -685,6 +860,21 @@ mod tests {
|
|||
assert_eq!(db_sites.len(), 1);
|
||||
assert_eq!(db_sites, vec![site.clone()]);
|
||||
|
||||
// add event to site
|
||||
let event_id = db
|
||||
.log_event(&site.hostname, &EVENT_TYPE_CREATE)
|
||||
.await
|
||||
.unwrap();
|
||||
let event = db.get_event(&site.hostname, &event_id).await.unwrap();
|
||||
assert_eq!(event.id, event_id);
|
||||
assert_eq!(event.event_type, EVENT_TYPE_CREATE);
|
||||
assert_eq!(event.site, site.hostname);
|
||||
|
||||
assert_eq!(
|
||||
db.list_all_site_events(&site.hostname).await.unwrap(),
|
||||
vec![event]
|
||||
);
|
||||
|
||||
// delete site
|
||||
db.delete_site(p.username, &site.hostname).await.unwrap();
|
||||
|
||||
|
|
Loading…
Reference in New Issue