mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2024-12-23 03:19:03 +00:00
Clean up datetime output and code
* For clarity, add `UTC` suffix for datetimes in the `Diagnostics` admin tab. * Format datetimes in the local timezone in the `Users` admin tab. * Refactor some datetime code and add doc comments.
This commit is contained in:
parent
219a9d9f5e
commit
455a23361f
@ -18,7 +18,7 @@ use crate::{
|
|||||||
db::{backup_database, models::*, DbConn, DbConnType},
|
db::{backup_database, models::*, DbConn, DbConnType},
|
||||||
error::{Error, MapResult},
|
error::{Error, MapResult},
|
||||||
mail,
|
mail,
|
||||||
util::get_display_size,
|
util::{get_display_size, format_naive_datetime_local},
|
||||||
CONFIG,
|
CONFIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -293,6 +293,7 @@ fn get_users_json(_token: AdminToken, conn: DbConn) -> JsonResult {
|
|||||||
#[get("/users/overview")]
|
#[get("/users/overview")]
|
||||||
fn users_overview(_token: AdminToken, conn: DbConn) -> ApiResult<Html<String>> {
|
fn users_overview(_token: AdminToken, conn: DbConn) -> ApiResult<Html<String>> {
|
||||||
let users = User::get_all(&conn);
|
let users = User::get_all(&conn);
|
||||||
|
let dt_fmt = "%Y-%m-%d %H:%M:%S %Z";
|
||||||
let users_json: Vec<Value> = users.iter()
|
let users_json: Vec<Value> = users.iter()
|
||||||
.map(|u| {
|
.map(|u| {
|
||||||
let mut usr = u.to_json(&conn);
|
let mut usr = u.to_json(&conn);
|
||||||
@ -300,9 +301,9 @@ fn users_overview(_token: AdminToken, conn: DbConn) -> ApiResult<Html<String>> {
|
|||||||
usr["attachment_count"] = json!(Attachment::count_by_user(&u.uuid, &conn));
|
usr["attachment_count"] = json!(Attachment::count_by_user(&u.uuid, &conn));
|
||||||
usr["attachment_size"] = json!(get_display_size(Attachment::size_by_user(&u.uuid, &conn) as i32));
|
usr["attachment_size"] = json!(get_display_size(Attachment::size_by_user(&u.uuid, &conn) as i32));
|
||||||
usr["user_enabled"] = json!(u.enabled);
|
usr["user_enabled"] = json!(u.enabled);
|
||||||
usr["created_at"] = json!(&u.created_at.format("%Y-%m-%d %H:%M:%S").to_string());
|
usr["created_at"] = json!(format_naive_datetime_local(&u.created_at, dt_fmt));
|
||||||
usr["last_active"] = match u.last_active(&conn) {
|
usr["last_active"] = match u.last_active(&conn) {
|
||||||
Some(timestamp) => json!(timestamp.format("%Y-%m-%d %H:%M:%S").to_string()),
|
Some(dt) => json!(format_naive_datetime_local(&dt, dt_fmt)),
|
||||||
None => json!("Never")
|
None => json!("Never")
|
||||||
};
|
};
|
||||||
usr
|
usr
|
||||||
@ -446,7 +447,7 @@ fn diagnostics(_token: AdminToken, _conn: DbConn) -> ApiResult<Html<String>> {
|
|||||||
// Run the date check as the last item right before filling the json.
|
// Run the date check as the last item right before filling the json.
|
||||||
// This should ensure that the time difference between the browser and the server is as minimal as possible.
|
// This should ensure that the time difference between the browser and the server is as minimal as possible.
|
||||||
let dt = Utc::now();
|
let dt = Utc::now();
|
||||||
let server_time = dt.format("%Y-%m-%d %H:%M:%S").to_string();
|
let server_time = dt.format("%Y-%m-%d %H:%M:%S UTC").to_string();
|
||||||
|
|
||||||
let diagnostics_json = json!({
|
let diagnostics_json = json!({
|
||||||
"dns_resolved": dns_resolved,
|
"dns_resolved": dns_resolved,
|
||||||
|
22
src/mail.rs
22
src/mail.rs
@ -1,7 +1,6 @@
|
|||||||
use std::{env, str::FromStr};
|
use std::{str::FromStr};
|
||||||
|
|
||||||
use chrono::{DateTime, Local};
|
use chrono::{DateTime, Local};
|
||||||
use chrono_tz::Tz;
|
|
||||||
use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
|
use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
|
||||||
|
|
||||||
use lettre::{
|
use lettre::{
|
||||||
@ -107,22 +106,6 @@ fn get_template(template_name: &str, data: &serde_json::Value) -> Result<(String
|
|||||||
Ok((subject, body))
|
Ok((subject, body))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_datetime(dt: &DateTime<Local>) -> String {
|
|
||||||
let fmt = "%A, %B %_d, %Y at %r %Z";
|
|
||||||
|
|
||||||
// With a DateTime<Local>, `%Z` formats as the time zone's UTC offset
|
|
||||||
// (e.g., `+00:00`). If the `TZ` environment variable is set, try to
|
|
||||||
// format as a time zone abbreviation instead (e.g., `UTC`).
|
|
||||||
if let Ok(tz) = env::var("TZ") {
|
|
||||||
if let Ok(tz) = tz.parse::<Tz>() {
|
|
||||||
return dt.with_timezone(&tz).format(fmt).to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, fall back to just displaying the UTC offset.
|
|
||||||
dt.format(fmt).to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_password_hint(address: &str, hint: Option<String>) -> EmptyResult {
|
pub fn send_password_hint(address: &str, hint: Option<String>) -> EmptyResult {
|
||||||
let template_name = if hint.is_some() {
|
let template_name = if hint.is_some() {
|
||||||
"email/pw_hint_some"
|
"email/pw_hint_some"
|
||||||
@ -257,13 +240,14 @@ pub fn send_new_device_logged_in(address: &str, ip: &str, dt: &DateTime<Local>,
|
|||||||
use crate::util::upcase_first;
|
use crate::util::upcase_first;
|
||||||
let device = upcase_first(device);
|
let device = upcase_first(device);
|
||||||
|
|
||||||
|
let fmt = "%A, %B %_d, %Y at %r %Z";
|
||||||
let (subject, body_html, body_text) = get_text(
|
let (subject, body_html, body_text) = get_text(
|
||||||
"email/new_device_logged_in",
|
"email/new_device_logged_in",
|
||||||
json!({
|
json!({
|
||||||
"url": CONFIG.domain(),
|
"url": CONFIG.domain(),
|
||||||
"ip": ip,
|
"ip": ip,
|
||||||
"device": device,
|
"device": device,
|
||||||
"datetime": format_datetime(dt),
|
"datetime": crate::util::format_datetime_local(dt, fmt),
|
||||||
}),
|
}),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
const hour = String(d.getUTCHours()).padStart(2, '0');
|
const hour = String(d.getUTCHours()).padStart(2, '0');
|
||||||
const minute = String(d.getUTCMinutes()).padStart(2, '0');
|
const minute = String(d.getUTCMinutes()).padStart(2, '0');
|
||||||
const seconds = String(d.getUTCSeconds()).padStart(2, '0');
|
const seconds = String(d.getUTCSeconds()).padStart(2, '0');
|
||||||
const browserUTC = year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + seconds;
|
const browserUTC = `${year}-${month}-${day} ${hour}:${minute}:${seconds} UTC`;
|
||||||
document.getElementById("time-browser-string").innerText = browserUTC;
|
document.getElementById("time-browser-string").innerText = browserUTC;
|
||||||
|
|
||||||
const serverUTC = document.getElementById("time-server-string").innerText;
|
const serverUTC = document.getElementById("time-server-string").innerText;
|
||||||
@ -147,4 +147,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
36
src/util.rs
36
src/util.rs
@ -322,12 +322,40 @@ pub fn get_env_bool(key: &str) -> Option<bool> {
|
|||||||
// Date util methods
|
// Date util methods
|
||||||
//
|
//
|
||||||
|
|
||||||
use chrono::NaiveDateTime;
|
use chrono::{DateTime, Local, NaiveDateTime, TimeZone};
|
||||||
|
use chrono_tz::Tz;
|
||||||
|
|
||||||
const DATETIME_FORMAT: &str = "%Y-%m-%dT%H:%M:%S%.6fZ";
|
/// Formats a UTC-offset `NaiveDateTime` in the format used by Bitwarden API
|
||||||
|
/// responses with "date" fields (`CreationDate`, `RevisionDate`, etc.).
|
||||||
|
pub fn format_date(dt: &NaiveDateTime) -> String {
|
||||||
|
dt.format("%Y-%m-%dT%H:%M:%S%.6fZ").to_string()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn format_date(date: &NaiveDateTime) -> String {
|
/// Formats a `DateTime<Local>` using the specified format string.
|
||||||
date.format(DATETIME_FORMAT).to_string()
|
///
|
||||||
|
/// For a `DateTime<Local>`, the `%Z` specifier normally formats as the
|
||||||
|
/// time zone's UTC offset (e.g., `+00:00`). In this function, if the
|
||||||
|
/// `TZ` environment variable is set, then `%Z` instead formats as the
|
||||||
|
/// abbreviation for that time zone (e.g., `UTC`).
|
||||||
|
pub fn format_datetime_local(dt: &DateTime<Local>, fmt: &str) -> String {
|
||||||
|
// Try parsing the `TZ` environment variable to enable formatting `%Z` as
|
||||||
|
// a time zone abbreviation.
|
||||||
|
if let Ok(tz) = env::var("TZ") {
|
||||||
|
if let Ok(tz) = tz.parse::<Tz>() {
|
||||||
|
return dt.with_timezone(&tz).format(fmt).to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, fall back to formatting `%Z` as a UTC offset.
|
||||||
|
dt.format(fmt).to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats a UTC-offset `NaiveDateTime` as a datetime in the local time zone.
|
||||||
|
///
|
||||||
|
/// This function basically converts the `NaiveDateTime` to a `DateTime<Local>`,
|
||||||
|
/// and then calls [format_datetime_local](crate::util::format_datetime_local).
|
||||||
|
pub fn format_naive_datetime_local(dt: &NaiveDateTime, fmt: &str) -> String {
|
||||||
|
format_datetime_local(&Local.from_utc_datetime(dt), fmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user