]> Untitled Git - lemmy.git/blob - server/lemmy_db/src/lib.rs
Merge remote-tracking branch 'weblate/main' into main
[lemmy.git] / server / lemmy_db / src / lib.rs
1 #[macro_use]
2 pub extern crate diesel;
3 #[macro_use]
4 pub extern crate strum_macros;
5 #[macro_use]
6 pub extern crate lazy_static;
7 pub extern crate bcrypt;
8 pub extern crate chrono;
9 pub extern crate log;
10 pub extern crate regex;
11 pub extern crate serde;
12 pub extern crate serde_json;
13 pub extern crate sha2;
14 pub extern crate strum;
15
16 use chrono::NaiveDateTime;
17 use diesel::{dsl::*, result::Error, *};
18 use regex::Regex;
19 use serde::{Deserialize, Serialize};
20 use std::{env, env::VarError};
21
22 pub mod activity;
23 pub mod category;
24 pub mod comment;
25 pub mod comment_view;
26 pub mod community;
27 pub mod community_view;
28 pub mod moderator;
29 pub mod moderator_views;
30 pub mod password_reset_request;
31 pub mod post;
32 pub mod post_view;
33 pub mod private_message;
34 pub mod private_message_view;
35 pub mod schema;
36 pub mod site;
37 pub mod site_view;
38 pub mod user;
39 pub mod user_mention;
40 pub mod user_mention_view;
41 pub mod user_view;
42
43 pub trait Crud<T> {
44   fn create(conn: &PgConnection, form: &T) -> Result<Self, Error>
45   where
46     Self: Sized;
47   fn read(conn: &PgConnection, id: i32) -> Result<Self, Error>
48   where
49     Self: Sized;
50   fn update(conn: &PgConnection, id: i32, form: &T) -> Result<Self, Error>
51   where
52     Self: Sized;
53   fn delete(conn: &PgConnection, id: i32) -> Result<usize, Error>
54   where
55     Self: Sized;
56 }
57
58 pub trait Followable<T> {
59   fn follow(conn: &PgConnection, form: &T) -> Result<Self, Error>
60   where
61     Self: Sized;
62   fn unfollow(conn: &PgConnection, form: &T) -> Result<usize, Error>
63   where
64     Self: Sized;
65 }
66
67 pub trait Joinable<T> {
68   fn join(conn: &PgConnection, form: &T) -> Result<Self, Error>
69   where
70     Self: Sized;
71   fn leave(conn: &PgConnection, form: &T) -> Result<usize, Error>
72   where
73     Self: Sized;
74 }
75
76 pub trait Likeable<T> {
77   fn read(conn: &PgConnection, id: i32) -> Result<Vec<Self>, Error>
78   where
79     Self: Sized;
80   fn like(conn: &PgConnection, form: &T) -> Result<Self, Error>
81   where
82     Self: Sized;
83   fn remove(conn: &PgConnection, form: &T) -> Result<usize, Error>
84   where
85     Self: Sized;
86 }
87
88 pub trait Bannable<T> {
89   fn ban(conn: &PgConnection, form: &T) -> Result<Self, Error>
90   where
91     Self: Sized;
92   fn unban(conn: &PgConnection, form: &T) -> Result<usize, Error>
93   where
94     Self: Sized;
95 }
96
97 pub trait Saveable<T> {
98   fn save(conn: &PgConnection, form: &T) -> Result<Self, Error>
99   where
100     Self: Sized;
101   fn unsave(conn: &PgConnection, form: &T) -> Result<usize, Error>
102   where
103     Self: Sized;
104 }
105
106 pub trait Readable<T> {
107   fn mark_as_read(conn: &PgConnection, form: &T) -> Result<Self, Error>
108   where
109     Self: Sized;
110   fn mark_as_unread(conn: &PgConnection, form: &T) -> Result<usize, Error>
111   where
112     Self: Sized;
113 }
114
115 pub trait MaybeOptional<T> {
116   fn get_optional(self) -> Option<T>;
117 }
118
119 impl<T> MaybeOptional<T> for T {
120   fn get_optional(self) -> Option<T> {
121     Some(self)
122   }
123 }
124
125 impl<T> MaybeOptional<T> for Option<T> {
126   fn get_optional(self) -> Option<T> {
127     self
128   }
129 }
130
131 pub fn get_database_url_from_env() -> Result<String, VarError> {
132   env::var("LEMMY_DATABASE_URL")
133 }
134
135 #[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
136 pub enum SortType {
137   Active,
138   Hot,
139   New,
140   TopDay,
141   TopWeek,
142   TopMonth,
143   TopYear,
144   TopAll,
145 }
146
147 #[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
148 pub enum ListingType {
149   All,
150   Subscribed,
151   Community,
152 }
153
154 #[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
155 pub enum SearchType {
156   All,
157   Comments,
158   Posts,
159   Communities,
160   Users,
161   Url,
162 }
163
164 pub fn fuzzy_search(q: &str) -> String {
165   let replaced = q.replace(" ", "%");
166   format!("%{}%", replaced)
167 }
168
169 pub fn limit_and_offset(page: Option<i64>, limit: Option<i64>) -> (i64, i64) {
170   let page = page.unwrap_or(1);
171   let limit = limit.unwrap_or(10);
172   let offset = limit * (page - 1);
173   (limit, offset)
174 }
175
176 pub fn naive_now() -> NaiveDateTime {
177   chrono::prelude::Utc::now().naive_utc()
178 }
179
180 pub fn is_email_regex(test: &str) -> bool {
181   EMAIL_REGEX.is_match(test)
182 }
183
184 pub fn diesel_option_overwrite(opt: &Option<String>) -> Option<Option<String>> {
185   match opt {
186     // An empty string is an erase
187     Some(unwrapped) => {
188       if !unwrapped.eq("") {
189         Some(Some(unwrapped.to_owned()))
190       } else {
191         Some(None)
192       }
193     }
194     None => None,
195   }
196 }
197
198 lazy_static! {
199   static ref EMAIL_REGEX: Regex =
200     Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap();
201 }
202
203 #[cfg(test)]
204 mod tests {
205   use super::fuzzy_search;
206   use crate::{get_database_url_from_env, is_email_regex};
207   use diesel::{Connection, PgConnection};
208
209   pub fn establish_unpooled_connection() -> PgConnection {
210     let db_url = match get_database_url_from_env() {
211       Ok(url) => url,
212       Err(e) => panic!(
213         "Failed to read database URL from env var LEMMY_DATABASE_URL: {}",
214         e
215       ),
216     };
217     PgConnection::establish(&db_url).unwrap_or_else(|_| panic!("Error connecting to {}", db_url))
218   }
219
220   #[test]
221   fn test_fuzzy_search() {
222     let test = "This is a fuzzy search";
223     assert_eq!(fuzzy_search(test), "%This%is%a%fuzzy%search%".to_string());
224   }
225
226   #[test]
227   fn test_email() {
228     assert!(is_email_regex("gush@gmail.com"));
229     assert!(!is_email_regex("nada_neutho"));
230   }
231 }