]> Untitled Git - lemmy.git/commitdiff
Merge remote-tracking branch 'origin/split-db-workspace' into move_views_to_diesel_split
authorDessalines <tyhou13@gmx.com>
Mon, 21 Dec 2020 14:28:20 +0000 (09:28 -0500)
committerDessalines <tyhou13@gmx.com>
Mon, 21 Dec 2020 14:28:20 +0000 (09:28 -0500)
30 files changed:
1  2 
Cargo.lock
Cargo.toml
lemmy_api/src/comment.rs
lemmy_api/src/community.rs
lemmy_api/src/lib.rs
lemmy_api/src/post.rs
lemmy_api/src/site.rs
lemmy_api/src/user.rs
lemmy_apub/src/activities/receive/private_message.rs
lemmy_apub/src/activity_queue.rs
lemmy_apub/src/inbox/community_inbox.rs
lemmy_apub/src/inbox/receive_for_community.rs
lemmy_apub/src/inbox/user_inbox.rs
lemmy_apub/src/objects/comment.rs
lemmy_db/Cargo.toml
lemmy_db/src/aggregates/comment_aggregates.rs
lemmy_db/src/aggregates/site_aggregates.rs
lemmy_db/src/lib.rs
lemmy_db/src/source/post.rs
lemmy_db/src/source/site.rs
lemmy_db/src/views/comment_view.rs
lemmy_db/src/views/post_view.rs
lemmy_db/src/views/site_view.rs
lemmy_db_schema/src/schema.rs
lemmy_db_schema/src/source/comment_report.rs
lemmy_db_schema/src/source/post_report.rs
lemmy_structs/src/lib.rs
lemmy_structs/src/site.rs
src/code_migrations.rs
tests/integration_test.rs

diff --combined Cargo.lock
index 815cd20f69d4e55b5ca064fba84937a6302418a4,6cc79feddc9a7d301c5290f5644c42018253d29f..060fa8913c3d463c35566fbdb67862e8403381b3
@@@ -1718,6 -1718,7 +1718,7 @@@ dependencies = 
   "lazy_static",
   "lemmy_apub",
   "lemmy_db",
+  "lemmy_db_schema",
   "lemmy_rate_limit",
   "lemmy_structs",
   "lemmy_utils",
@@@ -1762,6 -1763,7 +1763,7 @@@ dependencies = 
   "itertools",
   "lazy_static",
   "lemmy_db",
+  "lemmy_db_schema",
   "lemmy_structs",
   "lemmy_utils",
   "lemmy_websocket",
@@@ -1788,8 -1790,8 +1790,9 @@@ dependencies = 
   "bcrypt",
   "chrono",
   "diesel",
 + "diesel_migrations",
   "lazy_static",
+  "lemmy_db_schema",
   "lemmy_utils",
   "log",
   "regex",
   "url",
  ]
  
+ [[package]]
+ name = "lemmy_db_schema"
+ version = "0.1.0"
+ dependencies = [
+  "chrono",
+  "diesel",
+  "log",
+  "serde 1.0.118",
+  "serde_json",
+  "url",
+ ]
  [[package]]
  name = "lemmy_rate_limit"
  version = "0.1.0"
@@@ -1836,6 -1850,7 +1851,7 @@@ dependencies = 
   "lemmy_api",
   "lemmy_apub",
   "lemmy_db",
+  "lemmy_db_schema",
   "lemmy_rate_limit",
   "lemmy_structs",
   "lemmy_utils",
@@@ -1860,6 -1875,7 +1876,7 @@@ dependencies = 
   "chrono",
   "diesel",
   "lemmy_db",
+  "lemmy_db_schema",
   "lemmy_utils",
   "log",
   "serde 1.0.118",
@@@ -1901,6 -1917,7 +1918,7 @@@ dependencies = 
   "chrono",
   "diesel",
   "lemmy_db",
+  "lemmy_db_schema",
   "lemmy_rate_limit",
   "lemmy_structs",
   "lemmy_utils",
diff --combined Cargo.toml
index 40b28677591cdb631bbd1a5d0c390b2200664280,7f2b1a8be017defdba0706a8229802ed31c5ccc1..7bed59d1e9899fde53779a432dbcf17bcf9d83a1
@@@ -3,8 -3,8 +3,8 @@@ name = "lemmy_server
  version = "0.0.1"
  edition = "2018"
  
 -[profile.release]
 -lto = true
 +#[profile.release]
 +#lto = true
  
  [workspace]
  members = [
@@@ -12,6 -12,7 +12,7 @@@
      "lemmy_apub",
      "lemmy_utils",
      "lemmy_db",
+     "lemmy_db_schema",
      "lemmy_structs",
      "lemmy_rate_limit",
      "lemmy_websocket",
@@@ -21,6 -22,7 +22,7 @@@
  lemmy_api = { path = "./lemmy_api" }
  lemmy_apub = { path = "./lemmy_apub" }
  lemmy_utils = { path = "./lemmy_utils" }
+ lemmy_db_schema = { path = "./lemmy_db_schema" }
  lemmy_db = { path = "./lemmy_db" }
  lemmy_structs = { path = "./lemmy_structs" }
  lemmy_rate_limit = { path = "./lemmy_rate_limit" }
diff --combined lemmy_api/src/comment.rs
index e5f079ad2ae395aa556d41315ac5eedc2117e2dc,2f0f8a6198d7a34f33ccef51d472298183ec6518..bafde6bfbeb67d3d0736e97e5e88b7039e90cfd6
@@@ -1,6 -1,5 +1,6 @@@
  use crate::{
    check_community_ban,
 +  check_downvotes_enabled,
    collect_moderated_communities,
    get_post,
    get_user_from_jwt,
  use actix_web::web::Data;
  use lemmy_apub::{ApubLikeableType, ApubObjectType};
  use lemmy_db::{
-   source::{
-     comment::{Comment, CommentForm, CommentLike, CommentLikeForm, CommentSaved, CommentSavedForm},
-     comment_report::{CommentReport, CommentReportForm},
-     moderator::{ModRemoveComment, ModRemoveCommentForm},
-   },
+   source::comment::Comment_,
    views::{
      comment_report_view::{CommentReportQueryBuilder, CommentReportView},
      comment_view::{CommentQueryBuilder, CommentView},
 -    site_view::SiteView,
    },
    Crud,
    Likeable,
@@@ -27,6 -23,7 +23,7 @@@
    Saveable,
    SortType,
  };
 -use lemmy_db_schema::source::{comment::*, comment_report::*, moderator::*, post::Post, user::*};
++use lemmy_db_schema::source::{comment::*, comment_report::*, moderator::*};
  use lemmy_structs::{blocking, comment::*, send_local_notifs};
  use lemmy_utils::{
    apub::{make_apub_endpoint, EndpointType},
@@@ -108,7 -105,6 +105,7 @@@ impl Perform for CreateComment 
      updated_comment.send_create(&user, context).await?;
  
      // Scan the comment for user mentions, add those rows
 +    let post_id = post.id;
      let mentions = scrape_text_for_mentions(&comment_form.content);
      let recipient_ids = send_local_notifs(
        mentions,
      // You like your own comment by default
      let like_form = CommentLikeForm {
        comment_id: inserted_comment.id,
 -      post_id: data.post_id,
 +      post_id,
        user_id: user.id,
        score: 1,
      };
  
      // strip out the recipient_ids, so that
      // users don't get double notifs
 +    // TODO Do this in a different way
      res.recipient_ids = Vec::new();
  
      Ok(res)
@@@ -203,13 -198,16 +200,13 @@@ impl Perform for EditComment 
      updated_comment.send_update(&user, context).await?;
  
      // Do the mentions / recipients
 -    let post_id = orig_comment.post.id;
 -    let post = get_post(post_id, context.pool()).await?;
 -
      let updated_comment_content = updated_comment.content.to_owned();
      let mentions = scrape_text_for_mentions(&updated_comment_content);
      let recipient_ids = send_local_notifs(
        mentions,
        updated_comment,
        &user,
 -      post,
 +      orig_comment.post,
        context.pool(),
        false,
      )
  
      // strip out the recipient_ids, so that
      // users don't get double notifs
 +    // TODO again
      res.recipient_ids = Vec::new();
  
      Ok(res)
@@@ -295,13 -292,14 +292,13 @@@ impl Perform for DeleteComment 
      .await??;
  
      // Build the recipients
 -    let post_id = comment_view.post.id;
 -    let post = get_post(post_id, context.pool()).await?;
 +    let comment_view_2 = comment_view.clone();
      let mentions = vec![];
      let recipient_ids = send_local_notifs(
        mentions,
        updated_comment,
        &user,
 -      post,
 +      comment_view_2.post,
        context.pool(),
        false,
      )
      let mut res = CommentResponse {
        comment_view,
        recipient_ids,
 -      form_id: None,
 +      form_id: None, // TODO a comment delete might clear forms?
      };
  
      context.chat_server().do_send(SendComment {
  
      // strip out the recipient_ids, so that
      // users don't get double notifs
 +    // TODO again
      res.recipient_ids = Vec::new();
  
      Ok(res)
@@@ -390,14 -387,14 +387,14 @@@ impl Perform for RemoveComment 
      .await??;
  
      // Build the recipients
 -    let post_id = comment_view.post.id;
 -    let post = get_post(post_id, context.pool()).await?;
 +    let comment_view_2 = comment_view.clone();
 +
      let mentions = vec![];
      let recipient_ids = send_local_notifs(
        mentions,
        updated_comment,
        &user,
 -      post,
 +      comment_view_2.post,
        context.pool(),
        false,
      )
      let mut res = CommentResponse {
        comment_view,
        recipient_ids,
 -      form_id: None,
 +      form_id: None, // TODO maybe this might clear other forms
      };
  
      context.chat_server().do_send(SendComment {
  
      // strip out the recipient_ids, so that
      // users don't get double notifs
 +    // TODO again
      res.recipient_ids = Vec::new();
  
      Ok(res)
@@@ -436,23 -432,41 +433,23 @@@ impl Perform for MarkCommentAsRead 
      let data: &MarkCommentAsRead = &self;
      let user = get_user_from_jwt(&data.auth, context.pool()).await?;
  
 -    let edit_id = data.edit_id;
 +    let comment_id = data.comment_id;
      let orig_comment = blocking(context.pool(), move |conn| {
 -      CommentView::read(&conn, edit_id, None)
 +      CommentView::read(&conn, comment_id, None)
      })
      .await??;
  
      check_community_ban(user.id, orig_comment.community.id, context.pool()).await?;
  
      // Verify that only the recipient can mark as read
 -    // Needs to fetch the parent comment / post to get the recipient
 -    let parent_id = orig_comment.comment.parent_id;
 -    match parent_id {
 -      Some(pid) => {
 -        let parent_comment = blocking(context.pool(), move |conn| {
 -          CommentView::read(&conn, pid, None)
 -        })
 -        .await??;
 -        if user.id != parent_comment.creator.id {
 -          return Err(APIError::err("no_comment_edit_allowed").into());
 -        }
 -      }
 -      None => {
 -        let parent_post_id = orig_comment.post.id;
 -        let parent_post =
 -          blocking(context.pool(), move |conn| Post::read(conn, parent_post_id)).await??;
 -        if user.id != parent_post.creator_id {
 -          return Err(APIError::err("no_comment_edit_allowed").into());
 -        }
 -      }
 +    if user.id != orig_comment.get_recipient_id() {
 +      return Err(APIError::err("no_comment_edit_allowed").into());
      }
  
      // Do the mark as read
      let read = data.read;
      match blocking(context.pool(), move |conn| {
 -      Comment::update_read(conn, edit_id, read)
 +      Comment::update_read(conn, comment_id, read)
      })
      .await?
      {
      };
  
      // Refetch it
 -    let edit_id = data.edit_id;
 +    let edit_id = data.comment_id;
      let user_id = user.id;
      let comment_view = blocking(context.pool(), move |conn| {
        CommentView::read(conn, edit_id, Some(user_id))
@@@ -537,7 -551,12 +534,7 @@@ impl Perform for CreateCommentLike 
      let mut recipient_ids = Vec::new();
  
      // Don't do a downvote if site has downvotes disabled
 -    if data.score == -1 {
 -      let site_view = blocking(context.pool(), move |conn| SiteView::read(conn)).await??;
 -      if !site_view.site.enable_downvotes {
 -        return Err(APIError::err("downvotes_disabled").into());
 -      }
 -    }
 +    check_downvotes_enabled(data.score, context.pool()).await?;
  
      let comment_id = data.comment_id;
      let orig_comment = blocking(context.pool(), move |conn| {
      })
      .await??;
  
 -    let post_id = orig_comment.post.id;
 -    let post = get_post(post_id, context.pool()).await?;
 -    check_community_ban(user.id, post.community_id, context.pool()).await?;
 +    check_community_ban(user.id, orig_comment.community.id, context.pool()).await?;
  
 -    let comment_id = data.comment_id;
 -    let comment = blocking(context.pool(), move |conn| Comment::read(conn, comment_id)).await??;
 -
 -    // Add to recipient ids
 -    match comment.parent_id {
 -      Some(parent_id) => {
 -        let parent_comment =
 -          blocking(context.pool(), move |conn| Comment::read(conn, parent_id)).await??;
 -        if parent_comment.creator_id != user.id {
 -          let parent_user = blocking(context.pool(), move |conn| {
 -            User_::read(conn, parent_comment.creator_id)
 -          })
 -          .await??;
 -          recipient_ids.push(parent_user.id);
 -        }
 -      }
 -      None => {
 -        recipient_ids.push(post.creator_id);
 -      }
 -    }
 +    // Add parent user to recipients
 +    recipient_ids.push(orig_comment.get_recipient_id());
  
      let like_form = CommentLikeForm {
        comment_id: data.comment_id,
 -      post_id,
 +      post_id: orig_comment.post.id,
        user_id: user.id,
        score: data.score,
      };
      .await??;
  
      // Only add the like if the score isnt 0
 +    let comment = orig_comment.comment;
      let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
      if do_add {
        let like_form2 = like_form.clone();
      // strip out the recipient_ids, so that
      // users don't get double notifs
      res.recipient_ids = Vec::new();
 +    // TODO why
  
      Ok(res)
    }
index c5ac408295f47a251e34cb17755f6292922868cc,265132a4f3dfbae400d65495c77ec0fd22371e72..405491bd2a2f8da76a28d75fe835677fc5f43e4c
@@@ -11,8 -11,11 +11,11 @@@ use anyhow::Context
  use lemmy_apub::ActorType;
  use lemmy_db::{
    diesel_option_overwrite,
-   naive_now,
-   source::{comment::Comment, community::*, moderator::*, post::Post, site::*},
+   source::{
+     comment::Comment_,
+     community::{CommunityModerator_, Community_},
+     post::Post_,
+   },
    views::{
      comment_view::CommentQueryBuilder,
      community::{
    Joinable,
    SortType,
  };
+ use lemmy_db_schema::{
+   naive_now,
+   source::{comment::Comment, community::*, moderator::*, post::Post, site::*},
+ };
  use lemmy_structs::{blocking, community::*};
  use lemmy_utils::{
    apub::{generate_actor_keypair, make_apub_endpoint, EndpointType},
@@@ -58,22 -65,20 +65,22 @@@ impl Perform for GetCommunity 
      let user = get_user_from_jwt_opt(&data.auth, context.pool()).await?;
      let user_id = user.map(|u| u.id);
  
 -    let name = data.name.to_owned().unwrap_or_else(|| "main".to_string());
 -    let community = match data.id {
 -      Some(id) => blocking(context.pool(), move |conn| Community::read(conn, id)).await??,
 -      None => match blocking(context.pool(), move |conn| {
 -        Community::read_from_name(conn, &name)
 -      })
 -      .await?
 -      {
 -        Ok(community) => community,
 -        Err(_e) => return Err(APIError::err("couldnt_find_community").into()),
 -      },
 +    let community_id = match data.id {
 +      Some(id) => id,
 +      None => {
 +        let name = data.name.to_owned().unwrap_or_else(|| "main".to_string());
 +        match blocking(context.pool(), move |conn| {
 +          Community::read_from_name(conn, &name)
 +        })
 +        .await?
 +        {
 +          Ok(community) => community,
 +          Err(_e) => return Err(APIError::err("couldnt_find_community").into()),
 +        }
 +        .id
 +      }
      };
  
 -    let community_id = community.id;
      let community_view = match blocking(context.pool(), move |conn| {
        CommunityView::read(conn, community_id, user_id)
      })
@@@ -83,6 -88,7 +90,6 @@@
        Err(_e) => return Err(APIError::err("couldnt_find_community").into()),
      };
  
 -    let community_id = community.id;
      let moderators: Vec<CommunityModeratorView> = match blocking(context.pool(), move |conn| {
        CommunityModeratorView::for_community(conn, community_id)
      })
@@@ -179,7 -185,6 +186,7 @@@ impl Perform for CreateCommunity 
        Err(_e) => return Err(APIError::err("community_already_exists").into()),
      };
  
 +    // The community creator becomes a moderator
      let community_moderator_form = CommunityModeratorForm {
        community_id: inserted_community.id,
        user_id: user.id,
        return Err(APIError::err("community_moderator_already_exists").into());
      }
  
 +    // Follow your own community
      let community_follower_form = CommunityFollowerForm {
        community_id: inserted_community.id,
        user_id: user.id,
@@@ -587,15 -591,15 +594,15 @@@ impl Perform for BanFromCommunity 
      }
  
      // Remove/Restore their data if that's desired
 -    if let Some(remove_data) = data.remove_data {
 +    if data.remove_data {
        // Posts
        blocking(context.pool(), move |conn: &'_ _| {
 -        Post::update_removed_for_creator(conn, banned_user_id, Some(community_id), remove_data)
 +        Post::update_removed_for_creator(conn, banned_user_id, Some(community_id), true)
        })
        .await??;
  
        // Comments
 -      // Diesel doesn't allow updates with joins, so this has to be a loop
 +      // TODO Diesel doesn't allow updates with joins, so this has to be a loop
        let comments = blocking(context.pool(), move |conn| {
          CommentQueryBuilder::create(conn)
            .creator_id(banned_user_id)
        for comment_view in &comments {
          let comment_id = comment_view.comment.id;
          blocking(context.pool(), move |conn: &'_ _| {
 -          Comment::update_removed(conn, comment_id, remove_data)
 +          Comment::update_removed(conn, comment_id, true)
          })
          .await??;
        }
@@@ -746,7 -750,6 +753,7 @@@ impl Perform for TransferCommunity 
  
      let mut admins = blocking(context.pool(), move |conn| UserViewSafe::admins(conn)).await??;
  
 +    // Making sure the creator, if an admin, is at the top
      let creator_index = admins
        .iter()
        .position(|r| r.user.id == site_creator_id)
diff --combined lemmy_api/src/lib.rs
index eadb0d1ac9278e8e58318b09662173d61510daba,fc484c32393bec6e9af42ab3b6624e90d2d74a47..4b61539b4d9853b0af3048e31e70124e66a8f45f
@@@ -1,16 -1,16 +1,20 @@@
  use crate::claims::Claims;
  use actix_web::{web, web::Data};
  use lemmy_db::{
 -  source::community::{CommunityModerator_, Community_},
 +  source::{
-     community::{Community, CommunityModerator},
-     post::Post,
-     site::Site,
-     user::User_,
++    community::{CommunityModerator_, Community_},
++    site::Site_,
 +  },
    views::community::community_user_ban_view::CommunityUserBanView,
    Crud,
    DbPool,
  };
+ use lemmy_db_schema::source::{
+   community::{Community, CommunityModerator},
+   post::Post,
++  site::Site,
+   user::User_,
+ };
  use lemmy_structs::{blocking, comment::*, community::*, post::*, site::*, user::*};
  use lemmy_utils::{settings::Settings, APIError, ConnectionId, LemmyError};
  use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
@@@ -103,16 -103,6 +107,16 @@@ pub(crate) async fn check_community_ban
    }
  }
  
 +pub(crate) async fn check_downvotes_enabled(score: i16, pool: &DbPool) -> Result<(), LemmyError> {
 +  if score == -1 {
 +    let site = blocking(pool, move |conn| Site::read_simple(conn)).await??;
 +    if !site.enable_downvotes {
 +      return Err(APIError::err("downvotes_disabled").into());
 +    }
 +  }
 +  Ok(())
 +}
 +
  /// Returns a list of communities that the user moderates
  /// or if a community_id is supplied validates the user is a moderator
  /// of that community and returns the community id in a vec
diff --combined lemmy_api/src/post.rs
index f021b0d7ce2bc4545e423f11b392fcaf6fc34ff2,2dd834be99805ed37fcdb6ba86cf43124727bdef..20b5b8d556e1e6f77fef4a1f137675adc0858526
@@@ -1,6 -1,5 +1,6 @@@
  use crate::{
    check_community_ban,
 +  check_downvotes_enabled,
    check_optional_url,
    collect_moderated_communities,
    get_user_from_jwt,
  use actix_web::web::Data;
  use lemmy_apub::{ApubLikeableType, ApubObjectType};
  use lemmy_db::{
-   naive_now,
-   source::{
-     moderator::*,
-     post::*,
-     post_report::{PostReport, PostReportForm},
-   },
+   source::post::Post_,
    views::{
      comment_view::CommentQueryBuilder,
 -    community::{community_moderator_view::CommunityModeratorView, community_view::CommunityView},
 +    community::community_moderator_view::CommunityModeratorView,
      post_report_view::{PostReportQueryBuilder, PostReportView},
      post_view::{PostQueryBuilder, PostView},
 -    site_view::SiteView,
    },
    Crud,
    Likeable,
    Saveable,
    SortType,
  };
+ use lemmy_db_schema::{
+   naive_now,
+   source::{
+     moderator::*,
+     post::*,
+     post_report::{PostReport, PostReportForm},
+   },
+ };
  use lemmy_structs::{blocking, post::*};
  use lemmy_utils::{
    apub::{make_apub_endpoint, EndpointType},
@@@ -192,6 -195,12 +195,6 @@@ impl Perform for GetPost 
      })
      .await??;
  
 -    let community_id = post_view.community.id;
 -    let community = blocking(context.pool(), move |conn| {
 -      CommunityView::read(conn, community_id, user_id)
 -    })
 -    .await??;
 -
      let community_id = post_view.community.id;
      let moderators = blocking(context.pool(), move |conn| {
        CommunityModeratorView::for_community(conn, community_id)
      Ok(GetPostResponse {
        post_view,
        comments,
 -      community,
        moderators,
        online,
      })
@@@ -278,7 -288,12 +281,7 @@@ impl Perform for CreatePostLike 
      let user = get_user_from_jwt(&data.auth, context.pool()).await?;
  
      // Don't do a downvote if site has downvotes disabled
 -    if data.score == -1 {
 -      let site_view = blocking(context.pool(), move |conn| SiteView::read(conn)).await??;
 -      if !site_view.site.enable_downvotes {
 -        return Err(APIError::err("downvotes_disabled").into());
 -      }
 -    }
 +    check_downvotes_enabled(data.score, context.pool()).await?;
  
      // Check for a community ban
      let post_id = data.post_id;
diff --combined lemmy_api/src/site.rs
index 16c6ecec9bd7063a440ac791be5148f695858669,05cac0ae648f9fd7256f5947bbb1efee08cd99d7..e30e62303213683d5496352b47dd753686b42163
@@@ -10,9 -10,9 +10,8 @@@ use actix_web::web::Data
  use anyhow::Context;
  use lemmy_apub::fetcher::search_by_apub_id;
  use lemmy_db::{
 -  aggregates::site_aggregates::SiteAggregates,
    diesel_option_overwrite,
-   naive_now,
-   source::{category::*, moderator::*, site::*},
+   source::{category::Category_, site::Site_},
    views::{
      comment_view::CommentQueryBuilder,
      community::community_view::CommunityQueryBuilder,
    SearchType,
    SortType,
  };
+ use lemmy_db_schema::{
+   naive_now,
+   source::{
+     category::Category,
+     moderator::*,
+     site::{Site, *},
+   },
+ };
  use lemmy_structs::{blocking, site::*, user::Register};
  use lemmy_utils::{
    location_info,
@@@ -155,7 -163,7 +162,7 @@@ impl Perform for CreateSite 
    ) -> Result<SiteResponse, LemmyError> {
      let data: &CreateSite = &self;
  
 -    let read_site = move |conn: &'_ _| Site::read(conn, 1);
 +    let read_site = move |conn: &'_ _| Site::read_simple(conn);
      if blocking(context.pool(), read_site).await?.is_ok() {
        return Err(APIError::err("site_already_exists").into());
      };
  
      let site_view = blocking(context.pool(), move |conn| SiteView::read(conn)).await??;
  
 -    Ok(SiteResponse { site: site_view })
 +    Ok(SiteResponse { site_view })
    }
  }
  
@@@ -208,7 -216,7 +215,7 @@@ impl Perform for EditSite 
      // Make sure user is an admin
      is_admin(context.pool(), user.id).await?;
  
 -    let found_site = blocking(context.pool(), move |conn| Site::read(conn, 1)).await??;
 +    let found_site = blocking(context.pool(), move |conn| Site::read_simple(conn)).await??;
  
      let icon = diesel_option_overwrite(&data.icon);
      let banner = diesel_option_overwrite(&data.banner);
  
      let site_view = blocking(context.pool(), move |conn| SiteView::read(conn)).await??;
  
 -    let res = SiteResponse { site: site_view };
 +    let res = SiteResponse { site_view };
  
      context.chat_server().do_send(SendAllMessage {
        op: UserOperation::EditSite,
@@@ -255,41 -263,39 +262,41 @@@ impl Perform for GetSite 
    ) -> Result<GetSiteResponse, LemmyError> {
      let data: &GetSite = &self;
  
 -    // TODO refactor this a little
 -    let res = blocking(context.pool(), move |conn| Site::read(conn, 1)).await?;
 -    let site_view = if res.is_ok() {
 -      Some(blocking(context.pool(), move |conn| SiteView::read(conn)).await??)
 -    } else if let Some(setup) = Settings::get().setup.as_ref() {
 -      let register = Register {
 -        username: setup.admin_username.to_owned(),
 -        email: setup.admin_email.to_owned(),
 -        password: setup.admin_password.to_owned(),
 -        password_verify: setup.admin_password.to_owned(),
 -        admin: true,
 -        show_nsfw: true,
 -        captcha_uuid: None,
 -        captcha_answer: None,
 -      };
 -      let login_response = register.perform(context, websocket_id).await?;
 -      info!("Admin {} created", setup.admin_username);
 -
 -      let create_site = CreateSite {
 -        name: setup.site_name.to_owned(),
 -        description: None,
 -        icon: None,
 -        banner: None,
 -        enable_downvotes: true,
 -        open_registration: true,
 -        enable_nsfw: true,
 -        auth: login_response.jwt,
 -      };
 -      create_site.perform(context, websocket_id).await?;
 -      info!("Site {} created", setup.site_name);
 -      Some(blocking(context.pool(), move |conn| SiteView::read(conn)).await??)
 -    } else {
 -      None
 +    let site_view = match blocking(context.pool(), move |conn| SiteView::read(conn)).await? {
 +      Ok(site_view) => Some(site_view),
 +      // If the site isn't created yet, check the setup
 +      Err(_) => {
 +        if let Some(setup) = Settings::get().setup.as_ref() {
 +          let register = Register {
 +            username: setup.admin_username.to_owned(),
 +            email: setup.admin_email.to_owned(),
 +            password: setup.admin_password.to_owned(),
 +            password_verify: setup.admin_password.to_owned(),
 +            admin: true,
 +            show_nsfw: true,
 +            captcha_uuid: None,
 +            captcha_answer: None,
 +          };
 +          let login_response = register.perform(context, websocket_id).await?;
 +          info!("Admin {} created", setup.admin_username);
 +
 +          let create_site = CreateSite {
 +            name: setup.site_name.to_owned(),
 +            description: None,
 +            icon: None,
 +            banner: None,
 +            enable_downvotes: true,
 +            open_registration: true,
 +            enable_nsfw: true,
 +            auth: login_response.jwt,
 +          };
 +          create_site.perform(context, websocket_id).await?;
 +          info!("Site {} created", setup.site_name);
 +          Some(blocking(context.pool(), move |conn| SiteView::read(conn)).await??)
 +        } else {
 +          None
 +        }
 +      }
      };
  
      let mut admins = blocking(context.pool(), move |conn| UserViewSafe::admins(conn)).await??;
          u
        });
  
 -    let counts = blocking(context.pool(), move |conn| SiteAggregates::read(conn)).await??;
 -
      Ok(GetSiteResponse {
 -      site: site_view,
 +      site_view,
        admins,
        banned,
        online,
        version: version::VERSION.to_string(),
        my_user,
        federated_instances: linked_instances(context.pool()).await?,
 -      counts,
      })
    }
  }
@@@ -519,7 -528,7 +526,7 @@@ impl Perform for TransferSite 
      user.private_key = None;
      user.public_key = None;
  
 -    let read_site = blocking(context.pool(), move |conn| Site::read(conn, 1)).await??;
 +    let read_site = blocking(context.pool(), move |conn| Site::read_simple(conn)).await??;
  
      // Make sure user is the creator
      if read_site.creator_id != user.id {
  
      let banned = blocking(context.pool(), move |conn| UserViewSafe::banned(conn)).await??;
  
 -    let counts = blocking(context.pool(), move |conn| SiteAggregates::read(conn)).await??;
 -
      Ok(GetSiteResponse {
 -      site: Some(site_view),
 +      site_view: Some(site_view),
        admins,
        banned,
        online: 0,
        version: version::VERSION.to_string(),
        my_user: Some(user),
        federated_instances: linked_instances(context.pool()).await?,
 -      counts,
      })
    }
  }
@@@ -599,8 -611,12 +606,8 @@@ impl Perform for SaveSiteConfig 
      let user = get_user_from_jwt(&data.auth, context.pool()).await?;
  
      // Only let admins read this
 -    let admins = blocking(context.pool(), move |conn| UserViewSafe::admins(conn)).await??;
 -    let admin_ids: Vec<i32> = admins.into_iter().map(|m| m.user.id).collect();
 -
 -    if !admin_ids.contains(&user.id) {
 -      return Err(APIError::err("not_an_admin").into());
 -    }
 +    let user_id = user.id;
 +    is_admin(context.pool(), user_id).await?;
  
      // Make sure docker doesn't have :ro at the end of the volume, so its not a read-only filesystem
      let config_hjson = match Settings::save_config_file(&data.config_hjson) {
diff --combined lemmy_api/src/user.rs
index cca8dffb8909225d06ecb23c12ce5f9fef75ea60,98a186c316b9627fe69bb448a6203bcfd236aad0..34ef5022e17f470ed1ceada4a1dc81de2ea52e18
@@@ -16,17 -16,14 +16,15 @@@ use chrono::Duration
  use lemmy_apub::ApubObjectType;
  use lemmy_db::{
    diesel_option_overwrite,
-   naive_now,
    source::{
-     comment::*,
-     community::*,
-     moderator::*,
-     password_reset_request::*,
-     post::*,
-     private_message::*,
-     site::*,
-     user::*,
-     user_mention::*,
+     comment::Comment_,
+     community::Community_,
+     password_reset_request::PasswordResetRequest_,
+     post::Post_,
+     private_message::PrivateMessage_,
++    site::Site_,
+     user::User,
+     user_mention::UserMention_,
    },
    views::{
      comment_report_view::CommentReportView,
@@@ -38,6 -35,7 +36,6 @@@
      post_report_view::PostReportView,
      post_view::PostQueryBuilder,
      private_message_view::{PrivateMessageQueryBuilder, PrivateMessageView},
 -    site_view::SiteView,
      user_mention_view::{UserMentionQueryBuilder, UserMentionView},
      user_view::{UserViewDangerous, UserViewSafe},
    },
    ListingType,
    SortType,
  };
+ use lemmy_db_schema::{
+   naive_now,
+   source::{
+     comment::Comment,
+     community::*,
+     moderator::*,
+     password_reset_request::*,
+     post::Post,
+     private_message::*,
+     site::*,
+     user::*,
+     user_mention::*,
+   },
+ };
  use lemmy_structs::{blocking, send_email_to_user, user::*};
  use lemmy_utils::{
    apub::{generate_actor_keypair, make_apub_endpoint, EndpointType},
@@@ -119,8 -131,8 +131,8 @@@ impl Perform for Register 
      let data: &Register = &self;
  
      // Make sure site has open registration
 -    if let Ok(site_view) = blocking(context.pool(), move |conn| SiteView::read(conn)).await? {
 -      if !site_view.site.open_registration {
 +    if let Ok(site) = blocking(context.pool(), move |conn| Site::read_simple(conn)).await? {
 +      if !site.open_registration {
          return Err(APIError::err("registration_closed").into());
        }
      }
@@@ -346,6 -358,9 +358,6 @@@ impl Perform for SaveUserSettings 
      let data: &SaveUserSettings = &self;
      let user = get_user_from_jwt(&data.auth, context.pool()).await?;
  
 -    let user_id = user.id;
 -    let read_user = blocking(context.pool(), move |conn| User_::read(conn, user_id)).await??;
 -
      let avatar = diesel_option_overwrite(&data.avatar);
      let banner = diesel_option_overwrite(&data.banner);
      let email = diesel_option_overwrite(&data.email);
        }
      }
  
 +    let user_id = user.id;
      let password_encrypted = match &data.new_password {
        Some(new_password) => {
          match &data.new_password_verify {
              // Check the old password
              match &data.old_password {
                Some(old_password) => {
 -                let valid: bool =
 -                  verify(old_password, &read_user.password_encrypted).unwrap_or(false);
 +                let valid: bool = verify(old_password, &user.password_encrypted).unwrap_or(false);
                  if !valid {
                    return Err(APIError::err("password_incorrect").into());
                  }
            None => return Err(APIError::err("passwords_dont_match").into()),
          }
        }
 -      None => read_user.password_encrypted,
 +      None => user.password_encrypted,
      };
  
 +    let default_listing_type = ListingType::from_str(&data.default_listing_type)? as i16;
 +    let default_sort_type = SortType::from_str(&data.default_sort_type)? as i16;
 +
      let user_form = UserForm {
 -      name: read_user.name,
 +      name: user.name,
        email,
        matrix_user_id,
        avatar,
        banner,
        password_encrypted,
        preferred_username,
 -      published: Some(read_user.published),
 +      published: Some(user.published),
        updated: Some(naive_now()),
 -      admin: read_user.admin,
 -      banned: Some(read_user.banned),
 +      admin: user.admin,
 +      banned: Some(user.banned),
        show_nsfw: data.show_nsfw,
        theme: data.theme.to_owned(),
 -      default_sort_type: data.default_sort_type,
 -      default_listing_type: data.default_listing_type,
 +      default_sort_type,
 +      default_listing_type,
        lang: data.lang.to_owned(),
        show_avatars: data.show_avatars,
        send_notifications_to_email: data.send_notifications_to_email,
 -      actor_id: Some(read_user.actor_id),
 +      actor_id: Some(user.actor_id),
        bio,
 -      local: read_user.local,
 -      private_key: read_user.private_key,
 -      public_key: read_user.public_key,
 +      local: user.local,
 +      private_key: user.private_key,
 +      public_key: user.public_key,
        last_refreshed_at: None,
      };
  
@@@ -578,8 -590,9 +590,8 @@@ impl Perform for GetUserDetails 
  
      // Return the jwt
      Ok(GetUserDetailsResponse {
 -      // TODO need to figure out dangerous user view here
 -      user: user_view,
 -      user_dangerous,
 +      user_view,
 +      user_view_dangerous: user_dangerous,
        follows,
        moderates,
        comments,
@@@ -667,22 -680,22 +679,22 @@@ impl Perform for BanUser 
      }
  
      // Remove their data if that's desired
 -    if let Some(remove_data) = data.remove_data {
 +    if data.remove_data {
        // Posts
        blocking(context.pool(), move |conn: &'_ _| {
 -        Post::update_removed_for_creator(conn, banned_user_id, None, remove_data)
 +        Post::update_removed_for_creator(conn, banned_user_id, None, true)
        })
        .await??;
  
        // Communities
        blocking(context.pool(), move |conn: &'_ _| {
 -        Community::update_removed_for_creator(conn, banned_user_id, remove_data)
 +        Community::update_removed_for_creator(conn, banned_user_id, true)
        })
        .await??;
  
        // Comments
        blocking(context.pool(), move |conn: &'_ _| {
 -        Comment::update_removed_for_creator(conn, banned_user_id, remove_data)
 +        Comment::update_removed_for_creator(conn, banned_user_id, true)
        })
        .await??;
      }
      .await??;
  
      let res = BanUserResponse {
 -      user: user_view,
 +      user_view,
        banned: data.ban,
      };
  
@@@ -1089,9 -1102,7 +1101,9 @@@ impl Perform for CreatePrivateMessage 
      })
      .await??;
  
 -    let res = PrivateMessageResponse { message };
 +    let res = PrivateMessageResponse {
 +      private_message_view: message,
 +    };
  
      context.chat_server().do_send(SendUserRoomMessage {
        op: UserOperation::CreatePrivateMessage,
@@@ -1148,9 -1159,7 +1160,9 @@@ impl Perform for EditPrivateMessage 
      .await??;
      let recipient_id = message.recipient.id;
  
 -    let res = PrivateMessageResponse { message };
 +    let res = PrivateMessageResponse {
 +      private_message_view: message,
 +    };
  
      context.chat_server().do_send(SendUserRoomMessage {
        op: UserOperation::EditPrivateMessage,
@@@ -1213,9 -1222,7 +1225,9 @@@ impl Perform for DeletePrivateMessage 
      .await??;
      let recipient_id = message.recipient.id;
  
 -    let res = PrivateMessageResponse { message };
 +    let res = PrivateMessageResponse {
 +      private_message_view: message,
 +    };
  
      context.chat_server().do_send(SendUserRoomMessage {
        op: UserOperation::DeletePrivateMessage,
@@@ -1271,9 -1278,7 +1283,9 @@@ impl Perform for MarkPrivateMessageAsRe
      .await??;
      let recipient_id = message.recipient.id;
  
 -    let res = PrivateMessageResponse { message };
 +    let res = PrivateMessageResponse {
 +      private_message_view: message,
 +    };
  
      context.chat_server().do_send(SendUserRoomMessage {
        op: UserOperation::MarkPrivateMessageAsRead,
@@@ -1311,9 -1316,7 +1323,9 @@@ impl Perform for GetPrivateMessages 
      })
      .await??;
  
 -    Ok(PrivateMessagesResponse { messages })
 +    Ok(PrivateMessagesResponse {
 +      private_messages: messages,
 +    })
    }
  }
  
index 8f7952b6b067fa5bdf93a6039b75fe97217baad7,06c9cf2a81f10c1995d831b77f722529c627f54a..09c234cac2e9a2e93e46c2340886561a9e23cc79
@@@ -14,9 -14,10 +14,10 @@@ use activitystreams::
  };
  use anyhow::{anyhow, Context};
  use lemmy_db::{
-   source::private_message::PrivateMessage,
+   source::private_message::PrivateMessage_,
    views::private_message_view::PrivateMessageView,
  };
+ use lemmy_db_schema::source::private_message::PrivateMessage;
  use lemmy_structs::{blocking, user::PrivateMessageResponse};
  use lemmy_utils::{location_info, LemmyError};
  use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperation};
@@@ -47,11 -48,9 +48,11 @@@ pub(crate) async fn receive_create_priv
    })
    .await??;
  
 -  let res = PrivateMessageResponse { message };
 +  let res = PrivateMessageResponse {
 +    private_message_view: message,
 +  };
  
 -  let recipient_id = res.message.recipient.id;
 +  let recipient_id = res.private_message_view.recipient.id;
  
    context.chat_server().do_send(SendUserRoomMessage {
      op: UserOperation::CreatePrivateMessage,
@@@ -87,11 -86,9 +88,11 @@@ pub(crate) async fn receive_update_priv
    })
    .await??;
  
 -  let res = PrivateMessageResponse { message };
 +  let res = PrivateMessageResponse {
 +    private_message_view: message,
 +  };
  
 -  let recipient_id = res.message.recipient.id;
 +  let recipient_id = res.private_message_view.recipient.id;
  
    context.chat_server().do_send(SendUserRoomMessage {
      op: UserOperation::EditPrivateMessage,
@@@ -121,10 -118,8 +122,10 @@@ pub(crate) async fn receive_delete_priv
    })
    .await??;
  
 -  let res = PrivateMessageResponse { message };
 -  let recipient_id = res.message.recipient.id;
 +  let res = PrivateMessageResponse {
 +    private_message_view: message,
 +  };
 +  let recipient_id = res.private_message_view.recipient.id;
    context.chat_server().do_send(SendUserRoomMessage {
      op: UserOperation::EditPrivateMessage,
      response: res,
@@@ -158,10 -153,8 +159,10 @@@ pub(crate) async fn receive_undo_delete
    })
    .await??;
  
 -  let res = PrivateMessageResponse { message };
 -  let recipient_id = res.message.recipient.id;
 +  let res = PrivateMessageResponse {
 +    private_message_view: message,
 +  };
 +  let recipient_id = res.private_message_view.recipient.id;
    context.chat_server().do_send(SendUserRoomMessage {
      op: UserOperation::EditPrivateMessage,
      response: res,
index d94c7cbf75bed9ba207bc0e8d8d63c043b5b3dc9,597c182b7931b51e29371fc9ca7ca6e404c19ff8..fe70d8e8bdae6e412074056d770b7b2408b08ce6
@@@ -19,16 -19,14 +19,14 @@@ use background_jobs::
    WorkerConfig,
  };
  use itertools::Itertools;
- use lemmy_db::{
-   source::{community::Community, user::User_},
-   DbPool,
- };
+ use lemmy_db::DbPool;
+ use lemmy_db_schema::source::{community::Community, user::User_};
  use lemmy_utils::{location_info, settings::Settings, LemmyError};
  use lemmy_websocket::LemmyContext;
  use log::{debug, warn};
  use reqwest::Client;
  use serde::{export::fmt::Debug, Deserialize, Serialize};
 -use std::{collections::BTreeMap, future::Future, pin::Pin};
 +use std::{collections::BTreeMap, env, future::Future, pin::Pin};
  use url::Url;
  
  /// Sends a local activity to a single, remote actor.
@@@ -237,11 -235,7 +235,11 @@@ wher
        actor_id: actor.actor_id()?,
        private_key: actor.private_key().context(location_info!())?,
      };
 -    activity_sender.queue::<SendActivityTask>(message)?;
 +    if env::var("LEMMY_TEST_SEND_SYNC").is_ok() {
 +      do_send(message, &Client::default()).await?;
 +    } else {
 +      activity_sender.queue::<SendActivityTask>(message)?;
 +    }
    }
  
    Ok(())
@@@ -266,32 -260,30 +264,32 @@@ impl ActixJob for SendActivityTask 
    const BACKOFF: Backoff = Backoff::Exponential(2);
  
    fn run(self, state: Self::State) -> Self::Future {
 -    Box::pin(async move {
 -      let mut headers = BTreeMap::<String, String>::new();
 -      headers.insert("Content-Type".into(), "application/json".into());
 -      let result = sign_and_send(
 -        &state.client,
 -        headers,
 -        &self.inbox,
 -        self.activity.clone(),
 -        &self.actor_id,
 -        self.private_key.to_owned(),
 -      )
 -      .await;
 +    Box::pin(async move { do_send(self, &state.client).await })
 +  }
 +}
  
 -      if let Err(e) = result {
 -        warn!("{}", e);
 -        return Err(anyhow!(
 -          "Failed to send activity {} to {}",
 -          &self.activity,
 -          self.inbox
 -        ));
 -      }
 -      Ok(())
 -    })
 +async fn do_send(task: SendActivityTask, client: &Client) -> Result<(), Error> {
 +  let mut headers = BTreeMap::<String, String>::new();
 +  headers.insert("Content-Type".into(), "application/json".into());
 +  let result = sign_and_send(
 +    client,
 +    headers,
 +    &task.inbox,
 +    task.activity.clone(),
 +    &task.actor_id,
 +    task.private_key.to_owned(),
 +  )
 +  .await;
 +
 +  if let Err(e) = result {
 +    warn!("{}", e);
 +    return Err(anyhow!(
 +      "Failed to send activity {} to {}",
 +      &task.activity,
 +      task.inbox
 +    ));
    }
 +  Ok(())
  }
  
  pub fn create_activity_queue() -> QueueHandle {
index ec4d30ae8f06f8c08f2e056c75eb0a44291485a3,0573b589ffa99838e9b31f310ab671f56b3649eb..f82da236bd176aaa3b6d74bb9e58847c78f7aa9f
@@@ -27,15 -27,16 +27,16 @@@ use activitystreams::
  use actix_web::{web, HttpRequest, HttpResponse};
  use anyhow::{anyhow, Context};
  use lemmy_db::{
-   source::{
-     community::{Community, CommunityFollower, CommunityFollowerForm},
-     user::User_,
-   },
+   source::community::Community_,
    views::community::community_user_ban_view::CommunityUserBanView,
    ApubObject,
    DbPool,
    Followable,
  };
+ use lemmy_db_schema::source::{
+   community::{Community, CommunityFollower, CommunityFollowerForm},
+   user::User_,
+ };
  use lemmy_structs::blocking;
  use lemmy_utils::{location_info, LemmyError};
  use lemmy_websocket::LemmyContext;
@@@ -179,7 -180,7 +180,7 @@@ pub(crate) async fn community_receive_m
        .await?;
    }
  
 -  return Ok(HttpResponse::Ok().finish());
 +  Ok(HttpResponse::Ok().finish())
  }
  
  /// Handle a follow request from a remote user, adding the user as follower and returning an
index ff160144fb06214d3f347e4c71466185f9f2e3ec,1ead7558fb87b6b256cb8d81424b66d52c5c76ec..31c5efba148df32cb3fc48baa678b25041d3c885
@@@ -41,11 -41,8 +41,8 @@@ use activitystreams::
  };
  use anyhow::Context;
  use diesel::result::Error::NotFound;
- use lemmy_db::{
-   source::{comment::Comment, post::Post, site::Site},
-   ApubObject,
-   Crud,
- };
+ use lemmy_db::{ApubObject, Crud};
+ use lemmy_db_schema::source::{comment::Comment, post::Post, site::Site};
  use lemmy_structs::blocking;
  use lemmy_utils::{location_info, LemmyError};
  use lemmy_websocket::LemmyContext;
@@@ -350,7 -347,7 +347,7 @@@ async fn find_post_or_comment_by_id
      return Ok(PostOrComment::Comment(c));
    }
  
 -  return Err(NotFound.into());
 +  Err(NotFound.into())
  }
  
  async fn fetch_post_or_comment_by_id(
      return Ok(PostOrComment::Comment(comment));
    }
  
 -  return Err(NotFound.into());
 +  Err(NotFound.into())
  }
  
  fn get_like_object_id<Activity>(like_or_dislike: &Activity) -> Result<Url, LemmyError>
index dc387739b582d58dac9ed4fd9b509b90d04e3d61,1c23a691bd5d93b9ec30c8734d90932089563f9b..a9ca4b9444a938c8861a222c05043f8c865ea87d
@@@ -48,14 -48,11 +48,11 @@@ use activitystreams::
  use actix_web::{web, HttpRequest, HttpResponse};
  use anyhow::{anyhow, Context};
  use diesel::NotFound;
- use lemmy_db::{
-   source::{
-     community::{Community, CommunityFollower},
-     private_message::PrivateMessage,
-     user::User_,
-   },
-   ApubObject,
-   Followable,
+ use lemmy_db::{source::user::User, ApubObject, Followable};
+ use lemmy_db_schema::source::{
+   community::{Community, CommunityFollower},
+   private_message::PrivateMessage,
+   user::User_,
  };
  use lemmy_structs::blocking;
  use lemmy_utils::{location_info, LemmyError};
@@@ -396,5 -393,5 +393,5 @@@ async fn find_community_or_private_mess
      return Ok(CommunityOrPrivateMessage::PrivateMessage(p));
    }
  
 -  return Err(NotFound.into());
 +  Err(NotFound.into())
  }
index 0d1f6db80d442c1fa4852f5b8c49dea7a2d24140,d3341630aee5e3b21d3408b7b7803631e7b3f6ff..e922724856be9b768e1c5ccf2d8a6b8d83fda88a
@@@ -23,15 -23,12 +23,12 @@@ use activitystreams::
    prelude::*,
  };
  use anyhow::{anyhow, Context};
- use lemmy_db::{
-   source::{
-     comment::{Comment, CommentForm},
-     community::Community,
-     post::Post,
-     user::User_,
-   },
-   Crud,
-   DbPool,
+ use lemmy_db::{Crud, DbPool};
+ use lemmy_db_schema::source::{
+   comment::{Comment, CommentForm},
+   community::Community,
+   post::Post,
+   user::User_,
  };
  use lemmy_structs::blocking;
  use lemmy_utils::{
@@@ -118,7 -115,7 +115,7 @@@ impl FromApub for Comment 
          Comment::delete(conn, comment.id)
        })
        .await??;
 -      return Err(anyhow!("Post is locked").into());
 +      Err(anyhow!("Post is locked").into())
      } else {
        Ok(comment)
      }
diff --combined lemmy_db/Cargo.toml
index 5963f32cc331e8c81f77691417db884704627337,0442d0145ebcf885f7a3cc6a38545b65ee6dd45e..15dd749acaff940c7f98c68fea09fdf348be038f
@@@ -9,8 -9,8 +9,9 @@@ path = "src/lib.rs
  
  [dependencies]
  lemmy_utils = { path = "../lemmy_utils" }
+ lemmy_db_schema = { path = "../lemmy_db_schema" }
  diesel = { version = "1.4.5", features = ["postgres","chrono","r2d2","serde_json"] }
 +diesel_migrations = "1.4.0"
  chrono = { version = "0.4.19", features = ["serde"] }
  serde = { version = "1.0.118", features = ["derive"] }
  serde_json = { version = "1.0.60", features = ["preserve_order"] }
@@@ -18,7 -18,7 +19,7 @@@ strum = "0.20.0
  strum_macros = "0.20.1"
  log = "0.4.11"
  sha2 = "0.9.2"
- bcrypt = "0.9.0"
  url = { version = "2.2.0", features = ["serde"] }
  lazy_static = "1.4.0"
  regex = "1.4.2"
+ bcrypt = "0.9.0"
index 7304dacc212b9f61fff16ccb61b0f0c27bf86132,2bfd39393354530d7663edffa5913fe062e4e846..c6b726755a99383b96e6a0b2075140dc0e8592a0
@@@ -1,5 -1,5 +1,5 @@@
- use crate::schema::comment_aggregates;
  use diesel::{result::Error, *};
+ use lemmy_db_schema::schema::comment_aggregates;
  use serde::Serialize;
  
  #[derive(Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Clone)]
@@@ -20,210 -20,4 +20,210 @@@ impl CommentAggregates 
    }
  }
  
 -// TODO add tests here
 +#[cfg(test)]
 +mod tests {
 +  use crate::{
 +    aggregates::comment_aggregates::CommentAggregates,
 +    source::{
 +      comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
 +      community::{Community, CommunityForm},
 +      post::{Post, PostForm},
 +      user::{UserForm, User_},
 +    },
 +    tests::establish_unpooled_connection,
 +    Crud,
 +    Likeable,
 +    ListingType,
 +    SortType,
 +  };
 +
 +  #[test]
 +  fn test_crud() {
 +    let conn = establish_unpooled_connection();
 +
 +    let new_user = UserForm {
 +      name: "thommy_comment_agg".into(),
 +      preferred_username: None,
 +      password_encrypted: "nope".into(),
 +      email: None,
 +      matrix_user_id: None,
 +      avatar: None,
 +      banner: None,
 +      admin: false,
 +      banned: Some(false),
 +      published: None,
 +      updated: None,
 +      show_nsfw: false,
 +      theme: "browser".into(),
 +      default_sort_type: SortType::Hot as i16,
 +      default_listing_type: ListingType::Subscribed as i16,
 +      lang: "browser".into(),
 +      show_avatars: true,
 +      send_notifications_to_email: false,
 +      actor_id: None,
 +      bio: None,
 +      local: true,
 +      private_key: None,
 +      public_key: None,
 +      last_refreshed_at: None,
 +    };
 +
 +    let inserted_user = User_::create(&conn, &new_user).unwrap();
 +
 +    let another_user = UserForm {
 +      name: "jerry_comment_agg".into(),
 +      preferred_username: None,
 +      password_encrypted: "nope".into(),
 +      email: None,
 +      matrix_user_id: None,
 +      avatar: None,
 +      banner: None,
 +      admin: false,
 +      banned: Some(false),
 +      published: None,
 +      updated: None,
 +      show_nsfw: false,
 +      theme: "browser".into(),
 +      default_sort_type: SortType::Hot as i16,
 +      default_listing_type: ListingType::Subscribed as i16,
 +      lang: "browser".into(),
 +      show_avatars: true,
 +      send_notifications_to_email: false,
 +      actor_id: None,
 +      bio: None,
 +      local: true,
 +      private_key: None,
 +      public_key: None,
 +      last_refreshed_at: None,
 +    };
 +
 +    let another_inserted_user = User_::create(&conn, &another_user).unwrap();
 +
 +    let new_community = CommunityForm {
 +      name: "TIL_comment_agg".into(),
 +      creator_id: inserted_user.id,
 +      title: "nada".to_owned(),
 +      description: None,
 +      category_id: 1,
 +      nsfw: false,
 +      removed: None,
 +      deleted: None,
 +      updated: None,
 +      actor_id: None,
 +      local: true,
 +      private_key: None,
 +      public_key: None,
 +      last_refreshed_at: None,
 +      published: None,
 +      icon: None,
 +      banner: None,
 +    };
 +
 +    let inserted_community = Community::create(&conn, &new_community).unwrap();
 +
 +    let new_post = PostForm {
 +      name: "A test post".into(),
 +      url: None,
 +      body: None,
 +      creator_id: inserted_user.id,
 +      community_id: inserted_community.id,
 +      removed: None,
 +      deleted: None,
 +      locked: None,
 +      stickied: None,
 +      nsfw: false,
 +      updated: None,
 +      embed_title: None,
 +      embed_description: None,
 +      embed_html: None,
 +      thumbnail_url: None,
 +      ap_id: None,
 +      local: true,
 +      published: None,
 +    };
 +
 +    let inserted_post = Post::create(&conn, &new_post).unwrap();
 +
 +    let comment_form = CommentForm {
 +      content: "A test comment".into(),
 +      creator_id: inserted_user.id,
 +      post_id: inserted_post.id,
 +      removed: None,
 +      deleted: None,
 +      read: None,
 +      parent_id: None,
 +      published: None,
 +      updated: None,
 +      ap_id: None,
 +      local: true,
 +    };
 +
 +    let inserted_comment = Comment::create(&conn, &comment_form).unwrap();
 +
 +    let child_comment_form = CommentForm {
 +      content: "A test comment".into(),
 +      creator_id: inserted_user.id,
 +      post_id: inserted_post.id,
 +      removed: None,
 +      deleted: None,
 +      read: None,
 +      parent_id: Some(inserted_comment.id),
 +      published: None,
 +      updated: None,
 +      ap_id: None,
 +      local: true,
 +    };
 +
 +    let _inserted_child_comment = Comment::create(&conn, &child_comment_form).unwrap();
 +
 +    let comment_like = CommentLikeForm {
 +      comment_id: inserted_comment.id,
 +      post_id: inserted_post.id,
 +      user_id: inserted_user.id,
 +      score: 1,
 +    };
 +
 +    CommentLike::like(&conn, &comment_like).unwrap();
 +
 +    let comment_aggs_before_delete = CommentAggregates::read(&conn, inserted_comment.id).unwrap();
 +
 +    assert_eq!(1, comment_aggs_before_delete.score);
 +    assert_eq!(1, comment_aggs_before_delete.upvotes);
 +    assert_eq!(0, comment_aggs_before_delete.downvotes);
 +
 +    // Add a post dislike from the other user
 +    let comment_dislike = CommentLikeForm {
 +      comment_id: inserted_comment.id,
 +      post_id: inserted_post.id,
 +      user_id: another_inserted_user.id,
 +      score: -1,
 +    };
 +
 +    CommentLike::like(&conn, &comment_dislike).unwrap();
 +
 +    let comment_aggs_after_dislike = CommentAggregates::read(&conn, inserted_comment.id).unwrap();
 +
 +    assert_eq!(0, comment_aggs_after_dislike.score);
 +    assert_eq!(1, comment_aggs_after_dislike.upvotes);
 +    assert_eq!(1, comment_aggs_after_dislike.downvotes);
 +
 +    // Remove the first comment like
 +    CommentLike::remove(&conn, inserted_user.id, inserted_comment.id).unwrap();
 +    let after_like_remove = CommentAggregates::read(&conn, inserted_comment.id).unwrap();
 +    assert_eq!(-1, after_like_remove.score);
 +    assert_eq!(0, after_like_remove.upvotes);
 +    assert_eq!(1, after_like_remove.downvotes);
 +
 +    // Remove the parent post
 +    Post::delete(&conn, inserted_post.id).unwrap();
 +
 +    // Should be none found, since the post was deleted
 +    let after_delete = CommentAggregates::read(&conn, inserted_comment.id);
 +    assert!(after_delete.is_err());
 +
 +    // This should delete all the associated rows, and fire triggers
 +    User_::delete(&conn, another_inserted_user.id).unwrap();
 +    let user_num_deleted = User_::delete(&conn, inserted_user.id).unwrap();
 +    assert_eq!(1, user_num_deleted);
 +  }
 +}
index df3cad6f1ecff77fdc06c1d80728e41255c90ad3,52890d8144fa3a6bb8afe542914553b31a9e9fe7..70997a66a77dd7427216a49901afe49ad6e40e95
@@@ -1,12 -1,11 +1,12 @@@
- use crate::schema::site_aggregates;
  use diesel::{result::Error, *};
+ use lemmy_db_schema::schema::site_aggregates;
  use serde::Serialize;
  
 -#[derive(Queryable, Associations, Identifiable, PartialEq, Debug, Serialize)]
 +#[derive(Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Clone)]
  #[table_name = "site_aggregates"]
  pub struct SiteAggregates {
    pub id: i32,
 +  pub site_id: i32,
    pub users: i64,
    pub posts: i64,
    pub comments: i64,
@@@ -23,18 -22,17 +23,17 @@@ impl SiteAggregates 
  mod tests {
    use crate::{
      aggregates::site_aggregates::SiteAggregates,
-     source::{
-       comment::{Comment, CommentForm},
-       community::{Community, CommunityForm},
-       post::{Post, PostForm},
-       site::{Site, SiteForm},
-       user::{UserForm, User_},
-     },
      tests::establish_unpooled_connection,
      Crud,
      ListingType,
      SortType,
    };
+   use lemmy_db_schema::source::{
+     comment::{Comment, CommentForm},
+     community::{Community, CommunityForm},
+     post::{Post, PostForm},
+     user::{UserForm, User_},
+   };
  
    #[test]
    fn test_crud() {
  
      let inserted_user = User_::create(&conn, &new_user).unwrap();
  
 +    let site_form = SiteForm {
 +      name: "test_site".into(),
 +      description: None,
 +      icon: None,
 +      banner: None,
 +      creator_id: inserted_user.id,
 +      enable_downvotes: true,
 +      open_registration: true,
 +      enable_nsfw: true,
 +      updated: None,
 +    };
 +
 +    Site::create(&conn, &site_form).unwrap();
 +
      let new_community = CommunityForm {
        name: "TIL_site_agg".into(),
        creator_id: inserted_user.id,
      let user_num_deleted = User_::delete(&conn, inserted_user.id).unwrap();
      assert_eq!(1, user_num_deleted);
  
 -    let site_aggregates_after_delete = SiteAggregates::read(&conn).unwrap();
 -    assert_eq!(0, site_aggregates_after_delete.users);
 -    assert_eq!(0, site_aggregates_after_delete.communities);
 -    assert_eq!(0, site_aggregates_after_delete.posts);
 -    assert_eq!(0, site_aggregates_after_delete.comments);
 +    let after_delete = SiteAggregates::read(&conn);
 +    assert!(after_delete.is_err());
    }
  }
diff --combined lemmy_db/src/lib.rs
index 4df69ca432fb9da21e4d20a34a2c7afe4a2ebae4,9afb76191accc0f738fa4355eca1b6ca76189e84..8e3521478dcdf9eacb42149c5c286b9f451d6073
@@@ -4,19 -4,13 +4,17 @@@ extern crate diesel
  extern crate strum_macros;
  #[macro_use]
  extern crate lazy_static;
 +// this is used in tests
 +#[allow(unused_imports)]
 +#[macro_use]
 +extern crate diesel_migrations;
  
- use chrono::NaiveDateTime;
  use diesel::{result::Error, *};
  use regex::Regex;
  use serde::{Deserialize, Serialize};
  use std::{env, env::VarError};
  
  pub mod aggregates;
- pub mod schema;
  pub mod source;
  pub mod views;
  
@@@ -186,10 -180,6 +184,6 @@@ pub fn limit_and_offset(page: Option<i6
    (limit, offset)
  }
  
- pub fn naive_now() -> NaiveDateTime {
-   chrono::prelude::Utc::now().naive_utc()
- }
  pub fn is_email_regex(test: &str) -> bool {
    EMAIL_REGEX.is_match(test)
  }
@@@ -227,8 -217,6 +221,8 @@@ mod tests 
    use crate::{get_database_url_from_env, is_email_regex};
    use diesel::{Connection, PgConnection};
  
 +  embed_migrations!();
 +
    pub fn establish_unpooled_connection() -> PgConnection {
      let db_url = match get_database_url_from_env() {
        Ok(url) => url,
          e
        ),
      };
 -    PgConnection::establish(&db_url).unwrap_or_else(|_| panic!("Error connecting to {}", db_url))
 +    let conn =
 +      PgConnection::establish(&db_url).unwrap_or_else(|_| panic!("Error connecting to {}", db_url));
 +    embedded_migrations::run(&conn).unwrap();
 +    conn
    }
  
    #[test]
index 948791ea4ae1f8abfd75b40a06a8a0e30e5113d1,81f09e722de2098b1c1b3442f81ed7b30a4f1200..c681adbe47bf1282b7c5e188c63d0852121bc258
- use crate::{
+ use crate::{ApubObject, Crud, Likeable, Readable, Saveable};
+ use diesel::{dsl::*, result::Error, *};
+ use lemmy_db_schema::{
    naive_now,
-   schema::{post, post_like, post_read, post_saved},
-   ApubObject,
-   Crud,
-   Likeable,
-   Readable,
-   Saveable,
+   source::post::{
+     Post,
+     PostForm,
+     PostLike,
+     PostLikeForm,
+     PostRead,
+     PostReadForm,
+     PostSaved,
+     PostSavedForm,
+   },
  };
- use diesel::{dsl::*, result::Error, *};
- use serde::Serialize;
- use url::{ParseError, Url};
- #[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
- #[table_name = "post"]
- pub struct Post {
-   pub id: i32,
-   pub name: String,
-   pub url: Option<String>,
-   pub body: Option<String>,
-   pub creator_id: i32,
-   pub community_id: i32,
-   pub removed: bool,
-   pub locked: bool,
-   pub published: chrono::NaiveDateTime,
-   pub updated: Option<chrono::NaiveDateTime>,
-   pub deleted: bool,
-   pub nsfw: bool,
-   pub stickied: bool,
-   pub embed_title: Option<String>,
-   pub embed_description: Option<String>,
-   pub embed_html: Option<String>,
-   pub thumbnail_url: Option<String>,
-   pub ap_id: String,
-   pub local: bool,
- }
- #[derive(Insertable, AsChangeset)]
- #[table_name = "post"]
- pub struct PostForm {
-   pub name: String,
-   pub url: Option<String>,
-   pub body: Option<String>,
-   pub creator_id: i32,
-   pub community_id: i32,
-   pub removed: Option<bool>,
-   pub locked: Option<bool>,
-   pub published: Option<chrono::NaiveDateTime>,
-   pub updated: Option<chrono::NaiveDateTime>,
-   pub deleted: Option<bool>,
-   pub nsfw: bool,
-   pub stickied: Option<bool>,
-   pub embed_title: Option<String>,
-   pub embed_description: Option<String>,
-   pub embed_html: Option<String>,
-   pub thumbnail_url: Option<String>,
-   pub ap_id: Option<String>,
-   pub local: bool,
- }
- impl PostForm {
-   pub fn get_ap_id(&self) -> Result<Url, ParseError> {
-     Url::parse(&self.ap_id.as_ref().unwrap_or(&"not_a_url".to_string()))
-   }
- }
  
  impl Crud<PostForm> for Post {
    fn read(conn: &PgConnection, post_id: i32) -> Result<Self, Error> {
-     use crate::schema::post::dsl::*;
+     use lemmy_db_schema::schema::post::dsl::*;
      post.find(post_id).first::<Self>(conn)
    }
  
    fn delete(conn: &PgConnection, post_id: i32) -> Result<usize, Error> {
-     use crate::schema::post::dsl::*;
+     use lemmy_db_schema::schema::post::dsl::*;
      diesel::delete(post.find(post_id)).execute(conn)
    }
  
    fn create(conn: &PgConnection, new_post: &PostForm) -> Result<Self, Error> {
-     use crate::schema::post::dsl::*;
+     use lemmy_db_schema::schema::post::dsl::*;
      insert_into(post).values(new_post).get_result::<Self>(conn)
    }
  
    fn update(conn: &PgConnection, post_id: i32, new_post: &PostForm) -> Result<Self, Error> {
-     use crate::schema::post::dsl::*;
+     use lemmy_db_schema::schema::post::dsl::*;
      diesel::update(post.find(post_id))
        .set(new_post)
        .get_result::<Self>(conn)
    }
  }
  
- impl ApubObject<PostForm> for Post {
-   fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error> {
-     use crate::schema::post::dsl::*;
-     post.filter(ap_id.eq(object_id)).first::<Self>(conn)
-   }
-   fn upsert(conn: &PgConnection, post_form: &PostForm) -> Result<Post, Error> {
-     use crate::schema::post::dsl::*;
-     insert_into(post)
-       .values(post_form)
-       .on_conflict(ap_id)
-       .do_update()
-       .set(post_form)
-       .get_result::<Self>(conn)
-   }
+ pub trait Post_ {
+   //fn read(conn: &PgConnection, post_id: i32) -> Result<Post, Error>;
+   fn list_for_community(conn: &PgConnection, the_community_id: i32) -> Result<Vec<Post>, Error>;
+   fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: String) -> Result<Post, Error>;
+   fn permadelete_for_creator(conn: &PgConnection, for_creator_id: i32) -> Result<Vec<Post>, Error>;
+   fn update_deleted(conn: &PgConnection, post_id: i32, new_deleted: bool) -> Result<Post, Error>;
+   fn update_removed(conn: &PgConnection, post_id: i32, new_removed: bool) -> Result<Post, Error>;
+   fn update_removed_for_creator(
+     conn: &PgConnection,
+     for_creator_id: i32,
+     for_community_id: Option<i32>,
+     new_removed: bool,
+   ) -> Result<Vec<Post>, Error>;
+   fn update_locked(conn: &PgConnection, post_id: i32, new_locked: bool) -> Result<Post, Error>;
+   fn update_stickied(conn: &PgConnection, post_id: i32, new_stickied: bool) -> Result<Post, Error>;
+   fn is_post_creator(user_id: i32, post_creator_id: i32) -> bool;
  }
  
- impl Post {
-   pub fn list_for_community(
-     conn: &PgConnection,
-     the_community_id: i32,
-   ) -> Result<Vec<Self>, Error> {
-     use crate::schema::post::dsl::*;
+ impl Post_ for Post {
 -  // TODO: this is a duplicate?
 -  //fn read(conn: &PgConnection, post_id: i32) -> Result<Self, Error> {
 -  //  use lemmy_db_schema::schema::post::dsl::*;
 -  //  post.filter(id.eq(post_id)).first::<Self>(conn)
 -  //}
 -
+   fn list_for_community(conn: &PgConnection, the_community_id: i32) -> Result<Vec<Self>, Error> {
+     use lemmy_db_schema::schema::post::dsl::*;
      post
        .filter(community_id.eq(the_community_id))
        .then_order_by(published.desc())
        .load::<Self>(conn)
    }
  
-   pub fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: String) -> Result<Self, Error> {
-     use crate::schema::post::dsl::*;
+   fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: String) -> Result<Self, Error> {
+     use lemmy_db_schema::schema::post::dsl::*;
  
      diesel::update(post.find(post_id))
        .set(ap_id.eq(apub_id))
        .get_result::<Self>(conn)
    }
  
-   pub fn permadelete_for_creator(
-     conn: &PgConnection,
-     for_creator_id: i32,
-   ) -> Result<Vec<Self>, Error> {
-     use crate::schema::post::dsl::*;
+   fn permadelete_for_creator(conn: &PgConnection, for_creator_id: i32) -> Result<Vec<Self>, Error> {
+     use lemmy_db_schema::schema::post::dsl::*;
  
      let perma_deleted = "*Permananently Deleted*";
      let perma_deleted_url = "https://deleted.com";
        .get_results::<Self>(conn)
    }
  
-   pub fn update_deleted(
-     conn: &PgConnection,
-     post_id: i32,
-     new_deleted: bool,
-   ) -> Result<Self, Error> {
-     use crate::schema::post::dsl::*;
+   fn update_deleted(conn: &PgConnection, post_id: i32, new_deleted: bool) -> Result<Self, Error> {
+     use lemmy_db_schema::schema::post::dsl::*;
      diesel::update(post.find(post_id))
        .set((deleted.eq(new_deleted), updated.eq(naive_now())))
        .get_result::<Self>(conn)
    }
  
-   pub fn update_removed(
-     conn: &PgConnection,
-     post_id: i32,
-     new_removed: bool,
-   ) -> Result<Self, Error> {
-     use crate::schema::post::dsl::*;
+   fn update_removed(conn: &PgConnection, post_id: i32, new_removed: bool) -> Result<Self, Error> {
+     use lemmy_db_schema::schema::post::dsl::*;
      diesel::update(post.find(post_id))
        .set((removed.eq(new_removed), updated.eq(naive_now())))
        .get_result::<Self>(conn)
    }
  
-   pub fn update_removed_for_creator(
+   fn update_removed_for_creator(
      conn: &PgConnection,
      for_creator_id: i32,
      for_community_id: Option<i32>,
      new_removed: bool,
    ) -> Result<Vec<Self>, Error> {
-     use crate::schema::post::dsl::*;
+     use lemmy_db_schema::schema::post::dsl::*;
  
      let mut update = diesel::update(post).into_boxed();
      update = update.filter(creator_id.eq(for_creator_id));
        .get_results::<Self>(conn)
    }
  
-   pub fn update_locked(conn: &PgConnection, post_id: i32, new_locked: bool) -> Result<Self, Error> {
-     use crate::schema::post::dsl::*;
+   fn update_locked(conn: &PgConnection, post_id: i32, new_locked: bool) -> Result<Self, Error> {
+     use lemmy_db_schema::schema::post::dsl::*;
      diesel::update(post.find(post_id))
        .set(locked.eq(new_locked))
        .get_result::<Self>(conn)
    }
  
-   pub fn update_stickied(
-     conn: &PgConnection,
-     post_id: i32,
-     new_stickied: bool,
-   ) -> Result<Self, Error> {
-     use crate::schema::post::dsl::*;
+   fn update_stickied(conn: &PgConnection, post_id: i32, new_stickied: bool) -> Result<Self, Error> {
+     use lemmy_db_schema::schema::post::dsl::*;
      diesel::update(post.find(post_id))
        .set(stickied.eq(new_stickied))
        .get_result::<Self>(conn)
    }
  
-   pub fn is_post_creator(user_id: i32, post_creator_id: i32) -> bool {
+   fn is_post_creator(user_id: i32, post_creator_id: i32) -> bool {
      user_id == post_creator_id
    }
  }
  
- #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
- #[belongs_to(Post)]
- #[table_name = "post_like"]
- pub struct PostLike {
-   pub id: i32,
-   pub post_id: i32,
-   pub user_id: i32,
-   pub score: i16,
-   pub published: chrono::NaiveDateTime,
- }
+ impl ApubObject<PostForm> for Post {
+   fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error> {
+     use lemmy_db_schema::schema::post::dsl::*;
+     post.filter(ap_id.eq(object_id)).first::<Self>(conn)
+   }
  
- #[derive(Insertable, AsChangeset, Clone)]
- #[table_name = "post_like"]
- pub struct PostLikeForm {
-   pub post_id: i32,
-   pub user_id: i32,
-   pub score: i16,
+   fn upsert(conn: &PgConnection, post_form: &PostForm) -> Result<Post, Error> {
+     use lemmy_db_schema::schema::post::dsl::*;
+     insert_into(post)
+       .values(post_form)
+       .on_conflict(ap_id)
+       .do_update()
+       .set(post_form)
+       .get_result::<Self>(conn)
+   }
  }
  
  impl Likeable<PostLikeForm> for PostLike {
    fn like(conn: &PgConnection, post_like_form: &PostLikeForm) -> Result<Self, Error> {
-     use crate::schema::post_like::dsl::*;
+     use lemmy_db_schema::schema::post_like::dsl::*;
      insert_into(post_like)
        .values(post_like_form)
        .on_conflict((post_id, user_id))
        .get_result::<Self>(conn)
    }
    fn remove(conn: &PgConnection, user_id: i32, post_id: i32) -> Result<usize, Error> {
-     use crate::schema::post_like::dsl;
+     use lemmy_db_schema::schema::post_like::dsl;
      diesel::delete(
        dsl::post_like
          .filter(dsl::post_id.eq(post_id))
    }
  }
  
- #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
- #[belongs_to(Post)]
- #[table_name = "post_saved"]
- pub struct PostSaved {
-   pub id: i32,
-   pub post_id: i32,
-   pub user_id: i32,
-   pub published: chrono::NaiveDateTime,
- }
- #[derive(Insertable, AsChangeset)]
- #[table_name = "post_saved"]
- pub struct PostSavedForm {
-   pub post_id: i32,
-   pub user_id: i32,
- }
  impl Saveable<PostSavedForm> for PostSaved {
    fn save(conn: &PgConnection, post_saved_form: &PostSavedForm) -> Result<Self, Error> {
-     use crate::schema::post_saved::dsl::*;
+     use lemmy_db_schema::schema::post_saved::dsl::*;
      insert_into(post_saved)
        .values(post_saved_form)
        .on_conflict((post_id, user_id))
        .get_result::<Self>(conn)
    }
    fn unsave(conn: &PgConnection, post_saved_form: &PostSavedForm) -> Result<usize, Error> {
-     use crate::schema::post_saved::dsl::*;
+     use lemmy_db_schema::schema::post_saved::dsl::*;
      diesel::delete(
        post_saved
          .filter(post_id.eq(post_saved_form.post_id))
    }
  }
  
- #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
- #[belongs_to(Post)]
- #[table_name = "post_read"]
- pub struct PostRead {
-   pub id: i32,
-   pub post_id: i32,
-   pub user_id: i32,
-   pub published: chrono::NaiveDateTime,
- }
- #[derive(Insertable, AsChangeset)]
- #[table_name = "post_read"]
- pub struct PostReadForm {
-   pub post_id: i32,
-   pub user_id: i32,
- }
  impl Readable<PostReadForm> for PostRead {
    fn mark_as_read(conn: &PgConnection, post_read_form: &PostReadForm) -> Result<Self, Error> {
-     use crate::schema::post_read::dsl::*;
+     use lemmy_db_schema::schema::post_read::dsl::*;
      insert_into(post_read)
        .values(post_read_form)
        .get_result::<Self>(conn)
    }
  
    fn mark_as_unread(conn: &PgConnection, post_read_form: &PostReadForm) -> Result<usize, Error> {
-     use crate::schema::post_read::dsl::*;
+     use lemmy_db_schema::schema::post_read::dsl::*;
      diesel::delete(
        post_read
          .filter(post_id.eq(post_read_form.post_id))
  
  #[cfg(test)]
  mod tests {
-   use crate::{
-     source::{community::*, post::*, user::*},
-     tests::establish_unpooled_connection,
-     ListingType,
-     SortType,
+   use crate::{source::post::*, tests::establish_unpooled_connection, ListingType, SortType};
+   use lemmy_db_schema::source::{
+     community::{Community, CommunityForm},
+     user::*,
    };
  
    #[test]
index 8775191e1b3bf2773c38db16375f8434d6457524,2e0e99dfabe04b0736973584da6bfb773fab9c71..2510f46c9d4d4f76d7031ed573ab5c429348ef01
@@@ -1,71 -1,35 +1,45 @@@
- use crate::{naive_now, schema::site, Crud};
+ use crate::Crud;
  use diesel::{dsl::*, result::Error, *};
- use serde::Serialize;
- #[derive(Queryable, Identifiable, PartialEq, Debug, Clone, Serialize)]
- #[table_name = "site"]
- pub struct Site {
-   pub id: i32,
-   pub name: String,
-   pub description: Option<String>,
-   pub creator_id: i32,
-   pub published: chrono::NaiveDateTime,
-   pub updated: Option<chrono::NaiveDateTime>,
-   pub enable_downvotes: bool,
-   pub open_registration: bool,
-   pub enable_nsfw: bool,
-   pub icon: Option<String>,
-   pub banner: Option<String>,
- }
- #[derive(Insertable, AsChangeset)]
- #[table_name = "site"]
- pub struct SiteForm {
-   pub name: String,
-   pub description: Option<String>,
-   pub creator_id: i32,
-   pub updated: Option<chrono::NaiveDateTime>,
-   pub enable_downvotes: bool,
-   pub open_registration: bool,
-   pub enable_nsfw: bool,
-   // when you want to null out a column, you have to send Some(None)), since sending None means you just don't want to update that column.
-   pub icon: Option<Option<String>>,
-   pub banner: Option<Option<String>>,
- }
+ use lemmy_db_schema::{naive_now, source::site::*};
  
  impl Crud<SiteForm> for Site {
    fn read(conn: &PgConnection, _site_id: i32) -> Result<Self, Error> {
-     use crate::schema::site::dsl::*;
+     use lemmy_db_schema::schema::site::dsl::*;
      site.first::<Self>(conn)
    }
  
    fn create(conn: &PgConnection, new_site: &SiteForm) -> Result<Self, Error> {
-     use crate::schema::site::dsl::*;
+     use lemmy_db_schema::schema::site::dsl::*;
      insert_into(site).values(new_site).get_result::<Self>(conn)
    }
  
    fn update(conn: &PgConnection, site_id: i32, new_site: &SiteForm) -> Result<Self, Error> {
-     use crate::schema::site::dsl::*;
+     use lemmy_db_schema::schema::site::dsl::*;
      diesel::update(site.find(site_id))
        .set(new_site)
        .get_result::<Self>(conn)
    }
-     use crate::schema::site::dsl::*;
 +  fn delete(conn: &PgConnection, site_id: i32) -> Result<usize, Error> {
++    use lemmy_db_schema::schema::site::dsl::*;
 +    diesel::delete(site.find(site_id)).execute(conn)
 +  }
  }
  
- impl Site {
-   pub fn transfer(conn: &PgConnection, new_creator_id: i32) -> Result<Self, Error> {
-     use crate::schema::site::dsl::*;
+ pub trait Site_ {
+   fn transfer(conn: &PgConnection, new_creator_id: i32) -> Result<Site, Error>;
++  fn read_simple(conn: &PgConnection) -> Result<Site, Error>;
+ }
+ impl Site_ for Site {
+   fn transfer(conn: &PgConnection, new_creator_id: i32) -> Result<Site, Error> {
+     use lemmy_db_schema::schema::site::dsl::*;
      diesel::update(site.find(1))
        .set((creator_id.eq(new_creator_id), updated.eq(naive_now())))
        .get_result::<Self>(conn)
    }
-   pub fn read_simple(conn: &PgConnection) -> Result<Self, Error> {
-     use crate::schema::site::dsl::*;
 +
++  fn read_simple(conn: &PgConnection) -> Result<Self, Error> {
++    use lemmy_db_schema::schema::site::dsl::*;
 +    site.first::<Self>(conn)
 +  }
  }
index 8c7584471914445333eeb4d09cdb4463889bbd5e,7b1d0bc615e4707b13325f41638f33ff40e2e306..1b114e19057473e8deea406a01c3dee75895cba4
@@@ -3,6 -3,14 +3,14 @@@ use crate::
    functions::hot_rank,
    fuzzy_search,
    limit_and_offset,
+   views::ViewToVec,
+   ListingType,
+   MaybeOptional,
+   SortType,
+   ToSafe,
+ };
+ use diesel::{result::Error, *};
+ use lemmy_db_schema::{
    schema::{
      comment,
      comment_aggregates,
      post::Post,
      user::{UserAlias1, UserSafe, UserSafeAlias1, User_},
    },
-   views::ViewToVec,
-   ListingType,
-   MaybeOptional,
-   SortType,
-   ToSafe,
  };
- use diesel::{result::Error, *};
  use serde::Serialize;
  
  #[derive(Debug, PartialEq, Serialize, Clone)]
@@@ -145,15 -147,6 +147,15 @@@ impl CommentView 
        my_vote,
      })
    }
 +
 +  /// Gets the recipient user id.
 +  /// If there is no parent comment, its the post creator
 +  pub fn get_recipient_id(&self) -> i32 {
 +    match &self.recipient {
 +      Some(parent_commenter) => parent_commenter.id,
 +      None => self.post.creator_id,
 +    }
 +  }
  }
  
  pub struct CommentQueryBuilder<'a> {
@@@ -416,14 -409,8 +418,8 @@@ impl ViewToVec for CommentView 
  
  #[cfg(test)]
  mod tests {
-   use crate::{
-     source::{comment::*, community::*, post::*, user::*},
-     tests::establish_unpooled_connection,
-     views::comment_view::*,
-     Crud,
-     Likeable,
-     *,
-   };
+   use crate::{tests::establish_unpooled_connection, views::comment_view::*, Crud, Likeable, *};
+   use lemmy_db_schema::source::{comment::*, community::*, post::*, user::*};
  
    #[test]
    fn test_crud() {
  
      let _inserted_comment_like = CommentLike::like(&conn, &comment_like_form).unwrap();
  
 +    let agg = CommentAggregates::read(&conn, inserted_comment.id).unwrap();
 +
      let expected_comment_view_no_user = CommentView {
        creator_banned_from_community: false,
        my_vote: None,
          published: inserted_community.published,
        },
        counts: CommentAggregates {
 -        id: inserted_comment.id, // TODO
 +        id: agg.id,
          comment_id: inserted_comment.id,
          score: 1,
          upvotes: 1,
index 9a4dbbadb5fe5039094182d8742d77dc191c1c1f,358b46cd8fb497ffa9c382100f0a7c10be5b0963..3cfee1b371300c14ec24e7e19c28a912209b73ac
@@@ -3,6 -3,14 +3,14 @@@ use crate::
    functions::hot_rank,
    fuzzy_search,
    limit_and_offset,
+   views::ViewToVec,
+   ListingType,
+   MaybeOptional,
+   SortType,
+   ToSafe,
+ };
+ use diesel::{result::Error, *};
+ use lemmy_db_schema::{
    schema::{
      community,
      community_follower,
      post::{Post, PostRead, PostSaved},
      user::{UserSafe, User_},
    },
-   views::ViewToVec,
-   ListingType,
-   MaybeOptional,
-   SortType,
-   ToSafe,
  };
- use diesel::{result::Error, *};
  use serde::Serialize;
  
  #[derive(Debug, PartialEq, Serialize, Clone)]
@@@ -188,7 -190,7 +190,7 @@@ impl<'a> PostQueryBuilder<'a> 
    }
  
    pub fn my_user_id<T: MaybeOptional<i32>>(mut self, my_user_id: T) -> Self {
 -    self.community_id = my_user_id.get_optional();
 +    self.my_user_id = my_user_id.get_optional();
      self
    }
  
@@@ -406,13 -408,13 +408,13 @@@ impl ViewToVec for PostView 
  mod tests {
    use crate::{
      aggregates::post_aggregates::PostAggregates,
-     source::{community::*, post::*, user::*},
      tests::establish_unpooled_connection,
      views::post_view::{PostQueryBuilder, PostView},
      Crud,
      Likeable,
      *,
    };
+   use lemmy_db_schema::source::{community::*, post::*, user::*};
  
    #[test]
    fn test_crud() {
      let read_post_listing_with_user =
        PostView::read(&conn, inserted_post.id, Some(inserted_user.id)).unwrap();
  
 +    let agg = PostAggregates::read(&conn, inserted_post.id).unwrap();
 +
      // the non user version
      let expected_post_listing_no_user = PostView {
        post: Post {
          published: inserted_community.published,
        },
        counts: PostAggregates {
 -        id: inserted_post.id, // TODO this might fail
 +        id: agg.id,
          post_id: inserted_post.id,
          comments: 0,
          score: 1,
index 3c605277e10e646f16c35967da86771e26439e38,a56c8fe30169d74cee6acf73a18c5c5ff78e783e..7772ccdcef6b37da0ad2e81e25bc6a2c691a614a
@@@ -1,38 -1,27 +1,37 @@@
- use crate::{
-   aggregates::site_aggregates::SiteAggregates,
 -use crate::ToSafe;
++use crate::{aggregates::site_aggregates::SiteAggregates, ToSafe};
+ use diesel::{result::Error, *};
+ use lemmy_db_schema::{
 -  schema::{site, user_},
 +  schema::{site, site_aggregates, user_},
    source::{
      site::Site,
      user::{UserSafe, User_},
    },
-   ToSafe,
  };
- use diesel::{result::Error, *};
  use serde::Serialize;
  
  #[derive(Debug, Serialize, Clone)]
  pub struct SiteView {
    pub site: Site,
    pub creator: UserSafe,
 +  pub counts: SiteAggregates,
  }
  
  impl SiteView {
    pub fn read(conn: &PgConnection) -> Result<Self, Error> {
 -    let (site, creator) = site::table
 +    let (site, creator, counts) = site::table
        .inner_join(user_::table)
 -      .select((site::all_columns, User_::safe_columns_tuple()))
 -      .first::<(Site, UserSafe)>(conn)?;
 +      .inner_join(site_aggregates::table)
 +      .select((
 +        site::all_columns,
 +        User_::safe_columns_tuple(),
 +        site_aggregates::all_columns,
 +      ))
 +      .first::<(Site, UserSafe, SiteAggregates)>(conn)?;
  
 -    Ok(SiteView { site, creator })
 +    Ok(SiteView {
 +      site,
 +      creator,
 +      counts,
 +    })
    }
  }
index f0aca2db90acb8c032cbd55a3b4c46dda6bd2b0d,33e2389fdb929be0ee7d4954d03fc7b45e8f8a34..f0aca2db90acb8c032cbd55a3b4c46dda6bd2b0d
@@@ -362,7 -362,6 +362,7 @@@ table! 
  table! {
      site_aggregates (id) {
          id -> Int4,
 +        site_id -> Int4,
          users -> Int8,
          posts -> Int8,
          comments -> Int8,
@@@ -561,7 -560,6 +561,7 @@@ joinable!(post_report -> post (post_id)
  joinable!(post_saved -> post (post_id));
  joinable!(post_saved -> user_ (user_id));
  joinable!(site -> user_ (creator_id));
 +joinable!(site_aggregates -> site (site_id));
  joinable!(user_aggregates -> user_ (user_id));
  joinable!(user_ban -> user_ (user_id));
  joinable!(user_mention -> comment (comment_id));
index 0000000000000000000000000000000000000000,d94fed578cc38bbc35b35471e16a82d2bc0fa41e..ec53408d125a13e677a8df257d7e9af856418695
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,26 +1,28 @@@
 -#[derive(Identifiable, Queryable, Associations, PartialEq, Serialize, Deserialize, Debug, Clone)]
+ use crate::{schema::comment_report, source::comment::Comment};
+ use serde::{Deserialize, Serialize};
++#[derive(
++  Identifiable, Queryable, Associations, PartialEq, Serialize, Deserialize, Debug, Clone,
++)]
+ #[belongs_to(Comment)]
+ #[table_name = "comment_report"]
+ pub struct CommentReport {
+   pub id: i32,
+   pub creator_id: i32,
+   pub comment_id: i32,
+   pub original_comment_text: String,
+   pub reason: String,
+   pub resolved: bool,
+   pub resolver_id: Option<i32>,
+   pub published: chrono::NaiveDateTime,
+   pub updated: Option<chrono::NaiveDateTime>,
+ }
+ #[derive(Insertable, AsChangeset, Clone)]
+ #[table_name = "comment_report"]
+ pub struct CommentReportForm {
+   pub creator_id: i32,
+   pub comment_id: i32,
+   pub original_comment_text: String,
+   pub reason: String,
+ }
index 0000000000000000000000000000000000000000,608104dbc90dcf14bf8796f54d1de1919a6ea98a..b75fb954a078cc1a6bc77b01d8a2836523d68298
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,30 +1,32 @@@
 -#[derive(Identifiable, Queryable, Associations, PartialEq, Serialize, Deserialize, Debug, Clone)]
+ use crate::{schema::post_report, source::post::Post};
+ use serde::{Deserialize, Serialize};
++#[derive(
++  Identifiable, Queryable, Associations, PartialEq, Serialize, Deserialize, Debug, Clone,
++)]
+ #[belongs_to(Post)]
+ #[table_name = "post_report"]
+ pub struct PostReport {
+   pub id: i32,
+   pub creator_id: i32,
+   pub post_id: i32,
+   pub original_post_name: String,
+   pub original_post_url: Option<String>,
+   pub original_post_body: Option<String>,
+   pub reason: String,
+   pub resolved: bool,
+   pub resolver_id: Option<i32>,
+   pub published: chrono::NaiveDateTime,
+   pub updated: Option<chrono::NaiveDateTime>,
+ }
+ #[derive(Insertable, AsChangeset, Clone)]
+ #[table_name = "post_report"]
+ pub struct PostReportForm {
+   pub creator_id: i32,
+   pub post_id: i32,
+   pub original_post_name: String,
+   pub original_post_url: Option<String>,
+   pub original_post_body: Option<String>,
+   pub reason: String,
+ }
diff --combined lemmy_structs/src/lib.rs
index d19127384b773ab04864fd6e821aba4a4c5df388,d344f452959d0b0419a401818aaf433fe1faae17..080cb38521618761c8c1bdef1587747a99ba4cc9
@@@ -3,17 -3,15 +3,14 @@@ pub mod community
  pub mod post;
  pub mod site;
  pub mod user;
 -pub mod websocket;
  
  use diesel::PgConnection;
- use lemmy_db::{
-   source::{
-     comment::Comment,
-     post::Post,
-     user::User_,
-     user_mention::{UserMention, UserMentionForm},
-   },
-   Crud,
-   DbPool,
+ use lemmy_db::{source::user::User, Crud, DbPool};
+ use lemmy_db_schema::source::{
+   comment::Comment,
+   post::Post,
+   user::User_,
+   user_mention::{UserMention, UserMentionForm},
  };
  use lemmy_utils::{email::send_email, settings::Settings, utils::MentionData, LemmyError};
  use log::error;
index ff6c8a3912cb81a40b713043202d18ea8f89cea4,5011d84fffe6dcbedf57aba77896a68788ec3db0..f24d9f49ee42db21292b2d09f40a253653b4beea
@@@ -1,24 -1,25 +1,22 @@@
--use lemmy_db::{
-   source::{category::*, user::*},
 -  aggregates::site_aggregates::SiteAggregates,
--  views::{
--    comment_view::CommentView,
--    community::community_view::CommunityView,
--    moderator::{
--      mod_add_community_view::ModAddCommunityView,
--      mod_add_view::ModAddView,
--      mod_ban_from_community_view::ModBanFromCommunityView,
--      mod_ban_view::ModBanView,
--      mod_lock_post_view::ModLockPostView,
--      mod_remove_comment_view::ModRemoveCommentView,
--      mod_remove_community_view::ModRemoveCommunityView,
--      mod_remove_post_view::ModRemovePostView,
--      mod_sticky_post_view::ModStickyPostView,
--    },
--    post_view::PostView,
--    site_view::SiteView,
--    user_view::UserViewSafe,
++use lemmy_db::views::{
++  comment_view::CommentView,
++  community::community_view::CommunityView,
++  moderator::{
++    mod_add_community_view::ModAddCommunityView,
++    mod_add_view::ModAddView,
++    mod_ban_from_community_view::ModBanFromCommunityView,
++    mod_ban_view::ModBanView,
++    mod_lock_post_view::ModLockPostView,
++    mod_remove_comment_view::ModRemoveCommentView,
++    mod_remove_community_view::ModRemoveCommunityView,
++    mod_remove_post_view::ModRemovePostView,
++    mod_sticky_post_view::ModStickyPostView,
    },
++  post_view::PostView,
++  site_view::SiteView,
++  user_view::UserViewSafe,
  };
+ use lemmy_db_schema::source::{category::*, user::User_};
  use serde::{Deserialize, Serialize};
  
  #[derive(Deserialize)]
@@@ -100,14 -101,16 +98,14 @@@ pub struct GetSite 
    pub auth: Option<String>,
  }
  
 -// TODO combine siteresponse and getsiteresponse
  #[derive(Serialize, Clone)]
  pub struct SiteResponse {
 -  pub site: SiteView,
 +  pub site_view: SiteView,
  }
  
  #[derive(Serialize)]
  pub struct GetSiteResponse {
 -  pub site: Option<SiteView>, // Because the site might not be set up yet
 -  pub counts: SiteAggregates,
 +  pub site_view: Option<SiteView>, // Because the site might not be set up yet
    pub admins: Vec<UserViewSafe>,
    pub banned: Vec<UserViewSafe>,
    pub online: usize,
diff --combined src/code_migrations.rs
index af01982fc4a2e286640e7300af71a5fb529ad789,c3026a93b2905fa2dbece9ba359a948efed7cc55..73b030cb22dc2f39e53165b1247b2bb6419acafc
@@@ -4,6 -4,10 +4,10 @@@ use diesel::
    *,
  };
  use lemmy_db::{
+   source::{comment::Comment_, post::Post_, private_message::PrivateMessage_},
+   Crud,
+ };
+ use lemmy_db_schema::{
    naive_now,
    source::{
      comment::Comment,
@@@ -12,7 -16,6 +16,6 @@@
      private_message::PrivateMessage,
      user::{UserForm, User_},
    },
-   Crud,
  };
  use lemmy_utils::{
    apub::{generate_actor_keypair, make_apub_endpoint, EndpointType},
@@@ -33,7 -36,7 +36,7 @@@ pub fn run_advanced_migrations(conn: &P
  }
  
  fn user_updates_2020_04_02(conn: &PgConnection) -> Result<(), LemmyError> {
-   use lemmy_db::schema::user_::dsl::*;
+   use lemmy_db_schema::schema::user_::dsl::*;
  
    info!("Running user_updates_2020_04_02");
  
@@@ -43,6 -46,8 +46,6 @@@
      .filter(local.eq(true))
      .load::<User_>(conn)?;
  
 -  sql_query("alter table user_ disable trigger refresh_user").execute(conn)?;
 -
    for cuser in &incorrect_users {
      let keypair = generate_actor_keypair()?;
  
      User_::update(&conn, cuser.id, &form)?;
    }
  
 -  sql_query("alter table user_ enable trigger refresh_user").execute(conn)?;
 -
    info!("{} user rows updated.", incorrect_users.len());
  
    Ok(())
  }
  
  fn community_updates_2020_04_02(conn: &PgConnection) -> Result<(), LemmyError> {
-   use lemmy_db::schema::community::dsl::*;
+   use lemmy_db_schema::schema::community::dsl::*;
  
    info!("Running community_updates_2020_04_02");
  
@@@ -92,6 -99,8 +95,6 @@@
      .filter(local.eq(true))
      .load::<Community>(conn)?;
  
 -  sql_query("alter table community disable trigger refresh_community").execute(conn)?;
 -
    for ccommunity in &incorrect_communities {
      let keypair = generate_actor_keypair()?;
  
      Community::update(&conn, ccommunity.id, &form)?;
    }
  
 -  sql_query("alter table community enable trigger refresh_community").execute(conn)?;
 -
    info!("{} community rows updated.", incorrect_communities.len());
  
    Ok(())
  }
  
  fn post_updates_2020_04_03(conn: &PgConnection) -> Result<(), LemmyError> {
-   use lemmy_db::schema::post::dsl::*;
+   use lemmy_db_schema::schema::post::dsl::*;
  
    info!("Running post_updates_2020_04_03");
  
      .filter(local.eq(true))
      .load::<Post>(conn)?;
  
 -  sql_query("alter table post disable trigger refresh_post").execute(conn)?;
 -
    for cpost in &incorrect_posts {
      let apub_id = make_apub_endpoint(EndpointType::Post, &cpost.id.to_string()).to_string();
      Post::update_ap_id(&conn, cpost.id, apub_id)?;
  
    info!("{} post rows updated.", incorrect_posts.len());
  
 -  sql_query("alter table post enable trigger refresh_post").execute(conn)?;
 -
    Ok(())
  }
  
  fn comment_updates_2020_04_03(conn: &PgConnection) -> Result<(), LemmyError> {
-   use lemmy_db::schema::comment::dsl::*;
+   use lemmy_db_schema::schema::comment::dsl::*;
  
    info!("Running comment_updates_2020_04_03");
  
      .filter(local.eq(true))
      .load::<Comment>(conn)?;
  
 -  sql_query("alter table comment disable trigger refresh_comment").execute(conn)?;
 -
    for ccomment in &incorrect_comments {
      let apub_id = make_apub_endpoint(EndpointType::Comment, &ccomment.id.to_string()).to_string();
      Comment::update_ap_id(&conn, ccomment.id, apub_id)?;
    }
  
 -  sql_query("alter table comment enable trigger refresh_comment").execute(conn)?;
 -
    info!("{} comment rows updated.", incorrect_comments.len());
  
    Ok(())
  }
  
  fn private_message_updates_2020_05_05(conn: &PgConnection) -> Result<(), LemmyError> {
-   use lemmy_db::schema::private_message::dsl::*;
+   use lemmy_db_schema::schema::private_message::dsl::*;
  
    info!("Running private_message_updates_2020_05_05");
  
  }
  
  fn post_thumbnail_url_updates_2020_07_27(conn: &PgConnection) -> Result<(), LemmyError> {
-   use lemmy_db::schema::post::dsl::*;
+   use lemmy_db_schema::schema::post::dsl::*;
  
    info!("Running post_thumbnail_url_updates_2020_07_27");
  
index c8986454405f07387bb989139e7365193cd382f3,7c346d865e19435ba50e8c99baeb72a1cdd7dcaf..c507af0670133117ac9c50e9f1d880c3303d602b
@@@ -28,14 -28,10 +28,10 @@@ use lemmy_apub::
      user_inbox::user_inbox,
    },
  };
- use lemmy_db::{
-   source::{
-     community::{Community, CommunityForm},
-     user::{User_, *},
-   },
-   Crud,
-   ListingType,
-   SortType,
+ use lemmy_db::{Crud, ListingType, SortType};
+ use lemmy_db_schema::source::{
+   community::{Community, CommunityForm},
+   user::{UserForm, User_},
  };
  use lemmy_rate_limit::{rate_limiter::RateLimiter, RateLimit};
  use lemmy_utils::{apub::generate_actor_keypair, settings::Settings};
@@@ -60,10 -56,10 +56,10 @@@ fn create_context() -> LemmyContext 
    let activity_queue = create_activity_queue();
    let chat_server = ChatServer::startup(
      pool.clone(),
 -    rate_limiter.clone(),
 +    rate_limiter,
      |c, i, o, d| Box::pin(match_websocket_operation(c, i, o, d)),
      Client::default(),
 -    activity_queue.clone(),
 +    activity_queue,
    )
    .start();
    LemmyContext::create(
@@@ -95,7 -91,7 +91,7 @@@ fn create_user(conn: &PgConnection, nam
      lang: "browser".into(),
      show_avatars: true,
      send_notifications_to_email: false,
 -    actor_id: Some(format!("http://localhost:8536/u/{}", name).to_string()),
 +    actor_id: Some(format!("http://localhost:8536/u/{}", name)),
      bio: None,
      local: true,
      private_key: Some(user_keypair.private_key),
@@@ -156,7 -152,6 +152,7 @@@ fn create_http_request() -> HttpReques
  }
  
  #[actix_rt::test]
 +#[ignore]
  async fn test_shared_inbox_expired_signature() {
    let request = create_http_request();
    let context = create_context();
  }
  
  #[actix_rt::test]
 +#[ignore]
  async fn test_user_inbox_expired_signature() {
    let request = create_http_request();
    let context = create_context();
  }
  
  #[actix_rt::test]
 +#[ignore]
  async fn test_community_inbox_expired_signature() {
    let context = create_context();
    let connection = &context.pool().get().unwrap();