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,
18 traits::{ApubActor, Bannable, Crud, Followable, Joinable},
19 utils::{functions::lower, get_conn, DbPool},
22 use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl, TextExpressionMethods};
23 use diesel_async::RunQueryDsl;
26 impl Crud for Community {
27 type InsertForm = CommunityInsertForm;
28 type UpdateForm = CommunityUpdateForm;
29 type IdType = CommunityId;
30 async fn read(pool: &DbPool, community_id: CommunityId) -> Result<Self, Error> {
31 let conn = &mut get_conn(pool).await?;
32 community.find(community_id).first::<Self>(conn).await
35 async fn delete(pool: &DbPool, community_id: CommunityId) -> Result<usize, Error> {
36 let conn = &mut get_conn(pool).await?;
37 diesel::delete(community.find(community_id))
42 async fn create(pool: &DbPool, form: &Self::InsertForm) -> Result<Self, Error> {
43 let conn = &mut get_conn(pool).await?;
44 let community_ = insert_into(community)
46 .on_conflict(actor_id)
49 .get_result::<Self>(conn)
52 let site_languages = SiteLanguage::read_local(pool).await;
53 if let Ok(langs) = site_languages {
54 // if site exists, init user with site languages
55 CommunityLanguage::update(pool, langs, community_.id).await?;
57 // otherwise, init with all languages (this only happens during tests)
58 CommunityLanguage::update(pool, vec![], community_.id).await?;
66 community_id: CommunityId,
67 form: &Self::UpdateForm,
68 ) -> Result<Self, Error> {
69 let conn = &mut get_conn(pool).await?;
70 diesel::update(community.find(community_id))
72 .get_result::<Self>(conn)
78 impl Joinable for CommunityModerator {
79 type Form = CommunityModeratorForm;
82 community_moderator_form: &CommunityModeratorForm,
83 ) -> Result<Self, Error> {
84 use crate::schema::community_moderator::dsl::community_moderator;
85 let conn = &mut get_conn(pool).await?;
86 insert_into(community_moderator)
87 .values(community_moderator_form)
88 .get_result::<Self>(conn)
94 community_moderator_form: &CommunityModeratorForm,
95 ) -> Result<usize, Error> {
96 use crate::schema::community_moderator::dsl::{community_id, community_moderator, person_id};
97 let conn = &mut get_conn(pool).await?;
100 .filter(community_id.eq(community_moderator_form.community_id))
101 .filter(person_id.eq(community_moderator_form.person_id)),
108 pub enum CollectionType {
114 /// Get the community which has a given moderators or featured url, also return the collection type
115 pub async fn get_by_collection_url(
118 ) -> Result<(Community, CollectionType), Error> {
119 use crate::schema::community::dsl::{featured_url, moderators_url};
120 use CollectionType::*;
121 let conn = &mut get_conn(pool).await?;
123 .filter(moderators_url.eq(url))
127 return Ok((c, Moderators));
130 .filter(featured_url.eq(url))
134 return Ok((c, Featured));
136 Err(diesel::NotFound)
140 impl CommunityModerator {
141 pub async fn delete_for_community(
143 for_community_id: CommunityId,
144 ) -> Result<usize, Error> {
145 use crate::schema::community_moderator::dsl::{community_id, community_moderator};
146 let conn = &mut get_conn(pool).await?;
148 diesel::delete(community_moderator.filter(community_id.eq(for_community_id)))
153 pub async fn get_person_moderated_communities(
155 for_person_id: PersonId,
156 ) -> Result<Vec<CommunityId>, Error> {
157 use crate::schema::community_moderator::dsl::{community_id, community_moderator, person_id};
158 let conn = &mut get_conn(pool).await?;
160 .filter(person_id.eq(for_person_id))
161 .select(community_id)
162 .load::<CommunityId>(conn)
168 impl Bannable for CommunityPersonBan {
169 type Form = CommunityPersonBanForm;
172 community_person_ban_form: &CommunityPersonBanForm,
173 ) -> Result<Self, Error> {
174 use crate::schema::community_person_ban::dsl::{community_id, community_person_ban, person_id};
175 let conn = &mut get_conn(pool).await?;
176 insert_into(community_person_ban)
177 .values(community_person_ban_form)
178 .on_conflict((community_id, person_id))
180 .set(community_person_ban_form)
181 .get_result::<Self>(conn)
187 community_person_ban_form: &CommunityPersonBanForm,
188 ) -> Result<usize, Error> {
189 use crate::schema::community_person_ban::dsl::{community_id, community_person_ban, person_id};
190 let conn = &mut get_conn(pool).await?;
193 .filter(community_id.eq(community_person_ban_form.community_id))
194 .filter(person_id.eq(community_person_ban_form.person_id)),
201 impl CommunityFollower {
202 pub fn to_subscribed_type(follower: &Option<Self>) -> SubscribedType {
206 SubscribedType::Pending
208 SubscribedType::Subscribed
211 // If the row doesn't exist, the person isn't a follower.
212 None => SubscribedType::NotSubscribed,
218 impl Followable for CommunityFollower {
219 type Form = CommunityFollowerForm;
220 async fn follow(pool: &DbPool, form: &CommunityFollowerForm) -> Result<Self, Error> {
221 use crate::schema::community_follower::dsl::{community_follower, community_id, person_id};
222 let conn = &mut get_conn(pool).await?;
223 insert_into(community_follower)
225 .on_conflict((community_id, person_id))
228 .get_result::<Self>(conn)
231 async fn follow_accepted(
233 community_id_: CommunityId,
234 person_id_: PersonId,
235 ) -> Result<Self, Error> {
236 use crate::schema::community_follower::dsl::{
242 let conn = &mut get_conn(pool).await?;
245 .filter(community_id.eq(community_id_))
246 .filter(person_id.eq(person_id_)),
248 .set(pending.eq(false))
249 .get_result::<Self>(conn)
252 async fn unfollow(pool: &DbPool, form: &CommunityFollowerForm) -> Result<usize, Error> {
253 use crate::schema::community_follower::dsl::{community_follower, community_id, person_id};
254 let conn = &mut get_conn(pool).await?;
257 .filter(community_id.eq(&form.community_id))
258 .filter(person_id.eq(&form.person_id)),
266 impl ApubActor for Community {
267 async fn read_from_apub_id(pool: &DbPool, object_id: &DbUrl) -> Result<Option<Self>, Error> {
268 let conn = &mut get_conn(pool).await?;
271 .filter(actor_id.eq(object_id))
272 .first::<Community>(conn)
279 async fn read_from_name(
281 community_name: &str,
282 include_deleted: bool,
283 ) -> Result<Community, Error> {
284 let conn = &mut get_conn(pool).await?;
285 let mut q = community
287 .filter(local.eq(true))
288 .filter(lower(name).eq(lower(community_name)));
289 if !include_deleted {
290 q = q.filter(deleted.eq(false)).filter(removed.eq(false));
292 q.first::<Self>(conn).await
295 async fn read_from_name_and_domain(
297 community_name: &str,
298 protocol_domain: &str,
299 ) -> Result<Community, Error> {
300 let conn = &mut get_conn(pool).await?;
302 .filter(lower(name).eq(lower(community_name)))
303 .filter(actor_id.like(format!("{protocol_domain}%")))
316 CommunityFollowerForm,
319 CommunityModeratorForm,
321 CommunityPersonBanForm,
325 person::{Person, PersonInsertForm},
327 traits::{Bannable, Crud, Followable, Joinable},
328 utils::build_db_pool_for_tests,
330 use serial_test::serial;
334 async fn test_crud() {
335 let pool = &build_db_pool_for_tests().await;
337 let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string())
341 let new_person = PersonInsertForm::builder()
342 .name("bobbee".into())
343 .public_key("pubkey".to_string())
344 .instance_id(inserted_instance.id)
347 let inserted_person = Person::create(pool, &new_person).await.unwrap();
349 let new_community = CommunityInsertForm::builder()
351 .title("nada".to_owned())
352 .public_key("pubkey".to_string())
353 .instance_id(inserted_instance.id)
356 let inserted_community = Community::create(pool, &new_community).await.unwrap();
358 let expected_community = Community {
359 id: inserted_community.id,
361 title: "nada".to_owned(),
366 published: inserted_community.published,
368 actor_id: inserted_community.actor_id.clone(),
371 public_key: "pubkey".to_owned(),
372 last_refreshed_at: inserted_community.published,
375 followers_url: inserted_community.followers_url.clone(),
376 inbox_url: inserted_community.inbox_url.clone(),
377 shared_inbox_url: None,
378 moderators_url: None,
381 posting_restricted_to_mods: false,
382 instance_id: inserted_instance.id,
385 let community_follower_form = CommunityFollowerForm {
386 community_id: inserted_community.id,
387 person_id: inserted_person.id,
391 let inserted_community_follower = CommunityFollower::follow(pool, &community_follower_form)
395 let expected_community_follower = CommunityFollower {
396 id: inserted_community_follower.id,
397 community_id: inserted_community.id,
398 person_id: inserted_person.id,
400 published: inserted_community_follower.published,
403 let community_moderator_form = CommunityModeratorForm {
404 community_id: inserted_community.id,
405 person_id: inserted_person.id,
408 let inserted_community_moderator = CommunityModerator::join(pool, &community_moderator_form)
412 let expected_community_moderator = CommunityModerator {
413 id: inserted_community_moderator.id,
414 community_id: inserted_community.id,
415 person_id: inserted_person.id,
416 published: inserted_community_moderator.published,
419 let community_person_ban_form = CommunityPersonBanForm {
420 community_id: inserted_community.id,
421 person_id: inserted_person.id,
425 let inserted_community_person_ban = CommunityPersonBan::ban(pool, &community_person_ban_form)
429 let expected_community_person_ban = CommunityPersonBan {
430 id: inserted_community_person_ban.id,
431 community_id: inserted_community.id,
432 person_id: inserted_person.id,
433 published: inserted_community_person_ban.published,
437 let read_community = Community::read(pool, inserted_community.id).await.unwrap();
439 let update_community_form = CommunityUpdateForm::builder()
440 .title(Some("nada".to_owned()))
442 let updated_community = Community::update(pool, inserted_community.id, &update_community_form)
446 let ignored_community = CommunityFollower::unfollow(pool, &community_follower_form)
449 let left_community = CommunityModerator::leave(pool, &community_moderator_form)
452 let unban = CommunityPersonBan::unban(pool, &community_person_ban_form)
455 let num_deleted = Community::delete(pool, inserted_community.id)
458 Person::delete(pool, inserted_person.id).await.unwrap();
459 Instance::delete(pool, inserted_instance.id).await.unwrap();
461 assert_eq!(expected_community, read_community);
462 assert_eq!(expected_community, inserted_community);
463 assert_eq!(expected_community, updated_community);
464 assert_eq!(expected_community_follower, inserted_community_follower);
465 assert_eq!(expected_community_moderator, inserted_community_moderator);
466 assert_eq!(expected_community_person_ban, inserted_community_person_ban);
467 assert_eq!(1, ignored_community);
468 assert_eq!(1, left_community);
469 assert_eq!(1, unban);
470 // assert_eq!(2, loaded_count);
471 assert_eq!(1, num_deleted);