From a7ef71ba1f661688d61dca7484c9275c2e8766ca Mon Sep 17 00:00:00 2001 From: Stefan Melmuk Date: Sun, 22 Dec 2024 15:56:18 +0100 Subject: [PATCH] less boilerplate by using derive_more --- Cargo.lock | 22 ++++++ Cargo.toml | 2 + src/api/identity.rs | 2 +- src/api/notifications.rs | 2 +- src/db/models/attachment.rs | 40 +---------- src/db/models/cipher.rs | 42 ++--------- src/db/models/collection.rs | 42 ++--------- src/db/models/device.rs | 101 ++++++++------------------- src/db/models/folder.rs | 42 ++--------- src/db/models/group.rs | 42 ++--------- src/db/models/organization.rs | 127 +++------------------------------- src/db/models/user.rs | 44 ++---------- src/mail.rs | 12 +++- 13 files changed, 99 insertions(+), 421 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c15428a9f3..bc68767d82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -721,6 +721,27 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "devise" version = "0.4.2" @@ -3970,6 +3991,7 @@ dependencies = [ "dashmap", "data-encoding", "data-url", + "derive_more", "diesel", "diesel-derive-newtype", "diesel_logger", diff --git a/Cargo.toml b/Cargo.toml index 12ab7229e7..79cda3bb73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,6 +77,8 @@ serde_json = "1.0.133" diesel = { version = "2.2.6", features = ["chrono", "r2d2", "numeric"] } diesel_migrations = "2.2.0" diesel_logger = { version = "0.4.0", optional = true } + +derive_more = { version = "1.0.0", features = ["from", "into", "as_ref", "deref", "display"] } diesel-derive-newtype = "2.1.2" # Bundled/Static SQLite diff --git a/src/api/identity.rs b/src/api/identity.rs index 5cdef8796f..27bb8ab42c 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -385,7 +385,7 @@ async fn _user_api_key_login( let Some(client_user_uuid) = client_id.strip_prefix("user.") else { err!("Malformed client_id", format!("IP: {}.", ip.ip)) }; - let client_user_uuid: UserId = client_user_uuid.to_string().into(); + let client_user_uuid: UserId = client_user_uuid.into(); let Some(user) = User::find_by_uuid(&client_user_uuid, conn).await else { err!("Invalid client_id", format!("IP: {}.", ip.ip)) }; diff --git a/src/api/notifications.rs b/src/api/notifications.rs index 6c1e2b49f8..30ca79d539 100644 --- a/src/api/notifications.rs +++ b/src/api/notifications.rs @@ -72,7 +72,7 @@ impl WSEntryMapGuard { impl Drop for WSEntryMapGuard { fn drop(&mut self) { info!("Closing WS connection from {}", self.addr); - if let Some(mut entry) = self.users.map.get_mut(&self.user_uuid.to_string()) { + if let Some(mut entry) = self.users.map.get_mut(self.user_uuid.as_ref()) { entry.retain(|(uuid, _)| uuid != &self.entry_uuid); } } diff --git a/src/db/models/attachment.rs b/src/db/models/attachment.rs index 90d90ad702..c86bd636e7 100644 --- a/src/db/models/attachment.rs +++ b/src/db/models/attachment.rs @@ -1,13 +1,9 @@ use std::io::ErrorKind; use bigdecimal::{BigDecimal, ToPrimitive}; +use derive_more::{AsRef, Deref, Display}; use rocket::request::FromParam; use serde_json::Value; -use std::{ - borrow::Borrow, - fmt::{Display, Formatter}, - ops::Deref, -}; use super::{CipherId, OrganizationId, UserId}; use crate::CONFIG; @@ -234,41 +230,9 @@ impl Attachment { } } -#[derive(DieselNewType, FromForm, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, AsRef, Deref, DieselNewType, Display, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct AttachmentId(pub String); -impl AsRef for AttachmentId { - fn as_ref(&self) -> &str { - &self.0 - } -} - -impl Deref for AttachmentId { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Borrow for AttachmentId { - fn borrow(&self) -> &str { - &self.0 - } -} - -impl Display for AttachmentId { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl From for AttachmentId { - fn from(raw: String) -> Self { - Self(raw) - } -} - impl<'r> FromParam<'r> for AttachmentId { type Error = (); diff --git a/src/db/models/cipher.rs b/src/db/models/cipher.rs index 933b50eeed..06728f97a5 100644 --- a/src/db/models/cipher.rs +++ b/src/db/models/cipher.rs @@ -1,13 +1,9 @@ use crate::util::LowerCase; use crate::CONFIG; use chrono::{NaiveDateTime, TimeDelta, Utc}; +use derive_more::{AsRef, Deref, Display, From}; use rocket::request::FromParam; use serde_json::Value; -use std::{ - borrow::Borrow, - fmt::{Display, Formatter}, - ops::Deref, -}; use super::{ Attachment, CollectionCipher, CollectionId, Favorite, FolderCipher, FolderId, Group, Membership, MembershipStatus, @@ -1034,41 +1030,11 @@ impl Cipher { } } -#[derive(DieselNewType, FromForm, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive( + Clone, Debug, AsRef, Deref, DieselNewType, Display, From, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize, +)] pub struct CipherId(String); -impl AsRef for CipherId { - fn as_ref(&self) -> &str { - &self.0 - } -} - -impl Deref for CipherId { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Borrow for CipherId { - fn borrow(&self) -> &str { - &self.0 - } -} - -impl Display for CipherId { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl From for CipherId { - fn from(raw: String) -> Self { - Self(raw) - } -} - impl<'r> FromParam<'r> for CipherId { type Error = (); diff --git a/src/db/models/collection.rs b/src/db/models/collection.rs index 52d23fa6ef..7d94f9d54e 100644 --- a/src/db/models/collection.rs +++ b/src/db/models/collection.rs @@ -1,10 +1,6 @@ +use derive_more::{AsRef, Deref, Display, From}; use rocket::request::FromParam; use serde_json::Value; -use std::{ - borrow::Borrow, - fmt::{Display, Formatter}, - ops::Deref, -}; use super::{ CipherId, CollectionGroup, GroupUser, Membership, MembershipStatus, MembershipType, OrganizationId, User, UserId, @@ -790,41 +786,11 @@ impl CollectionUser { } } -#[derive(DieselNewType, FromForm, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive( + Clone, Debug, AsRef, Deref, DieselNewType, Display, From, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize, +)] pub struct CollectionId(String); -impl AsRef for CollectionId { - fn as_ref(&self) -> &str { - &self.0 - } -} - -impl Deref for CollectionId { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Borrow for CollectionId { - fn borrow(&self) -> &str { - &self.0 - } -} - -impl Display for CollectionId { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl From for CollectionId { - fn from(raw: String) -> Self { - Self(raw) - } -} - impl<'r> FromParam<'r> for CollectionId { type Error = (); diff --git a/src/db/models/device.rs b/src/db/models/device.rs index 267a3141e0..69c96bec0d 100644 --- a/src/db/models/device.rs +++ b/src/db/models/device.rs @@ -1,14 +1,9 @@ use chrono::{NaiveDateTime, Utc}; +use derive_more::{Display, From}; use rocket::request::FromParam; -use std::{ - borrow::Borrow, - fmt::{Display, Formatter}, - ops::Deref, -}; use super::UserId; use crate::{crypto, CONFIG}; -use core::fmt; db_object! { #[derive(Identifiable, Queryable, Insertable, AsChangeset)] @@ -250,68 +245,62 @@ impl Device { } } +#[derive(Display)] pub enum DeviceType { + #[display("Android")] Android = 0, + #[display("iOS")] Ios = 1, + #[display("Chrome Extension")] ChromeExtension = 2, + #[display("Firefox Extension")] FirefoxExtension = 3, + #[display("Opera Extension")] OperaExtension = 4, + #[display("Edge Extension")] EdgeExtension = 5, + #[display("Windows")] WindowsDesktop = 6, + #[display("macOS")] MacOsDesktop = 7, + #[display("Linux")] LinuxDesktop = 8, + #[display("Chrome")] ChromeBrowser = 9, + #[display("Firefox")] FirefoxBrowser = 10, + #[display("Opera")] OperaBrowser = 11, + #[display("Edge")] EdgeBrowser = 12, + #[display("Internet Explorer")] IEBrowser = 13, + #[display("Unknown Browser")] UnknownBrowser = 14, + #[display("Android")] AndroidAmazon = 15, + #[display("UWP")] Uwp = 16, + #[display("Safari")] SafariBrowser = 17, + #[display("Vivaldi")] VivaldiBrowser = 18, + #[display("Vivaldi Extension")] VivaldiExtension = 19, + #[display("Safari Extension")] SafariExtension = 20, + #[display("SDK")] Sdk = 21, + #[display("Server")] Server = 22, + #[display("Windows CLI")] WindowsCLI = 23, + #[display("macOS CLI")] MacOsCLI = 24, + #[display("Linux CLI")] LinuxCLI = 25, } -impl Display for DeviceType { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - DeviceType::Android => write!(f, "Android"), - DeviceType::Ios => write!(f, "iOS"), - DeviceType::ChromeExtension => write!(f, "Chrome Extension"), - DeviceType::FirefoxExtension => write!(f, "Firefox Extension"), - DeviceType::OperaExtension => write!(f, "Opera Extension"), - DeviceType::EdgeExtension => write!(f, "Edge Extension"), - DeviceType::WindowsDesktop => write!(f, "Windows"), - DeviceType::MacOsDesktop => write!(f, "macOS"), - DeviceType::LinuxDesktop => write!(f, "Linux"), - DeviceType::ChromeBrowser => write!(f, "Chrome"), - DeviceType::FirefoxBrowser => write!(f, "Firefox"), - DeviceType::OperaBrowser => write!(f, "Opera"), - DeviceType::EdgeBrowser => write!(f, "Edge"), - DeviceType::IEBrowser => write!(f, "Internet Explorer"), - DeviceType::UnknownBrowser => write!(f, "Unknown Browser"), - DeviceType::AndroidAmazon => write!(f, "Android"), - DeviceType::Uwp => write!(f, "UWP"), - DeviceType::SafariBrowser => write!(f, "Safari"), - DeviceType::VivaldiBrowser => write!(f, "Vivaldi"), - DeviceType::VivaldiExtension => write!(f, "Vivaldi Extension"), - DeviceType::SafariExtension => write!(f, "Safari Extension"), - DeviceType::Sdk => write!(f, "SDK"), - DeviceType::Server => write!(f, "Server"), - DeviceType::WindowsCLI => write!(f, "Windows CLI"), - DeviceType::MacOsCLI => write!(f, "macOS CLI"), - DeviceType::LinuxCLI => write!(f, "Linux CLI"), - } - } -} - impl DeviceType { pub fn from_i32(value: i32) -> DeviceType { match value { @@ -346,7 +335,7 @@ impl DeviceType { } } -#[derive(DieselNewType, FromForm, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, DieselNewType, Display, From, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct DeviceId(String); impl DeviceId { @@ -355,38 +344,6 @@ impl DeviceId { } } -impl AsRef for DeviceId { - fn as_ref(&self) -> &str { - &self.0 - } -} - -impl Deref for DeviceId { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Borrow for DeviceId { - fn borrow(&self) -> &str { - &self.0 - } -} - -impl Display for DeviceId { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl From for DeviceId { - fn from(raw: String) -> Self { - Self(raw) - } -} - impl<'r> FromParam<'r> for DeviceId { type Error = (); diff --git a/src/db/models/folder.rs b/src/db/models/folder.rs index 6a669ade4e..ea7208bd99 100644 --- a/src/db/models/folder.rs +++ b/src/db/models/folder.rs @@ -1,11 +1,7 @@ use chrono::{NaiveDateTime, Utc}; +use derive_more::{AsRef, Deref, Display, From}; use rocket::request::FromParam; use serde_json::Value; -use std::{ - borrow::Borrow, - fmt::{Display, Formatter}, - ops::Deref, -}; use super::{CipherId, User, UserId}; @@ -238,41 +234,11 @@ impl FolderCipher { } } -#[derive(DieselNewType, FromForm, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive( + Clone, Debug, AsRef, Deref, DieselNewType, Display, From, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize, +)] pub struct FolderId(String); -impl AsRef for FolderId { - fn as_ref(&self) -> &str { - &self.0 - } -} - -impl Deref for FolderId { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Borrow for FolderId { - fn borrow(&self) -> &str { - &self.0 - } -} - -impl Display for FolderId { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl From for FolderId { - fn from(raw: String) -> Self { - Self(raw) - } -} - impl<'r> FromParam<'r> for FolderId { type Error = (); diff --git a/src/db/models/group.rs b/src/db/models/group.rs index 60a2dce7eb..6bd4b6f90a 100644 --- a/src/db/models/group.rs +++ b/src/db/models/group.rs @@ -3,13 +3,9 @@ use crate::api::EmptyResult; use crate::db::DbConn; use crate::error::MapResult; use chrono::{NaiveDateTime, Utc}; +use derive_more::{AsRef, Deref, Display, From}; use rocket::request::FromParam; use serde_json::Value; -use std::{ - borrow::Borrow, - fmt::{Display, Formatter}, - ops::Deref, -}; db_object! { #[derive(Identifiable, Queryable, Insertable, AsChangeset)] @@ -602,41 +598,11 @@ impl GroupUser { } } -#[derive(DieselNewType, FromForm, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive( + Clone, Debug, AsRef, Deref, DieselNewType, Display, From, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize, +)] pub struct GroupId(String); -impl AsRef for GroupId { - fn as_ref(&self) -> &str { - &self.0 - } -} - -impl Deref for GroupId { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Borrow for GroupId { - fn borrow(&self) -> &str { - &self.0 - } -} - -impl Display for GroupId { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl From for GroupId { - fn from(raw: String) -> Self { - Self(raw) - } -} - impl<'r> FromParam<'r> for GroupId { type Error = (); diff --git a/src/db/models/organization.rs b/src/db/models/organization.rs index 6b37d302b0..c6f5caf0bf 100644 --- a/src/db/models/organization.rs +++ b/src/db/models/organization.rs @@ -1,13 +1,11 @@ use chrono::{NaiveDateTime, Utc}; +use derive_more::{AsRef, Deref, Display, From}; use num_traits::FromPrimitive; use rocket::request::FromParam; use serde_json::Value; use std::{ - borrow::Borrow, cmp::Ordering, collections::{HashMap, HashSet}, - fmt::{Display, Formatter}, - ops::Deref, }; use super::{ @@ -1059,41 +1057,13 @@ impl OrganizationApiKey { } } -#[derive(DieselNewType, FromForm, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive( + Clone, Debug, AsRef, Deref, DieselNewType, Display, From, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize, +)] +#[deref(forward)] +#[from(forward)] pub struct OrganizationId(String); -impl AsRef for OrganizationId { - fn as_ref(&self) -> &str { - &self.0 - } -} - -impl Deref for OrganizationId { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Borrow for OrganizationId { - fn borrow(&self) -> &str { - &self.0 - } -} - -impl Display for OrganizationId { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl From for OrganizationId { - fn from(raw: String) -> Self { - Self(raw) - } -} - impl<'r> FromParam<'r> for OrganizationId { type Error = (); @@ -1107,89 +1077,9 @@ impl<'r> FromParam<'r> for OrganizationId { } } -#[derive(DieselNewType, FromForm, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] -pub struct OrgApiKeyId(String); - -impl AsRef for OrgApiKeyId { - fn as_ref(&self) -> &str { - &self.0 - } -} - -impl Deref for OrgApiKeyId { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Borrow for OrgApiKeyId { - fn borrow(&self) -> &str { - &self.0 - } -} - -impl Display for OrgApiKeyId { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl From for OrgApiKeyId { - fn from(raw: String) -> Self { - Self(raw) - } -} - -impl<'r> FromParam<'r> for OrgApiKeyId { - type Error = (); - - #[inline(always)] - fn from_param(param: &'r str) -> Result { - if param.chars().all(|c| matches!(c, 'a'..='z' | 'A'..='Z' |'0'..='9' | '-')) { - Ok(Self(param.to_string())) - } else { - Err(()) - } - } -} - -#[derive(DieselNewType, FromForm, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, Deref, DieselNewType, Display, From, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct MembershipId(String); -impl AsRef for MembershipId { - fn as_ref(&self) -> &str { - &self.0 - } -} - -impl Deref for MembershipId { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Borrow for MembershipId { - fn borrow(&self) -> &str { - &self.0 - } -} - -impl Display for MembershipId { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl From for MembershipId { - fn from(raw: String) -> Self { - Self(raw) - } -} - impl<'r> FromParam<'r> for MembershipId { type Error = (); @@ -1203,6 +1093,9 @@ impl<'r> FromParam<'r> for MembershipId { } } +#[derive(Clone, Debug, DieselNewType, Display, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrgApiKeyId(String); + #[cfg(test)] mod tests { use super::*; diff --git a/src/db/models/user.rs b/src/db/models/user.rs index 99b3895594..411b9ac72a 100644 --- a/src/db/models/user.rs +++ b/src/db/models/user.rs @@ -1,11 +1,7 @@ use chrono::{NaiveDateTime, TimeDelta, Utc}; +use derive_more::{AsRef, Deref, Display, From}; use rocket::request::FromParam; use serde_json::Value; -use std::{ - borrow::Borrow, - fmt::{Display, Formatter}, - ops::Deref, -}; use super::{ Cipher, Device, EmergencyAccess, Favorite, Folder, Membership, MembershipType, TwoFactor, TwoFactorIncomplete, @@ -463,41 +459,13 @@ impl Invitation { } } -#[derive(DieselNewType, FromForm, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive( + Clone, Debug, AsRef, Deref, DieselNewType, Display, From, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize, +)] +#[deref(forward)] +#[from(forward)] pub struct UserId(String); -impl AsRef for UserId { - fn as_ref(&self) -> &str { - &self.0 - } -} - -impl Deref for UserId { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Borrow for UserId { - fn borrow(&self) -> &str { - &self.0 - } -} - -impl Display for UserId { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl From for UserId { - fn from(raw: String) -> Self { - Self(raw) - } -} - impl<'r> FromParam<'r> for UserId { type Error = (); diff --git a/src/mail.rs b/src/mail.rs index 476968fd06..29ee709479 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -272,14 +272,22 @@ pub async fn send_invite( invited_by_email, ); let invite_token = encode_jwt(&claims); + let org_id = match org_id { + Some(ref org_id) => org_id.as_ref(), + None => "_", + }; + let member_id = match member_id { + Some(ref member_id) => member_id.as_ref(), + None => "_", + }; let mut query = url::Url::parse("https://query.builder").unwrap(); { let mut query_params = query.query_pairs_mut(); query_params .append_pair("email", &user.email) .append_pair("organizationName", org_name) - .append_pair("organizationId", org_id.as_deref().unwrap_or("_")) - .append_pair("organizationUserId", member_id.as_deref().unwrap_or("_")) + .append_pair("organizationId", org_id) + .append_pair("organizationUserId", member_id) .append_pair("token", &invite_token); if user.private_key.is_some() { query_params.append_pair("orgUserHasExistingUser", "true");