Skip to content

Dan notifications backwards compatible #1531

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pgml-dashboard/src/components/layouts/head/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ mod default_head_template_test {

#[test]
fn set_head() {
let mut head = Head::new()
let head = Head::new()
.title("test title")
.description("test description")
.image("image/test_image.jpg");
Expand Down
12 changes: 5 additions & 7 deletions pgml-dashboard/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,12 +407,10 @@ pub fn replace_banner_product(

Notifications::update_viewed(&all_notification_cookies, cookies);

// Get the notification that triggered this call..
// unwrap notifications if fine since we should panic if this is missing.
let last_notification = context
let last_notification: Option<Notification> = context
.notifications
.as_ref()
.unwrap()
.unwrap_or(&vec![] as &Vec<Notification>)
.clone()
.into_iter()
.find(|n: &Notification| -> bool { n.id == id });
Expand Down Expand Up @@ -562,7 +560,7 @@ mod test {
.time_modal_viewed;

// Update modal view time for existing notification cookie
assert_eq!(time_modal_viewed.is_some(), true);
assert!(time_modal_viewed.is_some());

let response = client
.get("/notifications/product/modal/remove_modal?id=3")
Expand All @@ -576,7 +574,7 @@ mod test {
.time_modal_viewed;

// Update modal view time for new notification cookie
assert_eq!(time_modal_viewed.is_some(), true);
assert!(time_modal_viewed.is_some());
}

#[sqlx::test]
Expand Down Expand Up @@ -623,7 +621,7 @@ mod test {
.time_viewed;

// Update view time for new notification cookie
assert_eq!(time_viewed.is_some(), true);
assert!(time_viewed.is_some());
}

#[sqlx::test]
Expand Down
78 changes: 43 additions & 35 deletions pgml-dashboard/src/utils/cookies.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,52 @@
use chrono;
use rocket::http::{Cookie, CookieJar};
use rocket::serde::{Deserialize, Serialize};
use time::Duration;

/// Session data.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Notifications {
/// App-wide notifications.
notifications: Vec<NotificationCookie>,
}

/// App-wide notifications.
#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq)]
pub struct NotificationCookie {
/// Unique ID of the notification.
pub id: String,
/// Time the notification was viewed. Used for reshowing the notification.
pub time_viewed: Option<chrono::DateTime<chrono::Utc>>,
/// Time the notification modal was viewed. Used for reshowing the notification modal.
pub time_modal_viewed: Option<chrono::DateTime<chrono::Utc>>,
}

pub struct Notifications {}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct NotificationsCookieOld {
pub notifications: Vec<String>,
}

impl From<NotificationsCookieOld> for NotificationCookie {
fn from(old: NotificationsCookieOld) -> Self {
NotificationCookie {
id: old.notifications[0].clone(),
time_viewed: None,
time_modal_viewed: None,
}
}
}

impl Notifications {
pub fn update_viewed(all_desired_notifications: &Vec<NotificationCookie>, cookies: &CookieJar<'_>) {
let session = Notifications::safe_serialize_session(all_desired_notifications);
/// Update the viewed notifications in the session.
pub fn update_viewed(notifications: &[NotificationCookie], cookies: &CookieJar<'_>) {
let session = Notifications::safe_serialize_session(notifications);

let mut cookie = Cookie::new("session", session);
cookie.set_max_age(::time::Duration::weeks(4));
cookie.set_max_age(Duration::weeks(52 * 100)); // Keep the cookie "forever"
cookies.add_private(cookie);
}

/// Get viewed notifications from the session.
pub fn get_viewed(cookies: &CookieJar<'_>) -> Vec<NotificationCookie> {
match cookies.get_private("session") {
Some(session) => Notifications::safe_deserialize_session(session.value()),
Expand All @@ -28,40 +55,21 @@ impl Notifications {
}

pub fn safe_deserialize_session(session: &str) -> Vec<NotificationCookie> {
match serde_json::from_str::<serde_json::Value>(session).unwrap_or_else(|_| {
serde_json::from_str::<serde_json::Value>(&Notifications::safe_serialize_session(&vec![])).unwrap()
})["notifications"]
.as_array()
{
Some(items) => items
.into_iter()
.map(|notification| {
serde_json::from_str::<NotificationCookie>(&notification.to_string()).unwrap_or_else(|_| {
serde_json::from_str::<String>(&notification.to_string())
.and_then(|id| {
Ok(NotificationCookie {
id,
time_viewed: None,
time_modal_viewed: None,
})
})
.unwrap_or_else(|_| NotificationCookie::default())
})
})
.collect::<Vec<NotificationCookie>>(),
_ => vec![],
match serde_json::from_str::<Notifications>(session) {
Ok(notifications) => notifications.notifications,
Err(_) => match serde_json::from_str::<NotificationsCookieOld>(session) {
Ok(notifications) => vec![NotificationCookie::from(notifications)],
Err(_) => vec![],
},
}
}

pub fn safe_serialize_session(cookies: &Vec<NotificationCookie>) -> String {
let serialized = cookies
.iter()
.map(|x| serde_json::to_string(x))
.filter(|x| x.is_ok())
.map(|x| x.unwrap())
.collect::<Vec<String>>();
pub fn safe_serialize_session(notifications: &[NotificationCookie]) -> String {
let notifications = Notifications {
notifications: notifications.to_vec(),
};

format!(r#"{{"notifications": [{}]}}"#, serialized.join(","))
serde_json::to_string(&notifications).unwrap()
}
}

Expand Down Expand Up @@ -118,7 +126,7 @@ mod test {
time_viewed: None,
time_modal_viewed: None,
}];
let expected = r#"{"notifications": [{"id":"1","time_viewed":null,"time_modal_viewed":null}]}"#;
let expected = r#"{"notifications":[{"id":"1","time_viewed":null,"time_modal_viewed":null}]}"#;
assert_eq!(Notifications::safe_serialize_session(&cookies), expected);
}
}