2 use crate::api::user::Register;
3 use crate::api::{Oper, Perform};
4 use crate::settings::Settings;
5 use diesel::PgConnection;
9 #[derive(Serialize, Deserialize)]
10 pub struct ListCategories {}
12 #[derive(Serialize, Deserialize)]
13 pub struct ListCategoriesResponse {
14 categories: Vec<Category>,
17 #[derive(Serialize, Deserialize)]
21 community_id: Option<i32>,
28 #[derive(Serialize, Deserialize)]
29 pub struct SearchResponse {
31 comments: Vec<CommentView>,
33 communities: Vec<CommunityView>,
37 #[derive(Serialize, Deserialize)]
38 pub struct GetModlog {
39 mod_user_id: Option<i32>,
40 community_id: Option<i32>,
45 #[derive(Serialize, Deserialize)]
46 pub struct GetModlogResponse {
47 removed_posts: Vec<ModRemovePostView>,
48 locked_posts: Vec<ModLockPostView>,
49 stickied_posts: Vec<ModStickyPostView>,
50 removed_comments: Vec<ModRemoveCommentView>,
51 removed_communities: Vec<ModRemoveCommunityView>,
52 banned_from_community: Vec<ModBanFromCommunityView>,
53 banned: Vec<ModBanView>,
54 added_to_community: Vec<ModAddCommunityView>,
55 added: Vec<ModAddView>,
58 #[derive(Serialize, Deserialize)]
59 pub struct CreateSite {
61 pub description: Option<String>,
62 pub enable_downvotes: bool,
63 pub open_registration: bool,
64 pub enable_nsfw: bool,
68 #[derive(Serialize, Deserialize)]
71 description: Option<String>,
72 enable_downvotes: bool,
73 open_registration: bool,
78 #[derive(Serialize, Deserialize)]
81 #[derive(Serialize, Deserialize)]
82 pub struct SiteResponse {
86 #[derive(Serialize, Deserialize)]
87 pub struct GetSiteResponse {
88 site: Option<SiteView>,
89 admins: Vec<UserView>,
90 banned: Vec<UserView>,
94 #[derive(Serialize, Deserialize)]
95 pub struct TransferSite {
100 impl Perform<ListCategoriesResponse> for Oper<ListCategories> {
101 fn perform(&self, conn: &PgConnection) -> Result<ListCategoriesResponse, Error> {
102 let _data: &ListCategories = &self.data;
104 let categories: Vec<Category> = Category::list_all(&conn)?;
107 Ok(ListCategoriesResponse { categories })
111 impl Perform<GetModlogResponse> for Oper<GetModlog> {
112 fn perform(&self, conn: &PgConnection) -> Result<GetModlogResponse, Error> {
113 let data: &GetModlog = &self.data;
115 let removed_posts = ModRemovePostView::list(
122 let locked_posts = ModLockPostView::list(
129 let stickied_posts = ModStickyPostView::list(
136 let removed_comments = ModRemoveCommentView::list(
143 let banned_from_community = ModBanFromCommunityView::list(
150 let added_to_community = ModAddCommunityView::list(
158 // These arrays are only for the full modlog, when a community isn't given
159 let (removed_communities, banned, added) = if data.community_id.is_none() {
161 ModRemoveCommunityView::list(&conn, data.mod_user_id, data.page, data.limit)?,
162 ModBanView::list(&conn, data.mod_user_id, data.page, data.limit)?,
163 ModAddView::list(&conn, data.mod_user_id, data.page, data.limit)?,
166 (Vec::new(), Vec::new(), Vec::new())
170 Ok(GetModlogResponse {
176 banned_from_community,
184 impl Perform<SiteResponse> for Oper<CreateSite> {
185 fn perform(&self, conn: &PgConnection) -> Result<SiteResponse, Error> {
186 let data: &CreateSite = &self.data;
188 let claims = match Claims::decode(&data.auth) {
189 Ok(claims) => claims.claims,
190 Err(_e) => return Err(APIError::err("not_logged_in").into()),
193 if let Err(slurs) = slur_check(&data.name) {
194 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
197 if let Some(description) = &data.description {
198 if let Err(slurs) = slur_check(description) {
199 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
203 let user_id = claims.id;
205 // Make sure user is an admin
206 if !UserView::read(&conn, user_id)?.admin {
207 return Err(APIError::err("not_an_admin").into());
210 let site_form = SiteForm {
211 name: data.name.to_owned(),
212 description: data.description.to_owned(),
214 enable_downvotes: data.enable_downvotes,
215 open_registration: data.open_registration,
216 enable_nsfw: data.enable_nsfw,
220 match Site::create(&conn, &site_form) {
222 Err(_e) => return Err(APIError::err("site_already_exists").into()),
225 let site_view = SiteView::read(&conn)?;
227 Ok(SiteResponse { site: site_view })
231 impl Perform<SiteResponse> for Oper<EditSite> {
232 fn perform(&self, conn: &PgConnection) -> Result<SiteResponse, Error> {
233 let data: &EditSite = &self.data;
235 let claims = match Claims::decode(&data.auth) {
236 Ok(claims) => claims.claims,
237 Err(_e) => return Err(APIError::err("not_logged_in").into()),
240 if let Err(slurs) = slur_check(&data.name) {
241 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
244 if let Some(description) = &data.description {
245 if let Err(slurs) = slur_check(description) {
246 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
250 let user_id = claims.id;
252 // Make sure user is an admin
253 if !UserView::read(&conn, user_id)?.admin {
254 return Err(APIError::err("not_an_admin").into());
257 let found_site = Site::read(&conn, 1)?;
259 let site_form = SiteForm {
260 name: data.name.to_owned(),
261 description: data.description.to_owned(),
262 creator_id: found_site.creator_id,
263 updated: Some(naive_now()),
264 enable_downvotes: data.enable_downvotes,
265 open_registration: data.open_registration,
266 enable_nsfw: data.enable_nsfw,
269 match Site::update(&conn, 1, &site_form) {
271 Err(_e) => return Err(APIError::err("couldnt_update_site").into()),
274 let site_view = SiteView::read(&conn)?;
276 Ok(SiteResponse { site: site_view })
280 impl Perform<GetSiteResponse> for Oper<GetSite> {
281 fn perform(&self, conn: &PgConnection) -> Result<GetSiteResponse, Error> {
282 let _data: &GetSite = &self.data;
284 let site = Site::read(&conn, 1);
285 let site_view = if site.is_ok() {
286 Some(SiteView::read(&conn)?)
287 } else if let Some(setup) = Settings::get().setup.as_ref() {
288 let register = Register {
289 username: setup.admin_username.to_owned(),
290 email: setup.admin_email.to_owned(),
291 password: setup.admin_password.to_owned(),
292 password_verify: setup.admin_password.to_owned(),
296 let login_response = Oper::new(register).perform(&conn)?;
297 info!("Admin {} created", setup.admin_username);
299 let create_site = CreateSite {
300 name: setup.site_name.to_owned(),
302 enable_downvotes: false,
303 open_registration: false,
305 auth: login_response.jwt,
307 Oper::new(create_site).perform(&conn)?;
308 info!("Site {} created", setup.site_name);
309 Some(SiteView::read(&conn)?)
314 let mut admins = UserView::admins(&conn)?;
315 if site_view.is_some() {
316 let site_creator_id = site_view.to_owned().unwrap().creator_id;
317 let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
318 let creator_user = admins.remove(creator_index);
319 admins.insert(0, creator_user);
322 let banned = UserView::banned(&conn)?;
333 impl Perform<SearchResponse> for Oper<Search> {
334 fn perform(&self, conn: &PgConnection) -> Result<SearchResponse, Error> {
335 let data: &Search = &self.data;
337 let user_id: Option<i32> = match &data.auth {
338 Some(auth) => match Claims::decode(&auth) {
340 let user_id = claims.claims.id;
348 let sort = SortType::from_str(&data.sort)?;
349 let type_ = SearchType::from_str(&data.type_)?;
351 let mut posts = Vec::new();
352 let mut comments = Vec::new();
353 let mut communities = Vec::new();
354 let mut users = Vec::new();
356 // TODO no clean / non-nsfw searching rn
359 SearchType::Posts => {
360 posts = PostQueryBuilder::create(&conn)
363 .for_community_id(data.community_id)
364 .search_term(data.q.to_owned())
370 SearchType::Comments => {
371 comments = CommentQueryBuilder::create(&conn)
373 .search_term(data.q.to_owned())
379 SearchType::Communities => {
380 communities = CommunityQueryBuilder::create(&conn)
382 .search_term(data.q.to_owned())
387 SearchType::Users => {
388 users = UserQueryBuilder::create(&conn)
390 .search_term(data.q.to_owned())
396 posts = PostQueryBuilder::create(&conn)
399 .for_community_id(data.community_id)
400 .search_term(data.q.to_owned())
406 comments = CommentQueryBuilder::create(&conn)
408 .search_term(data.q.to_owned())
414 communities = CommunityQueryBuilder::create(&conn)
416 .search_term(data.q.to_owned())
421 users = UserQueryBuilder::create(&conn)
423 .search_term(data.q.to_owned())
429 posts = PostQueryBuilder::create(&conn)
432 .for_community_id(data.community_id)
433 .url_search(data.q.to_owned())
442 type_: data.type_.to_owned(),
451 impl Perform<GetSiteResponse> for Oper<TransferSite> {
452 fn perform(&self, conn: &PgConnection) -> Result<GetSiteResponse, Error> {
453 let data: &TransferSite = &self.data;
455 let claims = match Claims::decode(&data.auth) {
456 Ok(claims) => claims.claims,
457 Err(_e) => return Err(APIError::err("not_logged_in").into()),
460 let user_id = claims.id;
462 let read_site = Site::read(&conn, 1)?;
464 // Make sure user is the creator
465 if read_site.creator_id != user_id {
466 return Err(APIError::err("not_an_admin").into());
469 let site_form = SiteForm {
470 name: read_site.name,
471 description: read_site.description,
472 creator_id: data.user_id,
473 updated: Some(naive_now()),
474 enable_downvotes: read_site.enable_downvotes,
475 open_registration: read_site.open_registration,
476 enable_nsfw: read_site.enable_nsfw,
479 match Site::update(&conn, 1, &site_form) {
481 Err(_e) => return Err(APIError::err("couldnt_update_site").into()),
485 let form = ModAddForm {
486 mod_user_id: user_id,
487 other_user_id: data.user_id,
488 removed: Some(false),
491 ModAdd::create(&conn, &form)?;
493 let site_view = SiteView::read(&conn)?;
495 let mut admins = UserView::admins(&conn)?;
496 let creator_index = admins
498 .position(|r| r.id == site_view.creator_id)
500 let creator_user = admins.remove(creator_index);
501 admins.insert(0, creator_user);
503 let banned = UserView::banned(&conn)?;
506 site: Some(site_view),