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