2 newtypes::{CommunityId, DbUrl, PersonId},
3 schema::community::dsl::{actor_id, community, deleted, local, name, removed},
5 actor_language::{CommunityLanguage, SiteLanguage},
12 CommunityModeratorForm,
14 CommunityPersonBanForm,
19 traits::{ApubActor, Bannable, Crud, DeleteableOrRemoveable, Followable, Joinable},
20 utils::{functions::lower, get_conn, DbPool},
23 use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl, TextExpressionMethods};
24 use diesel_async::RunQueryDsl;
40 posting_restricted_to_mods,
46 source::community::Community,
65 posting_restricted_to_mods,
69 impl ToSafe for Community {
70 type SafeColumns = Columns;
71 fn safe_columns_tuple() -> Self::SafeColumns {
87 posting_restricted_to_mods,
95 impl Crud for Community {
96 type InsertForm = CommunityInsertForm;
97 type UpdateForm = CommunityUpdateForm;
98 type IdType = CommunityId;
99 async fn read(pool: &DbPool, community_id: CommunityId) -> Result<Self, Error> {
100 let conn = &mut get_conn(pool).await?;
101 community.find(community_id).first::<Self>(conn).await
104 async fn delete(pool: &DbPool, community_id: CommunityId) -> Result<usize, Error> {
105 let conn = &mut get_conn(pool).await?;
106 diesel::delete(community.find(community_id))
111 async fn create(pool: &DbPool, form: &Self::InsertForm) -> Result<Self, Error> {
112 let conn = &mut get_conn(pool).await?;
113 let community_ = insert_into(community)
115 .on_conflict(actor_id)
118 .get_result::<Self>(conn)
121 let site_languages = SiteLanguage::read_local(pool).await;
122 if let Ok(langs) = site_languages {
123 // if site exists, init user with site languages
124 CommunityLanguage::update(pool, langs, community_.id).await?;
126 // otherwise, init with all languages (this only happens during tests)
127 CommunityLanguage::update(pool, vec![], community_.id).await?;
135 community_id: CommunityId,
136 form: &Self::UpdateForm,
137 ) -> Result<Self, Error> {
138 let conn = &mut get_conn(pool).await?;
139 diesel::update(community.find(community_id))
141 .get_result::<Self>(conn)
147 impl Joinable for CommunityModerator {
148 type Form = CommunityModeratorForm;
151 community_moderator_form: &CommunityModeratorForm,
152 ) -> Result<Self, Error> {
153 use crate::schema::community_moderator::dsl::community_moderator;
154 let conn = &mut get_conn(pool).await?;
155 insert_into(community_moderator)
156 .values(community_moderator_form)
157 .get_result::<Self>(conn)
163 community_moderator_form: &CommunityModeratorForm,
164 ) -> Result<usize, Error> {
165 use crate::schema::community_moderator::dsl::{community_id, community_moderator, person_id};
166 let conn = &mut get_conn(pool).await?;
169 .filter(community_id.eq(community_moderator_form.community_id))
170 .filter(person_id.eq(community_moderator_form.person_id)),
177 impl DeleteableOrRemoveable for CommunitySafe {
178 fn blank_out_deleted_or_removed_info(mut self) -> Self {
179 self.title = String::new();
180 self.description = None;
187 impl DeleteableOrRemoveable for Community {
188 fn blank_out_deleted_or_removed_info(mut self) -> Self {
189 self.title = String::new();
190 self.description = None;
197 impl CommunityModerator {
198 pub async fn delete_for_community(
200 for_community_id: CommunityId,
201 ) -> Result<usize, Error> {
202 use crate::schema::community_moderator::dsl::{community_id, community_moderator};
203 let conn = &mut get_conn(pool).await?;
205 diesel::delete(community_moderator.filter(community_id.eq(for_community_id)))
210 pub async fn get_person_moderated_communities(
212 for_person_id: PersonId,
213 ) -> Result<Vec<CommunityId>, Error> {
214 use crate::schema::community_moderator::dsl::{community_id, community_moderator, person_id};
215 let conn = &mut get_conn(pool).await?;
217 .filter(person_id.eq(for_person_id))
218 .select(community_id)
219 .load::<CommunityId>(conn)
225 impl Bannable for CommunityPersonBan {
226 type Form = CommunityPersonBanForm;
229 community_person_ban_form: &CommunityPersonBanForm,
230 ) -> Result<Self, Error> {
231 use crate::schema::community_person_ban::dsl::{community_id, community_person_ban, person_id};
232 let conn = &mut get_conn(pool).await?;
233 insert_into(community_person_ban)
234 .values(community_person_ban_form)
235 .on_conflict((community_id, person_id))
237 .set(community_person_ban_form)
238 .get_result::<Self>(conn)
244 community_person_ban_form: &CommunityPersonBanForm,
245 ) -> Result<usize, Error> {
246 use crate::schema::community_person_ban::dsl::{community_id, community_person_ban, person_id};
247 let conn = &mut get_conn(pool).await?;
250 .filter(community_id.eq(community_person_ban_form.community_id))
251 .filter(person_id.eq(community_person_ban_form.person_id)),
258 impl CommunityFollower {
259 pub fn to_subscribed_type(follower: &Option<Self>) -> SubscribedType {
263 SubscribedType::Pending
265 SubscribedType::Subscribed
268 // If the row doesn't exist, the person isn't a follower.
269 None => SubscribedType::NotSubscribed,
275 impl Followable for CommunityFollower {
276 type Form = CommunityFollowerForm;
277 async fn follow(pool: &DbPool, form: &CommunityFollowerForm) -> Result<Self, Error> {
278 use crate::schema::community_follower::dsl::{community_follower, community_id, person_id};
279 let conn = &mut get_conn(pool).await?;
280 insert_into(community_follower)
282 .on_conflict((community_id, person_id))
285 .get_result::<Self>(conn)
288 async fn follow_accepted(
290 community_id_: CommunityId,
291 person_id_: PersonId,
292 ) -> Result<Self, Error> {
293 use crate::schema::community_follower::dsl::{
299 let conn = &mut get_conn(pool).await?;
302 .filter(community_id.eq(community_id_))
303 .filter(person_id.eq(person_id_)),
305 .set(pending.eq(false))
306 .get_result::<Self>(conn)
309 async fn unfollow(pool: &DbPool, form: &CommunityFollowerForm) -> Result<usize, Error> {
310 use crate::schema::community_follower::dsl::{community_follower, community_id, person_id};
311 let conn = &mut get_conn(pool).await?;
314 .filter(community_id.eq(&form.community_id))
315 .filter(person_id.eq(&form.person_id)),
323 impl ApubActor for Community {
324 async fn read_from_apub_id(pool: &DbPool, object_id: &DbUrl) -> Result<Option<Self>, Error> {
325 let conn = &mut get_conn(pool).await?;
328 .filter(actor_id.eq(object_id))
329 .first::<Community>(conn)
336 async fn read_from_name(
338 community_name: &str,
339 include_deleted: bool,
340 ) -> Result<Community, Error> {
341 let conn = &mut get_conn(pool).await?;
342 let mut q = community
344 .filter(local.eq(true))
345 .filter(lower(name).eq(lower(community_name)));
346 if !include_deleted {
347 q = q.filter(deleted.eq(false)).filter(removed.eq(false));
349 q.first::<Self>(conn).await
352 async fn read_from_name_and_domain(
354 community_name: &str,
355 protocol_domain: &str,
356 ) -> Result<Community, Error> {
357 let conn = &mut get_conn(pool).await?;
359 .filter(lower(name).eq(lower(community_name)))
360 .filter(actor_id.like(format!("{protocol_domain}%")))
373 CommunityFollowerForm,
376 CommunityModeratorForm,
378 CommunityPersonBanForm,
382 person::{Person, PersonInsertForm},
384 traits::{Bannable, Crud, Followable, Joinable},
385 utils::build_db_pool_for_tests,
387 use serial_test::serial;
391 async fn test_crud() {
392 let pool = &build_db_pool_for_tests().await;
394 let inserted_instance = Instance::create(pool, "my_domain.tld").await.unwrap();
396 let new_person = PersonInsertForm::builder()
397 .name("bobbee".into())
398 .public_key("pubkey".to_string())
399 .instance_id(inserted_instance.id)
402 let inserted_person = Person::create(pool, &new_person).await.unwrap();
404 let new_community = CommunityInsertForm::builder()
406 .title("nada".to_owned())
407 .public_key("pubkey".to_string())
408 .instance_id(inserted_instance.id)
411 let inserted_community = Community::create(pool, &new_community).await.unwrap();
413 let expected_community = Community {
414 id: inserted_community.id,
416 title: "nada".to_owned(),
421 published: inserted_community.published,
423 actor_id: inserted_community.actor_id.clone(),
426 public_key: "pubkey".to_owned(),
427 last_refreshed_at: inserted_community.published,
430 followers_url: inserted_community.followers_url.clone(),
431 inbox_url: inserted_community.inbox_url.clone(),
432 shared_inbox_url: None,
434 posting_restricted_to_mods: false,
435 instance_id: inserted_instance.id,
438 let community_follower_form = CommunityFollowerForm {
439 community_id: inserted_community.id,
440 person_id: inserted_person.id,
444 let inserted_community_follower = CommunityFollower::follow(pool, &community_follower_form)
448 let expected_community_follower = CommunityFollower {
449 id: inserted_community_follower.id,
450 community_id: inserted_community.id,
451 person_id: inserted_person.id,
453 published: inserted_community_follower.published,
456 let community_moderator_form = CommunityModeratorForm {
457 community_id: inserted_community.id,
458 person_id: inserted_person.id,
461 let inserted_community_moderator = CommunityModerator::join(pool, &community_moderator_form)
465 let expected_community_moderator = CommunityModerator {
466 id: inserted_community_moderator.id,
467 community_id: inserted_community.id,
468 person_id: inserted_person.id,
469 published: inserted_community_moderator.published,
472 let community_person_ban_form = CommunityPersonBanForm {
473 community_id: inserted_community.id,
474 person_id: inserted_person.id,
478 let inserted_community_person_ban = CommunityPersonBan::ban(pool, &community_person_ban_form)
482 let expected_community_person_ban = CommunityPersonBan {
483 id: inserted_community_person_ban.id,
484 community_id: inserted_community.id,
485 person_id: inserted_person.id,
486 published: inserted_community_person_ban.published,
490 let read_community = Community::read(pool, inserted_community.id).await.unwrap();
492 let update_community_form = CommunityUpdateForm::builder()
493 .title(Some("nada".to_owned()))
495 let updated_community = Community::update(pool, inserted_community.id, &update_community_form)
499 let ignored_community = CommunityFollower::unfollow(pool, &community_follower_form)
502 let left_community = CommunityModerator::leave(pool, &community_moderator_form)
505 let unban = CommunityPersonBan::unban(pool, &community_person_ban_form)
508 let num_deleted = Community::delete(pool, inserted_community.id)
511 Person::delete(pool, inserted_person.id).await.unwrap();
512 Instance::delete(pool, inserted_instance.id).await.unwrap();
514 assert_eq!(expected_community, read_community);
515 assert_eq!(expected_community, inserted_community);
516 assert_eq!(expected_community, updated_community);
517 assert_eq!(expected_community_follower, inserted_community_follower);
518 assert_eq!(expected_community_moderator, inserted_community_moderator);
519 assert_eq!(expected_community_person_ban, inserted_community_person_ban);
520 assert_eq!(1, ignored_community);
521 assert_eq!(1, left_community);
522 assert_eq!(1, unban);
523 // assert_eq!(2, loaded_count);
524 assert_eq!(1, num_deleted);