forked from trustification/trustification
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TC-1672 Dashboard - User Preferences back end (trustification#1695)
* TC-1672 sqllite db init * chore: user reset endpoint * suggest changes Signed-off-by: carlosthe19916 <[email protected]> --------- Signed-off-by: carlosthe19916 <[email protected]> Co-authored-by: carlosthe19916 <[email protected]>
- Loading branch information
1 parent
aee88ab
commit ef7e39c
Showing
18 changed files
with
396 additions
and
13 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,32 @@ | ||
use actix_http::body::BoxBody; | ||
use actix_http::StatusCode; | ||
use actix_web::http::header::ContentType; | ||
use actix_web::{HttpResponse, ResponseError}; | ||
use trustification_common::error::ErrorInformation; | ||
|
||
#[derive(Debug, thiserror::Error)] | ||
pub enum Error { | ||
#[error(transparent)] | ||
OpenId(#[from] openid::error::Error), | ||
} | ||
|
||
impl ResponseError for Error { | ||
fn status_code(&self) -> StatusCode { | ||
match self { | ||
Error::OpenId(_) => StatusCode::UNAUTHORIZED, | ||
} | ||
} | ||
|
||
fn error_response(&self) -> HttpResponse<BoxBody> { | ||
let mut res = HttpResponse::build(self.status_code()); | ||
res.insert_header(ContentType::json()); | ||
|
||
match self { | ||
Error::OpenId(openid) => res.json(ErrorInformation { | ||
error: format!("{}", self.status_code()), | ||
message: format!("{}", openid), | ||
details: openid.to_string(), | ||
}), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
deploy/k8s/charts/trustification/templates/helpers/_preferences.tpl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{{/* | ||
Volume mounts for the user preferences configuration. | ||
Arguments (dict): | ||
* root - . | ||
* module - module object | ||
*/}} | ||
{{- define "trustification.preferences.db.volumeMount" }} | ||
- name: user-preferences-db-path | ||
mountPath: /data/db/ | ||
{{- end }} | ||
|
||
|
||
{{/* | ||
Volume for the user preferences data. | ||
*/}} | ||
{{- define "trustification.preferences.db.volume" }} | ||
- name: user-preferences-db-path | ||
persistentVolumeClaim: | ||
claimName: user-preferences-db-path | ||
{{- end }} | ||
|
||
{{/* | ||
db path | ||
*/}} | ||
{{- define "trustification.preferences.db.path" -}} | ||
/data/db/ | ||
{{- end }} |
15 changes: 15 additions & 0 deletions
15
deploy/k8s/charts/trustification/templates/services/spog/api/010-PersistentVolumeClaim.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{{- if .Values.modules.spogApi.enabled }} | ||
{{- $mod := dict "root" . "name" "user-preferences-db-path" "component" "spog" "module" .Values.modules.spogApi -}} | ||
kind: PersistentVolumeClaim | ||
apiVersion: v1 | ||
metadata: | ||
name: {{ include "trustification.common.name" $mod }} | ||
labels: | ||
{{- include "trustification.common.labels" $mod | nindent 4 }} | ||
spec: | ||
accessModes: | ||
- ReadWriteOnce | ||
resources: | ||
requests: | ||
storage: {{ $mod.module.storageSize | default "10Mi" | quote }} | ||
{{end}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
use actix_web::body::BoxBody; | ||
use actix_web::http::header::ContentType; | ||
use actix_web::{HttpResponse, ResponseError}; | ||
use http::StatusCode; | ||
use spog_model::dashboard::UserPreferences; | ||
use sqlx::sqlite::SqliteConnectOptions; | ||
use sqlx::{Row, SqlitePool}; | ||
use std::path::Path; | ||
use std::str::FromStr; | ||
use trustification_common::error::ErrorInformation; | ||
|
||
#[allow(dead_code)] | ||
static DB_FILE_NAME: &str = "preferences.db"; | ||
|
||
#[allow(dead_code)] | ||
pub struct Db { | ||
pool: SqlitePool, | ||
} | ||
|
||
#[derive(Debug, thiserror::Error)] | ||
pub enum Error { | ||
#[error("JSON parse error: {0}")] | ||
Json(#[from] serde_json::Error), | ||
#[error("data base error: {0}")] | ||
Db(#[from] sqlx::Error), | ||
} | ||
|
||
impl ResponseError for Error { | ||
fn status_code(&self) -> StatusCode { | ||
match self { | ||
Error::Json(_) => StatusCode::INTERNAL_SERVER_ERROR, | ||
Error::Db(_) => StatusCode::INTERNAL_SERVER_ERROR, | ||
} | ||
} | ||
|
||
fn error_response(&self) -> HttpResponse<BoxBody> { | ||
let mut res = HttpResponse::build(self.status_code()); | ||
res.insert_header(ContentType::json()); | ||
|
||
match self { | ||
Error::Json(json) => res.json(ErrorInformation { | ||
error: format!("{}", self.status_code()), | ||
message: format!("{}", json), | ||
details: json.to_string(), | ||
}), | ||
Error::Db(db) => res.json(ErrorInformation { | ||
error: format!("{}", self.status_code()), | ||
message: format!("{}", db), | ||
details: db.to_string(), | ||
}), | ||
} | ||
} | ||
} | ||
|
||
impl Db { | ||
#[allow(dead_code)] | ||
pub async fn new(base: impl AsRef<Path>) -> Result<Self, Error> { | ||
let db = Self { | ||
pool: SqlitePool::connect_with(if cfg!(test) { | ||
SqliteConnectOptions::from_str(":memory:")? | ||
} else { | ||
SqliteConnectOptions::default() | ||
.filename(base.as_ref().join(DB_FILE_NAME)) | ||
.create_if_missing(true) | ||
}) | ||
.await?, | ||
}; | ||
db.initialize().await?; | ||
Ok(db) | ||
} | ||
|
||
#[allow(dead_code)] | ||
async fn initialize(&self) -> Result<(), Error> { | ||
self.create_user_preferences_table().await?; | ||
Ok(()) | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub async fn create_user_preferences_table(&self) -> Result<(), Error> { | ||
sqlx::query( | ||
r#"CREATE TABLE IF NOT EXISTS preferences ( | ||
user_id TEXT, | ||
preference TEXT | ||
)"#, | ||
) | ||
.execute(&self.pool) | ||
.await?; | ||
|
||
sqlx::query( | ||
r#" | ||
create unique index if not exists user_id_idx on preferences ( user_id ) ; | ||
"#, | ||
) | ||
.execute(&self.pool) | ||
.await?; | ||
|
||
Ok(()) | ||
} | ||
#[allow(dead_code)] | ||
pub async fn update_user_preferences(&self, preferences: UserPreferences) -> Result<(), Error> { | ||
let content = preferences.preferences.unwrap_or_default(); | ||
|
||
sqlx::query( | ||
r#" | ||
INSERT OR REPLACE INTO preferences ( user_id, preference) | ||
VALUES ($1, $2); | ||
"#, | ||
) | ||
.bind(preferences.user_id) | ||
.bind(serde_json::to_string(&content).unwrap_or_default()) | ||
.execute(&self.pool) | ||
.await?; | ||
|
||
Ok(()) | ||
} | ||
#[allow(dead_code)] | ||
pub async fn select_preferences_by_user_id(&self, user_id: String) -> Result<UserPreferences, Error> { | ||
let result = sqlx::query( | ||
r#" | ||
select user_id, preference from preferences where user_id = $1; | ||
"#, | ||
) | ||
.bind(user_id) | ||
.fetch_all(&self.pool) | ||
.await?; | ||
|
||
if result.is_empty() { | ||
Ok(UserPreferences::default()) | ||
} else { | ||
let p = UserPreferences { | ||
user_id: result[0].get("user_id"), | ||
preferences: serde_json::from_str(result[0].get("preference"))?, | ||
}; | ||
Ok(p) | ||
} | ||
} | ||
} | ||
#[cfg(test)] | ||
mod test { | ||
use crate::db::Db; | ||
use spog_model::dashboard::{Preferences, UserPreferences}; | ||
#[actix_web::test] | ||
async fn update_user_preferences() -> Result<(), anyhow::Error> { | ||
let pre_preferences = Preferences { | ||
sbom1: Some("11".to_string()), | ||
sbom2: Some("21".to_string()), | ||
sbom3: Some("31".to_string()), | ||
sbom4: Some("41".to_string()), | ||
}; | ||
|
||
let post_preferences = Preferences { | ||
sbom1: Some("1".to_string()), | ||
sbom2: Some("2".to_string()), | ||
sbom3: Some("3".to_string()), | ||
sbom4: Some("4".to_string()), | ||
}; | ||
|
||
let db = Db::new(".").await?; | ||
db.update_user_preferences(UserPreferences { | ||
user_id: "xiabai".to_string(), | ||
preferences: Some(pre_preferences.clone()), | ||
}) | ||
.await?; | ||
db.update_user_preferences(UserPreferences { | ||
user_id: "user1".to_string(), | ||
preferences: Some(pre_preferences.clone()), | ||
}) | ||
.await?; | ||
|
||
let result = db.select_preferences_by_user_id("user1".to_string()).await?; | ||
assert_eq!("user1", result.user_id); | ||
assert_eq!( | ||
"11".to_string(), | ||
result.preferences.unwrap_or_default().sbom1.unwrap_or_default() | ||
); | ||
|
||
db.update_user_preferences(UserPreferences { | ||
user_id: "user1".to_string(), | ||
preferences: Some(post_preferences.clone()), | ||
}) | ||
.await?; | ||
|
||
let result = db.select_preferences_by_user_id("xiabai".to_string()).await?; | ||
assert_eq!("xiabai", result.user_id); | ||
|
||
let result = db.select_preferences_by_user_id("user1".to_string()).await?; | ||
assert_eq!("user1", result.user_id); | ||
assert_eq!( | ||
"1".to_string(), | ||
result.preferences.unwrap_or_default().sbom1.unwrap_or_default() | ||
); | ||
Ok(()) | ||
} | ||
} |
Oops, something went wrong.