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_view = if let Ok(_site) = Site::read(&conn, 1) {
285 Some(SiteView::read(&conn)?)
286 } else if let Some(setup) = Settings::get().setup.as_ref() {
287 let register = Register {
288 username: setup.admin_username.to_owned(),
289 email: setup.admin_email.to_owned(),
290 password: setup.admin_password.to_owned(),
291 password_verify: setup.admin_password.to_owned(),
295 let login_response = Oper::new(register).perform(&conn)?;
296 info!("Admin {} created", setup.admin_username);
298 let create_site = CreateSite {
299 name: setup.site_name.to_owned(),
301 enable_downvotes: false,
302 open_registration: false,
304 auth: login_response.jwt,
306 Oper::new(create_site).perform(&conn)?;
307 info!("Site {} created", setup.site_name);
308 Some(SiteView::read(&conn)?)
313 let mut admins = UserView::admins(&conn)?;
315 // Make sure the site creator is the top admin
316 if let Some(site_view) = site_view.to_owned() {
317 let site_creator_id = site_view.creator_id;
318 // TODO investigate why this is sometimes coming back null
319 // Maybe user_.admin isn't being set to true?
320 if let Some(creator_index) = admins.iter().position(|r| r.id == site_creator_id) {
321 let creator_user = admins.remove(creator_index);
322 admins.insert(0, creator_user);
326 let banned = UserView::banned(&conn)?;
337 impl Perform<SearchResponse> for Oper<Search> {
338 fn perform(&self, conn: &PgConnection) -> Result<SearchResponse, Error> {
339 let data: &Search = &self.data;
341 let user_id: Option<i32> = match &data.auth {
342 Some(auth) => match Claims::decode(&auth) {
344 let user_id = claims.claims.id;
352 let sort = SortType::from_str(&data.sort)?;
353 let type_ = SearchType::from_str(&data.type_)?;
355 let mut posts = Vec::new();
356 let mut comments = Vec::new();
357 let mut communities = Vec::new();
358 let mut users = Vec::new();
360 // TODO no clean / non-nsfw searching rn
363 SearchType::Posts => {
364 posts = PostQueryBuilder::create(&conn)
367 .for_community_id(data.community_id)
368 .search_term(data.q.to_owned())
374 SearchType::Comments => {
375 comments = CommentQueryBuilder::create(&conn)
377 .search_term(data.q.to_owned())
383 SearchType::Communities => {
384 communities = CommunityQueryBuilder::create(&conn)
386 .search_term(data.q.to_owned())
391 SearchType::Users => {
392 users = UserQueryBuilder::create(&conn)
394 .search_term(data.q.to_owned())
400 posts = PostQueryBuilder::create(&conn)
403 .for_community_id(data.community_id)
404 .search_term(data.q.to_owned())
410 comments = CommentQueryBuilder::create(&conn)
412 .search_term(data.q.to_owned())
418 communities = CommunityQueryBuilder::create(&conn)
420 .search_term(data.q.to_owned())
425 users = UserQueryBuilder::create(&conn)
427 .search_term(data.q.to_owned())
433 posts = PostQueryBuilder::create(&conn)
436 .for_community_id(data.community_id)
437 .url_search(data.q.to_owned())
446 type_: data.type_.to_owned(),
455 impl Perform<GetSiteResponse> for Oper<TransferSite> {
456 fn perform(&self, conn: &PgConnection) -> Result<GetSiteResponse, Error> {
457 let data: &TransferSite = &self.data;
459 let claims = match Claims::decode(&data.auth) {
460 Ok(claims) => claims.claims,
461 Err(_e) => return Err(APIError::err("not_logged_in").into()),
464 let user_id = claims.id;
466 let read_site = Site::read(&conn, 1)?;
468 // Make sure user is the creator
469 if read_site.creator_id != user_id {
470 return Err(APIError::err("not_an_admin").into());
473 let site_form = SiteForm {
474 name: read_site.name,
475 description: read_site.description,
476 creator_id: data.user_id,
477 updated: Some(naive_now()),
478 enable_downvotes: read_site.enable_downvotes,
479 open_registration: read_site.open_registration,
480 enable_nsfw: read_site.enable_nsfw,
483 match Site::update(&conn, 1, &site_form) {
485 Err(_e) => return Err(APIError::err("couldnt_update_site").into()),
489 let form = ModAddForm {
490 mod_user_id: user_id,
491 other_user_id: data.user_id,
492 removed: Some(false),
495 ModAdd::create(&conn, &form)?;
497 let site_view = SiteView::read(&conn)?;
499 let mut admins = UserView::admins(&conn)?;
500 let creator_index = admins
502 .position(|r| r.id == site_view.creator_id)
504 let creator_user = admins.remove(creator_index);
505 admins.insert(0, creator_user);
507 let banned = UserView::banned(&conn)?;
510 site: Some(site_view),