2 use diesel::PgConnection;
5 #[derive(Serialize, Deserialize)]
6 pub struct ListCategories {}
8 #[derive(Serialize, Deserialize)]
9 pub struct ListCategoriesResponse {
10 categories: Vec<Category>,
13 #[derive(Serialize, Deserialize)]
17 community_id: Option<i32>,
24 #[derive(Serialize, Deserialize)]
25 pub struct SearchResponse {
27 comments: Vec<CommentView>,
29 communities: Vec<CommunityView>,
33 #[derive(Serialize, Deserialize)]
34 pub struct GetModlog {
35 mod_user_id: Option<i32>,
36 community_id: Option<i32>,
41 #[derive(Serialize, Deserialize)]
42 pub struct GetModlogResponse {
43 removed_posts: Vec<ModRemovePostView>,
44 locked_posts: Vec<ModLockPostView>,
45 stickied_posts: Vec<ModStickyPostView>,
46 removed_comments: Vec<ModRemoveCommentView>,
47 removed_communities: Vec<ModRemoveCommunityView>,
48 banned_from_community: Vec<ModBanFromCommunityView>,
49 banned: Vec<ModBanView>,
50 added_to_community: Vec<ModAddCommunityView>,
51 added: Vec<ModAddView>,
54 #[derive(Serialize, Deserialize)]
55 pub struct CreateSite {
57 description: Option<String>,
58 enable_downvotes: bool,
59 open_registration: bool,
64 #[derive(Serialize, Deserialize)]
67 description: Option<String>,
68 enable_downvotes: bool,
69 open_registration: bool,
74 #[derive(Serialize, Deserialize)]
77 #[derive(Serialize, Deserialize)]
78 pub struct SiteResponse {
82 #[derive(Serialize, Deserialize)]
83 pub struct GetSiteResponse {
84 site: Option<SiteView>,
85 admins: Vec<UserView>,
86 banned: Vec<UserView>,
90 #[derive(Serialize, Deserialize)]
91 pub struct TransferSite {
96 impl Perform<ListCategoriesResponse> for Oper<ListCategories> {
97 fn perform(&self, conn: &PgConnection) -> Result<ListCategoriesResponse, Error> {
98 let _data: &ListCategories = &self.data;
100 let categories: Vec<Category> = Category::list_all(&conn)?;
103 Ok(ListCategoriesResponse { categories })
107 impl Perform<GetModlogResponse> for Oper<GetModlog> {
108 fn perform(&self, conn: &PgConnection) -> Result<GetModlogResponse, Error> {
109 let data: &GetModlog = &self.data;
111 let removed_posts = ModRemovePostView::list(
118 let locked_posts = ModLockPostView::list(
125 let stickied_posts = ModStickyPostView::list(
132 let removed_comments = ModRemoveCommentView::list(
139 let banned_from_community = ModBanFromCommunityView::list(
146 let added_to_community = ModAddCommunityView::list(
154 // These arrays are only for the full modlog, when a community isn't given
155 let (removed_communities, banned, added) = if data.community_id.is_none() {
157 ModRemoveCommunityView::list(&conn, data.mod_user_id, data.page, data.limit)?,
158 ModBanView::list(&conn, data.mod_user_id, data.page, data.limit)?,
159 ModAddView::list(&conn, data.mod_user_id, data.page, data.limit)?,
162 (Vec::new(), Vec::new(), Vec::new())
166 Ok(GetModlogResponse {
172 banned_from_community,
180 impl Perform<SiteResponse> for Oper<CreateSite> {
181 fn perform(&self, conn: &PgConnection) -> Result<SiteResponse, Error> {
182 let data: &CreateSite = &self.data;
184 let claims = match Claims::decode(&data.auth) {
185 Ok(claims) => claims.claims,
186 Err(_e) => return Err(APIError::err("not_logged_in").into()),
189 if let Err(slurs) = slur_check(&data.name) {
190 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
193 if let Some(description) = &data.description {
194 if let Err(slurs) = slur_check(description) {
195 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
199 let user_id = claims.id;
201 // Make sure user is an admin
202 if !UserView::read(&conn, user_id)?.admin {
203 return Err(APIError::err("not_an_admin").into());
206 let site_form = SiteForm {
207 name: data.name.to_owned(),
208 description: data.description.to_owned(),
210 enable_downvotes: data.enable_downvotes,
211 open_registration: data.open_registration,
212 enable_nsfw: data.enable_nsfw,
216 match Site::create(&conn, &site_form) {
218 Err(_e) => return Err(APIError::err("site_already_exists").into()),
221 let site_view = SiteView::read(&conn)?;
223 Ok(SiteResponse { site: site_view })
227 impl Perform<SiteResponse> for Oper<EditSite> {
228 fn perform(&self, conn: &PgConnection) -> Result<SiteResponse, Error> {
229 let data: &EditSite = &self.data;
231 let claims = match Claims::decode(&data.auth) {
232 Ok(claims) => claims.claims,
233 Err(_e) => return Err(APIError::err("not_logged_in").into()),
236 if let Err(slurs) = slur_check(&data.name) {
237 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
240 if let Some(description) = &data.description {
241 if let Err(slurs) = slur_check(description) {
242 return Err(APIError::err(&slurs_vec_to_str(slurs)).into());
246 let user_id = claims.id;
248 // Make sure user is an admin
249 if !UserView::read(&conn, user_id)?.admin {
250 return Err(APIError::err("not_an_admin").into());
253 let found_site = Site::read(&conn, 1)?;
255 let site_form = SiteForm {
256 name: data.name.to_owned(),
257 description: data.description.to_owned(),
258 creator_id: found_site.creator_id,
259 updated: Some(naive_now()),
260 enable_downvotes: data.enable_downvotes,
261 open_registration: data.open_registration,
262 enable_nsfw: data.enable_nsfw,
265 match Site::update(&conn, 1, &site_form) {
267 Err(_e) => return Err(APIError::err("couldnt_update_site").into()),
270 let site_view = SiteView::read(&conn)?;
272 Ok(SiteResponse { site: site_view })
276 impl Perform<GetSiteResponse> for Oper<GetSite> {
277 fn perform(&self, conn: &PgConnection) -> Result<GetSiteResponse, Error> {
278 let _data: &GetSite = &self.data;
280 // It can return a null site in order to redirect
281 let site_view = match Site::read(&conn, 1) {
282 Ok(_site) => Some(SiteView::read(&conn)?),
286 let mut admins = UserView::admins(&conn)?;
287 if site_view.is_some() {
288 let site_creator_id = site_view.to_owned().unwrap().creator_id;
289 let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
290 let creator_user = admins.remove(creator_index);
291 admins.insert(0, creator_user);
294 let banned = UserView::banned(&conn)?;
305 impl Perform<SearchResponse> for Oper<Search> {
306 fn perform(&self, conn: &PgConnection) -> Result<SearchResponse, Error> {
307 let data: &Search = &self.data;
309 let user_id: Option<i32> = match &data.auth {
310 Some(auth) => match Claims::decode(&auth) {
312 let user_id = claims.claims.id;
320 let sort = SortType::from_str(&data.sort)?;
321 let type_ = SearchType::from_str(&data.type_)?;
323 let mut posts = Vec::new();
324 let mut comments = Vec::new();
325 let mut communities = Vec::new();
326 let mut users = Vec::new();
328 // TODO no clean / non-nsfw searching rn
331 SearchType::Posts => {
332 posts = PostQueryBuilder::create(&conn)
335 .for_community_id(data.community_id)
336 .search_term(data.q.to_owned())
342 SearchType::Comments => {
343 comments = CommentQueryBuilder::create(&conn)
345 .search_term(data.q.to_owned())
351 SearchType::Communities => {
352 communities = CommunityQueryBuilder::create(&conn)
354 .search_term(data.q.to_owned())
359 SearchType::Users => {
360 users = UserQueryBuilder::create(&conn)
362 .search_term(data.q.to_owned())
368 posts = PostQueryBuilder::create(&conn)
371 .for_community_id(data.community_id)
372 .search_term(data.q.to_owned())
378 comments = CommentQueryBuilder::create(&conn)
380 .search_term(data.q.to_owned())
386 communities = CommunityQueryBuilder::create(&conn)
388 .search_term(data.q.to_owned())
393 users = UserQueryBuilder::create(&conn)
395 .search_term(data.q.to_owned())
401 posts = PostQueryBuilder::create(&conn)
404 .for_community_id(data.community_id)
405 .url_search(data.q.to_owned())
414 type_: data.type_.to_owned(),
423 impl Perform<GetSiteResponse> for Oper<TransferSite> {
424 fn perform(&self, conn: &PgConnection) -> Result<GetSiteResponse, Error> {
425 let data: &TransferSite = &self.data;
427 let claims = match Claims::decode(&data.auth) {
428 Ok(claims) => claims.claims,
429 Err(_e) => return Err(APIError::err("not_logged_in").into()),
432 let user_id = claims.id;
434 let read_site = Site::read(&conn, 1)?;
436 // Make sure user is the creator
437 if read_site.creator_id != user_id {
438 return Err(APIError::err("not_an_admin").into());
441 let site_form = SiteForm {
442 name: read_site.name,
443 description: read_site.description,
444 creator_id: data.user_id,
445 updated: Some(naive_now()),
446 enable_downvotes: read_site.enable_downvotes,
447 open_registration: read_site.open_registration,
448 enable_nsfw: read_site.enable_nsfw,
451 match Site::update(&conn, 1, &site_form) {
453 Err(_e) => return Err(APIError::err("couldnt_update_site").into()),
457 let form = ModAddForm {
458 mod_user_id: user_id,
459 other_user_id: data.user_id,
460 removed: Some(false),
463 ModAdd::create(&conn, &form)?;
465 let site_view = SiteView::read(&conn)?;
467 let mut admins = UserView::admins(&conn)?;
468 let creator_index = admins
470 .position(|r| r.id == site_view.creator_id)
472 let creator_user = admins.remove(creator_index);
473 admins.insert(0, creator_user);
475 let banned = UserView::banned(&conn)?;
478 site: Some(site_view),