]> Untitled Git - lemmy.git/blob - lemmy_db/src/lib.rs
Merge pull request 'Set valid context for our extra fields (ref #1220)' (#142) from...
[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
8 use chrono::NaiveDateTime;
9 use diesel::{result::Error, *};
10 use regex::Regex;
11 use serde::{Deserialize, Serialize};
12 use std::{env, env::VarError};
13
14 pub mod activity;
15 pub mod category;
16 pub mod comment;
17 pub mod comment_report;
18 pub mod comment_view;
19 pub mod community;
20 pub mod community_view;
21 pub mod moderator;
22 pub mod moderator_views;
23 pub mod password_reset_request;
24 pub mod post;
25 pub mod post_report;
26 pub mod post_view;
27 pub mod private_message;
28 pub mod private_message_view;
29 pub mod schema;
30 pub mod site;
31 pub mod site_view;
32 pub mod user;
33 pub mod user_mention;
34 pub mod user_mention_view;
35 pub mod user_view;
36
37 pub type DbPool = diesel::r2d2::Pool<diesel::r2d2::ConnectionManager<diesel::PgConnection>>;
38
39 pub trait Crud<T> {
40   fn create(conn: &PgConnection, form: &T) -> Result<Self, Error>
41   where
42     Self: Sized;
43   fn read(conn: &PgConnection, id: i32) -> Result<Self, Error>
44   where
45     Self: Sized;
46   fn update(conn: &PgConnection, id: i32, form: &T) -> Result<Self, Error>
47   where
48     Self: Sized;
49   fn delete(_conn: &PgConnection, _id: i32) -> Result<usize, Error>
50   where
51     Self: Sized,
52   {
53     unimplemented!()
54   }
55 }
56
57 pub trait Followable<T> {
58   fn follow(conn: &PgConnection, form: &T) -> Result<Self, Error>
59   where
60     Self: Sized;
61   fn follow_accepted(conn: &PgConnection, community_id: i32, user_id: i32) -> Result<Self, Error>
62   where
63     Self: Sized;
64   fn unfollow(conn: &PgConnection, form: &T) -> Result<usize, Error>
65   where
66     Self: Sized;
67   fn has_local_followers(conn: &PgConnection, community_id: i32) -> Result<bool, Error>;
68 }
69
70 pub trait Joinable<T> {
71   fn join(conn: &PgConnection, form: &T) -> Result<Self, Error>
72   where
73     Self: Sized;
74   fn leave(conn: &PgConnection, form: &T) -> Result<usize, Error>
75   where
76     Self: Sized;
77 }
78
79 pub trait Likeable<T> {
80   fn like(conn: &PgConnection, form: &T) -> Result<Self, Error>
81   where
82     Self: Sized;
83   fn remove(conn: &PgConnection, user_id: i32, item_id: i32) -> 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 Reportable<T> {
116   fn report(conn: &PgConnection, form: &T) -> Result<Self, Error>
117   where
118     Self: Sized;
119   fn resolve(conn: &PgConnection, report_id: i32, resolver_id: i32) -> Result<usize, Error>
120   where
121     Self: Sized;
122   fn unresolve(conn: &PgConnection, report_id: i32, resolver_id: i32) -> Result<usize, Error>
123   where
124     Self: Sized;
125 }
126
127 pub trait MaybeOptional<T> {
128   fn get_optional(self) -> Option<T>;
129 }
130
131 impl<T> MaybeOptional<T> for T {
132   fn get_optional(self) -> Option<T> {
133     Some(self)
134   }
135 }
136
137 impl<T> MaybeOptional<T> for Option<T> {
138   fn get_optional(self) -> Option<T> {
139     self
140   }
141 }
142
143 pub fn get_database_url_from_env() -> Result<String, VarError> {
144   env::var("LEMMY_DATABASE_URL")
145 }
146
147 #[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
148 pub enum SortType {
149   Active,
150   Hot,
151   New,
152   TopDay,
153   TopWeek,
154   TopMonth,
155   TopYear,
156   TopAll,
157 }
158
159 #[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
160 pub enum ListingType {
161   All,
162   Local,
163   Subscribed,
164   Community,
165 }
166
167 #[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
168 pub enum SearchType {
169   All,
170   Comments,
171   Posts,
172   Communities,
173   Users,
174   Url,
175 }
176
177 pub fn fuzzy_search(q: &str) -> String {
178   let replaced = q.replace(" ", "%");
179   format!("%{}%", replaced)
180 }
181
182 pub fn limit_and_offset(page: Option<i64>, limit: Option<i64>) -> (i64, i64) {
183   let page = page.unwrap_or(1);
184   let limit = limit.unwrap_or(10);
185   let offset = limit * (page - 1);
186   (limit, offset)
187 }
188
189 pub fn naive_now() -> NaiveDateTime {
190   chrono::prelude::Utc::now().naive_utc()
191 }
192
193 pub fn is_email_regex(test: &str) -> bool {
194   EMAIL_REGEX.is_match(test)
195 }
196
197 pub fn diesel_option_overwrite(opt: &Option<String>) -> Option<Option<String>> {
198   match opt {
199     // An empty string is an erase
200     Some(unwrapped) => {
201       if !unwrapped.eq("") {
202         Some(Some(unwrapped.to_owned()))
203       } else {
204         Some(None)
205       }
206     }
207     None => None,
208   }
209 }
210
211 lazy_static! {
212   static ref EMAIL_REGEX: Regex =
213     Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap();
214 }
215
216 #[cfg(test)]
217 mod tests {
218   use super::fuzzy_search;
219   use crate::{get_database_url_from_env, is_email_regex};
220   use diesel::{Connection, PgConnection};
221
222   pub fn establish_unpooled_connection() -> PgConnection {
223     let db_url = match get_database_url_from_env() {
224       Ok(url) => url,
225       Err(e) => panic!(
226         "Failed to read database URL from env var LEMMY_DATABASE_URL: {}",
227         e
228       ),
229     };
230     PgConnection::establish(&db_url).unwrap_or_else(|_| panic!("Error connecting to {}", db_url))
231   }
232
233   #[test]
234   fn test_fuzzy_search() {
235     let test = "This is a fuzzy search";
236     assert_eq!(fuzzy_search(test), "%This%is%a%fuzzy%search%".to_string());
237   }
238
239   #[test]
240   fn test_email() {
241     assert!(is_email_regex("gush@gmail.com"));
242     assert!(!is_email_regex("nada_neutho"));
243   }
244 }