* Moving settings to Database.
- Moves many settings into the database. Fixes #2285
- Adds a local_site and instance table. Fixes #2365 . Fixes #2368
- Separates SQL update an insert forms, to avoid runtime errors.
- Adds TypedBuilder to all the SQL forms, instead of default.
* Fix weird clippy issue.
* Removing extra lines.
* Some fixes from suggestions.
* Fixing apub tests.
* Using instance creation helper function.
* Move forms to their own line.
* Trying to fix local_site_data, still broken.
* Fixing federation tests.
* Trying to fix check features 1.
* Addressing PR comments.
* Adding check_apub to all verify functions.
"lemmy_db_views_moderator",
"lemmy_utils",
"percent-encoding",
+ "regex",
"reqwest",
"reqwest-middleware",
"rosetta-i18n",
"sha2",
"strum",
"strum_macros",
+ "typed-builder",
"url",
]
"serial_test",
"tracing",
"typed-builder",
+ "url",
]
[[package]]
"strum_macros",
"tracing",
"tracing-error",
+ "typed-builder",
"url",
"uuid 1.1.2",
]
"browser": true
},
"plugins": [
- "jane"
+ "@typescript-eslint"
],
"extends": [
- "plugin:jane/recommended",
- "plugin:jane/typescript"
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
-module.exports = Object.assign(require('eslint-plugin-jane/prettier-ts'), {
- arrowParens: 'avoid',
+module.exports = Object.assign(require("eslint-plugin-prettier"), {
+ arrowParens: "avoid",
semi: true,
});
"devDependencies": {
"@sniptt/monads": "^0.5.10",
"@types/jest": "^26.0.23",
+ "@typescript-eslint/eslint-plugin": "^5.21.0",
+ "@typescript-eslint/parser": "^5.21.0",
"class-transformer": "^0.5.1",
- "eslint": "^8.20.0",
- "eslint-plugin-jane": "^11.2.2",
+ "eslint": "^8.25.0",
+ "eslint-plugin-prettier": "^4.0.0",
"jest": "^27.0.6",
- "lemmy-js-client": "0.17.0-rc.37",
+ "lemmy-js-client": "0.17.0-rc.47",
"node-fetch": "^2.6.1",
"prettier": "^2.7.1",
"reflect-metadata": "^0.1.13",
"ts-jest": "^27.0.3",
- "typescript": "^4.6.4"
+ "typescript": "^4.8.4"
}
}
jest.setTimeout(180000);
-import {None, Some} from '@sniptt/monads';
-import { CommentView } from 'lemmy-js-client';
-import { PostResponse } from 'lemmy-js-client';
+import { None, Some } from "@sniptt/monads";
+import { CommentView } from "lemmy-js-client";
+import { PostResponse } from "lemmy-js-client";
import {
alpha,
getComments,
getCommentParentId,
resolveCommunity,
-} from './shared';
+} from "./shared";
let postRes: PostResponse;
await followBeta(alpha);
await followBeta(gamma);
let betaCommunity = (await resolveBetaCommunity(alpha)).community;
- postRes = await createPost(
- alpha,
- betaCommunity.unwrap().community.id
- );
+ postRes = await createPost(alpha, betaCommunity.unwrap().community.id);
});
afterAll(async () => {
expect(commentOne.comment.removed).toBe(commentOne.comment.removed);
}
-test('Create a comment', async () => {
+test("Create a comment", async () => {
let commentRes = await createComment(alpha, postRes.post_view.post.id, None);
expect(commentRes.comment_view.comment.content).toBeDefined();
expect(commentRes.comment_view.community.local).toBe(false);
expect(commentRes.comment_view.counts.score).toBe(1);
// Make sure that comment is liked on beta
- let betaComment = (await resolveComment(beta, commentRes.comment_view.comment)).comment.unwrap();
+ let betaComment = (
+ await resolveComment(beta, commentRes.comment_view.comment)
+ ).comment.unwrap();
expect(betaComment).toBeDefined();
expect(betaComment.community.local).toBe(true);
expect(betaComment.creator.local).toBe(false);
assertCommentFederation(betaComment, commentRes.comment_view);
});
-test('Create a comment in a non-existent post', async () => {
- let commentRes = await createComment(alpha, -1, None) as any;
- expect(commentRes.error).toBe('couldnt_find_post');
+test("Create a comment in a non-existent post", async () => {
+ let commentRes = (await createComment(alpha, -1, None)) as any;
+ expect(commentRes.error).toBe("couldnt_find_post");
});
-test('Update a comment', async () => {
+test("Update a comment", async () => {
let commentRes = await createComment(alpha, postRes.post_view.post.id, None);
// Federate the comment first
- let betaComment = (await resolveComment(beta, commentRes.comment_view.comment)).comment;
+ let betaComment = (
+ await resolveComment(beta, commentRes.comment_view.comment)
+ ).comment;
assertCommentFederation(betaComment.unwrap(), commentRes.comment_view);
let updateCommentRes = await editComment(
commentRes.comment_view.comment.id
);
expect(updateCommentRes.comment_view.comment.content).toBe(
- 'A jest test federated comment update'
+ "A jest test federated comment update"
);
expect(updateCommentRes.comment_view.community.local).toBe(false);
expect(updateCommentRes.comment_view.creator.local).toBe(true);
// Make sure that post is updated on beta
- let betaCommentUpdated = (await resolveComment(
- beta,
- commentRes.comment_view.comment
- )).comment.unwrap();
- assertCommentFederation(
- betaCommentUpdated,
- updateCommentRes.comment_view
- );
+ let betaCommentUpdated = (
+ await resolveComment(beta, commentRes.comment_view.comment)
+ ).comment.unwrap();
+ assertCommentFederation(betaCommentUpdated, updateCommentRes.comment_view);
});
-test('Delete a comment', async () => {
+test("Delete a comment", async () => {
let commentRes = await createComment(alpha, postRes.post_view.post.id, None);
let deleteCommentRes = await deleteComment(
expect(deleteCommentRes.comment_view.comment.content).toBe("");
// Make sure that comment is undefined on beta
- let betaCommentRes = await resolveComment(beta, commentRes.comment_view.comment) as any;
- expect(betaCommentRes.error).toBe('couldnt_find_object');
+ let betaCommentRes = (await resolveComment(
+ beta,
+ commentRes.comment_view.comment
+ )) as any;
+ expect(betaCommentRes.error).toBe("couldnt_find_object");
let undeleteCommentRes = await deleteComment(
alpha,
expect(undeleteCommentRes.comment_view.comment.deleted).toBe(false);
// Make sure that comment is undeleted on beta
- let betaComment2 = (await resolveComment(beta, commentRes.comment_view.comment)).comment.unwrap();
+ let betaComment2 = (
+ await resolveComment(beta, commentRes.comment_view.comment)
+ ).comment.unwrap();
expect(betaComment2.comment.deleted).toBe(false);
- assertCommentFederation(
- betaComment2,
- undeleteCommentRes.comment_view
- );
+ assertCommentFederation(betaComment2, undeleteCommentRes.comment_view);
});
-test('Remove a comment from admin and community on the same instance', async () => {
+test("Remove a comment from admin and community on the same instance", async () => {
let commentRes = await createComment(alpha, postRes.post_view.post.id, None);
// Get the id for beta
expect(removeCommentRes.comment_view.comment.content).toBe("");
// Make sure that comment is removed on alpha (it gets pushed since an admin from beta removed it)
- let refetchedPostComments = await getComments(alpha, postRes.post_view.post.id);
+ let refetchedPostComments = await getComments(
+ alpha,
+ postRes.post_view.post.id
+ );
expect(refetchedPostComments.comments[0].comment.removed).toBe(true);
let unremoveCommentRes = await removeComment(beta, false, betaCommentId);
expect(unremoveCommentRes.comment_view.comment.removed).toBe(false);
// Make sure that comment is unremoved on beta
- let refetchedPostComments2 = await getComments(alpha, postRes.post_view.post.id);
+ let refetchedPostComments2 = await getComments(
+ alpha,
+ postRes.post_view.post.id
+ );
expect(refetchedPostComments2.comments[0].comment.removed).toBe(false);
assertCommentFederation(
refetchedPostComments2.comments[0],
);
});
-test('Remove a comment from admin and community on different instance', async () => {
+test("Remove a comment from admin and community on different instance", async () => {
let alpha_user = await registerUser(alpha);
let newAlphaApi: API = {
client: alpha.client,
newAlphaApi,
newCommunity.community_view.community.id
);
- let commentRes = await createComment(newAlphaApi, newPost.post_view.post.id, None);
+ let commentRes = await createComment(
+ newAlphaApi,
+ newPost.post_view.post.id,
+ None
+ );
expect(commentRes.comment_view.comment.content).toBeDefined();
// Beta searches that to cache it, then removes it
- let betaComment = (await resolveComment(beta, commentRes.comment_view.comment)).comment.unwrap();
+ let betaComment = (
+ await resolveComment(beta, commentRes.comment_view.comment)
+ ).comment.unwrap();
let removeCommentRes = await removeComment(
beta,
true,
expect(removeCommentRes.comment_view.comment.removed).toBe(true);
// Make sure its not removed on alpha
- let refetchedPostComments = await getComments(alpha, newPost.post_view.post.id);
+ let refetchedPostComments = await getComments(
+ alpha,
+ newPost.post_view.post.id
+ );
expect(refetchedPostComments.comments[0].comment.removed).toBe(false);
- assertCommentFederation(refetchedPostComments.comments[0], commentRes.comment_view);
+ assertCommentFederation(
+ refetchedPostComments.comments[0],
+ commentRes.comment_view
+ );
});
-test('Unlike a comment', async () => {
+test("Unlike a comment", async () => {
let commentRes = await createComment(alpha, postRes.post_view.post.id, None);
let unlike = await likeComment(alpha, 0, commentRes.comment_view.comment);
expect(unlike.comment_view.counts.score).toBe(0);
// Make sure that post is unliked on beta
- let betaComment = (await resolveComment(beta, commentRes.comment_view.comment)).comment.unwrap();
+ let betaComment = (
+ await resolveComment(beta, commentRes.comment_view.comment)
+ ).comment.unwrap();
expect(betaComment).toBeDefined();
expect(betaComment.community.local).toBe(true);
expect(betaComment.creator.local).toBe(false);
expect(betaComment.counts.score).toBe(0);
});
-test('Federated comment like', async () => {
+test("Federated comment like", async () => {
let commentRes = await createComment(alpha, postRes.post_view.post.id, None);
// Find the comment on beta
- let betaComment = (await resolveComment(beta, commentRes.comment_view.comment)).comment.unwrap();
+ let betaComment = (
+ await resolveComment(beta, commentRes.comment_view.comment)
+ ).comment.unwrap();
let like = await likeComment(beta, 1, betaComment.comment);
expect(like.comment_view.counts.score).toBe(2);
expect(postComments.comments[0].counts.score).toBe(2);
});
-test('Reply to a comment', async () => {
+test("Reply to a comment", async () => {
// Create a comment on alpha, find it on beta
let commentRes = await createComment(alpha, postRes.post_view.post.id, None);
- let betaComment = (await resolveComment(beta, commentRes.comment_view.comment)).comment.unwrap();
+ let betaComment = (
+ await resolveComment(beta, commentRes.comment_view.comment)
+ ).comment.unwrap();
// find that comment id on beta
expect(replyRes.comment_view.comment.content).toBeDefined();
expect(replyRes.comment_view.community.local).toBe(true);
expect(replyRes.comment_view.creator.local).toBe(true);
- expect(getCommentParentId(replyRes.comment_view.comment).unwrap()).toBe(betaComment.comment.id);
+ expect(getCommentParentId(replyRes.comment_view.comment).unwrap()).toBe(
+ betaComment.comment.id
+ );
expect(replyRes.comment_view.counts.score).toBe(1);
// Make sure that comment is seen on alpha
let postComments = await getComments(alpha, postRes.post_view.post.id);
let alphaComment = postComments.comments[0];
expect(alphaComment.comment.content).toBeDefined();
- expect(getCommentParentId(alphaComment.comment).unwrap()).toBe(postComments.comments[1].comment.id);
+ expect(getCommentParentId(alphaComment.comment).unwrap()).toBe(
+ postComments.comments[1].comment.id
+ );
expect(alphaComment.community.local).toBe(false);
expect(alphaComment.creator.local).toBe(false);
expect(alphaComment.counts.score).toBe(1);
assertCommentFederation(alphaComment, replyRes.comment_view);
});
-test('Mention beta', async () => {
+test("Mention beta", async () => {
// Create a mention on alpha
- let mentionContent = 'A test mention of @lemmy_beta@lemmy-beta:8551';
+ let mentionContent = "A test mention of @lemmy_beta@lemmy-beta:8551";
let commentRes = await createComment(alpha, postRes.post_view.post.id, None);
let mentionRes = await createComment(
alpha,
expect(mentionsRes.mentions[0].counts.score).toBe(1);
});
-test('Comment Search', async () => {
+test("Comment Search", async () => {
let commentRes = await createComment(alpha, postRes.post_view.post.id, None);
- let betaComment = (await resolveComment(beta, commentRes.comment_view.comment)).comment.unwrap();
+ let betaComment = (
+ await resolveComment(beta, commentRes.comment_view.comment)
+ ).comment.unwrap();
assertCommentFederation(betaComment, commentRes.comment_view);
});
-test('A and G subscribe to B (center) A posts, G mentions B, it gets announced to A', async () => {
+test("A and G subscribe to B (center) A posts, G mentions B, it gets announced to A", async () => {
// Create a local post
- let alphaCommunity = (await resolveCommunity(alpha, "!main@lemmy-alpha:8541")).community.unwrap();
+ let alphaCommunity = (
+ await resolveCommunity(alpha, "!main@lemmy-alpha:8541")
+ ).community.unwrap();
let alphaPost = await createPost(alpha, alphaCommunity.community.id);
expect(alphaPost.post_view.community.local).toBe(true);
// Make sure gamma sees it
- let gammaPost = (await resolvePost(gamma, alphaPost.post_view.post)).post.unwrap();
+ let gammaPost = (
+ await resolvePost(gamma, alphaPost.post_view.post)
+ ).post.unwrap();
let commentContent =
- 'A jest test federated comment announce, lets mention @lemmy_beta@lemmy-beta:8551';
+ "A jest test federated comment announce, lets mention @lemmy_beta@lemmy-beta:8551";
let commentRes = await createComment(
gamma,
gammaPost.post.id,
expect(commentRes.comment_view.counts.score).toBe(1);
// Make sure alpha sees it
- let alphaPostComments2 = await getComments(alpha, alphaPost.post_view.post.id);
+ let alphaPostComments2 = await getComments(
+ alpha,
+ alphaPost.post_view.post.id
+ );
expect(alphaPostComments2.comments[0].comment.content).toBe(commentContent);
expect(alphaPostComments2.comments[0].community.local).toBe(true);
expect(alphaPostComments2.comments[0].creator.local).toBe(false);
expect(alphaPostComments2.comments[0].counts.score).toBe(1);
- assertCommentFederation(alphaPostComments2.comments[0], commentRes.comment_view);
+ assertCommentFederation(
+ alphaPostComments2.comments[0],
+ commentRes.comment_view
+ );
// Make sure beta has mentions
let mentionsRes = await getMentions(beta);
// expect(mentionsRes.mentions[0].score).toBe(1);
});
-test('Check that activity from another instance is sent to third instance', async () => {
+test("Check that activity from another instance is sent to third instance", async () => {
// Alpha and gamma users follow beta community
let alphaFollow = await followBeta(alpha);
expect(alphaFollow.community_view.community.local).toBe(false);
- expect(alphaFollow.community_view.community.name).toBe('main');
+ expect(alphaFollow.community_view.community.name).toBe("main");
let gammaFollow = await followBeta(gamma);
expect(gammaFollow.community_view.community.local).toBe(false);
- expect(gammaFollow.community_view.community.name).toBe('main');
+ expect(gammaFollow.community_view.community.name).toBe("main");
// Create a post on beta
let betaPost = await createPost(beta, 2);
expect(betaPost.post_view.community.local).toBe(true);
// Make sure gamma and alpha see it
- let gammaPost = (await resolvePost(gamma, betaPost.post_view.post)).post.unwrap();
+ let gammaPost = (
+ await resolvePost(gamma, betaPost.post_view.post)
+ ).post.unwrap();
expect(gammaPost.post).toBeDefined();
- let alphaPost = (await resolvePost(alpha, betaPost.post_view.post)).post.unwrap();
+ let alphaPost = (
+ await resolvePost(alpha, betaPost.post_view.post)
+ ).post.unwrap();
expect(alphaPost.post).toBeDefined();
// The bug: gamma comments, and alpha should see it.
- let commentContent = 'Comment from gamma';
+ let commentContent = "Comment from gamma";
let commentRes = await createComment(
gamma,
gammaPost.post.id,
expect(alphaPostComments2.comments[0].community.local).toBe(false);
expect(alphaPostComments2.comments[0].creator.local).toBe(false);
expect(alphaPostComments2.comments[0].counts.score).toBe(1);
- assertCommentFederation(alphaPostComments2.comments[0], commentRes.comment_view);
+ assertCommentFederation(
+ alphaPostComments2.comments[0],
+ commentRes.comment_view
+ );
await unfollowRemotes(alpha);
await unfollowRemotes(gamma);
});
-test('Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedded comments, A subs to B, B updates the lowest level comment, A fetches both the post and all the inreplyto comments for that post.', async () => {
+test("Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedded comments, A subs to B, B updates the lowest level comment, A fetches both the post and all the inreplyto comments for that post.", async () => {
// Unfollow all remote communities
let site = await unfollowRemotes(alpha);
expect(
let postRes = await createPost(beta, 2);
expect(postRes.post_view.post.name).toBeDefined();
- let parentCommentContent = 'An invisible top level comment from beta';
+ let parentCommentContent = "An invisible top level comment from beta";
let parentCommentRes = await createComment(
beta,
postRes.post_view.post.id,
);
// B creates a comment, then a child one of that.
- let childCommentContent = 'An invisible child comment from beta';
+ let childCommentContent = "An invisible child comment from beta";
let childCommentRes = await createComment(
beta,
postRes.post_view.post.id,
// Follow beta again
let follow = await followBeta(alpha);
expect(follow.community_view.community.local).toBe(false);
- expect(follow.community_view.community.name).toBe('main');
+ expect(follow.community_view.community.name).toBe("main");
// An update to the child comment on beta, should push the post, parent, and child to alpha now
- let updatedCommentContent = 'An update child comment from beta';
+ let updatedCommentContent = Some("An update child comment from beta");
let updateRes = await editComment(
beta,
childCommentRes.comment_view.comment.id,
updatedCommentContent
);
- expect(updateRes.comment_view.comment.content).toBe(updatedCommentContent);
+ expect(updateRes.comment_view.comment.content).toBe(
+ updatedCommentContent.unwrap()
+ );
// Get the post from alpha
- let alphaPostB = (await resolvePost(alpha, postRes.post_view.post)).post.unwrap();
+ let alphaPostB = (
+ await resolvePost(alpha, postRes.post_view.post)
+ ).post.unwrap();
let alphaPost = await getPost(alpha, alphaPostB.post.id);
let alphaPostComments = await getComments(alpha, alphaPostB.post.id);
expect(alphaPost.post_view.post.name).toBeDefined();
- assertCommentFederation(alphaPostComments.comments[1], parentCommentRes.comment_view);
- assertCommentFederation(alphaPostComments.comments[0], updateRes.comment_view);
+ assertCommentFederation(
+ alphaPostComments.comments[1],
+ parentCommentRes.comment_view
+ );
+ assertCommentFederation(
+ alphaPostComments.comments[0],
+ updateRes.comment_view
+ );
expect(alphaPost.post_view.community.local).toBe(false);
expect(alphaPost.post_view.creator.local).toBe(false);
await unfollowRemotes(alpha);
});
-
-test('Report a comment', async () => {
+test("Report a comment", async () => {
let betaCommunity = (await resolveBetaCommunity(beta)).community.unwrap();
- let postRes = (await createPost(beta, betaCommunity.community.id)).post_view.post;
+ let postRes = (await createPost(beta, betaCommunity.community.id)).post_view
+ .post;
expect(postRes).toBeDefined();
- let commentRes = (await createComment(beta, postRes.id, None)).comment_view.comment;
+ let commentRes = (await createComment(beta, postRes.id, None)).comment_view
+ .comment;
expect(commentRes).toBeDefined();
- let alphaComment = (await resolveComment(alpha, commentRes)).comment.unwrap().comment;
- let alphaReport = (await reportComment(alpha, alphaComment.id, randomString(10)))
- .comment_report_view.comment_report;
+ let alphaComment = (await resolveComment(alpha, commentRes)).comment.unwrap()
+ .comment;
+ let alphaReport = (
+ await reportComment(alpha, alphaComment.id, randomString(10))
+ ).comment_report_view.comment_report;
- let betaReport = (await listCommentReports(beta)).comment_reports[0].comment_report;
+ let betaReport = (await listCommentReports(beta)).comment_reports[0]
+ .comment_report;
expect(betaReport).toBeDefined();
expect(betaReport.resolved).toBe(false);
- expect(betaReport.original_comment_text).toBe(alphaReport.original_comment_text);
+ expect(betaReport.original_comment_text).toBe(
+ alphaReport.original_comment_text
+ );
expect(betaReport.reason).toBe(alphaReport.reason);
});
-function N(gamma: API, id: number, N: any, commentContent: string) {
- throw new Error('Function not implemented.');
-}
-
jest.setTimeout(120000);
-import { CommunityView } from 'lemmy-js-client';
+import { CommunityView } from "lemmy-js-client";
import {
alpha,
createPost,
getPost,
resolvePost,
-} from './shared';
+} from "./shared";
beforeAll(async () => {
await setupLogins();
expect(communityOne.community.description.unwrapOr("none")).toBe(
communityTwo.community.description.unwrapOr("none")
);
- expect(communityOne.community.icon.unwrapOr("none")).toBe(communityTwo.community.icon.unwrapOr("none"));
- expect(communityOne.community.banner.unwrapOr("none")).toBe(communityTwo.community.banner.unwrapOr("none"));
+ expect(communityOne.community.icon.unwrapOr("none")).toBe(
+ communityTwo.community.icon.unwrapOr("none")
+ );
+ expect(communityOne.community.banner.unwrapOr("none")).toBe(
+ communityTwo.community.banner.unwrapOr("none")
+ );
expect(communityOne.community.published).toBe(
communityTwo.community.published
);
expect(communityOne.community.deleted).toBe(communityTwo.community.deleted);
}
-test('Create community', async () => {
+test("Create community", async () => {
let communityRes = await createCommunity(alpha);
expect(communityRes.community_view.community.name).toBeDefined();
// A dupe check
let prevName = communityRes.community_view.community.name;
let communityRes2: any = await createCommunity(alpha, prevName);
- expect(communityRes2['error']).toBe('community_already_exists');
+ expect(communityRes2["error"]).toBe("community_already_exists");
// Cache the community on beta, make sure it has the other fields
let searchShort = `!${prevName}@lemmy-alpha:8541`;
- let betaCommunity = (await resolveCommunity(beta, searchShort)).community.unwrap();
+ let betaCommunity = (
+ await resolveCommunity(beta, searchShort)
+ ).community.unwrap();
assertCommunityFederation(betaCommunity, communityRes.community_view);
});
-test('Delete community', async () => {
+test("Delete community", async () => {
let communityRes = await createCommunity(beta);
// Cache the community on Alpha
let searchShort = `!${communityRes.community_view.community.name}@lemmy-beta:8551`;
- let alphaCommunity = (await resolveCommunity(alpha, searchShort)).community.unwrap();
+ let alphaCommunity = (
+ await resolveCommunity(alpha, searchShort)
+ ).community.unwrap();
assertCommunityFederation(alphaCommunity, communityRes.community_view);
// Follow the community from alpha
- let follow = await followCommunity(
- alpha,
- true,
- alphaCommunity.community.id
- );
+ let follow = await followCommunity(alpha, true, alphaCommunity.community.id);
// Make sure the follow response went through
expect(follow.community_view.community.local).toBe(false);
communityRes.community_view.community.id
);
expect(deleteCommunityRes.community_view.community.deleted).toBe(true);
- expect(deleteCommunityRes.community_view.community.title).toBe(communityRes.community_view.community.title);
+ expect(deleteCommunityRes.community_view.community.title).toBe(
+ communityRes.community_view.community.title
+ );
// Make sure it got deleted on A
let communityOnAlphaDeleted = await getCommunity(
);
});
-test('Remove community', async () => {
+test("Remove community", async () => {
let communityRes = await createCommunity(beta);
// Cache the community on Alpha
let searchShort = `!${communityRes.community_view.community.name}@lemmy-beta:8551`;
- let alphaCommunity = (await resolveCommunity(alpha, searchShort)).community.unwrap();
+ let alphaCommunity = (
+ await resolveCommunity(alpha, searchShort)
+ ).community.unwrap();
assertCommunityFederation(alphaCommunity, communityRes.community_view);
// Follow the community from alpha
- let follow = await followCommunity(
- alpha,
- true,
- alphaCommunity.community.id
- );
+ let follow = await followCommunity(alpha, true, alphaCommunity.community.id);
// Make sure the follow response went through
expect(follow.community_view.community.local).toBe(false);
communityRes.community_view.community.id
);
expect(removeCommunityRes.community_view.community.removed).toBe(true);
- expect(removeCommunityRes.community_view.community.title).toBe(communityRes.community_view.community.title);
+ expect(removeCommunityRes.community_view.community.title).toBe(
+ communityRes.community_view.community.title
+ );
// Make sure it got Removed on A
let communityOnAlphaRemoved = await getCommunity(
);
});
-test('Search for beta community', async () => {
+test("Search for beta community", async () => {
let communityRes = await createCommunity(beta);
expect(communityRes.community_view.community.name).toBeDefined();
let searchShort = `!${communityRes.community_view.community.name}@lemmy-beta:8551`;
- let alphaCommunity = (await resolveCommunity(alpha, searchShort)).community.unwrap();
+ let alphaCommunity = (
+ await resolveCommunity(alpha, searchShort)
+ ).community.unwrap();
assertCommunityFederation(alphaCommunity, communityRes.community_view);
});
-test('Admin actions in remote community are not federated to origin', async () => {
+test("Admin actions in remote community are not federated to origin", async () => {
// create a community on alpha
let communityRes = (await createCommunity(alpha)).community_view;
expect(communityRes.community.name).toBeDefined();
// gamma follows community and posts in it
- let gammaCommunity = (await resolveCommunity(gamma, communityRes.community.actor_id)).community.unwrap();
- let gammaFollow = (await followCommunity(gamma, true, gammaCommunity.community.id));
+ let gammaCommunity = (
+ await resolveCommunity(gamma, communityRes.community.actor_id)
+ ).community.unwrap();
+ let gammaFollow = await followCommunity(
+ gamma,
+ true,
+ gammaCommunity.community.id
+ );
expect(gammaFollow.community_view.subscribed).toBe("Subscribed");
- let gammaPost = (await createPost(gamma, gammaCommunity.community.id)).post_view;
+ let gammaPost = (await createPost(gamma, gammaCommunity.community.id))
+ .post_view;
expect(gammaPost.post.id).toBeDefined();
expect(gammaPost.creator_banned_from_community).toBe(false);
// admin of beta decides to ban gamma from community
- let betaCommunity = (await resolveCommunity(beta, communityRes.community.actor_id)).community.unwrap();
- let bannedUserInfo1 = (await getSite(gamma)).my_user.unwrap().local_user_view.person;
- let bannedUserInfo2 = (await resolvePerson(beta, bannedUserInfo1.actor_id)).person.unwrap();
- let banRes = (await banPersonFromCommunity(beta, bannedUserInfo2.person.id, betaCommunity.community.id, true, true));
- console.log(banRes);
+ let betaCommunity = (
+ await resolveCommunity(beta, communityRes.community.actor_id)
+ ).community.unwrap();
+ let bannedUserInfo1 = (await getSite(gamma)).my_user.unwrap().local_user_view
+ .person;
+ let bannedUserInfo2 = (
+ await resolvePerson(beta, bannedUserInfo1.actor_id)
+ ).person.unwrap();
+ let banRes = await banPersonFromCommunity(
+ beta,
+ bannedUserInfo2.person.id,
+ betaCommunity.community.id,
+ true,
+ true
+ );
expect(banRes.banned).toBe(true);
// ban doesnt federate to community's origin instance alpha
expect(alphaPost.creator_banned_from_community).toBe(false);
// and neither to gamma
- let gammaPost2 = (await getPost(gamma, gammaPost.post.id));
+ let gammaPost2 = await getPost(gamma, gammaPost.post.id);
expect(gammaPost2.post_view.creator_banned_from_community).toBe(false);
});
jest.setTimeout(120000);
-import {SubscribedType} from 'lemmy-js-client';
+import { SubscribedType } from "lemmy-js-client";
+
import {
alpha,
setupLogins,
followCommunity,
unfollowRemotes,
getSite,
- delay,
-} from './shared';
+} from "./shared";
beforeAll(async () => {
await setupLogins();
await unfollowRemotes(alpha);
});
-test('Follow federated community', async () => {
+test("Follow federated community", async () => {
let betaCommunity = (await resolveBetaCommunity(alpha)).community.unwrap();
- let follow = await followCommunity(
- alpha,
- true,
- betaCommunity.community.id
- );
+ let follow = await followCommunity(alpha, true, betaCommunity.community.id);
// Make sure the follow response went through
expect(follow.community_view.community.local).toBe(false);
- expect(follow.community_view.community.name).toBe('main');
+ expect(follow.community_view.community.name).toBe("main");
expect(follow.community_view.subscribed).toBe(SubscribedType.Subscribed);
// Check it from local
let site = await getSite(alpha);
- let remoteCommunityId = site.my_user.unwrap().follows.find(
- c => c.community.local == false
- ).community.id;
+ let remoteCommunityId = site.my_user
+ .unwrap()
+ .follows.find(c => c.community.local == false).community.id;
expect(remoteCommunityId).toBeDefined();
expect(site.my_user.unwrap().follows.length).toBe(2);
jest.setTimeout(120000);
-import {None} from '@sniptt/monads';
-import { PostView, CommunityView } from 'lemmy-js-client';
+import { None } from "@sniptt/monads";
+import { PostView, CommunityView } from "lemmy-js-client";
+
import {
alpha,
beta,
API,
getSite,
unfollows,
- resolveCommunity
-} from './shared';
+ resolveCommunity,
+} from "./shared";
let betaCommunity: CommunityView;
function assertPostFederation(postOne: PostView, postTwo: PostView) {
expect(postOne.post.ap_id).toBe(postTwo.post.ap_id);
expect(postOne.post.name).toBe(postTwo.post.name);
- expect(postOne.post.body.unwrapOr("none")).toBe(postTwo.post.body.unwrapOr("none"));
- expect(postOne.post.url.unwrapOr("none")).toBe(postTwo.post.url.unwrapOr("none"));
+ expect(postOne.post.body.unwrapOr("none")).toBe(
+ postTwo.post.body.unwrapOr("none")
+ );
+ expect(postOne.post.url.unwrapOr("https://google.com/")).toBe(
+ postTwo.post.url.unwrapOr("https://google.com/")
+ );
expect(postOne.post.nsfw).toBe(postTwo.post.nsfw);
- expect(postOne.post.embed_title.unwrapOr("none")).toBe(postTwo.post.embed_title.unwrapOr("none"));
- expect(postOne.post.embed_description.unwrapOr("none")).toBe(postTwo.post.embed_description.unwrapOr("none"));
- expect(postOne.post.embed_html.unwrapOr("none")).toBe(postTwo.post.embed_html.unwrapOr("none"));
+ expect(postOne.post.embed_title.unwrapOr("none")).toBe(
+ postTwo.post.embed_title.unwrapOr("none")
+ );
+ expect(postOne.post.embed_description.unwrapOr("none")).toBe(
+ postTwo.post.embed_description.unwrapOr("none")
+ );
+ expect(postOne.post.embed_video_url.unwrapOr("none")).toBe(
+ postTwo.post.embed_video_url.unwrapOr("none")
+ );
expect(postOne.post.published).toBe(postTwo.post.published);
expect(postOne.community.actor_id).toBe(postTwo.community.actor_id);
expect(postOne.post.locked).toBe(postTwo.post.locked);
expect(postOne.post.deleted).toBe(postTwo.post.deleted);
}
-test('Create a post', async () => {
+test("Create a post", async () => {
let postRes = await createPost(alpha, betaCommunity.community.id);
expect(postRes.post_view.post).toBeDefined();
expect(postRes.post_view.community.local).toBe(false);
expect(postRes.post_view.counts.score).toBe(1);
// Make sure that post is liked on beta
- let betaPost = (await resolvePost(beta, postRes.post_view.post)).post.unwrap();
+ let betaPost = (
+ await resolvePost(beta, postRes.post_view.post)
+ ).post.unwrap();
expect(betaPost).toBeDefined();
expect(betaPost.community.local).toBe(true);
// Delta only follows beta, so it should not see an alpha ap_id
let deltaPost = (await resolvePost(delta, postRes.post_view.post)).post;
- expect(deltaPost.isNone()).toBe(true)
+ expect(deltaPost.isNone()).toBe(true);
// Epsilon has alpha blocked, it should not see the alpha post
let epsilonPost = (await resolvePost(epsilon, postRes.post_view.post)).post;
expect(epsilonPost.isNone()).toBe(true);
});
-test('Create a post in a non-existent community', async () => {
- let postRes = await createPost(alpha, -2) as any;
- expect(postRes.error).toBe('couldnt_find_community');
+test("Create a post in a non-existent community", async () => {
+ let postRes = (await createPost(alpha, -2)) as any;
+ expect(postRes.error).toBe("couldnt_find_community");
});
-test('Unlike a post', async () => {
+test("Unlike a post", async () => {
let postRes = await createPost(alpha, betaCommunity.community.id);
let unlike = await likePost(alpha, 0, postRes.post_view.post);
expect(unlike.post_view.counts.score).toBe(0);
expect(unlike2.post_view.counts.score).toBe(0);
// Make sure that post is unliked on beta
- let betaPost = (await resolvePost(beta, postRes.post_view.post)).post.unwrap();
+ let betaPost = (
+ await resolvePost(beta, postRes.post_view.post)
+ ).post.unwrap();
expect(betaPost).toBeDefined();
expect(betaPost.community.local).toBe(true);
expect(betaPost.creator.local).toBe(false);
assertPostFederation(betaPost, postRes.post_view);
});
-test('Update a post', async () => {
+test("Update a post", async () => {
let postRes = await createPost(alpha, betaCommunity.community.id);
- let updatedName = 'A jest test federated post, updated';
+ let updatedName = "A jest test federated post, updated";
let updatedPost = await editPost(alpha, postRes.post_view.post);
expect(updatedPost.post_view.post.name).toBe(updatedName);
expect(updatedPost.post_view.community.local).toBe(false);
expect(updatedPost.post_view.creator.local).toBe(true);
// Make sure that post is updated on beta
- let betaPost = (await resolvePost(beta, postRes.post_view.post)).post.unwrap();
+ let betaPost = (
+ await resolvePost(beta, postRes.post_view.post)
+ ).post.unwrap();
expect(betaPost.community.local).toBe(true);
expect(betaPost.creator.local).toBe(false);
expect(betaPost.post.name).toBe(updatedName);
assertPostFederation(betaPost, updatedPost.post_view);
// Make sure lemmy beta cannot update the post
- let updatedPostBeta = await editPost(beta, betaPost.post) as any;
- expect(updatedPostBeta.error).toBe('no_post_edit_allowed');
+ let updatedPostBeta = (await editPost(beta, betaPost.post)) as any;
+ expect(updatedPostBeta.error).toBe("no_post_edit_allowed");
});
-test('Sticky a post', async () => {
+test("Sticky a post", async () => {
let postRes = await createPost(alpha, betaCommunity.community.id);
- let betaPost1 = (await resolvePost(beta, postRes.post_view.post)).post.unwrap();
+ let betaPost1 = (
+ await resolvePost(beta, postRes.post_view.post)
+ ).post.unwrap();
let stickiedPostRes = await stickyPost(beta, true, betaPost1.post);
expect(stickiedPostRes.post_view.post.stickied).toBe(true);
// Make sure that post is stickied on beta
- let betaPost = (await resolvePost(beta, postRes.post_view.post)).post.unwrap();
+ let betaPost = (
+ await resolvePost(beta, postRes.post_view.post)
+ ).post.unwrap();
expect(betaPost.community.local).toBe(true);
expect(betaPost.creator.local).toBe(false);
expect(betaPost.post.stickied).toBe(true);
expect(unstickiedPost.post_view.post.stickied).toBe(false);
// Make sure that post is unstickied on beta
- let betaPost2 = (await resolvePost(beta, postRes.post_view.post)).post.unwrap();
+ let betaPost2 = (
+ await resolvePost(beta, postRes.post_view.post)
+ ).post.unwrap();
expect(betaPost2.community.local).toBe(true);
expect(betaPost2.creator.local).toBe(false);
expect(betaPost2.post.stickied).toBe(false);
// Make sure that gamma cannot sticky the post on beta
- let gammaPost = (await resolvePost(gamma, postRes.post_view.post)).post.unwrap();
+ let gammaPost = (
+ await resolvePost(gamma, postRes.post_view.post)
+ ).post.unwrap();
let gammaTrySticky = await stickyPost(gamma, true, gammaPost.post);
- let betaPost3 = (await resolvePost(beta, postRes.post_view.post)).post.unwrap();
+ let betaPost3 = (
+ await resolvePost(beta, postRes.post_view.post)
+ ).post.unwrap();
expect(gammaTrySticky.post_view.post.stickied).toBe(true);
expect(betaPost3.post.stickied).toBe(false);
});
-test('Lock a post', async () => {
+test("Lock a post", async () => {
await followCommunity(alpha, true, betaCommunity.community.id);
let postRes = await createPost(alpha, betaCommunity.community.id);
// Lock the post
- let betaPost1 = (await resolvePost(beta, postRes.post_view.post)).post.unwrap();
+ let betaPost1 = (
+ await resolvePost(beta, postRes.post_view.post)
+ ).post.unwrap();
let lockedPostRes = await lockPost(beta, true, betaPost1.post);
expect(lockedPostRes.post_view.post.locked).toBe(true);
// Try to make a new comment there, on alpha
let comment: any = await createComment(alpha, alphaPost1.post.id, None);
- expect(comment['error']).toBe('locked');
+ expect(comment["error"]).toBe("locked");
// Unlock a post
let unlockedPost = await lockPost(beta, false, betaPost1.post);
expect(commentAlpha).toBeDefined();
});
-test('Delete a post', async () => {
+test("Delete a post", async () => {
let postRes = await createPost(alpha, betaCommunity.community.id);
expect(postRes.post_view.post).toBeDefined();
expect(undeletedPost.post_view.post.deleted).toBe(false);
// Make sure lemmy beta sees post is undeleted
- let betaPost2 = (await resolvePost(beta, postRes.post_view.post)).post.unwrap();
+ let betaPost2 = (
+ await resolvePost(beta, postRes.post_view.post)
+ ).post.unwrap();
expect(betaPost2.post.deleted).toBe(false);
assertPostFederation(betaPost2, undeletedPost.post_view);
// Make sure lemmy beta cannot delete the post
- let deletedPostBeta = await deletePost(beta, true, betaPost2.post) as any;
- expect(deletedPostBeta.error).toStrictEqual('no_post_edit_allowed');
+ let deletedPostBeta = (await deletePost(beta, true, betaPost2.post)) as any;
+ expect(deletedPostBeta.error).toStrictEqual("no_post_edit_allowed");
});
-test('Remove a post from admin and community on different instance', async () => {
- let gammaCommunity = await resolveCommunity(gamma, betaCommunity.community.actor_id);
- let postRes = await createPost(gamma, gammaCommunity.community.unwrap().community.id);
+test("Remove a post from admin and community on different instance", async () => {
+ let gammaCommunity = await resolveCommunity(
+ gamma,
+ betaCommunity.community.actor_id
+ );
+ let postRes = await createPost(
+ gamma,
+ gammaCommunity.community.unwrap().community.id
+ );
- let alphaPost = (await resolvePost(alpha, postRes.post_view.post)).post.unwrap();
+ let alphaPost = (
+ await resolvePost(alpha, postRes.post_view.post)
+ ).post.unwrap();
let removedPost = await removePost(alpha, true, alphaPost.post);
expect(removedPost.post_view.post.removed).toBe(true);
expect(removedPost.post_view.post.name).toBe(postRes.post_view.post.name);
// Make sure lemmy beta sees post is NOT removed
- let betaPost = (await resolvePost(beta, postRes.post_view.post)).post.unwrap();
+ let betaPost = (
+ await resolvePost(beta, postRes.post_view.post)
+ ).post.unwrap();
expect(betaPost.post.removed).toBe(false);
// Undelete
expect(undeletedPost.post_view.post.removed).toBe(false);
// Make sure lemmy beta sees post is undeleted
- let betaPost2 = (await resolvePost(beta, postRes.post_view.post)).post.unwrap();
+ let betaPost2 = (
+ await resolvePost(beta, postRes.post_view.post)
+ ).post.unwrap();
expect(betaPost2.post.removed).toBe(false);
assertPostFederation(betaPost2, undeletedPost.post_view);
});
-test('Remove a post from admin and community on same instance', async () => {
+test("Remove a post from admin and community on same instance", async () => {
await followBeta(alpha);
let postRes = await createPost(alpha, betaCommunity.community.id);
expect(postRes.post_view.post).toBeDefined();
await unfollowRemotes(alpha);
});
-test('Search for a post', async () => {
+test("Search for a post", async () => {
await unfollowRemotes(alpha);
let postRes = await createPost(alpha, betaCommunity.community.id);
expect(postRes.post_view.post).toBeDefined();
- let betaPost = (await resolvePost(beta, postRes.post_view.post)).post.unwrap();
+ let betaPost = (
+ await resolvePost(beta, postRes.post_view.post)
+ ).post.unwrap();
expect(betaPost.post.name).toBeDefined();
});
-test('Enforce site ban for federated user', async () => {
+test("Enforce site ban for federated user", async () => {
// create a test user
let alphaUserJwt = await registerUser(alpha);
expect(alphaUserJwt).toBeDefined();
let alpha_user: API = {
- client: alpha.client,
- auth: alphaUserJwt.jwt,
+ client: alpha.client,
+ auth: alphaUserJwt.jwt,
};
- let alphaUserActorId = (await getSite(alpha_user)).my_user.unwrap().local_user_view.person.actor_id;
+ let alphaUserActorId = (await getSite(alpha_user)).my_user.unwrap()
+ .local_user_view.person.actor_id;
expect(alphaUserActorId).toBeDefined();
- let alphaPerson = (await resolvePerson(alpha_user, alphaUserActorId)).person.unwrap();
+ let alphaPerson = (
+ await resolvePerson(alpha_user, alphaUserActorId)
+ ).person.unwrap();
expect(alphaPerson).toBeDefined();
// alpha makes post in beta community, it federates to beta instance
expect(searchBeta1.posts[0]).toBeDefined();
// ban alpha from its instance
- let banAlpha = await banPersonFromSite(alpha, alphaPerson.person.id, true, true);
+ let banAlpha = await banPersonFromSite(
+ alpha,
+ alphaPerson.person.id,
+ true,
+ true
+ );
expect(banAlpha.banned).toBe(true);
// alpha ban should be federated to beta
expect(searchBeta2.posts[0]).toBeUndefined();
// Unban alpha
- let unBanAlpha = await banPersonFromSite(alpha, alphaPerson.person.id, false, false);
+ let unBanAlpha = await banPersonFromSite(
+ alpha,
+ alphaPerson.person.id,
+ false,
+ false
+ );
expect(unBanAlpha.banned).toBe(false);
// alpha makes new post in beta community, it federates
let searchBeta3 = await searchPostLocal(beta, postRes2.post_view.post);
expect(searchBeta3.posts[0]).toBeDefined();
- let alphaUserOnBeta2 = await resolvePerson(beta, alphaUserActorId)
+ let alphaUserOnBeta2 = await resolvePerson(beta, alphaUserActorId);
expect(alphaUserOnBeta2.person.unwrap().person.banned).toBe(false);
});
-test('Enforce community ban for federated user', async () => {
+test("Enforce community ban for federated user", async () => {
let alphaShortname = `@lemmy_alpha@lemmy-alpha:8541`;
let alphaPerson = (await resolvePerson(beta, alphaShortname)).person.unwrap();
expect(alphaPerson).toBeDefined();
expect(searchBeta1.posts[0]).toBeDefined();
// ban alpha from beta community
- let banAlpha = await banPersonFromCommunity(beta, alphaPerson.person.id, 2, true, true);
+ let banAlpha = await banPersonFromCommunity(
+ beta,
+ alphaPerson.person.id,
+ 2,
+ true,
+ true
+ );
expect(banAlpha.banned).toBe(true);
// ensure that the post by alpha got removed
expect(searchBeta2.posts[0]).toBeDefined();
});
-
-test('A and G subscribe to B (center) A posts, it gets announced to G', async () => {
+test("A and G subscribe to B (center) A posts, it gets announced to G", async () => {
let postRes = await createPost(alpha, betaCommunity.community.id);
expect(postRes.post_view.post).toBeDefined();
- let betaPost = (await resolvePost(gamma, postRes.post_view.post)).post.unwrap();
+ let betaPost = (
+ await resolvePost(gamma, postRes.post_view.post)
+ ).post.unwrap();
expect(betaPost.post.name).toBeDefined();
});
-test('Report a post', async () => {
+test("Report a post", async () => {
let betaCommunity = (await resolveBetaCommunity(beta)).community.unwrap();
let postRes = await createPost(beta, betaCommunity.community.id);
expect(postRes.post_view.post).toBeDefined();
- let alphaPost = (await resolvePost(alpha, postRes.post_view.post)).post.unwrap();
- let alphaReport = (await reportPost(alpha, alphaPost.post.id, randomString(10)))
- .post_report_view.post_report;
+ let alphaPost = (
+ await resolvePost(alpha, postRes.post_view.post)
+ ).post.unwrap();
+ let alphaReport = (
+ await reportPost(alpha, alphaPost.post.id, randomString(10))
+ ).post_report_view.post_report;
let betaReport = (await listPostReports(beta)).post_reports[0].post_report;
expect(betaReport).toBeDefined();
expect(betaReport.resolved).toBe(false);
expect(betaReport.original_post_name).toBe(alphaReport.original_post_name);
- expect(betaReport.original_post_url.unwrapOr("none")).toBe(alphaReport.original_post_url.unwrapOr("none"));
- expect(betaReport.original_post_body.unwrapOr("none")).toBe(alphaReport.original_post_body.unwrapOr("none"));
+ expect(betaReport.original_post_url.unwrapOr("none")).toBe(
+ alphaReport.original_post_url.unwrapOr("none")
+ );
+ expect(betaReport.original_post_body.unwrapOr("none")).toBe(
+ alphaReport.original_post_body.unwrapOr("none")
+ );
expect(betaReport.reason).toBe(alphaReport.reason);
});
listPrivateMessages,
deletePrivateMessage,
unfollowRemotes,
-} from './shared';
+} from "./shared";
let recipient_id: number;
await unfollowRemotes(alpha);
});
-test('Create a private message', async () => {
+test("Create a private message", async () => {
let pmRes = await createPrivateMessage(alpha, recipient_id);
expect(pmRes.private_message_view.private_message.content).toBeDefined();
expect(pmRes.private_message_view.private_message.local).toBe(true);
expect(betaPms.private_messages[0].recipient.local).toBe(true);
});
-test('Update a private message', async () => {
- let updatedContent = 'A jest test federated private message edited';
+test("Update a private message", async () => {
+ let updatedContent = "A jest test federated private message edited";
let pmRes = await createPrivateMessage(alpha, recipient_id);
let pmUpdated = await editPrivateMessage(
);
});
-test('Delete a private message', async () => {
+test("Delete a private message", async () => {
let pmRes = await createPrivateMessage(alpha, recipient_id);
let betaPms1 = await listPrivateMessages(beta);
let deletedPmRes = await deletePrivateMessage(
-import {None, Some, Option} from '@sniptt/monads';
+import { None, Some, Option } from "@sniptt/monads";
import {
Login,
LoginResponse,
EditSite,
CommentSortType,
GetComments,
- GetCommentsResponse
-} from 'lemmy-js-client';
+ GetCommentsResponse,
+} from "lemmy-js-client";
export interface API {
client: LemmyHttp;
}
export let alpha: API = {
- client: new LemmyHttp('http://127.0.0.1:8541'),
+ client: new LemmyHttp("http://127.0.0.1:8541"),
auth: None,
};
export let beta: API = {
- client: new LemmyHttp('http://127.0.0.1:8551'),
+ client: new LemmyHttp("http://127.0.0.1:8551"),
auth: None,
};
export let gamma: API = {
- client: new LemmyHttp('http://127.0.0.1:8561'),
+ client: new LemmyHttp("http://127.0.0.1:8561"),
auth: None,
};
export let delta: API = {
- client: new LemmyHttp('http://127.0.0.1:8571'),
+ client: new LemmyHttp("http://127.0.0.1:8571"),
auth: None,
};
export let epsilon: API = {
- client: new LemmyHttp('http://127.0.0.1:8581'),
+ client: new LemmyHttp("http://127.0.0.1:8581"),
auth: None,
};
-const password = 'lemmylemmy'
+const password = "lemmylemmy";
export async function setupLogins() {
let formAlpha = new Login({
- username_or_email: 'lemmy_alpha',
+ username_or_email: "lemmy_alpha",
password,
});
let resAlpha = alpha.client.login(formAlpha);
let formBeta = new Login({
- username_or_email: 'lemmy_beta',
+ username_or_email: "lemmy_beta",
password,
});
let resBeta = beta.client.login(formBeta);
let formGamma = new Login({
- username_or_email: 'lemmy_gamma',
+ username_or_email: "lemmy_gamma",
password,
});
let resGamma = gamma.client.login(formGamma);
let formDelta = new Login({
- username_or_email: 'lemmy_delta',
+ username_or_email: "lemmy_delta",
password,
});
let resDelta = delta.client.login(formDelta);
let formEpsilon = new Login({
- username_or_email: 'lemmy_epsilon',
+ username_or_email: "lemmy_epsilon",
password,
});
let resEpsilon = epsilon.client.login(formEpsilon);
// Registration applications are now enabled by default, need to disable them
let editSiteForm = new EditSite({
+ require_application: Some(false),
+ federation_debug: Some(true),
name: None,
sidebar: None,
description: None,
enable_nsfw: None,
community_creation_admin_only: None,
require_email_verification: None,
- require_application: Some(false),
application_question: None,
private_instance: None,
default_theme: None,
- legal_information: None,
default_post_listing_type: None,
+ legal_information: None,
+ application_email_admins: None,
+ hide_modlog_mod_names: None,
+ discussion_languages: None,
+ slur_filter_regex: None,
+ actor_name_max_length: None,
+ rate_limit_message: Some(999),
+ rate_limit_message_per_second: None,
+ rate_limit_post: Some(999),
+ rate_limit_post_per_second: None,
+ rate_limit_register: Some(999),
+ rate_limit_register_per_second: None,
+ rate_limit_image: Some(999),
+ rate_limit_image_per_second: None,
+ rate_limit_comment: Some(999),
+ rate_limit_comment_per_second: None,
+ rate_limit_search: Some(999),
+ rate_limit_search_per_second: None,
+ federation_enabled: None,
+ federation_strict_allowlist: None,
+ federation_http_fetch_retry_limit: None,
+ federation_worker_count: None,
+ captcha_enabled: None,
+ captcha_difficulty: None,
+ allowed_instances: None,
+ blocked_instances: None,
auth: "",
});
+
+ // Set the blocks and auths for each
editSiteForm.auth = alpha.auth.unwrap();
+ editSiteForm.allowed_instances = Some([
+ "lemmy-beta",
+ "lemmy-gamma",
+ "lemmy-delta",
+ "lemmy-epsilon",
+ ]);
await alpha.client.editSite(editSiteForm);
+
editSiteForm.auth = beta.auth.unwrap();
+ editSiteForm.allowed_instances = Some([
+ "lemmy-alpha",
+ "lemmy-gamma",
+ "lemmy-delta",
+ "lemmy-epsilon",
+ ]);
await beta.client.editSite(editSiteForm);
+
editSiteForm.auth = gamma.auth.unwrap();
+ editSiteForm.allowed_instances = Some([
+ "lemmy-alpha",
+ "lemmy-beta",
+ "lemmy-delta",
+ "lemmy-epsilon",
+ ]);
await gamma.client.editSite(editSiteForm);
+
+ editSiteForm.allowed_instances = Some(["lemmy-beta"]);
editSiteForm.auth = delta.auth.unwrap();
await delta.client.editSite(editSiteForm);
+
editSiteForm.auth = epsilon.auth.unwrap();
+ editSiteForm.allowed_instances = Some([]);
+ editSiteForm.blocked_instances = Some(["lemmy-alpha"]);
await epsilon.client.editSite(editSiteForm);
// Create the main alpha/beta communities
): Promise<PostResponse> {
let name = randomString(5);
let body = Some(randomString(10));
- let url = Some('https://google.com/');
+ let url = Some("https://google.com/");
let form = new CreatePost({
name,
url,
community_id,
nsfw: None,
honeypot: None,
+ language_id: None,
});
return api.client.createPost(form);
}
export async function editPost(api: API, post: Post): Promise<PostResponse> {
- let name = Some('A jest test federated post, updated');
+ let name = Some("A jest test federated post, updated");
let form = new EditPost({
name,
post_id: post.id,
nsfw: None,
url: None,
body: None,
+ language_id: None,
});
return api.client.editPost(form);
}
): Promise<ResolveObjectResponse> {
// Use short-hand search url
let form = new ResolveObject({
- q: '!main@lemmy-beta:8551',
+ q: "!main@lemmy-beta:8551",
auth: api.auth,
});
return api.client.resolveObject(form);
let form = new FollowCommunity({
community_id,
follow,
- auth: api.auth.unwrap()
+ auth: api.auth.unwrap(),
});
return api.client.followCommunity(form);
}
let form = new CreatePostLike({
post_id: post.id,
score: score,
- auth: api.auth.unwrap()
+ auth: api.auth.unwrap(),
});
return api.client.likePost(form);
api: API,
post_id: number,
parent_id: Option<number>,
- content = 'a jest test comment'
+ content = "a jest test comment"
): Promise<CommentResponse> {
let form = new CreateComment({
content,
post_id,
parent_id,
form_id: None,
+ language_id: None,
auth: api.auth.unwrap(),
});
return api.client.createComment(form);
export async function editComment(
api: API,
comment_id: number,
- content = 'A jest test federated comment update'
+ content = Some("A jest test federated comment update")
): Promise<CommentResponse> {
let form = new EditComment({
content,
comment_id,
form_id: None,
- auth: api.auth.unwrap()
+ language_id: None,
+ distinguished: None,
+ auth: api.auth.unwrap(),
});
return api.client.editComment(form);
}
return api.client.removeComment(form);
}
-export async function getMentions(api: API): Promise<GetPersonMentionsResponse> {
+export async function getMentions(
+ api: API
+): Promise<GetPersonMentionsResponse> {
let form = new GetPersonMentions({
sort: Some(CommentSortType.New),
unread_only: Some(false),
api: API,
name_: string = randomString(5)
): Promise<CommunityResponse> {
- let description = Some('a sample description');
+ let description = Some("a sample description");
let form = new CreateCommunity({
name: name_,
title: name_,
api: API,
recipient_id: number
): Promise<PrivateMessageResponse> {
- let content = 'A jest test federated private message';
+ let content = "A jest test federated private message";
let form = new CreatePrivateMessage({
content,
recipient_id,
api: API,
private_message_id: number
): Promise<PrivateMessageResponse> {
- let updatedContent = 'A jest test federated private message edited';
+ let updatedContent = "A jest test federated private message edited";
let form = new EditPrivateMessage({
content: updatedContent,
private_message_id,
return api.client.register(form);
}
-export async function saveUserSettingsBio(
- api: API
-): Promise<LoginResponse> {
+export async function saveUserSettingsBio(api: API): Promise<LoginResponse> {
let form = new SaveUserSettings({
show_nsfw: Some(true),
- theme: Some('darkly'),
+ theme: Some("darkly"),
default_sort_type: Some(Object.keys(SortType).indexOf(SortType.Active)),
- default_listing_type: Some(Object.keys(ListingType).indexOf(ListingType.All)),
- lang: Some('en'),
+ default_listing_type: Some(
+ Object.keys(ListingType).indexOf(ListingType.All)
+ ),
+ interface_language: Some("en"),
show_avatars: Some(true),
send_notifications_to_email: Some(false),
- bio: Some('a changed bio'),
+ bio: Some("a changed bio"),
avatar: None,
banner: None,
display_name: None,
show_bot_accounts: None,
show_new_post_notifs: None,
bot_account: None,
+ discussion_languages: None,
auth: api.auth.unwrap(),
});
return saveUserSettings(api, form);
export async function saveUserSettingsFederated(
api: API
): Promise<LoginResponse> {
- let avatar = Some('https://image.flaticon.com/icons/png/512/35/35896.png');
- let banner = Some('https://image.flaticon.com/icons/png/512/36/35896.png');
- let bio = Some('a changed bio');
+ let avatar = Some("https://image.flaticon.com/icons/png/512/35/35896.png");
+ let banner = Some("https://image.flaticon.com/icons/png/512/36/35896.png");
+ let bio = Some("a changed bio");
let form = new SaveUserSettings({
show_nsfw: Some(false),
- theme: Some(''),
+ theme: Some(""),
default_sort_type: Some(Object.keys(SortType).indexOf(SortType.Hot)),
- default_listing_type: Some(Object.keys(ListingType).indexOf(ListingType.All)),
- lang: Some(''),
+ default_listing_type: Some(
+ Object.keys(ListingType).indexOf(ListingType.All)
+ ),
+ interface_language: Some(""),
avatar,
banner,
- display_name: Some('user321'),
+ display_name: Some("user321"),
show_avatars: Some(false),
send_notifications_to_email: Some(false),
bio,
bot_account: None,
show_bot_accounts: None,
show_new_post_notifs: None,
+ discussion_languages: None,
auth: api.auth.unwrap(),
});
return await saveUserSettings(alpha, form);
return api.client.saveUserSettings(form);
}
-export async function deleteUser(
- api: API
-): Promise<DeleteAccountResponse> {
+export async function deleteUser(api: API): Promise<DeleteAccountResponse> {
let form = new DeleteAccount({
auth: api.auth.unwrap(),
- password
+ password,
});
return api.client.deleteAccount(form);
}
-export async function getSite(
- api: API
-): Promise<GetSiteResponse> {
+export async function getSite(api: API): Promise<GetSiteResponse> {
let form = new GetSite({
auth: api.auth,
});
return api.client.getPrivateMessages(form);
}
-export async function unfollowRemotes(
- api: API
-): Promise<GetSiteResponse> {
+export async function unfollowRemotes(api: API): Promise<GetSiteResponse> {
// Unfollow all remote communities
let site = await getSite(api);
- let remoteFollowed = site.my_user.unwrap().follows.filter(
- c => c.community.local == false
- );
+ let remoteFollowed = site.my_user
+ .unwrap()
+ .follows.filter(c => c.community.local == false);
for (let cu of remoteFollowed) {
await followCommunity(api, false, cu.community.id);
}
export async function followBeta(api: API): Promise<CommunityResponse> {
let betaCommunity = (await resolveBetaCommunity(api)).community;
if (betaCommunity.isSome()) {
- let follow = await followCommunity(api, true, betaCommunity.unwrap().community.id);
+ let follow = await followCommunity(
+ api,
+ true,
+ betaCommunity.unwrap().community.id
+ );
return follow;
} else {
return Promise.reject("no community worked");
return api.client.createPostReport(form);
}
-export async function listPostReports(api: API): Promise<ListPostReportsResponse> {
+export async function listPostReports(
+ api: API
+): Promise<ListPostReportsResponse> {
let form = new ListPostReports({
auth: api.auth.unwrap(),
page: None,
return api.client.createCommentReport(form);
}
-export async function listCommentReports(api: API): Promise<ListCommentReportsResponse> {
+export async function listCommentReports(
+ api: API
+): Promise<ListCommentReportsResponse> {
let form = new ListCommentReports({
page: None,
limit: None,
return api.client.listCommentReports(form);
}
-export function delay(millis: number = 500) {
+export function delay(millis = 500) {
return new Promise(resolve => setTimeout(resolve, millis));
}
}
export function randomString(length: number): string {
- var result = '';
- var characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_';
+ var result = "";
+ var characters =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
jest.setTimeout(120000);
-import {None} from '@sniptt/monads';
-import {
- PersonViewSafe,
-} from 'lemmy-js-client';
+import { None } from "@sniptt/monads";
+import { PersonViewSafe } from "lemmy-js-client";
import {
alpha,
resolveComment,
saveUserSettingsFederated,
setupLogins,
-} from './shared';
+} from "./shared";
beforeAll(async () => {
await setupLogins();
let apShortname: string;
-function assertUserFederation(userOne: PersonViewSafe, userTwo: PersonViewSafe) {
+function assertUserFederation(
+ userOne: PersonViewSafe,
+ userTwo: PersonViewSafe
+) {
expect(userOne.person.name).toBe(userTwo.person.name);
- expect(userOne.person.display_name.unwrapOr("none")).toBe(userTwo.person.display_name.unwrapOr("none"));
- expect(userOne.person.bio.unwrapOr("none")).toBe(userTwo.person.bio.unwrapOr("none"));
+ expect(userOne.person.display_name.unwrapOr("none")).toBe(
+ userTwo.person.display_name.unwrapOr("none")
+ );
+ expect(userOne.person.bio.unwrapOr("none")).toBe(
+ userTwo.person.bio.unwrapOr("none")
+ );
expect(userOne.person.actor_id).toBe(userTwo.person.actor_id);
- expect(userOne.person.avatar.unwrapOr("none")).toBe(userTwo.person.avatar.unwrapOr("none"));
- expect(userOne.person.banner.unwrapOr("none")).toBe(userTwo.person.banner.unwrapOr("none"));
+ expect(userOne.person.avatar.unwrapOr("none")).toBe(
+ userTwo.person.avatar.unwrapOr("none")
+ );
+ expect(userOne.person.banner.unwrapOr("none")).toBe(
+ userTwo.person.banner.unwrapOr("none")
+ );
expect(userOne.person.published).toBe(userTwo.person.published);
}
-test('Create user', async () => {
+test("Create user", async () => {
let userRes = await registerUser(alpha);
expect(userRes.jwt).toBeDefined();
alpha.auth = userRes.jwt;
-
+
let site = await getSite(alpha);
expect(site.my_user).toBeDefined();
- apShortname = `@${site.my_user.unwrap().local_user_view.person.name}@lemmy-alpha:8541`;
+ apShortname = `@${
+ site.my_user.unwrap().local_user_view.person.name
+ }@lemmy-alpha:8541`;
});
-test('Set some user settings, check that they are federated', async () => {
+test("Set some user settings, check that they are federated", async () => {
await saveUserSettingsFederated(alpha);
let alphaPerson = (await resolvePerson(alpha, apShortname)).person.unwrap();
let betaPerson = (await resolvePerson(beta, apShortname)).person.unwrap();
assertUserFederation(alphaPerson, betaPerson);
});
-test('Delete user', async () => {
+test("Delete user", async () => {
let userRes = await registerUser(alpha);
expect(userRes.jwt).toBeDefined();
let user: API = {
client: alpha.client,
- auth: userRes.jwt
- }
+ auth: userRes.jwt,
+ };
// make a local post and comment
- let alphaCommunity = (await resolveCommunity(user, '!main@lemmy-alpha:8541')).community.unwrap();
- let localPost = (await createPost(user, alphaCommunity.community.id)).post_view.post;
+ let alphaCommunity = (
+ await resolveCommunity(user, "!main@lemmy-alpha:8541")
+ ).community.unwrap();
+ let localPost = (await createPost(user, alphaCommunity.community.id))
+ .post_view.post;
expect(localPost).toBeDefined();
- let localComment = (await createComment(user, localPost.id, None)).comment_view.comment;
+ let localComment = (await createComment(user, localPost.id, None))
+ .comment_view.comment;
expect(localComment).toBeDefined();
// make a remote post and comment
let betaCommunity = (await resolveBetaCommunity(user)).community.unwrap();
- let remotePost = (await createPost(user, betaCommunity.community.id)).post_view.post;
+ let remotePost = (await createPost(user, betaCommunity.community.id))
+ .post_view.post;
expect(remotePost).toBeDefined();
- let remoteComment = (await createComment(user, remotePost.id, None)).comment_view.comment;
+ let remoteComment = (await createComment(user, remotePost.id, None))
+ .comment_view.comment;
expect(remoteComment).toBeDefined();
await deleteUser(user);
expect((await resolvePost(alpha, localPost)).post.isNone()).toBe(true);
- expect((await resolveComment(alpha, localComment)).comment.isNone()).toBe(true)
- expect((await resolvePost(alpha, remotePost)).post.isNone()).toBe(true)
- expect((await resolveComment(alpha, remoteComment)).comment.isNone()).toBe(true)
+ expect((await resolveComment(alpha, localComment)).comment.isNone()).toBe(
+ true
+ );
+ expect((await resolvePost(alpha, remotePost)).post.isNone()).toBe(true);
+ expect((await resolveComment(alpha, remoteComment)).comment.isNone()).toBe(
+ true
+ );
});
dependencies:
"@babel/highlight" "^7.10.4"
-"@babel/code-frame@^7.12.11", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6":
+"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
json5 "^2.2.1"
semver "^6.3.0"
-"@babel/generator@^7.12.11", "@babel/generator@^7.18.9", "@babel/generator@^7.7.2":
+"@babel/generator@^7.18.9", "@babel/generator@^7.7.2":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.9.tgz#68337e9ea8044d6ddc690fb29acae39359cca0a5"
integrity sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
-"@babel/helper-function-name@^7.12.11", "@babel/helper-function-name@^7.18.9":
+"@babel/helper-function-name@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0"
integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==
dependencies:
"@babel/types" "^7.18.6"
-"@babel/helper-split-export-declaration@^7.12.11", "@babel/helper-split-export-declaration@^7.18.6":
+"@babel/helper-split-export-declaration@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
dependencies:
"@babel/types" "^7.18.6"
-"@babel/helper-validator-identifier@^7.12.11", "@babel/helper-validator-identifier@^7.15.7", "@babel/helper-validator-identifier@^7.18.6":
+"@babel/helper-validator-identifier@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
chalk "^2.0.0"
js-tokens "^4.0.0"
-"@babel/parser@^7.1.0", "@babel/parser@^7.12.11", "@babel/parser@^7.14.7", "@babel/parser@^7.18.6", "@babel/parser@^7.18.9":
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.6", "@babel/parser@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.9.tgz#f2dde0c682ccc264a9a8595efd030a5cc8fd2539"
integrity sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==
-"@babel/parser@^7.7.0":
- version "7.12.11"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.11.tgz#9ce3595bcd74bc5c466905e86c535b8b25011e79"
- integrity sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==
-
"@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
-"@babel/runtime-corejs3@^7.10.2":
- version "7.12.5"
- resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.12.5.tgz#ffee91da0eb4c6dae080774e94ba606368e414f4"
- integrity sha512-roGr54CsTmNPPzZoCP1AmDXuBoNao7tnSA83TXTwt+UK5QVyh1DIJnrgYRPWKCF2flqZQXwa7Yr8v7VmLzF0YQ==
- dependencies:
- core-js-pure "^3.0.0"
- regenerator-runtime "^0.13.4"
-
-"@babel/runtime@^7.10.2":
- version "7.12.5"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
- integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
- dependencies:
- regenerator-runtime "^0.13.4"
-
-"@babel/runtime@^7.16.3":
- version "7.18.9"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a"
- integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==
- dependencies:
- regenerator-runtime "^0.13.4"
-
"@babel/template@^7.18.6", "@babel/template@^7.3.3":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31"
debug "^4.1.0"
globals "^11.1.0"
-"@babel/traverse@^7.7.0":
- version "7.12.12"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.12.tgz#d0cd87892704edd8da002d674bc811ce64743376"
- integrity sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==
- dependencies:
- "@babel/code-frame" "^7.12.11"
- "@babel/generator" "^7.12.11"
- "@babel/helper-function-name" "^7.12.11"
- "@babel/helper-split-export-declaration" "^7.12.11"
- "@babel/parser" "^7.12.11"
- "@babel/types" "^7.12.12"
- debug "^4.1.0"
- globals "^11.1.0"
- lodash "^4.17.19"
-
-"@babel/types@^7.0.0", "@babel/types@^7.12.12", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
+"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.9.tgz#7148d64ba133d8d73a41b3172ac4b83a1452205f"
integrity sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==
"@babel/helper-validator-identifier" "^7.18.6"
to-fast-properties "^2.0.0"
-"@babel/types@^7.7.0":
- version "7.12.12"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.12.tgz#4608a6ec313abbd87afa55004d373ad04a96c299"
- integrity sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==
- dependencies:
- "@babel/helper-validator-identifier" "^7.12.11"
- lodash "^4.17.19"
- to-fast-properties "^2.0.0"
-
"@bcoe/v8-coverage@^0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
-"@eslint/eslintrc@^1.3.0":
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f"
- integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==
+"@eslint/eslintrc@^1.3.3":
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.3.tgz#2b044ab39fdfa75b4688184f9e573ce3c5b0ff95"
+ integrity sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
- espree "^9.3.2"
+ espree "^9.4.0"
globals "^13.15.0"
ignore "^5.2.0"
import-fresh "^3.2.1"
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
-"@humanwhocodes/config-array@^0.9.2":
- version "0.9.5"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7"
- integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==
+"@humanwhocodes/config-array@^0.10.5":
+ version "0.10.7"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.10.7.tgz#6d53769fd0c222767e6452e8ebda825c22e9f0dc"
+ integrity sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==
dependencies:
"@humanwhocodes/object-schema" "^1.2.1"
debug "^4.1.1"
minimatch "^3.0.4"
+"@humanwhocodes/module-importer@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
+ integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
+
"@humanwhocodes/object-schema@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
-"@types/json5@^0.0.29":
- version "0.0.29"
- resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
- integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
-
"@types/node@*":
version "18.6.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.6.1.tgz#828e4785ccca13f44e2fb6852ae0ef11e3e20ba5"
integrity sha512-z+2vB6yDt1fNwKOeGbckpmirO+VBDuQqecXkgeIqDlaOtmKn6hPR/viQ8cxCfqLU4fTlvM3+YjM367TukWdxpg==
-"@types/normalize-package-data@^2.4.0":
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
- integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
-
"@types/prettier@^2.1.5":
version "2.6.4"
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.4.tgz#ad899dad022bab6b5a9f0a0fe67c2f7a4a8950ed"
integrity sha512-fOwvpvQYStpb/zHMx0Cauwywu9yLDmzWiiQBC7gJyq5tYLUXFZvDG7VK1B7WBxxjBJNKFOZ0zLoOQn8vmATbhw==
+"@types/semver@^7.3.12":
+ version "7.3.12"
+ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.12.tgz#920447fdd78d76b19de0438b7f60df3c4a80bf1c"
+ integrity sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==
+
"@types/stack-utils@^2.0.0":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
dependencies:
"@types/yargs-parser" "*"
-"@typescript-eslint/eslint-plugin@5.9.0":
- version "5.9.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.9.0.tgz#382182d5cb062f52aac54434cfc47c28898c8006"
- integrity sha512-qT4lr2jysDQBQOPsCCvpPUZHjbABoTJW8V9ZzIYKHMfppJtpdtzszDYsldwhFxlhvrp7aCHeXD1Lb9M1zhwWwQ==
+"@typescript-eslint/eslint-plugin@^5.21.0":
+ version "5.40.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.1.tgz#3203a6ff396b1194083faaa6e5110c401201d7d5"
+ integrity sha512-FsWboKkWdytGiXT5O1/R9j37YgcjO8MKHSUmWnIEjVaz0krHkplPnYi7mwdb+5+cs0toFNQb0HIrN7zONdIEWg==
dependencies:
- "@typescript-eslint/experimental-utils" "5.9.0"
- "@typescript-eslint/scope-manager" "5.9.0"
- "@typescript-eslint/type-utils" "5.9.0"
- debug "^4.3.2"
- functional-red-black-tree "^1.0.1"
- ignore "^5.1.8"
+ "@typescript-eslint/scope-manager" "5.40.1"
+ "@typescript-eslint/type-utils" "5.40.1"
+ "@typescript-eslint/utils" "5.40.1"
+ debug "^4.3.4"
+ ignore "^5.2.0"
regexpp "^3.2.0"
- semver "^7.3.5"
+ semver "^7.3.7"
tsutils "^3.21.0"
-"@typescript-eslint/experimental-utils@5.9.0":
- version "5.9.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.9.0.tgz#652762d37d6565ef07af285021b8347b6c79a827"
- integrity sha512-ZnLVjBrf26dn7ElyaSKa6uDhqwvAi4jBBmHK1VxuFGPRAxhdi18ubQYSGA7SRiFiES3q9JiBOBHEBStOFkwD2g==
+"@typescript-eslint/parser@^5.21.0":
+ version "5.40.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.40.1.tgz#e7f8295dd8154d0d37d661ddd8e2f0ecfdee28dd"
+ integrity sha512-IK6x55va5w4YvXd4b3VrXQPldV9vQTxi5ov+g4pMANsXPTXOcfjx08CRR1Dfrcc51syPtXHF5bgLlMHYFrvQtg==
dependencies:
- "@types/json-schema" "^7.0.9"
- "@typescript-eslint/scope-manager" "5.9.0"
- "@typescript-eslint/types" "5.9.0"
- "@typescript-eslint/typescript-estree" "5.9.0"
- eslint-scope "^5.1.1"
- eslint-utils "^3.0.0"
-
-"@typescript-eslint/experimental-utils@^5.0.0":
- version "5.31.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.31.0.tgz#f2b23ebeebd31358ce44cf5be7c3411127627b84"
- integrity sha512-Yiar0ggNPyOsvrslJBdOo3jc3wjI6NnmWOQBA8WhR54YPbVqTNLuuHC6zxEt8FIgMozerxRlAncwznEjK+cJVA==
- dependencies:
- "@typescript-eslint/utils" "5.31.0"
-
-"@typescript-eslint/parser@5.9.0":
- version "5.9.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.9.0.tgz#fdbb08767a4caa6ca6ccfed5f9ffe9387f0c7d97"
- integrity sha512-/6pOPz8yAxEt4PLzgbFRDpZmHnXCeZgPDrh/1DaVKOjvn/UPMlWhbx/gA96xRi2JxY1kBl2AmwVbyROUqys5xQ==
- dependencies:
- "@typescript-eslint/scope-manager" "5.9.0"
- "@typescript-eslint/types" "5.9.0"
- "@typescript-eslint/typescript-estree" "5.9.0"
- debug "^4.3.2"
-
-"@typescript-eslint/scope-manager@5.31.0":
- version "5.31.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz#f47a794ba84d9b818ab7f8f44fff55a61016c606"
- integrity sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg==
- dependencies:
- "@typescript-eslint/types" "5.31.0"
- "@typescript-eslint/visitor-keys" "5.31.0"
+ "@typescript-eslint/scope-manager" "5.40.1"
+ "@typescript-eslint/types" "5.40.1"
+ "@typescript-eslint/typescript-estree" "5.40.1"
+ debug "^4.3.4"
-"@typescript-eslint/scope-manager@5.9.0":
- version "5.9.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.9.0.tgz#02dfef920290c1dcd7b1999455a3eaae7a1a3117"
- integrity sha512-DKtdIL49Qxk2a8icF6whRk7uThuVz4A6TCXfjdJSwOsf+9ree7vgQWcx0KOyCdk0i9ETX666p4aMhrRhxhUkyg==
+"@typescript-eslint/scope-manager@5.40.1":
+ version "5.40.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.40.1.tgz#a7a5197dfd234622a2421ea590ee0ccc02e18dfe"
+ integrity sha512-jkn4xsJiUQucI16OLCXrLRXDZ3afKhOIqXs4R3O+M00hdQLKR58WuyXPZZjhKLFCEP2g+TXdBRtLQ33UfAdRUg==
dependencies:
- "@typescript-eslint/types" "5.9.0"
- "@typescript-eslint/visitor-keys" "5.9.0"
+ "@typescript-eslint/types" "5.40.1"
+ "@typescript-eslint/visitor-keys" "5.40.1"
-"@typescript-eslint/type-utils@5.9.0":
- version "5.9.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.9.0.tgz#fd5963ead04bc9b7af9c3a8e534d8d39f1ce5f93"
- integrity sha512-uVCb9dJXpBrK1071ri5aEW7ZHdDHAiqEjYznF3HSSvAJXyrkxGOw2Ejibz/q6BXdT8lea8CMI0CzKNFTNI6TEQ==
+"@typescript-eslint/type-utils@5.40.1":
+ version "5.40.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.40.1.tgz#091e4ce3bebbdb68f4980bae9dee2e4e1725f601"
+ integrity sha512-DLAs+AHQOe6n5LRraXiv27IYPhleF0ldEmx6yBqBgBLaNRKTkffhV1RPsjoJBhVup2zHxfaRtan8/YRBgYhU9Q==
dependencies:
- "@typescript-eslint/experimental-utils" "5.9.0"
- debug "^4.3.2"
+ "@typescript-eslint/typescript-estree" "5.40.1"
+ "@typescript-eslint/utils" "5.40.1"
+ debug "^4.3.4"
tsutils "^3.21.0"
-"@typescript-eslint/types@5.31.0":
- version "5.31.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.31.0.tgz#7aa389122b64b18e473c1672fb3b8310e5f07a9a"
- integrity sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g==
+"@typescript-eslint/types@5.40.1":
+ version "5.40.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.40.1.tgz#de37f4f64de731ee454bb2085d71030aa832f749"
+ integrity sha512-Icg9kiuVJSwdzSQvtdGspOlWNjVDnF3qVIKXdJ103o36yRprdl3Ge5cABQx+csx960nuMF21v8qvO31v9t3OHw==
-"@typescript-eslint/types@5.9.0":
- version "5.9.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.9.0.tgz#e5619803e39d24a03b3369506df196355736e1a3"
- integrity sha512-mWp6/b56Umo1rwyGCk8fPIzb9Migo8YOniBGPAQDNC6C52SeyNGN4gsVwQTAR+RS2L5xyajON4hOLwAGwPtUwg==
-
-"@typescript-eslint/typescript-estree@5.31.0":
- version "5.31.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz#eb92970c9d6e3946690d50c346fb9b1d745ee882"
- integrity sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw==
+"@typescript-eslint/typescript-estree@5.40.1":
+ version "5.40.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.1.tgz#9a7d25492f02c69882ce5e0cd1857b0c55645d72"
+ integrity sha512-5QTP/nW5+60jBcEPfXy/EZL01qrl9GZtbgDZtDPlfW5zj/zjNrdI2B5zMUHmOsfvOr2cWqwVdWjobCiHcedmQA==
dependencies:
- "@typescript-eslint/types" "5.31.0"
- "@typescript-eslint/visitor-keys" "5.31.0"
+ "@typescript-eslint/types" "5.40.1"
+ "@typescript-eslint/visitor-keys" "5.40.1"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
semver "^7.3.7"
tsutils "^3.21.0"
-"@typescript-eslint/typescript-estree@5.9.0":
- version "5.9.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.9.0.tgz#0e5c6f03f982931abbfbc3c1b9df5fbf92a3490f"
- integrity sha512-kxo3xL2mB7XmiVZcECbaDwYCt3qFXz99tBSuVJR4L/sR7CJ+UNAPrYILILktGj1ppfZ/jNt/cWYbziJUlHl1Pw==
- dependencies:
- "@typescript-eslint/types" "5.9.0"
- "@typescript-eslint/visitor-keys" "5.9.0"
- debug "^4.3.2"
- globby "^11.0.4"
- is-glob "^4.0.3"
- semver "^7.3.5"
- tsutils "^3.21.0"
-
-"@typescript-eslint/utils@5.31.0":
- version "5.31.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.31.0.tgz#e146fa00dca948bfe547d665b2138a2dc1b79acd"
- integrity sha512-kcVPdQS6VIpVTQ7QnGNKMFtdJdvnStkqS5LeALr4rcwx11G6OWb2HB17NMPnlRHvaZP38hL9iK8DdE9Fne7NYg==
+"@typescript-eslint/utils@5.40.1":
+ version "5.40.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.40.1.tgz#3204fb73a559d3b7bab7dc9d3c44487c2734a9ca"
+ integrity sha512-a2TAVScoX9fjryNrW6BZRnreDUszxqm9eQ9Esv8n5nXApMW0zeANUYlwh/DED04SC/ifuBvXgZpIK5xeJHQ3aw==
dependencies:
"@types/json-schema" "^7.0.9"
- "@typescript-eslint/scope-manager" "5.31.0"
- "@typescript-eslint/types" "5.31.0"
- "@typescript-eslint/typescript-estree" "5.31.0"
+ "@types/semver" "^7.3.12"
+ "@typescript-eslint/scope-manager" "5.40.1"
+ "@typescript-eslint/types" "5.40.1"
+ "@typescript-eslint/typescript-estree" "5.40.1"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
+ semver "^7.3.7"
-"@typescript-eslint/visitor-keys@5.31.0":
- version "5.31.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz#b0eca264df01ce85dceb76aebff3784629258f54"
- integrity sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg==
+"@typescript-eslint/visitor-keys@5.40.1":
+ version "5.40.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.1.tgz#f3d2bf5af192f4432b84cec6fdcb387193518754"
+ integrity sha512-A2DGmeZ+FMja0geX5rww+DpvILpwo1OsiQs0M+joPWJYsiEFBLsH0y1oFymPNul6Z5okSmHpP4ivkc2N0Cgfkw==
dependencies:
- "@typescript-eslint/types" "5.31.0"
+ "@typescript-eslint/types" "5.40.1"
eslint-visitor-keys "^3.3.0"
-"@typescript-eslint/visitor-keys@5.9.0":
- version "5.9.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.0.tgz#7585677732365e9d27f1878150fab3922784a1a6"
- integrity sha512-6zq0mb7LV0ThExKlecvpfepiB+XEtFv/bzx7/jKSgyXTFD7qjmSu1FoiS0x3OZaiS+UIXpH2vd9O89f02RCtgw==
- dependencies:
- "@typescript-eslint/types" "5.9.0"
- eslint-visitor-keys "^3.0.0"
-
abab@^2.0.3, abab@^2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
-acorn@^8.2.4, acorn@^8.7.1:
+acorn@^8.2.4, acorn@^8.8.0:
version "8.8.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
-aria-query@^4.2.2:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b"
- integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==
- dependencies:
- "@babel/runtime" "^7.10.2"
- "@babel/runtime-corejs3" "^7.10.2"
-
-array-includes@^3.1.2:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.2.tgz#a8db03e0b88c8c6aeddc49cb132f9bcab4ebf9c8"
- integrity sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==
- dependencies:
- call-bind "^1.0.0"
- define-properties "^1.1.3"
- es-abstract "^1.18.0-next.1"
- get-intrinsic "^1.0.1"
- is-string "^1.0.5"
-
-array-includes@^3.1.4, array-includes@^3.1.5:
- version "3.1.5"
- resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb"
- integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.19.5"
- get-intrinsic "^1.1.1"
- is-string "^1.0.7"
-
array-union@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
-array.prototype.flat@^1.2.5:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz#0b0c1567bf57b38b56b4c97b8aa72ab45e4adc7b"
- integrity sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.2"
- es-shim-unscopables "^1.0.0"
-
-array.prototype.flatmap@^1.2.5:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz#a7e8ed4225f4788a70cd910abcf0791e76a5534f"
- integrity sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.2"
- es-shim-unscopables "^1.0.0"
-
-ast-types-flow@^0.0.7:
- version "0.0.7"
- resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
- integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0=
-
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
-axe-core@^4.3.5:
- version "4.4.3"
- resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.3.tgz#11c74d23d5013c0fa5d183796729bc3482bd2f6f"
- integrity sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==
-
-axobject-query@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
- integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==
-
-babel-eslint@10.1.0:
- version "10.1.0"
- resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232"
- integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==
- dependencies:
- "@babel/code-frame" "^7.0.0"
- "@babel/parser" "^7.7.0"
- "@babel/traverse" "^7.7.0"
- "@babel/types" "^7.7.0"
- eslint-visitor-keys "^1.0.0"
- resolve "^1.12.0"
-
babel-jest@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
-builtin-modules@^3.0.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
- integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
-
-call-bind@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce"
- integrity sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==
- dependencies:
- function-bind "^1.1.1"
- get-intrinsic "^1.0.0"
-
-call-bind@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
- integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
- dependencies:
- function-bind "^1.1.1"
- get-intrinsic "^1.0.2"
-
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
-ci-info@^3.2.0, ci-info@^3.3.0:
+ci-info@^3.2.0:
version "3.3.2"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.2.tgz#6d2967ffa407466481c6c90b6e16b3098f080128"
integrity sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==
resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336"
integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==
-clean-regexp@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/clean-regexp/-/clean-regexp-1.0.0.tgz#8df7c7aae51fd36874e8f8d05b9180bc11a3fed7"
- integrity sha1-jffHquUf02h06PjQW5GAvBGj/tc=
- dependencies:
- escape-string-regexp "^1.0.5"
-
cliui@^7.0.2:
version "7.0.4"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
dependencies:
safe-buffer "~5.1.1"
-core-js-pure@^3.0.0:
- version "3.8.2"
- resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.8.2.tgz#286f885c0dac1cdcd6d78397392abc25ddeca225"
- integrity sha512-v6zfIQqL/pzTVAbZvYUozsxNfxcFb6Ks3ZfEbuneJl3FW9Jb8F6vLWB6f+qTmAu72msUdyb84V8d/yBFf7FNnw==
-
cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
dependencies:
cssom "~0.3.6"
-damerau-levenshtein@^1.0.7:
- version "1.0.8"
- resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
- integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==
-
data-urls@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b"
dependencies:
ms "2.1.2"
-debug@^2.6.9:
- version "2.6.9"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
- integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
- dependencies:
- ms "2.0.0"
-
-debug@^3.2.7:
- version "3.2.7"
- resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
- integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
- dependencies:
- ms "^2.1.1"
-
decimal.js@^10.2.1:
version "10.3.1"
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
-define-properties@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
- integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
- dependencies:
- object-keys "^1.0.12"
-
-define-properties@^1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1"
- integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==
- dependencies:
- has-property-descriptors "^1.0.0"
- object-keys "^1.1.1"
-
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
dependencies:
path-type "^4.0.0"
-doctrine@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
- integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
- dependencies:
- esutils "^2.0.2"
-
doctrine@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
-emoji-regex@^9.2.2:
- version "9.2.2"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
- integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
-
error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
dependencies:
is-arrayish "^0.2.1"
-es-abstract@^1.18.0-next.1:
- version "1.18.0-next.1"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68"
- integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==
- dependencies:
- es-to-primitive "^1.2.1"
- function-bind "^1.1.1"
- has "^1.0.3"
- has-symbols "^1.0.1"
- is-callable "^1.2.2"
- is-negative-zero "^2.0.0"
- is-regex "^1.1.1"
- object-inspect "^1.8.0"
- object-keys "^1.1.1"
- object.assign "^4.1.1"
- string.prototype.trimend "^1.0.1"
- string.prototype.trimstart "^1.0.1"
-
-es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5:
- version "1.20.1"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814"
- integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==
- dependencies:
- call-bind "^1.0.2"
- es-to-primitive "^1.2.1"
- function-bind "^1.1.1"
- function.prototype.name "^1.1.5"
- get-intrinsic "^1.1.1"
- get-symbol-description "^1.0.0"
- has "^1.0.3"
- has-property-descriptors "^1.0.0"
- has-symbols "^1.0.3"
- internal-slot "^1.0.3"
- is-callable "^1.2.4"
- is-negative-zero "^2.0.2"
- is-regex "^1.1.4"
- is-shared-array-buffer "^1.0.2"
- is-string "^1.0.7"
- is-weakref "^1.0.2"
- object-inspect "^1.12.0"
- object-keys "^1.1.1"
- object.assign "^4.1.2"
- regexp.prototype.flags "^1.4.3"
- string.prototype.trimend "^1.0.5"
- string.prototype.trimstart "^1.0.5"
- unbox-primitive "^1.0.2"
-
-es-shim-unscopables@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241"
- integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==
- dependencies:
- has "^1.0.3"
-
-es-to-primitive@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
- integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
- dependencies:
- is-callable "^1.1.4"
- is-date-object "^1.0.1"
- is-symbol "^1.0.2"
-
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
optionalDependencies:
source-map "~0.6.1"
-eslint-config-prettier@8.3.0:
- version "8.3.0"
- resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a"
- integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==
-
-eslint-import-resolver-node@^0.3.6:
- version "0.3.6"
- resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd"
- integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==
- dependencies:
- debug "^3.2.7"
- resolve "^1.20.0"
-
-eslint-module-utils@^2.7.2:
- version "2.7.3"
- resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee"
- integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==
- dependencies:
- debug "^3.2.7"
- find-up "^2.1.0"
-
-eslint-plugin-babel@5.3.1:
- version "5.3.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz#75a2413ffbf17e7be57458301c60291f2cfbf560"
- integrity sha512-VsQEr6NH3dj664+EyxJwO4FCYm/00JhYb3Sk3ft8o+fpKuIfQ9TaW6uVUfvwMXHcf/lsnRIoyFPsLMyiWCSL/g==
- dependencies:
- eslint-rule-composer "^0.3.0"
-
-eslint-plugin-es@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893"
- integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==
- dependencies:
- eslint-utils "^2.0.0"
- regexpp "^3.0.0"
-
-eslint-plugin-import@2.25.4:
- version "2.25.4"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1"
- integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==
- dependencies:
- array-includes "^3.1.4"
- array.prototype.flat "^1.2.5"
- debug "^2.6.9"
- doctrine "^2.1.0"
- eslint-import-resolver-node "^0.3.6"
- eslint-module-utils "^2.7.2"
- has "^1.0.3"
- is-core-module "^2.8.0"
- is-glob "^4.0.3"
- minimatch "^3.0.4"
- object.values "^1.1.5"
- resolve "^1.20.0"
- tsconfig-paths "^3.12.0"
-
-eslint-plugin-jane@^11.2.2:
- version "11.2.2"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jane/-/eslint-plugin-jane-11.2.2.tgz#6ad3394d94009e03531fa8a509d147ff88b60303"
- integrity sha512-y2yZucJ0g/siHwR5eZbsrAvc0u4qIuc0JeSmR0JgKAbidA6OJZTivgOhyqmeGIBewTBkHpCiqjFzQqB6rD4CnA==
- dependencies:
- "@typescript-eslint/eslint-plugin" "5.9.0"
- "@typescript-eslint/parser" "5.9.0"
- babel-eslint "10.1.0"
- eslint-config-prettier "8.3.0"
- eslint-plugin-babel "5.3.1"
- eslint-plugin-import "2.25.4"
- eslint-plugin-jest "25.3.4"
- eslint-plugin-jsx-a11y "6.5.1"
- eslint-plugin-node "11.1.0"
- eslint-plugin-prettier "3.4.1"
- eslint-plugin-promise "6.0.0"
- eslint-plugin-react "7.28.0"
- eslint-plugin-react-hooks "4.3.0"
- eslint-plugin-unicorn "40.0.0"
-
-eslint-plugin-jest@25.3.4:
- version "25.3.4"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-25.3.4.tgz#2031dfe495be1463330f8b80096ddc91f8e6387f"
- integrity sha512-CCnwG71wvabmwq/qkz0HWIqBHQxw6pXB1uqt24dxqJ9WB34pVg49bL1sjXphlJHgTMWGhBjN1PicdyxDxrfP5A==
- dependencies:
- "@typescript-eslint/experimental-utils" "^5.0.0"
-
-eslint-plugin-jsx-a11y@6.5.1:
- version "6.5.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz#cdbf2df901040ca140b6ec14715c988889c2a6d8"
- integrity sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==
- dependencies:
- "@babel/runtime" "^7.16.3"
- aria-query "^4.2.2"
- array-includes "^3.1.4"
- ast-types-flow "^0.0.7"
- axe-core "^4.3.5"
- axobject-query "^2.2.0"
- damerau-levenshtein "^1.0.7"
- emoji-regex "^9.2.2"
- has "^1.0.3"
- jsx-ast-utils "^3.2.1"
- language-tags "^1.0.5"
- minimatch "^3.0.4"
-
-eslint-plugin-node@11.1.0:
- version "11.1.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d"
- integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==
- dependencies:
- eslint-plugin-es "^3.0.0"
- eslint-utils "^2.0.0"
- ignore "^5.1.1"
- minimatch "^3.0.4"
- resolve "^1.10.1"
- semver "^6.1.0"
-
-eslint-plugin-prettier@3.4.1:
- version "3.4.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5"
- integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==
+eslint-plugin-prettier@^4.0.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b"
+ integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==
dependencies:
prettier-linter-helpers "^1.0.0"
-eslint-plugin-promise@6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz#017652c07c9816413a41e11c30adc42c3d55ff18"
- integrity sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==
-
-eslint-plugin-react-hooks@4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172"
- integrity sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==
-
-eslint-plugin-react@7.28.0:
- version "7.28.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz#8f3ff450677571a659ce76efc6d80b6a525adbdf"
- integrity sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==
- dependencies:
- array-includes "^3.1.4"
- array.prototype.flatmap "^1.2.5"
- doctrine "^2.1.0"
- estraverse "^5.3.0"
- jsx-ast-utils "^2.4.1 || ^3.0.0"
- minimatch "^3.0.4"
- object.entries "^1.1.5"
- object.fromentries "^2.0.5"
- object.hasown "^1.1.0"
- object.values "^1.1.5"
- prop-types "^15.7.2"
- resolve "^2.0.0-next.3"
- semver "^6.3.0"
- string.prototype.matchall "^4.0.6"
-
-eslint-plugin-unicorn@40.0.0:
- version "40.0.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-40.0.0.tgz#a8226cab9c62b303e44fc41b1333a146e5676b86"
- integrity sha512-5GRXISfBk8jMmYk1eeNDw8zSRnWTxBjWkzx2Prre6E2/yLu2twozZ3EomLWCBu9nWms/ZE361BItyMQwfnG1qA==
- dependencies:
- "@babel/helper-validator-identifier" "^7.15.7"
- ci-info "^3.3.0"
- clean-regexp "^1.0.0"
- eslint-utils "^3.0.0"
- esquery "^1.4.0"
- indent-string "^4.0.0"
- is-builtin-module "^3.1.0"
- lodash "^4.17.21"
- pluralize "^8.0.0"
- read-pkg-up "^7.0.1"
- regexp-tree "^0.1.24"
- safe-regex "^2.1.1"
- semver "^7.3.5"
- strip-indent "^3.0.0"
-
-eslint-rule-composer@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9"
- integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==
-
eslint-scope@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
esrecurse "^4.3.0"
estraverse "^5.2.0"
-eslint-utils@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
- integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
- dependencies:
- eslint-visitor-keys "^1.1.0"
-
eslint-utils@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672"
dependencies:
eslint-visitor-keys "^2.0.0"
-eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
- integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
-
eslint-visitor-keys@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
-eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0:
+eslint-visitor-keys@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
-eslint@^8.20.0:
- version "8.20.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.20.0.tgz#048ac56aa18529967da8354a478be4ec0a2bc81b"
- integrity sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA==
+eslint@^8.25.0:
+ version "8.25.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.25.0.tgz#00eb962f50962165d0c4ee3327708315eaa8058b"
+ integrity sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==
dependencies:
- "@eslint/eslintrc" "^1.3.0"
- "@humanwhocodes/config-array" "^0.9.2"
+ "@eslint/eslintrc" "^1.3.3"
+ "@humanwhocodes/config-array" "^0.10.5"
+ "@humanwhocodes/module-importer" "^1.0.1"
ajv "^6.10.0"
chalk "^4.0.0"
cross-spawn "^7.0.2"
eslint-scope "^7.1.1"
eslint-utils "^3.0.0"
eslint-visitor-keys "^3.3.0"
- espree "^9.3.2"
+ espree "^9.4.0"
esquery "^1.4.0"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
file-entry-cache "^6.0.1"
- functional-red-black-tree "^1.0.1"
+ find-up "^5.0.0"
glob-parent "^6.0.1"
globals "^13.15.0"
+ globby "^11.1.0"
+ grapheme-splitter "^1.0.4"
ignore "^5.2.0"
import-fresh "^3.0.0"
imurmurhash "^0.1.4"
is-glob "^4.0.0"
+ js-sdsl "^4.1.4"
js-yaml "^4.1.0"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.4.1"
strip-ansi "^6.0.1"
strip-json-comments "^3.1.0"
text-table "^0.2.0"
- v8-compile-cache "^2.0.3"
-espree@^9.3.2:
- version "9.3.2"
- resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596"
- integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==
+espree@^9.4.0:
+ version "9.4.0"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.0.tgz#cd4bc3d6e9336c433265fc0aa016fc1aaf182f8a"
+ integrity sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==
dependencies:
- acorn "^8.7.1"
+ acorn "^8.8.0"
acorn-jsx "^5.3.2"
eslint-visitor-keys "^3.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
-estraverse@^5.2.0, estraverse@^5.3.0:
+estraverse@^5.2.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
dependencies:
to-regex-range "^5.0.1"
-find-up@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
- integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
- dependencies:
- locate-path "^2.0.0"
-
find-up@^4.0.0, find-up@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
locate-path "^5.0.0"
path-exists "^4.0.0"
+find-up@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+ integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+ dependencies:
+ locate-path "^6.0.0"
+ path-exists "^4.0.0"
+
flat-cache@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
-function.prototype.name@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621"
- integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.0"
- functions-have-names "^1.2.2"
-
-functional-red-black-tree@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
- integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
-
-functions-have-names@^1.2.2:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
- integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
-
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
-get-intrinsic@^1.0.0, get-intrinsic@^1.0.1, get-intrinsic@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49"
- integrity sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==
- dependencies:
- function-bind "^1.1.1"
- has "^1.0.3"
- has-symbols "^1.0.1"
-
-get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598"
- integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==
- dependencies:
- function-bind "^1.1.1"
- has "^1.0.3"
- has-symbols "^1.0.3"
-
get-package-type@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
-get-symbol-description@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6"
- integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==
- dependencies:
- call-bind "^1.0.2"
- get-intrinsic "^1.1.1"
-
glob-parent@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
dependencies:
type-fest "^0.20.2"
-globby@^11.0.4, globby@^11.1.0:
+globby@^11.1.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
-has-bigints@^1.0.1, has-bigints@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
- integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
+grapheme-splitter@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
+ integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-has-property-descriptors@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861"
- integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==
- dependencies:
- get-intrinsic "^1.1.1"
-
-has-symbols@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
- integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
-
-has-symbols@^1.0.2, has-symbols@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
- integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
-
-has-tostringtag@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
- integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
- dependencies:
- has-symbols "^1.0.2"
-
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
dependencies:
function-bind "^1.1.1"
-hosted-git-info@^2.1.4:
- version "2.8.8"
- resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
- integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
-
html-encoding-sniffer@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3"
dependencies:
safer-buffer ">= 2.1.2 < 3"
-ignore@^5.1.1:
- version "5.1.8"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
- integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
-
-ignore@^5.1.8, ignore@^5.2.0:
+ignore@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
-indent-string@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
- integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
-
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-internal-slot@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
- integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==
- dependencies:
- get-intrinsic "^1.1.0"
- has "^1.0.3"
- side-channel "^1.0.4"
-
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
-is-bigint@^1.0.1:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
- integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==
- dependencies:
- has-bigints "^1.0.1"
-
-is-boolean-object@^1.1.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719"
- integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==
- dependencies:
- call-bind "^1.0.2"
- has-tostringtag "^1.0.0"
-
-is-builtin-module@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.1.0.tgz#6fdb24313b1c03b75f8b9711c0feb8c30b903b00"
- integrity sha512-OV7JjAgOTfAFJmHZLvpSTb4qi0nIILDV1gWPYDnDJUTNFM5aGlRAhk4QcT8i7TuAleeEV5Fdkqn3t4mS+Q11fg==
- dependencies:
- builtin-modules "^3.0.0"
-
-is-callable@^1.1.4, is-callable@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9"
- integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==
-
-is-callable@^1.2.4:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
- integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==
-
-is-core-module@^2.1.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a"
- integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==
- dependencies:
- has "^1.0.3"
-
-is-core-module@^2.8.0, is-core-module@^2.9.0:
+is-core-module@^2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69"
integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==
dependencies:
has "^1.0.3"
-is-date-object@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
- integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
-
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
dependencies:
is-extglob "^2.1.1"
-is-negative-zero@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
- integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==
-
-is-negative-zero@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
- integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==
-
-is-number-object@^1.0.4:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc"
- integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==
- dependencies:
- has-tostringtag "^1.0.0"
-
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5"
integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==
-is-regex@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9"
- integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==
- dependencies:
- has-symbols "^1.0.1"
-
-is-regex@^1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
- integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
- dependencies:
- call-bind "^1.0.2"
- has-tostringtag "^1.0.0"
-
-is-shared-array-buffer@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
- integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==
- dependencies:
- call-bind "^1.0.2"
-
is-stream@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
-is-string@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6"
- integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==
-
-is-string@^1.0.7:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
- integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
- dependencies:
- has-tostringtag "^1.0.0"
-
-is-symbol@^1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
- integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
- dependencies:
- has-symbols "^1.0.1"
-
-is-symbol@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c"
- integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==
- dependencies:
- has-symbols "^1.0.2"
-
is-typedarray@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==
-is-weakref@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
- integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==
- dependencies:
- call-bind "^1.0.2"
-
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
import-local "^3.0.2"
jest-cli "^27.5.1"
-"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+js-sdsl@^4.1.4:
+ version "4.1.5"
+ resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.1.5.tgz#1ff1645e6b4d1b028cd3f862db88c9d887f26e2a"
+ integrity sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==
+
+js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
-json5@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
- integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
- dependencies:
- minimist "^1.2.0"
-
-"jsx-ast-utils@^2.4.1 || ^3.0.0":
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82"
- integrity sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==
- dependencies:
- array-includes "^3.1.2"
- object.assign "^4.1.2"
-
-jsx-ast-utils@^3.2.1:
- version "3.3.2"
- resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.2.tgz#afe5efe4332cd3515c065072bd4d6b0aa22152bd"
- integrity sha512-4ZCADZHRkno244xlNnn4AOG6sRQ7iBZ5BbgZ4vW4y5IZw7cVUD1PPeblm1xx/nfmMxPdt/LHsXZW8z/j58+l9Q==
- dependencies:
- array-includes "^3.1.5"
- object.assign "^4.1.2"
-
kleur@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
-language-subtag-registry@~0.3.2:
- version "0.3.21"
- resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a"
- integrity sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==
-
-language-tags@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a"
- integrity sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=
- dependencies:
- language-subtag-registry "~0.3.2"
-
-lemmy-js-client@0.17.0-rc.37:
- version "0.17.0-rc.37"
- resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.37.tgz#f211171ea478f095d02676b4e69f69aa300cb571"
- integrity sha512-Piz8fnfZnCIFm8AG6Nqw0Oh4i0yr0ZmOwp07FogXMjSP4HKZItHDiDFhXR1qBFklIH7aI0wrvqnLzoIW19SITg==
+lemmy-js-client@0.17.0-rc.47:
+ version "0.17.0-rc.47"
+ resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.47.tgz#6094657d2868767532c0e837a31f9af6273b345b"
+ integrity sha512-Pc1wyr6sX4Z6LS75NVu46WAXeci5G80+Y9ZBXEAmgM+OZGuOCLUq8lAHRvTwr7M0pj0gxo5yP+i3qPVmTPf+EA==
leven@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
-locate-path@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
- integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
- dependencies:
- p-locate "^2.0.0"
- path-exists "^3.0.0"
-
locate-path@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
dependencies:
p-locate "^4.1.0"
+locate-path@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+ integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+ dependencies:
+ p-locate "^5.0.0"
+
lodash.memoize@4.x:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-lodash@^4.17.19, lodash@^4.17.21, lodash@^4.7.0:
+lodash@^4.7.0:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-loose-envify@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
- integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
- dependencies:
- js-tokens "^3.0.0 || ^4.0.0"
-
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
-min-indent@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
- integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
-
minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
dependencies:
brace-expansion "^1.1.7"
-minimist@^1.2.0:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
-
-minimist@^1.2.6:
- version "1.2.6"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
- integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
-
-ms@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
- integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
-
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-ms@^2.1.1:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
- integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
-
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
-normalize-package-data@^2.5.0:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
- integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
- dependencies:
- hosted-git-info "^2.1.4"
- resolve "^1.10.0"
- semver "2 || 3 || 4 || 5"
- validate-npm-package-license "^3.0.1"
-
normalize-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.1.tgz#10a9f268fbf4c461249ebcfe38e359aa36e2577c"
integrity sha512-JYOWTeFoS0Z93587vRJgASD5Ut11fYl5NyihP3KrYBvMe1FRRs6RN7m20SA/16GM4P6hTnZjT+UmDOt38UeXNg==
-object-assign@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
- integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
-
-object-inspect@^1.12.0:
- version "1.12.2"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea"
- integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==
-
-object-inspect@^1.8.0, object-inspect@^1.9.0:
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a"
- integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==
-
-object-keys@^1.0.12, object-keys@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
- integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
-
-object.assign@^4.1.1, object.assign@^4.1.2:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
- integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
- dependencies:
- call-bind "^1.0.0"
- define-properties "^1.1.3"
- has-symbols "^1.0.1"
- object-keys "^1.1.1"
-
-object.entries@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861"
- integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.1"
-
-object.fromentries@^2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251"
- integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.1"
-
-object.hasown@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.1.tgz#ad1eecc60d03f49460600430d97f23882cf592a3"
- integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==
- dependencies:
- define-properties "^1.1.4"
- es-abstract "^1.19.5"
-
-object.values@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac"
- integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.1"
-
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
type-check "^0.4.0"
word-wrap "^1.2.3"
-p-limit@^1.1.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
- integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
- dependencies:
- p-try "^1.0.0"
-
p-limit@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
dependencies:
p-try "^2.0.0"
-p-locate@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
- integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
+p-limit@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+ integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
dependencies:
- p-limit "^1.1.0"
+ yocto-queue "^0.1.0"
p-locate@^4.1.0:
version "4.1.0"
dependencies:
p-limit "^2.2.0"
-p-try@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
- integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
+p-locate@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+ integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+ dependencies:
+ p-limit "^3.0.2"
p-try@^2.0.0:
version "2.2.0"
dependencies:
callsites "^3.0.0"
-parse-json@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.1.0.tgz#f96088cdf24a8faa9aea9a009f2d9d942c999646"
- integrity sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==
- dependencies:
- "@babel/code-frame" "^7.0.0"
- error-ex "^1.3.1"
- json-parse-even-better-errors "^2.3.0"
- lines-and-columns "^1.1.6"
-
parse-json@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
-path-exists@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
- integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
-
path-exists@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
-path-parse@^1.0.6, path-parse@^1.0.7:
+path-parse@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
dependencies:
find-up "^4.0.0"
-pluralize@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
- integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==
-
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
kleur "^3.0.3"
sisteransi "^1.0.5"
-prop-types@^15.7.2:
- version "15.7.2"
- resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
- integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
- dependencies:
- loose-envify "^1.4.0"
- object-assign "^4.1.1"
- react-is "^16.8.1"
-
psl@^1.1.33:
version "1.9.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
-react-is@^16.8.1:
- version "16.13.1"
- resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
- integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
-
react-is@^17.0.1:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
-read-pkg-up@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
- integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==
- dependencies:
- find-up "^4.1.0"
- read-pkg "^5.2.0"
- type-fest "^0.8.1"
-
-read-pkg@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
- integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
- dependencies:
- "@types/normalize-package-data" "^2.4.0"
- normalize-package-data "^2.5.0"
- parse-json "^5.0.0"
- type-fest "^0.6.0"
-
reflect-metadata@^0.1.13:
version "0.1.13"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
-regenerator-runtime@^0.13.4:
- version "0.13.7"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
- integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
-
-regexp-tree@^0.1.24:
- version "0.1.24"
- resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.24.tgz#3d6fa238450a4d66e5bc9c4c14bb720e2196829d"
- integrity sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==
-
-regexp-tree@~0.1.1:
- version "0.1.21"
- resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.21.tgz#55e2246b7f7d36f1b461490942fa780299c400d7"
- integrity sha512-kUUXjX4AnqnR8KRTCrayAo9PzYMRKmVoGgaz2tBuz0MF3g1ZbGebmtW0yFHfFK9CmBjQKeYIgoL22pFLBJY7sw==
-
-regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3:
- version "1.4.3"
- resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac"
- integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- functions-have-names "^1.2.2"
-
-regexpp@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
- integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
-
regexpp@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9"
integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==
-resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0:
- version "1.19.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c"
- integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==
- dependencies:
- is-core-module "^2.1.0"
- path-parse "^1.0.6"
-
resolve@^1.20.0:
version "1.22.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
-resolve@^2.0.0-next.3:
- version "2.0.0-next.4"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660"
- integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==
- dependencies:
- is-core-module "^2.9.0"
- path-parse "^1.0.7"
- supports-preserve-symlinks-flag "^1.0.0"
-
reusify@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-safe-regex@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-2.1.1.tgz#f7128f00d056e2fe5c11e81a1324dd974aadced2"
- integrity sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==
- dependencies:
- regexp-tree "~0.1.1"
-
"safer-buffer@>= 2.1.2 < 3":
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
dependencies:
xmlchars "^2.2.0"
-"semver@2 || 3 || 4 || 5":
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
- integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
-
-semver@7.x, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7:
+semver@7.x, semver@^7.3.2, semver@^7.3.7:
version "7.3.7"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
dependencies:
lru-cache "^6.0.0"
-semver@^6.0.0, semver@^6.1.0, semver@^6.3.0:
+semver@^6.0.0, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
-side-channel@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
- integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
- dependencies:
- call-bind "^1.0.0"
- get-intrinsic "^1.0.2"
- object-inspect "^1.9.0"
-
signal-exit@^3.0.2, signal-exit@^3.0.3:
version "3.0.7"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
-spdx-correct@^3.0.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
- integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==
- dependencies:
- spdx-expression-parse "^3.0.0"
- spdx-license-ids "^3.0.0"
-
-spdx-exceptions@^2.1.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d"
- integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==
-
-spdx-expression-parse@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
- integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
- dependencies:
- spdx-exceptions "^2.1.0"
- spdx-license-ids "^3.0.0"
-
-spdx-license-ids@^3.0.0:
- version "3.0.7"
- resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65"
- integrity sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==
-
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
-string.prototype.matchall@^4.0.6:
- version "4.0.7"
- resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d"
- integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.1"
- get-intrinsic "^1.1.1"
- has-symbols "^1.0.3"
- internal-slot "^1.0.3"
- regexp.prototype.flags "^1.4.1"
- side-channel "^1.0.4"
-
-string.prototype.trimend@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz#a22bd53cca5c7cf44d7c9d5c732118873d6cd18b"
- integrity sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==
- dependencies:
- call-bind "^1.0.0"
- define-properties "^1.1.3"
-
-string.prototype.trimend@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0"
- integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.19.5"
-
-string.prototype.trimstart@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa"
- integrity sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==
- dependencies:
- call-bind "^1.0.0"
- define-properties "^1.1.3"
-
-string.prototype.trimstart@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef"
- integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==
- dependencies:
- call-bind "^1.0.2"
- define-properties "^1.1.4"
- es-abstract "^1.19.5"
-
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
dependencies:
ansi-regex "^5.0.1"
-strip-bom@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
- integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
-
strip-bom@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878"
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
-strip-indent@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
- integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
- dependencies:
- min-indent "^1.0.0"
-
strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
semver "7.x"
yargs-parser "20.x"
-tsconfig-paths@^3.12.0:
- version "3.14.1"
- resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
- integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==
- dependencies:
- "@types/json5" "^0.0.29"
- json5 "^1.0.1"
- minimist "^1.2.6"
- strip-bom "^3.0.0"
-
tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
-type-fest@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
- integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
-
-type-fest@^0.8.1:
- version "0.8.1"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
- integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
-
typedarray-to-buffer@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
dependencies:
is-typedarray "^1.0.0"
-typescript@^4.6.4:
- version "4.7.4"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
- integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
-
-unbox-primitive@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
- integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==
- dependencies:
- call-bind "^1.0.2"
- has-bigints "^1.0.2"
- has-symbols "^1.0.3"
- which-boxed-primitive "^1.0.2"
+typescript@^4.8.4:
+ version "4.8.4"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6"
+ integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==
universalify@^0.1.2:
version "0.1.2"
dependencies:
punycode "^2.1.0"
-v8-compile-cache@^2.0.3:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132"
- integrity sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==
-
v8-to-istanbul@^8.1.0:
version "8.1.1"
resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed"
convert-source-map "^1.6.0"
source-map "^0.7.3"
-validate-npm-package-license@^3.0.1:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
- integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
- dependencies:
- spdx-correct "^3.0.0"
- spdx-expression-parse "^3.0.0"
-
w3c-hr-time@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"
tr46 "^2.1.0"
webidl-conversions "^6.1.0"
-which-boxed-primitive@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
- integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
- dependencies:
- is-bigint "^1.0.1"
- is-boolean-object "^1.1.0"
- is-number-object "^1.0.4"
- is-string "^1.0.5"
- is-symbol "^1.0.3"
-
which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
string-width "^4.2.0"
y18n "^5.0.5"
yargs-parser "^20.2.2"
+
+yocto-queue@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+ integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
# https://join-lemmy.org/docs/en/administration/configuration.html
{
hostname: lemmy-alpha
- federation: {
- enabled: true
- }
- slur_filter:
- '''
- (fag(g|got|tard)?\b|cock\s?sucker(s|ing)?|ni((g{2,}|q)+|[gq]{2,})[e3r]+(s|z)?|mudslime?s?|kikes?|\bspi(c|k)s?\b|\bchinks?|gooks?|bitch(es|ing|y)?|whor(es?|ing)|\btr(a|@)nn?(y|ies?)|\b(b|re|r)tard(ed)?s?)
- '''
}
# Maximum number of active sql connections
pool_size: 5
}
- # rate limits for various user actions, by user ip
- rate_limit: {
- # Maximum number of messages created in interval
- message: 180
- # Interval length for message limit, in seconds
- message_per_second: 60
- # Maximum number of posts created in interval
- post: 6
- # Interval length for post limit, in seconds
- post_per_second: 600
- # Maximum number of registrations in interval
- register: 3
- # Interval length for registration limit, in seconds
- register_per_second: 3600
- # Maximum number of image uploads in interval
- image: 6
- # Interval length for image uploads, in seconds
- image_per_second: 3600
- # Maximum number of comments created in interval
- comment: 6
- # Interval length for comment limit, in seconds
- comment_per_second: 600
- search: 60
- # Interval length for search limit, in seconds
- search_per_second: 600
- }
# Settings related to activitypub federation
- federation: {
- # Whether to enable activitypub federation.
- enabled: false
- # Allows and blocks are described here:
- # https://join-lemmy.org/docs/en/administration/federation_getting_started.html
- #
- # list of instances with which federation is allowed
- allowed_instances: [
- instance1.tld
- instance2.tld
- /* ... */
- ]
- # Instances which we never federate anything with (but previously federated objects are unaffected)
- blocked_instances: [
- string
- /* ... */
- ]
- # If true, only federate with instances on the allowlist and block everything else. If false
- # use allowlist only for remote communities, and posts/comments in local communities
- # (meaning remote communities will show content from arbitrary instances).
- strict_allowlist: true
- # Maximum number of HTTP requests allowed to handle a single incoming activity (or a single object fetch through the search).
- http_fetch_retry_limit: 25
- # Number of workers for sending outgoing activities. Search logs for Activity queue stats to
- # see information. If running number is consistently close to the worker_count, you should
- # increase it.
- worker_count: 64
- # Use federation debug mode. Allows connecting to http and localhost urls. Also sends outgoing
- # activities synchronously for easier testing. Do not use in production.
- debug: false
- }
# Pictrs image server configuration.
pictrs: {
# Address where pictrs is available (for image hosting)
# Set a custom pictrs API key. ( Required for deleting images )
api_key: "string"
}
- captcha: {
- # Whether captcha is required for signup
- enabled: false
- # Can be easy, medium, or hard
- difficulty: "medium"
- }
# Email sending configuration. All options except login/password are mandatory
email: {
# Hostname and port of the smtp server
port: 8536
# Whether the site is available over TLS. Needs to be true for federation to work.
tls_enabled: true
- # A regex list of slurs to block / hide
- slur_filter: "(\bThis\b)|(\bis\b)|(\bsample\b)"
- # Maximum length of local community and user names
- actor_name_max_length: 20
}
source::{
comment::{CommentLike, CommentLikeForm},
comment_reply::CommentReply,
+ local_site::LocalSite,
},
traits::Likeable,
};
websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
let data: &CreateCommentLike = self;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let mut recipient_ids = Vec::<LocalUserId>::new();
// Don't do a downvote if site has downvotes disabled
- check_downvotes_enabled(data.score, context.pool()).await?;
+ check_downvotes_enabled(data.score, &local_site)?;
let comment_id = data.comment_id;
let orig_comment = blocking(context.pool(), move |conn| {
};
use lemmy_apub::protocol::activities::community::report::Report;
use lemmy_db_schema::{
- source::comment_report::{CommentReport, CommentReportForm},
+ source::{
+ comment_report::{CommentReport, CommentReportForm},
+ local_site::LocalSite,
+ },
traits::Reportable,
};
use lemmy_db_views::structs::{CommentReportView, CommentView};
let data: &CreateCommentReport = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
let reason = self.reason.trim();
- check_report_reason(reason, context)?;
+ check_report_reason(reason, &local_site)?;
let person_id = local_user_view.person.id;
let comment_id = data.comment_id;
use lemmy_apub::protocol::activities::community::update::UpdateCommunity;
use lemmy_db_schema::{
source::{
- community::{Community, CommunityForm},
+ community::{Community, CommunityUpdateForm},
moderator::{ModHideCommunity, ModHideCommunityForm},
},
traits::Crud,
- utils::naive_now,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
is_admin(&local_user_view)?;
- let community_id = data.community_id;
- let read_community = blocking(context.pool(), move |conn| {
- Community::read(conn, community_id)
- })
- .await??;
-
- let community_form = CommunityForm {
- name: read_community.name,
- title: read_community.title,
- description: Some(read_community.description.to_owned()),
- hidden: Some(data.hidden),
- updated: Some(naive_now()),
- ..CommunityForm::default()
- };
+ let community_form = CommunityUpdateForm::builder()
+ .hidden(Some(data.hidden))
+ .build();
let mod_hide_community_form = ModHideCommunityForm {
community_id: data.community_id,
post::*,
private_message::*,
site::*,
+ utils::local_site_to_slur_regex,
websocket::*,
};
+use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_utils::{error::LemmyError, utils::check_slurs, ConnectionId};
use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
use serde::Deserialize;
}
/// Check size of report and remove whitespace
-pub(crate) fn check_report_reason(reason: &str, context: &LemmyContext) -> Result<(), LemmyError> {
- check_slurs(reason, &context.settings().slur_regex())?;
+pub(crate) fn check_report_reason(reason: &str, local_site: &LocalSite) -> Result<(), LemmyError> {
+ let slur_regex = &local_site_to_slur_regex(local_site);
+
+ check_slurs(reason, slur_regex)?;
if reason.is_empty() {
return Err(LemmyError::from_message("report_reason_required"));
}
use lemmy_api_common::utils::check_validator_time;
use lemmy_db_schema::{
source::{
- local_user::{LocalUser, LocalUserForm},
- person::{Person, PersonForm},
+ instance::Instance,
+ local_user::{LocalUser, LocalUserInsertForm},
+ person::{Person, PersonInsertForm},
secret::Secret,
},
traits::Crud,
let secret = Secret::init(conn).unwrap();
let settings = &SETTINGS.to_owned();
- let new_person = PersonForm {
- name: "Gerry9812".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("Gerry9812".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let local_user_form = LocalUserForm {
- person_id: Some(inserted_person.id),
- password_encrypted: Some("123456".to_string()),
- ..LocalUserForm::default()
- };
+ let local_user_form = LocalUserInsertForm::builder()
+ .person_id(inserted_person.id)
+ .password_encrypted("123456".to_string())
+ .build();
let inserted_local_user = LocalUser::create(conn, &local_user_form).unwrap();
use lemmy_db_schema::{
source::{
moderator::{ModAdd, ModAddForm},
- person::Person,
+ person::{Person, PersonUpdateForm},
},
traits::Crud,
};
let added = data.added;
let added_person_id = data.person_id;
let added_admin = blocking(context.pool(), move |conn| {
- Person::add_admin(conn, added_person_id, added)
+ Person::update(
+ conn,
+ added_person_id,
+ &PersonUpdateForm::builder().admin(Some(added)).build(),
+ )
})
.await?
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_user"))?;
use lemmy_db_schema::{
source::{
moderator::{ModBan, ModBanForm},
- person::Person,
- site::Site,
+ person::{Person, PersonUpdateForm},
},
traits::Crud,
};
+use lemmy_db_views::structs::SiteView;
use lemmy_db_views_actor::structs::PersonViewSafe;
use lemmy_utils::{error::LemmyError, utils::naive_from_unix, ConnectionId};
use lemmy_websocket::{messages::SendAllMessage, LemmyContext, UserOperation};
let banned_person_id = data.person_id;
let expires = data.expires.map(naive_from_unix);
- let ban_person = move |conn: &mut _| Person::ban_person(conn, banned_person_id, ban, expires);
- let person = blocking(context.pool(), ban_person)
- .await?
- .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_user"))?;
+ let person = blocking(context.pool(), move |conn| {
+ Person::update(
+ conn,
+ banned_person_id,
+ &PersonUpdateForm::builder()
+ .banned(Some(ban))
+ .ban_expires(Some(expires))
+ .build(),
+ )
+ })
+ .await?
+ .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_user"))?;
// Remove their data if that's desired
let remove_data = data.remove_data.unwrap_or(false);
})
.await??;
- let site = SiteOrCommunity::Site(blocking(context.pool(), Site::read_local).await??.into());
+ let site = SiteOrCommunity::Site(
+ blocking(context.pool(), SiteView::read_local)
+ .await??
+ .site
+ .into(),
+ );
// if the action affects a local user, federate to other instances
if person.local {
if ban {
use actix_web::web::Data;
use captcha::{gen, Difficulty};
use chrono::Duration;
-use lemmy_api_common::person::{CaptchaResponse, GetCaptcha, GetCaptchaResponse};
-use lemmy_db_schema::utils::naive_now;
+use lemmy_api_common::{
+ person::{CaptchaResponse, GetCaptcha, GetCaptchaResponse},
+ utils::blocking,
+};
+use lemmy_db_schema::{source::local_site::LocalSite, utils::naive_now};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_websocket::{messages::CaptchaItem, LemmyContext};
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
- let captcha_settings = &context.settings().captcha;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
- if !captcha_settings.enabled {
+ if !local_site.captcha_enabled {
return Ok(GetCaptchaResponse { ok: None });
}
- let captcha = gen(match captcha_settings.difficulty.as_str() {
+ let captcha = gen(match local_site.captcha_difficulty.as_str() {
"easy" => Difficulty::Easy,
"hard" => Difficulty::Hard,
_ => Difficulty::Medium,
person::{Login, LoginResponse},
utils::{blocking, check_registration_application, check_user_valid},
};
-use lemmy_db_schema::source::site::Site;
+use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::{claims::Claims, error::LemmyError, ConnectionId};
use lemmy_websocket::LemmyContext;
) -> Result<LoginResponse, LemmyError> {
let data: &Login = self;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
+
// Fetch that username / email
let username_or_email = data.username_or_email.clone();
let local_user_view = blocking(context.pool(), move |conn| {
local_user_view.person.deleted,
)?;
- let site = blocking(context.pool(), Site::read_local).await??;
- if site.require_email_verification && !local_user_view.local_user.email_verified {
+ if local_site.require_email_verification && !local_user_view.local_user.email_verified {
return Err(LemmyError::from_message("email_not_verified"));
}
- check_registration_application(&site, &local_user_view, context.pool()).await?;
+ check_registration_application(&local_user_view, &local_site, context.pool()).await?;
// Return the jwt
Ok(LoginResponse {
person::{MarkPersonMentionAsRead, PersonMentionResponse},
utils::{blocking, get_local_user_view_from_jwt},
};
-use lemmy_db_schema::{source::person_mention::PersonMention, traits::Crud};
+use lemmy_db_schema::{
+ source::person_mention::{PersonMention, PersonMentionUpdateForm},
+ traits::Crud,
+};
use lemmy_db_views_actor::structs::PersonMentionView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_websocket::LemmyContext;
}
let person_mention_id = read_person_mention.id;
- let read = data.read;
- let update_mention =
- move |conn: &mut _| PersonMention::update_read(conn, person_mention_id, read);
- blocking(context.pool(), update_mention)
- .await?
- .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
+ let read = Some(data.read);
+ blocking(context.pool(), move |conn| {
+ PersonMention::update(conn, person_mention_id, &PersonMentionUpdateForm { read })
+ })
+ .await?
+ .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
let person_mention_id = read_person_mention.id;
let person_id = local_user_view.person.id;
person::{CommentReplyResponse, MarkCommentReplyAsRead},
utils::{blocking, get_local_user_view_from_jwt},
};
-use lemmy_db_schema::{source::comment_reply::CommentReply, traits::Crud};
+use lemmy_db_schema::{
+ source::comment_reply::{CommentReply, CommentReplyUpdateForm},
+ traits::Crud,
+};
use lemmy_db_views_actor::structs::CommentReplyView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_websocket::LemmyContext;
}
let comment_reply_id = read_comment_reply.id;
- let read = data.read;
- let update_reply = move |conn: &mut _| CommentReply::update_read(conn, comment_reply_id, read);
- blocking(context.pool(), update_reply)
- .await?
- .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
+ let read = Some(data.read);
+ blocking(context.pool(), move |conn| {
+ CommentReply::update(conn, comment_reply_id, &CommentReplyUpdateForm { read })
+ })
+ .await?
+ .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
let comment_reply_id = read_comment_reply.id;
let person_id = local_user_view.person.id;
use lemmy_db_schema::{
source::{
actor_language::LocalUserLanguage,
- local_user::{LocalUser, LocalUserForm},
- person::{Person, PersonForm},
- site::Site,
+ local_site::LocalSite,
+ local_user::{LocalUser, LocalUserUpdateForm},
+ person::{Person, PersonUpdateForm},
},
traits::Crud,
- utils::{diesel_option_overwrite, diesel_option_overwrite_to_url, naive_now},
+ utils::{diesel_option_overwrite, diesel_option_overwrite_to_url},
};
use lemmy_utils::{
claims::Claims,
let data: &SaveUserSettings = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
let avatar = diesel_option_overwrite_to_url(&data.avatar)?;
let banner = diesel_option_overwrite_to_url(&data.banner)?;
// When the site requires email, make sure email is not Some(None). IE, an overwrite to a None value
if let Some(email) = &email {
- let site_fut = blocking(context.pool(), Site::read_local);
- if email.is_none() && site_fut.await??.require_email_verification {
+ if email.is_none() && local_site.require_email_verification {
return Err(LemmyError::from_message("email_required"));
}
}
if let Some(Some(display_name)) = &display_name {
if !is_valid_display_name(
display_name.trim(),
- context.settings().actor_name_max_length,
+ local_site.actor_name_max_length as usize,
) {
return Err(LemmyError::from_message("invalid_username"));
}
let person_id = local_user_view.person.id;
let default_listing_type = data.default_listing_type;
let default_sort_type = data.default_sort_type;
- let password_encrypted = local_user_view.local_user.password_encrypted;
- let public_key = Some(local_user_view.person.public_key);
-
- let person_form = PersonForm {
- name: local_user_view.person.name,
- avatar,
- banner,
- inbox_url: None,
- display_name,
- published: None,
- updated: Some(naive_now()),
- banned: None,
- deleted: None,
- actor_id: None,
- bio,
- local: None,
- admin: None,
- private_key: None,
- public_key,
- last_refreshed_at: None,
- shared_inbox_url: None,
- matrix_user_id,
- bot_account,
- ban_expires: None,
- };
+
+ let person_form = PersonUpdateForm::builder()
+ .display_name(display_name)
+ .bio(bio)
+ .matrix_user_id(matrix_user_id)
+ .bot_account(bot_account)
+ .avatar(avatar)
+ .banner(banner)
+ .build();
blocking(context.pool(), move |conn| {
Person::update(conn, person_id, &person_form)
.await??;
}
- let local_user_form = LocalUserForm {
- person_id: Some(person_id),
- email,
- password_encrypted: Some(password_encrypted),
- show_nsfw: data.show_nsfw,
- show_bot_accounts: data.show_bot_accounts,
- show_scores: data.show_scores,
- theme: data.theme.to_owned(),
- default_sort_type,
- default_listing_type,
- interface_language: data.interface_language.to_owned(),
- show_avatars: data.show_avatars,
- show_read_posts: data.show_read_posts,
- show_new_post_notifs: data.show_new_post_notifs,
- send_notifications_to_email: data.send_notifications_to_email,
- email_verified: None,
- accepted_application: None,
- };
+ let local_user_form = LocalUserUpdateForm::builder()
+ .email(email)
+ .show_avatars(data.show_avatars)
+ .show_read_posts(data.show_read_posts)
+ .show_new_post_notifs(data.show_new_post_notifs)
+ .send_notifications_to_email(data.send_notifications_to_email)
+ .show_nsfw(data.show_nsfw)
+ .show_bot_accounts(data.show_bot_accounts)
+ .show_scores(data.show_scores)
+ .default_sort_type(default_sort_type)
+ .default_listing_type(default_listing_type)
+ .theme(data.theme.to_owned())
+ .interface_language(data.interface_language.to_owned())
+ .build();
let local_user_res = blocking(context.pool(), move |conn| {
LocalUser::update(conn, local_user_id, &local_user_form)
use lemmy_db_schema::{
source::{
email_verification::EmailVerification,
- local_user::{LocalUser, LocalUserForm},
+ local_user::{LocalUser, LocalUserUpdateForm},
},
traits::Crud,
};
.await?
.map_err(|e| LemmyError::from_error_message(e, "token_not_found"))?;
- let form = LocalUserForm {
+ let form = LocalUserUpdateForm::builder()
// necessary in case this is a new signup
- email_verified: Some(true),
+ .email_verified(Some(true))
// necessary in case email of an existing user was changed
- email: Some(Some(verification.email)),
- ..LocalUserForm::default()
- };
+ .email(Some(Some(verification.email)))
+ .build();
let local_user_id = verification.local_user_id;
blocking(context.pool(), move |conn| {
LocalUser::update(conn, local_user_id, &form)
},
};
use lemmy_db_schema::{
- source::post::{Post, PostLike, PostLikeForm},
+ source::{
+ local_site::LocalSite,
+ post::{Post, PostLike, PostLikeForm},
+ },
traits::{Crud, Likeable},
};
use lemmy_utils::{error::LemmyError, ConnectionId};
let data: &CreatePostLike = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
// Don't do a downvote if site has downvotes disabled
- check_downvotes_enabled(data.score, context.pool()).await?;
+ check_downvotes_enabled(data.score, &local_site)?;
// Check for a community ban
let post_id = data.post_id;
use lemmy_db_schema::{
source::{
moderator::{ModLockPost, ModLockPostForm},
- post::Post,
+ post::{Post, PostUpdateForm},
},
traits::Crud,
};
let post_id = data.post_id;
let locked = data.locked;
let updated_post: ApubPost = blocking(context.pool(), move |conn| {
- Post::update_locked(conn, post_id, locked)
+ Post::update(
+ conn,
+ post_id,
+ &PostUpdateForm::builder().locked(Some(locked)).build(),
+ )
})
.await??
.into();
use lemmy_db_schema::{
source::{
moderator::{ModStickyPost, ModStickyPostForm},
- post::Post,
+ post::{Post, PostUpdateForm},
},
traits::Crud,
};
let post_id = data.post_id;
let stickied = data.stickied;
let updated_post: ApubPost = blocking(context.pool(), move |conn| {
- Post::update_stickied(conn, post_id, stickied)
+ Post::update(
+ conn,
+ post_id,
+ &PostUpdateForm::builder().stickied(Some(stickied)).build(),
+ )
})
.await??
.into();
};
use lemmy_apub::protocol::activities::community::report::Report;
use lemmy_db_schema::{
- source::post_report::{PostReport, PostReportForm},
+ source::{
+ local_site::LocalSite,
+ post_report::{PostReport, PostReportForm},
+ },
traits::Reportable,
};
use lemmy_db_views::structs::{PostReportView, PostView};
let data: &CreatePostReport = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
let reason = self.reason.trim();
- check_report_reason(reason, context)?;
+ check_report_reason(reason, &local_site)?;
let person_id = local_user_view.person.id;
let post_id = data.post_id;
private_message::{MarkPrivateMessageAsRead, PrivateMessageResponse},
utils::{blocking, get_local_user_view_from_jwt},
};
-use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud};
+use lemmy_db_schema::{
+ source::private_message::{PrivateMessage, PrivateMessageUpdateForm},
+ traits::Crud,
+};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperation};
let private_message_id = data.private_message_id;
let read = data.read;
blocking(context.pool(), move |conn| {
- PrivateMessage::update_read(conn, private_message_id, read)
+ PrivateMessage::update(
+ conn,
+ private_message_id,
+ &PrivateMessageUpdateForm::builder().read(Some(read)).build(),
+ )
})
.await?
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_private_message"))?;
use lemmy_db_schema::{
newtypes::CommunityId,
source::{
+ local_site::LocalSite,
private_message::PrivateMessage,
private_message_report::{PrivateMessageReport, PrivateMessageReportForm},
},
) -> Result<Self::Response, LemmyError> {
let local_user_view =
get_local_user_view_from_jwt(&self.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
let reason = self.reason.trim();
- check_report_reason(reason, context)?;
+ check_report_reason(reason, &local_site)?;
let person_id = local_user_view.person.id;
let private_message_id = self.private_message_id;
use actix_web::web::Data;
use lemmy_api_common::{
site::{GetSiteResponse, LeaveAdmin},
- utils::{blocking, build_federated_instances, get_local_user_view_from_jwt, is_admin},
+ utils::{blocking, get_local_user_view_from_jwt, is_admin},
};
use lemmy_db_schema::{
source::{
actor_language::SiteLanguage,
language::Language,
moderator::{ModAdd, ModAddForm},
- person::Person,
+ person::{Person, PersonUpdateForm},
},
traits::Crud,
};
let person_id = local_user_view.person.id;
blocking(context.pool(), move |conn| {
- Person::leave_admin(conn, person_id)
+ Person::update(
+ conn,
+ person_id,
+ &PersonUpdateForm::builder().admin(Some(false)).build(),
+ )
})
.await??;
let site_view = blocking(context.pool(), SiteView::read_local).await??;
let admins = blocking(context.pool(), PersonViewSafe::admins).await??;
- let federated_instances = build_federated_instances(context.pool(), context.settings()).await?;
-
let all_languages = blocking(context.pool(), Language::read_all).await??;
let discussion_languages = blocking(context.pool(), SiteLanguage::read_local).await??;
Ok(GetSiteResponse {
- site_view: Some(site_view),
+ site_view,
admins,
online: 0,
version: version::VERSION.to_string(),
my_user: None,
- federated_instances,
+ federated_instances: None,
all_languages,
discussion_languages,
})
};
use lemmy_db_schema::{
newtypes::{CommunityId, PersonId},
- source::site::Site,
+ source::local_site::LocalSite,
ModlogActionType,
};
use lemmy_db_views_moderator::structs::{
let local_user_view =
get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
- check_private_instance(&local_user_view, context.pool()).await?;
+ check_private_instance(&local_user_view, &local_site)?;
let type_ = data.type_.unwrap_or(All);
let community_id = data.community_id;
- let site = blocking(context.pool(), Site::read_local).await??;
let (local_person_id, is_admin) = match local_user_view {
Some(s) => (s.person.id, is_admin(&s).is_ok()),
None => (PersonId(-1), false),
&& is_mod_or_admin(context.pool(), local_person_id, community_id_value)
.await
.is_ok();
- let hide_modlog_names = site.hide_modlog_mod_names && !is_mod_of_community && !is_admin;
+ let hide_modlog_names = local_site.hide_modlog_mod_names && !is_mod_of_community && !is_admin;
let mod_person_id = if hide_modlog_names {
None
};
use lemmy_db_schema::{
source::{
- local_user::{LocalUser, LocalUserForm},
- registration_application::{RegistrationApplication, RegistrationApplicationForm},
+ local_user::{LocalUser, LocalUserUpdateForm},
+ registration_application::{RegistrationApplication, RegistrationApplicationUpdateForm},
},
traits::Crud,
utils::diesel_option_overwrite,
// Update the registration with reason, admin_id
let deny_reason = diesel_option_overwrite(&data.deny_reason);
- let app_form = RegistrationApplicationForm {
- admin_id: Some(local_user_view.person.id),
+ let app_form = RegistrationApplicationUpdateForm {
+ admin_id: Some(Some(local_user_view.person.id)),
deny_reason,
- ..RegistrationApplicationForm::default()
};
let registration_application = blocking(context.pool(), move |conn| {
.await??;
// Update the local_user row
- let local_user_form = LocalUserForm {
- accepted_application: Some(data.approve),
- ..LocalUserForm::default()
- };
+ let local_user_form = LocalUserUpdateForm::builder()
+ .accepted_application(Some(data.approve))
+ .build();
let approved_user_id = registration_application.local_user_id;
blocking(context.pool(), move |conn| {
site::{ListRegistrationApplications, ListRegistrationApplicationsResponse},
utils::{blocking, get_local_user_view_from_jwt, is_admin},
};
-use lemmy_db_schema::source::site::Site;
+use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_db_views::registration_application_view::RegistrationApplicationQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_websocket::LemmyContext;
let data = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
// Make sure user is an admin
is_admin(&local_user_view)?;
let unread_only = data.unread_only;
- let verified_email_only = blocking(context.pool(), Site::read_local)
- .await??
- .require_email_verification;
+ let verified_email_only = local_site.require_email_verification;
let page = data.page;
let limit = data.limit;
site::{GetUnreadRegistrationApplicationCount, GetUnreadRegistrationApplicationCountResponse},
utils::{blocking, get_local_user_view_from_jwt, is_admin},
};
-use lemmy_db_schema::source::site::Site;
+use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_db_views::structs::RegistrationApplicationView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_websocket::LemmyContext;
let data = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
// Only let admins do this
is_admin(&local_user_view)?;
- let verified_email_only = blocking(context.pool(), Site::read_local)
- .await??
- .require_email_verification;
+ let verified_email_only = local_site.require_email_verification;
let registration_applications = blocking(context.pool(), move |conn| {
RegistrationApplicationView::get_unread_count(conn, verified_email_only)
utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
use lemmy_apub::fetcher::search::{search_query_to_object_id, SearchableObjects};
-use lemmy_db_schema::{newtypes::PersonId, utils::DbPool};
+use lemmy_db_schema::{newtypes::PersonId, source::local_site::LocalSite, utils::DbPool};
use lemmy_db_views::structs::{CommentView, PostView};
use lemmy_db_views_actor::structs::{CommunityView, PersonViewSafe};
use lemmy_utils::{error::LemmyError, ConnectionId};
let local_user_view =
get_local_user_view_from_jwt_opt(self.auth.as_ref(), context.pool(), context.secret())
.await?;
- check_private_instance(&local_user_view, context.pool()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
+ check_private_instance(&local_user_view, &local_site)?;
let res = search_query_to_object_id(&self.q, local_user_view.is_none(), context)
.await
};
use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
use lemmy_db_schema::{
- source::community::Community,
+ source::{community::Community, local_site::LocalSite},
traits::DeleteableOrRemoveable,
utils::post_to_comment_sort_type,
SearchType,
let local_user_view =
get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
- check_private_instance(&local_user_view, context.pool()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
+
+ check_private_instance(&local_user_view, &local_site)?;
let person_id = local_user_view.as_ref().map(|u| u.person.id);
let local_user = local_user_view.map(|l| l.local_user);
encoding = { version = "0.2.33", optional = true }
reqwest-middleware = { version = "0.1.6", optional = true }
webpage = { version = "1.4.0", default-features = false, features = ["serde"], optional = true }
+regex = "1.6.0"
[dev-dependencies]
actix-rt = { version = "2.7.0", default-features = false }
pub application_email_admins: Option<bool>,
pub auth: Sensitive<String>,
pub hide_modlog_mod_names: Option<bool>,
+ pub legal_information: Option<String>,
+ pub slur_filter_regex: Option<String>,
+ pub actor_name_max_length: Option<i32>,
+ pub rate_limit_message: Option<i32>,
+ pub rate_limit_message_per_second: Option<i32>,
+ pub rate_limit_post: Option<i32>,
+ pub rate_limit_post_per_second: Option<i32>,
+ pub rate_limit_register: Option<i32>,
+ pub rate_limit_register_per_second: Option<i32>,
+ pub rate_limit_image: Option<i32>,
+ pub rate_limit_image_per_second: Option<i32>,
+ pub rate_limit_comment: Option<i32>,
+ pub rate_limit_comment_per_second: Option<i32>,
+ pub rate_limit_search: Option<i32>,
+ pub rate_limit_search_per_second: Option<i32>,
+ pub federation_enabled: Option<bool>,
+ pub federation_debug: Option<bool>,
+ pub federation_strict_allowlist: Option<bool>,
+ pub federation_http_fetch_retry_limit: Option<i32>,
+ pub federation_worker_count: Option<i32>,
+ pub captcha_enabled: Option<bool>,
+ pub captcha_difficulty: Option<String>,
+ pub allowed_instances: Option<Vec<String>>,
+ pub blocked_instances: Option<Vec<String>>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub application_email_admins: Option<bool>,
pub hide_modlog_mod_names: Option<bool>,
pub discussion_languages: Option<Vec<LanguageId>>,
+ pub slur_filter_regex: Option<String>,
+ pub actor_name_max_length: Option<i32>,
+ pub rate_limit_message: Option<i32>,
+ pub rate_limit_message_per_second: Option<i32>,
+ pub rate_limit_post: Option<i32>,
+ pub rate_limit_post_per_second: Option<i32>,
+ pub rate_limit_register: Option<i32>,
+ pub rate_limit_register_per_second: Option<i32>,
+ pub rate_limit_image: Option<i32>,
+ pub rate_limit_image_per_second: Option<i32>,
+ pub rate_limit_comment: Option<i32>,
+ pub rate_limit_comment_per_second: Option<i32>,
+ pub rate_limit_search: Option<i32>,
+ pub rate_limit_search_per_second: Option<i32>,
+ pub federation_enabled: Option<bool>,
+ pub federation_debug: Option<bool>,
+ pub federation_strict_allowlist: Option<bool>,
+ pub federation_http_fetch_retry_limit: Option<i32>,
+ pub federation_worker_count: Option<i32>,
+ pub captcha_enabled: Option<bool>,
+ pub captcha_difficulty: Option<String>,
+ pub allowed_instances: Option<Vec<String>>,
+ pub blocked_instances: Option<Vec<String>>,
pub auth: Sensitive<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GetSiteResponse {
- pub site_view: Option<SiteView>, // Because the site might not be set up yet
+ pub site_view: SiteView,
pub admins: Vec<PersonViewSafe>,
pub online: usize,
pub version: String,
impls::person::is_banned,
newtypes::{CommunityId, LocalUserId, PersonId, PostId},
source::{
- comment::Comment,
- community::Community,
+ comment::{Comment, CommentUpdateForm},
+ community::{Community, CommunityUpdateForm},
email_verification::{EmailVerification, EmailVerificationForm},
+ instance::Instance,
+ local_site::LocalSite,
+ local_site_rate_limit::LocalSiteRateLimit,
password_reset_request::PasswordResetRequest,
- person::Person,
+ person::{Person, PersonUpdateForm},
person_block::PersonBlock,
post::{Post, PostRead, PostReadForm},
registration_application::RegistrationApplication,
secret::Secret,
- site::Site,
},
traits::{Crud, Readable},
utils::DbPool,
claims::Claims,
email::{send_email, translations::Lang},
error::LemmyError,
+ rate_limit::RateLimitConfig,
settings::structs::Settings,
- utils::generate_random_string,
+ utils::{build_slur_regex, generate_random_string},
};
+use regex::Regex;
use reqwest_middleware::ClientWithMiddleware;
use rosetta_i18n::{Language, LanguageId};
use std::str::FromStr;
}
#[tracing::instrument(skip_all)]
-pub async fn check_downvotes_enabled(score: i16, pool: &DbPool) -> Result<(), LemmyError> {
- if score == -1 {
- let site = blocking(pool, Site::read_local).await??;
- if !site.enable_downvotes {
- return Err(LemmyError::from_message("downvotes_disabled"));
- }
+pub fn check_downvotes_enabled(score: i16, local_site: &LocalSite) -> Result<(), LemmyError> {
+ if score == -1 && !local_site.enable_downvotes {
+ return Err(LemmyError::from_message("downvotes_disabled"));
}
Ok(())
}
#[tracing::instrument(skip_all)]
-pub async fn check_private_instance(
+pub fn check_private_instance(
local_user_view: &Option<LocalUserView>,
- pool: &DbPool,
+ local_site: &LocalSite,
) -> Result<(), LemmyError> {
- if local_user_view.is_none() {
- let site = blocking(pool, Site::read_local).await?;
-
- // The site might not be set up yet
- if let Ok(site) = site {
- if site.private_instance {
- return Err(LemmyError::from_message("instance_is_private"));
- }
- }
+ if local_user_view.is_none() && local_site.private_instance {
+ return Err(LemmyError::from_message("instance_is_private"));
}
Ok(())
}
#[tracing::instrument(skip_all)]
pub async fn build_federated_instances(
+ local_site: &LocalSite,
pool: &DbPool,
- settings: &Settings,
) -> Result<Option<FederatedInstances>, LemmyError> {
- let federation_config = &settings.federation;
- let hostname = &settings.hostname;
- let federation = federation_config.to_owned();
- if federation.enabled {
- let distinct_communities = blocking(pool, move |conn| {
- Community::distinct_federated_communities(conn)
- })
- .await??;
-
- let allowed = federation.allowed_instances;
- let blocked = federation.blocked_instances;
+ if local_site.federation_enabled {
+ // TODO I hate that this requires 3 queries
+ let linked = blocking(pool, Instance::linked).await??;
+ let allowed = blocking(pool, Instance::allowlist).await??;
+ let blocked = blocking(pool, Instance::blocklist).await??;
- let mut linked = distinct_communities
- .iter()
- .map(|actor_id| Ok(actor_id.host_str().unwrap_or("").to_string()))
- .collect::<Result<Vec<String>, LemmyError>>()?;
-
- if let Some(allowed) = allowed.as_ref() {
- linked.extend_from_slice(allowed);
- }
-
- if let Some(blocked) = blocked.as_ref() {
- linked.retain(|a| !blocked.contains(a) && !a.eq(hostname));
- }
-
- // Sort and remove dupes
- linked.sort_unstable();
- linked.dedup();
+ // These can return empty vectors, so convert them to options
+ let allowed = (!allowed.is_empty()).then(|| allowed);
+ let blocked = (!blocked.is_empty()).then(|| blocked);
Ok(Some(FederatedInstances {
linked,
})
}
+pub fn local_site_rate_limit_to_rate_limit_config(
+ local_site_rate_limit: &LocalSiteRateLimit,
+) -> RateLimitConfig {
+ let l = local_site_rate_limit;
+ RateLimitConfig {
+ message: l.message,
+ message_per_second: l.message_per_second,
+ post: l.post,
+ post_per_second: l.post_per_second,
+ register: l.register,
+ register_per_second: l.register_per_second,
+ image: l.image,
+ image_per_second: l.image_per_second,
+ comment: l.comment,
+ comment_per_second: l.comment_per_second,
+ search: l.search,
+ search_per_second: l.search_per_second,
+ }
+}
+
+pub fn local_site_to_slur_regex(local_site: &LocalSite) -> Option<Regex> {
+ build_slur_regex(local_site.slur_filter_regex.as_deref())
+}
+
+pub fn local_site_opt_to_slur_regex(local_site: &Option<LocalSite>) -> Option<Regex> {
+ local_site
+ .as_ref()
+ .map(local_site_to_slur_regex)
+ .unwrap_or(None)
+}
+
pub fn send_application_approved_email(
user: &LocalUserView,
settings: &Settings,
}
pub async fn check_registration_application(
- site: &Site,
local_user_view: &LocalUserView,
+ local_site: &LocalSite,
pool: &DbPool,
) -> Result<(), LemmyError> {
- if site.require_application
+ if local_site.require_application
&& !local_user_view.local_user.accepted_application
&& !local_user_view.person.admin
{
Ok(())
}
-/// TODO this check should be removed after https://github.com/LemmyNet/lemmy/issues/868 is done.
-pub async fn check_private_instance_and_federation_enabled(
- pool: &DbPool,
- settings: &Settings,
+pub fn check_private_instance_and_federation_enabled(
+ local_site: &LocalSite,
) -> Result<(), LemmyError> {
- let site_opt = blocking(pool, Site::read_local).await?;
-
- if let Ok(site) = site_opt {
- if site.private_instance && settings.federation.enabled {
- return Err(LemmyError::from_message(
- "Cannot have both private instance and federation enabled.",
- ));
- }
+ if local_site.private_instance && local_site.federation_enabled {
+ return Err(LemmyError::from_message(
+ "Cannot have both private instance and federation enabled.",
+ ));
}
Ok(())
}
// Update the fields to None
blocking(pool, move |conn| {
- Person::remove_avatar_and_banner(conn, banned_person_id)
+ Person::update(
+ conn,
+ banned_person_id,
+ &PersonUpdateForm::builder()
+ .avatar(Some(None))
+ .banner(Some(None))
+ .build(),
+ )
})
.await??;
for first_mod_community in banned_user_first_communities {
let community_id = first_mod_community.community.id;
- blocking(pool, move |conn: &mut _| {
- Community::update_removed(conn, community_id, true)
+ blocking(pool, move |conn| {
+ Community::update(
+ conn,
+ community_id,
+ &CommunityUpdateForm::builder().removed(Some(true)).build(),
+ )
})
.await??;
}
// Update the fields to None
blocking(pool, move |conn| {
- Community::remove_avatar_and_banner(conn, community_id)
+ Community::update(
+ conn,
+ community_id,
+ &CommunityUpdateForm::builder()
+ .icon(Some(None))
+ .banner(Some(None))
+ .build(),
+ )
})
.await??;
}
for comment_view in &comments {
let comment_id = comment_view.comment.id;
blocking(pool, move |conn| {
- Comment::update_removed(conn, comment_id, true)
+ Comment::update(
+ conn,
+ comment_id,
+ &CommentUpdateForm::builder().removed(Some(true)).build(),
+ )
})
.await??;
}
Ok(())
}
-pub async fn listing_type_with_site_default(
+pub fn listing_type_with_site_default(
listing_type: Option<ListingType>,
- pool: &DbPool,
+ local_site: &LocalSite,
) -> Result<ListingType, LemmyError> {
- Ok(match listing_type {
- Some(l) => l,
- None => {
- let site = blocking(pool, Site::read_local).await??;
- ListingType::from_str(&site.default_post_listing_type)?
- }
- })
+ Ok(listing_type.unwrap_or(ListingType::from_str(
+ &local_site.default_post_listing_type,
+ )?))
}
check_post_deleted_or_removed,
get_local_user_view_from_jwt,
get_post,
+ local_site_to_slur_regex,
},
};
use lemmy_apub::{
use lemmy_db_schema::{
source::{
actor_language::CommunityLanguage,
- comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
- comment_reply::CommentReply,
- person_mention::PersonMention,
+ comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm, CommentUpdateForm},
+ comment_reply::{CommentReply, CommentReplyUpdateForm},
+ local_site::LocalSite,
+ person_mention::{PersonMention, PersonMentionUpdateForm},
},
traits::{Crud, Likeable},
};
let data: &CreateComment = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
- let content_slurs_removed =
- remove_slurs(&data.content.to_owned(), &context.settings().slur_regex());
+ let content_slurs_removed = remove_slurs(
+ &data.content.to_owned(),
+ &local_site_to_slur_regex(&local_site),
+ );
// Check for a community ban
let post_id = data.post_id;
})
.await??;
- let comment_form = CommentForm {
- content: content_slurs_removed,
- post_id: data.post_id,
- creator_id: local_user_view.person.id,
- language_id: Some(language_id),
- ..CommentForm::default()
- };
+ let comment_form = CommentInsertForm::builder()
+ .content(content_slurs_removed.to_owned())
+ .post_id(data.post_id)
+ .creator_id(local_user_view.person.id)
+ .language_id(Some(language_id))
+ .build();
// Create the comment
let comment_form2 = comment_form.clone();
&inserted_comment_id.to_string(),
&protocol_and_hostname,
)?;
- Ok(Comment::update_ap_id(conn, inserted_comment_id, apub_id)?)
+ Ok(Comment::update(
+ conn,
+ inserted_comment_id,
+ &CommentUpdateForm::builder().ap_id(Some(apub_id)).build(),
+ )?)
})
.await?
.map_err(|e| e.with_message("couldnt_create_comment"))?;
// Scan the comment for user mentions, add those rows
let post_id = post.id;
- let mentions = scrape_text_for_mentions(&comment_form.content);
+ let mentions = scrape_text_for_mentions(&content_slurs_removed);
let recipient_ids = send_local_notifs(
mentions,
&updated_comment,
.await?;
if let Ok(reply) = comment_reply {
blocking(context.pool(), move |conn| {
- CommentReply::update_read(conn, reply.id, true)
+ CommentReply::update(conn, reply.id, &CommentReplyUpdateForm { read: Some(true) })
})
.await?
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_replies"))?;
.await?;
if let Ok(mention) = person_mention {
blocking(context.pool(), move |conn| {
- PersonMention::update_read(conn, mention.id, true)
+ PersonMention::update(
+ conn,
+ mention.id,
+ &PersonMentionUpdateForm { read: Some(true) },
+ )
})
.await?
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_person_mentions"))?;
};
use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
use lemmy_db_schema::{
- source::{comment::Comment, community::Community, post::Post},
+ source::{
+ comment::{Comment, CommentUpdateForm},
+ community::Community,
+ post::Post,
+ },
traits::Crud,
};
use lemmy_db_views::structs::CommentView;
// Do the delete
let deleted = data.deleted;
let updated_comment = blocking(context.pool(), move |conn| {
- Comment::update_deleted(conn, comment_id, deleted)
+ Comment::update(
+ conn,
+ comment_id,
+ &CommentUpdateForm::builder().deleted(Some(deleted)).build(),
+ )
})
.await?
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
};
use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
use lemmy_db_schema::{
- source::{comment::Comment, community::Community},
+ source::{comment::Comment, community::Community, local_site::LocalSite},
traits::{Crud, DeleteableOrRemoveable},
};
use lemmy_db_views::comment_view::CommentQuery;
let local_user_view =
get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
- check_private_instance(&local_user_view, context.pool()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
+ check_private_instance(&local_user_view, &local_site)?;
let community_id = data.community_id;
- let listing_type = listing_type_with_site_default(data.type_, context.pool()).await?;
+ let listing_type = listing_type_with_site_default(data.type_, &local_site)?;
let community_actor_id = if let Some(name) = &data.community_name {
resolve_actor_identifier::<ApubCommunity, Community>(name, context, true)
comment::{CommentResponse, GetComment},
utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
+use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_db_views::structs::CommentView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_websocket::LemmyContext;
let local_user_view =
get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
- check_private_instance(&local_user_view, context.pool()).await?;
+ check_private_instance(&local_user_view, &local_site)?;
let person_id = local_user_view.map(|u| u.person.id);
let id = data.id;
use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
use lemmy_db_schema::{
source::{
- comment::Comment,
+ comment::{Comment, CommentUpdateForm},
community::Community,
moderator::{ModRemoveComment, ModRemoveCommentForm},
post::Post,
// Do the remove
let removed = data.removed;
let updated_comment = blocking(context.pool(), move |conn| {
- Comment::update_removed(conn, comment_id, removed)
+ Comment::update(
+ conn,
+ comment_id,
+ &CommentUpdateForm::builder().removed(Some(removed)).build(),
+ )
})
.await?
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
check_post_deleted_or_removed,
get_local_user_view_from_jwt,
is_mod_or_admin,
+ local_site_to_slur_regex,
},
};
use lemmy_apub::protocol::activities::{
use lemmy_db_schema::{
source::{
actor_language::CommunityLanguage,
- comment::{Comment, CommentForm},
+ comment::{Comment, CommentUpdateForm},
+ local_site::LocalSite,
},
traits::Crud,
};
let data: &EditComment = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
let comment_id = data.comment_id;
let orig_comment = blocking(context.pool(), move |conn| {
let content_slurs_removed = data
.content
.as_ref()
- .map(|c| remove_slurs(c, &context.settings().slur_regex()));
+ .map(|c| remove_slurs(c, &local_site_to_slur_regex(&local_site)));
let comment_id = data.comment_id;
- let form = CommentForm {
- creator_id: orig_comment.comment.creator_id,
- post_id: orig_comment.comment.post_id,
- content: content_slurs_removed.unwrap_or(orig_comment.comment.content),
- distinguished: data.distinguished,
- language_id: data.language_id,
- ..Default::default()
- };
+ let form = CommentUpdateForm::builder()
+ .content(content_slurs_removed)
+ .distinguished(data.distinguished)
+ .language_id(data.language_id)
+ .build();
let updated_comment = blocking(context.pool(), move |conn| {
Comment::update(conn, comment_id, &form)
})
use actix_web::web::Data;
use lemmy_api_common::{
community::{CommunityResponse, CreateCommunity},
- utils::{blocking, get_local_user_view_from_jwt, is_admin},
+ utils::{blocking, get_local_user_view_from_jwt, is_admin, local_site_to_slur_regex},
};
use lemmy_apub::{
generate_followers_url,
EndpointType,
};
use lemmy_db_schema::{
- source::{
- community::{
- Community,
- CommunityFollower,
- CommunityFollowerForm,
- CommunityForm,
- CommunityModerator,
- CommunityModeratorForm,
- },
- site::Site,
+ source::community::{
+ Community,
+ CommunityFollower,
+ CommunityFollowerForm,
+ CommunityInsertForm,
+ CommunityModerator,
+ CommunityModeratorForm,
},
traits::{Crud, Followable, Joinable},
- utils::{diesel_option_overwrite, diesel_option_overwrite_to_url},
+ utils::diesel_option_overwrite_to_url_create,
};
+use lemmy_db_views::structs::SiteView;
use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{
error::LemmyError,
let data: &CreateCommunity = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let site_view = blocking(context.pool(), SiteView::read_local).await??;
+ let local_site = site_view.local_site;
- let local_site = blocking(context.pool(), Site::read_local).await??;
if local_site.community_creation_admin_only && is_admin(&local_user_view).is_err() {
return Err(LemmyError::from_message(
"only_admins_can_create_communities",
}
// Check to make sure the icon and banners are urls
- let icon = diesel_option_overwrite_to_url(&data.icon)?;
- let banner = diesel_option_overwrite_to_url(&data.banner)?;
- let description = diesel_option_overwrite(&data.description);
+ let icon = diesel_option_overwrite_to_url_create(&data.icon)?;
+ let banner = diesel_option_overwrite_to_url_create(&data.banner)?;
- check_slurs(&data.name, &context.settings().slur_regex())?;
- check_slurs(&data.title, &context.settings().slur_regex())?;
- check_slurs_opt(&data.description, &context.settings().slur_regex())?;
+ let slur_regex = local_site_to_slur_regex(&local_site);
+ check_slurs(&data.name, &slur_regex)?;
+ check_slurs(&data.title, &slur_regex)?;
+ check_slurs_opt(&data.description, &slur_regex)?;
- if !is_valid_actor_name(&data.name, context.settings().actor_name_max_length) {
+ if !is_valid_actor_name(&data.name, local_site.actor_name_max_length as usize) {
return Err(LemmyError::from_message("invalid_community_name"));
}
// When you create a community, make sure the user becomes a moderator and a follower
let keypair = generate_actor_keypair()?;
- let community_form = CommunityForm {
- name: data.name.to_owned(),
- title: data.title.to_owned(),
- description,
- icon,
- banner,
- nsfw: data.nsfw,
- actor_id: Some(community_actor_id.to_owned()),
- private_key: Some(Some(keypair.private_key)),
- public_key: Some(keypair.public_key),
- followers_url: Some(generate_followers_url(&community_actor_id)?),
- inbox_url: Some(generate_inbox_url(&community_actor_id)?),
- shared_inbox_url: Some(Some(generate_shared_inbox_url(&community_actor_id)?)),
- posting_restricted_to_mods: data.posting_restricted_to_mods,
- ..CommunityForm::default()
- };
+ let community_form = CommunityInsertForm::builder()
+ .name(data.name.to_owned())
+ .title(data.title.to_owned())
+ .description(data.description.to_owned())
+ .icon(icon)
+ .banner(banner)
+ .nsfw(data.nsfw)
+ .actor_id(Some(community_actor_id.to_owned()))
+ .private_key(Some(keypair.private_key))
+ .public_key(keypair.public_key)
+ .followers_url(Some(generate_followers_url(&community_actor_id)?))
+ .inbox_url(Some(generate_inbox_url(&community_actor_id)?))
+ .shared_inbox_url(Some(generate_shared_inbox_url(&community_actor_id)?))
+ .posting_restricted_to_mods(data.posting_restricted_to_mods)
+ .instance_id(site_view.site.instance_id)
+ .build();
let inserted_community = blocking(context.pool(), move |conn| {
Community::create(conn, &community_form)
utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
-use lemmy_db_schema::source::community::Community;
+use lemmy_db_schema::{
+ source::community::{Community, CommunityUpdateForm},
+ traits::Crud,
+};
use lemmy_db_views_actor::structs::CommunityModeratorView;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
let community_id = data.community_id;
let deleted = data.deleted;
let updated_community = blocking(context.pool(), move |conn| {
- Community::update_deleted(conn, community_id, deleted)
+ Community::update(
+ conn,
+ community_id,
+ &CommunityUpdateForm::builder()
+ .deleted(Some(deleted))
+ .build(),
+ )
})
.await?
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_community"))?;
community::{ListCommunities, ListCommunitiesResponse},
utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
-use lemmy_db_schema::traits::DeleteableOrRemoveable;
+use lemmy_db_schema::{source::local_site::LocalSite, traits::DeleteableOrRemoveable};
use lemmy_db_views_actor::community_view::CommunityQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_websocket::LemmyContext;
let local_user_view =
get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
- check_private_instance(&local_user_view, context.pool()).await?;
+ check_private_instance(&local_user_view, &local_site)?;
let person_id = local_user_view.to_owned().map(|l| l.person.id);
};
use lemmy_db_schema::{
impls::actor_language::default_post_language,
- source::{actor_language::CommunityLanguage, community::Community, site::Site},
+ source::{
+ actor_language::CommunityLanguage,
+ community::Community,
+ local_site::LocalSite,
+ site::Site,
+ },
traits::DeleteableOrRemoveable,
};
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
let local_user_view =
get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
if data.name.is_none() && data.id.is_none() {
return Err(LemmyError::from_message("no_id_given"));
}
- check_private_instance(&local_user_view, context.pool()).await?;
+ check_private_instance(&local_user_view, &local_site)?;
let person_id = local_user_view.as_ref().map(|u| u.person.id);
use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
use lemmy_db_schema::{
source::{
- community::Community,
+ community::{Community, CommunityUpdateForm},
moderator::{ModRemoveCommunity, ModRemoveCommunityForm},
},
traits::Crud,
let community_id = data.community_id;
let removed = data.removed;
let updated_community = blocking(context.pool(), move |conn| {
- Community::update_removed(conn, community_id, removed)
+ Community::update(
+ conn,
+ community_id,
+ &CommunityUpdateForm::builder()
+ .removed(Some(removed))
+ .build(),
+ )
})
.await?
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_community"))?;
use actix_web::web::Data;
use lemmy_api_common::{
community::{CommunityResponse, EditCommunity},
- utils::{blocking, get_local_user_view_from_jwt},
+ utils::{blocking, get_local_user_view_from_jwt, local_site_to_slur_regex},
};
use lemmy_apub::protocol::activities::community::update::UpdateCommunity;
use lemmy_db_schema::{
newtypes::{LanguageId, PersonId},
source::{
actor_language::{CommunityLanguage, SiteLanguage},
- community::{Community, CommunityForm},
+ community::{Community, CommunityUpdateForm},
+ local_site::LocalSite,
},
traits::Crud,
- utils::{diesel_option_overwrite, diesel_option_overwrite_to_url, naive_now},
+ utils::{diesel_option_overwrite, diesel_option_overwrite_to_url},
};
use lemmy_db_views_actor::structs::CommunityModeratorView;
use lemmy_utils::{error::LemmyError, utils::check_slurs_opt, ConnectionId};
let data: &EditCommunity = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
let icon = diesel_option_overwrite_to_url(&data.icon)?;
let banner = diesel_option_overwrite_to_url(&data.banner)?;
let description = diesel_option_overwrite(&data.description);
- check_slurs_opt(&data.title, &context.settings().slur_regex())?;
- check_slurs_opt(&data.description, &context.settings().slur_regex())?;
+ let slur_regex = local_site_to_slur_regex(&local_site);
+ check_slurs_opt(&data.title, &slur_regex)?;
+ check_slurs_opt(&data.description, &slur_regex)?;
// Verify its a mod (only mods can edit it)
let community_id = data.community_id;
.await??;
}
- let read_community = blocking(context.pool(), move |conn| {
- Community::read(conn, community_id)
- })
- .await??;
-
- let community_form = CommunityForm {
- name: read_community.name,
- title: data.title.to_owned().unwrap_or(read_community.title),
- description,
- icon,
- banner,
- nsfw: data.nsfw,
- posting_restricted_to_mods: data.posting_restricted_to_mods,
- updated: Some(naive_now()),
- ..CommunityForm::default()
- };
+ let community_form = CommunityUpdateForm::builder()
+ .title(data.title.to_owned())
+ .description(description)
+ .icon(icon)
+ .banner(banner)
+ .nsfw(data.nsfw)
+ .posting_restricted_to_mods(data.posting_restricted_to_mods)
+ .build();
let community_id = data.community_id;
let updated_community = blocking(context.pool(), move |conn| {
check_community_deleted_or_removed,
get_local_user_view_from_jwt,
honeypot_check,
+ local_site_to_slur_regex,
mark_post_as_read,
},
};
source::{
actor_language::CommunityLanguage,
community::Community,
- post::{Post, PostForm, PostLike, PostLikeForm},
+ local_site::LocalSite,
+ post::{Post, PostInsertForm, PostLike, PostLikeForm, PostUpdateForm},
},
traits::{Crud, Likeable},
- utils::diesel_option_overwrite,
};
use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{
let data: &CreatePost = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
- let slur_regex = &context.settings().slur_regex();
- check_slurs(&data.name, slur_regex)?;
- check_slurs_opt(&data.body, slur_regex)?;
+ let slur_regex = local_site_to_slur_regex(&local_site);
+ check_slurs(&data.name, &slur_regex)?;
+ check_slurs_opt(&data.body, &slur_regex)?;
honeypot_check(&data.honeypot)?;
let data_url = data.url.as_ref();
- let url = Some(data_url.map(clean_url_params).map(Into::into)); // TODO no good way to handle a "clear"
- let body = diesel_option_overwrite(&data.body);
+ let url = data_url.map(clean_url_params).map(Into::into); // TODO no good way to handle a "clear"
if !is_valid_post_title(&data.name) {
return Err(LemmyError::from_message("invalid_post_title"));
let (metadata_res, thumbnail_url) =
fetch_site_data(context.client(), context.settings(), data_url).await;
let (embed_title, embed_description, embed_video_url) = metadata_res
- .map(|u| (Some(u.title), Some(u.description), Some(u.embed_video_url)))
+ .map(|u| (u.title, u.description, u.embed_video_url))
.unwrap_or_default();
let language_id = match data.language_id {
})
.await??;
- let post_form = PostForm {
- name: data.name.trim().to_owned(),
- url,
- body,
- community_id: data.community_id,
- creator_id: local_user_view.person.id,
- nsfw: data.nsfw,
- embed_title,
- embed_description,
- embed_video_url,
- language_id,
- thumbnail_url: Some(thumbnail_url),
- ..PostForm::default()
- };
+ let post_form = PostInsertForm::builder()
+ .name(data.name.trim().to_owned())
+ .url(url)
+ .body(data.body.to_owned())
+ .community_id(data.community_id)
+ .creator_id(local_user_view.person.id)
+ .nsfw(data.nsfw)
+ .embed_title(embed_title)
+ .embed_description(embed_description)
+ .embed_video_url(embed_video_url)
+ .language_id(language_id)
+ .thumbnail_url(thumbnail_url)
+ .build();
let inserted_post =
match blocking(context.pool(), move |conn| Post::create(conn, &post_form)).await? {
&inserted_post_id.to_string(),
&protocol_and_hostname,
)?;
- Ok(Post::update_ap_id(conn, inserted_post_id, apub_id)?)
+ Ok(Post::update(
+ conn,
+ inserted_post_id,
+ &PostUpdateForm::builder().ap_id(Some(apub_id)).build(),
+ )?)
})
.await?
.map_err(|e| e.with_message("couldnt_create_post"))?;
};
use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
use lemmy_db_schema::{
- source::{community::Community, post::Post},
+ source::{
+ community::Community,
+ post::{Post, PostUpdateForm},
+ },
traits::Crud,
};
use lemmy_utils::{error::LemmyError, ConnectionId};
let post_id = data.post_id;
let deleted = data.deleted;
let updated_post = blocking(context.pool(), move |conn| {
- Post::update_deleted(conn, post_id, deleted)
+ Post::update(
+ conn,
+ post_id,
+ &PostUpdateForm::builder().deleted(Some(deleted)).build(),
+ )
})
.await??;
},
};
use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
-use lemmy_db_schema::{source::community::Community, traits::DeleteableOrRemoveable};
+use lemmy_db_schema::{
+ source::{community::Community, local_site::LocalSite},
+ traits::DeleteableOrRemoveable,
+};
use lemmy_db_views::post_view::PostQuery;
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_websocket::LemmyContext;
let local_user_view =
get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
- check_private_instance(&local_user_view, context.pool()).await?;
+ check_private_instance(&local_user_view, &local_site)?;
let is_logged_in = local_user_view.is_some();
let sort = data.sort;
- let listing_type = listing_type_with_site_default(data.type_, context.pool()).await?;
+ let listing_type = listing_type_with_site_default(data.type_, &local_site)?;
let page = data.page;
let limit = data.limit;
};
use lemmy_db_schema::{
aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm},
- source::comment::Comment,
+ source::{comment::Comment, local_site::LocalSite},
traits::{Crud, DeleteableOrRemoveable},
};
use lemmy_db_views::structs::PostView;
let local_user_view =
get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
- check_private_instance(&local_user_view, context.pool()).await?;
+ check_private_instance(&local_user_view, &local_site)?;
let person_id = local_user_view.map(|u| u.person.id);
source::{
community::Community,
moderator::{ModRemovePost, ModRemovePostForm},
- post::Post,
+ post::{Post, PostUpdateForm},
},
traits::Crud,
};
let post_id = data.post_id;
let removed = data.removed;
let updated_post = blocking(context.pool(), move |conn| {
- Post::update_removed(conn, post_id, removed)
+ Post::update(
+ conn,
+ post_id,
+ &PostUpdateForm::builder().removed(Some(removed)).build(),
+ )
})
.await??;
check_community_ban,
check_community_deleted_or_removed,
get_local_user_view_from_jwt,
+ local_site_to_slur_regex,
},
};
use lemmy_apub::protocol::activities::{
use lemmy_db_schema::{
source::{
actor_language::CommunityLanguage,
- post::{Post, PostForm},
+ local_site::LocalSite,
+ post::{Post, PostUpdateForm},
},
traits::Crud,
- utils::{diesel_option_overwrite, naive_now},
+ utils::diesel_option_overwrite,
};
use lemmy_utils::{
error::LemmyError,
let data: &EditPost = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
let data_url = data.url.as_ref();
let url = Some(data_url.map(clean_url_params).map(Into::into));
let body = diesel_option_overwrite(&data.body);
- let slur_regex = &context.settings().slur_regex();
- check_slurs_opt(&data.name, slur_regex)?;
- check_slurs_opt(&data.body, slur_regex)?;
+ let slur_regex = local_site_to_slur_regex(&local_site);
+ check_slurs_opt(&data.name, &slur_regex)?;
+ check_slurs_opt(&data.body, &slur_regex)?;
if let Some(name) = &data.name {
if !is_valid_post_title(name) {
})
.await??;
- let post_form = PostForm {
- creator_id: orig_post.creator_id.to_owned(),
- community_id: orig_post.community_id,
- name: data.name.to_owned().unwrap_or(orig_post.name),
- url,
- body,
- nsfw: data.nsfw,
- updated: Some(naive_now()),
- embed_title,
- embed_description,
- embed_video_url,
- language_id: data.language_id,
- thumbnail_url: Some(thumbnail_url),
- ..PostForm::default()
- };
+ let post_form = PostUpdateForm::builder()
+ .name(data.name.to_owned())
+ .url(url)
+ .body(body)
+ .nsfw(data.nsfw)
+ .embed_title(embed_title)
+ .embed_description(embed_description)
+ .embed_video_url(embed_video_url)
+ .language_id(data.language_id)
+ .thumbnail_url(Some(thumbnail_url))
+ .build();
let post_id = data.post_id;
let res = blocking(context.pool(), move |conn| {
check_person_block,
get_interface_language,
get_local_user_view_from_jwt,
+ local_site_to_slur_regex,
send_email_to_user,
},
};
EndpointType,
};
use lemmy_db_schema::{
- source::private_message::{PrivateMessage, PrivateMessageForm},
+ source::{
+ local_site::LocalSite,
+ private_message::{PrivateMessage, PrivateMessageInsertForm, PrivateMessageUpdateForm},
+ },
traits::Crud,
};
use lemmy_db_views::structs::LocalUserView;
let data: &CreatePrivateMessage = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
- let content_slurs_removed =
- remove_slurs(&data.content.to_owned(), &context.settings().slur_regex());
+ let content_slurs_removed = remove_slurs(
+ &data.content.to_owned(),
+ &local_site_to_slur_regex(&local_site),
+ );
check_person_block(local_user_view.person.id, data.recipient_id, context.pool()).await?;
- let private_message_form = PrivateMessageForm {
- content: content_slurs_removed.to_owned(),
- creator_id: local_user_view.person.id,
- recipient_id: data.recipient_id,
- ..PrivateMessageForm::default()
- };
+ let private_message_form = PrivateMessageInsertForm::builder()
+ .content(content_slurs_removed.to_owned())
+ .creator_id(local_user_view.person.id)
+ .recipient_id(data.recipient_id)
+ .build();
let inserted_private_message = match blocking(context.pool(), move |conn| {
PrivateMessage::create(conn, &private_message_form)
&inserted_private_message_id.to_string(),
&protocol_and_hostname,
)?;
- Ok(PrivateMessage::update_ap_id(
+ Ok(PrivateMessage::update(
conn,
- inserted_private_message_id,
- apub_id,
+ inserted_private_message.id,
+ &PrivateMessageUpdateForm::builder()
+ .ap_id(Some(apub_id))
+ .build(),
)?)
},
)
utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_apub::activities::deletion::send_apub_delete_private_message;
-use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud};
+use lemmy_db_schema::{
+ source::private_message::{PrivateMessage, PrivateMessageUpdateForm},
+ traits::Crud,
+};
use lemmy_utils::{error::LemmyError, ConnectionId};
use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
let private_message_id = data.private_message_id;
let deleted = data.deleted;
let updated_private_message = blocking(context.pool(), move |conn| {
- PrivateMessage::update_deleted(conn, private_message_id, deleted)
+ PrivateMessage::update(
+ conn,
+ private_message_id,
+ &PrivateMessageUpdateForm::builder()
+ .deleted(Some(deleted))
+ .build(),
+ )
})
.await?
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_private_message"))?;
use actix_web::web::Data;
use lemmy_api_common::{
private_message::{EditPrivateMessage, PrivateMessageResponse},
- utils::{blocking, get_local_user_view_from_jwt},
+ utils::{blocking, get_local_user_view_from_jwt, local_site_to_slur_regex},
};
use lemmy_apub::protocol::activities::{
create_or_update::private_message::CreateOrUpdatePrivateMessage,
CreateOrUpdateType,
};
-use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud};
+use lemmy_db_schema::{
+ source::{
+ local_site::LocalSite,
+ private_message::{PrivateMessage, PrivateMessageUpdateForm},
+ },
+ traits::Crud,
+ utils::naive_now,
+};
use lemmy_utils::{error::LemmyError, utils::remove_slurs, ConnectionId};
use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
let data: &EditPrivateMessage = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
// Checking permissions
let private_message_id = data.private_message_id;
}
// Doing the update
- let content_slurs_removed = remove_slurs(&data.content, &context.settings().slur_regex());
+ let content_slurs_removed = remove_slurs(&data.content, &local_site_to_slur_regex(&local_site));
let private_message_id = data.private_message_id;
let updated_private_message = blocking(context.pool(), move |conn| {
- PrivateMessage::update_content(conn, private_message_id, &content_slurs_removed)
+ PrivateMessage::update(
+ conn,
+ private_message_id,
+ &PrivateMessageUpdateForm::builder()
+ .content(Some(content_slurs_removed))
+ .updated(Some(Some(naive_now())))
+ .build(),
+ )
})
.await?
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_private_message"))?;
use actix_web::web::Data;
use lemmy_api_common::{
site::{CreateSite, SiteResponse},
- utils::{blocking, get_local_user_view_from_jwt, is_admin, site_description_length_check},
+ utils::{
+ blocking,
+ get_local_user_view_from_jwt,
+ is_admin,
+ local_site_to_slur_regex,
+ site_description_length_check,
+ },
};
use lemmy_apub::generate_site_inbox_url;
use lemmy_db_schema::{
newtypes::DbUrl,
- source::site::{Site, SiteForm},
+ source::{
+ local_site::{LocalSite, LocalSiteUpdateForm},
+ local_site_rate_limit::{LocalSiteRateLimit, LocalSiteRateLimitUpdateForm},
+ site::{Site, SiteUpdateForm},
+ },
traits::Crud,
utils::{diesel_option_overwrite, diesel_option_overwrite_to_url, naive_now},
};
use lemmy_db_views::structs::SiteView;
use lemmy_utils::{
error::LemmyError,
- utils::{check_slurs, check_slurs_opt},
+ utils::{check_application_question, check_slurs, check_slurs_opt},
ConnectionId,
};
use lemmy_websocket::LemmyContext;
) -> Result<SiteResponse, LemmyError> {
let data: &CreateSite = self;
- let read_site = Site::read_local;
- if blocking(context.pool(), read_site).await?.is_ok() {
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
+
+ if local_site.site_setup {
return Err(LemmyError::from_message("site_already_exists"));
};
let icon = diesel_option_overwrite_to_url(&data.icon)?;
let banner = diesel_option_overwrite_to_url(&data.banner)?;
- check_slurs(&data.name, &context.settings().slur_regex())?;
- check_slurs_opt(&data.description, &context.settings().slur_regex())?;
+ let slur_regex = local_site_to_slur_regex(&local_site);
+ check_slurs(&data.name, &slur_regex)?;
+ check_slurs_opt(&data.description, &slur_regex)?;
// Make sure user is an admin
is_admin(&local_user_view)?;
site_description_length_check(desc)?;
}
+ let application_question = diesel_option_overwrite(&data.application_question);
+ check_application_question(&application_question, &data.require_application)?;
+
let actor_id: DbUrl = Url::parse(&context.settings().get_protocol_and_hostname())?.into();
let inbox_url = Some(generate_site_inbox_url(&actor_id)?);
let keypair = generate_actor_keypair()?;
- let site_form = SiteForm {
- name: data.name.to_owned(),
- sidebar,
- description,
- icon,
- banner,
- enable_downvotes: data.enable_downvotes,
- open_registration: data.open_registration,
- enable_nsfw: data.enable_nsfw,
- community_creation_admin_only: data.community_creation_admin_only,
- actor_id: Some(actor_id),
- last_refreshed_at: Some(naive_now()),
- inbox_url,
- private_key: Some(Some(keypair.private_key)),
- public_key: Some(keypair.public_key),
- default_theme: data.default_theme.clone(),
- default_post_listing_type: data.default_post_listing_type.clone(),
- application_email_admins: data.application_email_admins,
- hide_modlog_mod_names: data.hide_modlog_mod_names,
- ..SiteForm::default()
- };
+ let site_form = SiteUpdateForm::builder()
+ .name(Some(data.name.to_owned()))
+ .sidebar(sidebar)
+ .description(description)
+ .icon(icon)
+ .banner(banner)
+ .actor_id(Some(actor_id))
+ .last_refreshed_at(Some(naive_now()))
+ .inbox_url(inbox_url)
+ .private_key(Some(Some(keypair.private_key)))
+ .public_key(Some(keypair.public_key))
+ .build();
+
+ let site_id = local_site.site_id;
+ blocking(context.pool(), move |conn| {
+ Site::update(conn, site_id, &site_form)
+ })
+ .await??;
+
+ let local_site_form = LocalSiteUpdateForm::builder()
+ // Set the site setup to true
+ .site_setup(Some(true))
+ .enable_downvotes(data.enable_downvotes)
+ .open_registration(data.open_registration)
+ .enable_nsfw(data.enable_nsfw)
+ .community_creation_admin_only(data.community_creation_admin_only)
+ .require_email_verification(data.require_email_verification)
+ .require_application(data.require_application)
+ .application_question(application_question)
+ .private_instance(data.private_instance)
+ .default_theme(data.default_theme.clone())
+ .default_post_listing_type(data.default_post_listing_type.clone())
+ .legal_information(diesel_option_overwrite(&data.legal_information))
+ .application_email_admins(data.application_email_admins)
+ .hide_modlog_mod_names(data.hide_modlog_mod_names)
+ .updated(Some(Some(naive_now())))
+ .slur_filter_regex(diesel_option_overwrite(&data.slur_filter_regex))
+ .actor_name_max_length(data.actor_name_max_length)
+ .federation_enabled(data.federation_enabled)
+ .federation_debug(data.federation_debug)
+ .federation_strict_allowlist(data.federation_strict_allowlist)
+ .federation_http_fetch_retry_limit(data.federation_http_fetch_retry_limit)
+ .federation_worker_count(data.federation_worker_count)
+ .captcha_enabled(data.captcha_enabled)
+ .captcha_difficulty(data.captcha_difficulty.to_owned())
+ .build();
+ blocking(context.pool(), move |conn| {
+ LocalSite::update(conn, &local_site_form)
+ })
+ .await??;
+
+ let local_site_rate_limit_form = LocalSiteRateLimitUpdateForm::builder()
+ .message(data.rate_limit_message)
+ .message_per_second(data.rate_limit_message_per_second)
+ .post(data.rate_limit_post)
+ .post_per_second(data.rate_limit_post_per_second)
+ .register(data.rate_limit_register)
+ .register_per_second(data.rate_limit_register_per_second)
+ .image(data.rate_limit_image)
+ .image_per_second(data.rate_limit_image_per_second)
+ .comment(data.rate_limit_comment)
+ .comment_per_second(data.rate_limit_comment_per_second)
+ .search(data.rate_limit_search)
+ .search_per_second(data.rate_limit_search_per_second)
+ .build();
- let create_site = move |conn: &mut _| Site::create(conn, &site_form);
- blocking(context.pool(), create_site)
- .await?
- .map_err(|e| LemmyError::from_error_message(e, "site_already_exists"))?;
+ blocking(context.pool(), move |conn| {
+ LocalSiteRateLimit::update(conn, &local_site_rate_limit_form)
+ })
+ .await??;
let site_view = blocking(context.pool(), SiteView::read_local).await??;
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- person::Register,
- site::{CreateSite, GetSite, GetSiteResponse, MyUserInfo},
+ site::{GetSite, GetSiteResponse, MyUserInfo},
utils::{blocking, build_federated_instances, get_local_user_settings_view_from_jwt_opt},
};
use lemmy_db_schema::source::{actor_language::SiteLanguage, language::Language};
};
use lemmy_utils::{error::LemmyError, version, ConnectionId};
use lemmy_websocket::{messages::GetUsersOnline, LemmyContext};
-use tracing::info;
#[async_trait::async_trait(?Send)]
impl PerformCrud for GetSite {
type Response = GetSiteResponse;
- #[tracing::instrument(skip(context, websocket_id))]
+ #[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
- websocket_id: Option<ConnectionId>,
+ _websocket_id: Option<ConnectionId>,
) -> Result<GetSiteResponse, LemmyError> {
let data: &GetSite = self;
- let site_view = match blocking(context.pool(), SiteView::read_local).await? {
- Ok(site_view) => Some(site_view),
- // If the site isn't created yet, check the setup
- Err(_) => {
- if let Some(setup) = context.settings().setup.as_ref() {
- let register = Register {
- username: setup.admin_username.to_owned(),
- email: setup.admin_email.clone().map(|s| s.into()),
- password: setup.admin_password.clone().into(),
- password_verify: setup.admin_password.clone().into(),
- show_nsfw: true,
- captcha_uuid: None,
- captcha_answer: None,
- honeypot: None,
- answer: None,
- };
- let admin_jwt = register
- .perform(context, websocket_id)
- .await?
- .jwt
- .expect("jwt is returned from registration on newly created site");
- info!("Admin {} created", setup.admin_username);
-
- let create_site = CreateSite {
- name: setup.site_name.to_owned(),
- auth: admin_jwt,
- ..CreateSite::default()
- };
- create_site.perform(context, websocket_id).await?;
- info!("Site {} created", setup.site_name);
- Some(blocking(context.pool(), SiteView::read_local).await??)
- } else {
- None
- }
- }
- };
+ let site_view = blocking(context.pool(), SiteView::read_local).await??;
let admins = blocking(context.pool(), PersonViewSafe::admins).await??;
None
};
- let federated_instances = build_federated_instances(context.pool(), context.settings()).await?;
+ let federated_instances =
+ build_federated_instances(&site_view.local_site, context.pool()).await?;
let all_languages = blocking(context.pool(), Language::read_all).await??;
let discussion_languages = blocking(context.pool(), SiteLanguage::read_local).await??;
use actix_web::web::Data;
use lemmy_api_common::{
site::{EditSite, SiteResponse},
- utils::{blocking, get_local_user_view_from_jwt, is_admin, site_description_length_check},
+ utils::{
+ blocking,
+ get_local_user_view_from_jwt,
+ is_admin,
+ local_site_to_slur_regex,
+ site_description_length_check,
+ },
};
use lemmy_db_schema::{
source::{
actor_language::SiteLanguage,
+ federation_allowlist::FederationAllowList,
+ federation_blocklist::FederationBlockList,
+ local_site::{LocalSite, LocalSiteUpdateForm},
+ local_site_rate_limit::{LocalSiteRateLimit, LocalSiteRateLimitUpdateForm},
local_user::LocalUser,
- site::{Site, SiteForm},
+ site::{Site, SiteUpdateForm},
},
traits::Crud,
utils::{diesel_option_overwrite, diesel_option_overwrite_to_url, naive_now},
ListingType,
};
use lemmy_db_views::structs::SiteView;
-use lemmy_utils::{error::LemmyError, utils::check_slurs_opt, ConnectionId};
+use lemmy_utils::{
+ error::LemmyError,
+ utils::{check_application_question, check_slurs_opt},
+ ConnectionId,
+};
use lemmy_websocket::{messages::SendAllMessage, LemmyContext, UserOperationCrud};
-use std::{default::Default, str::FromStr};
+use std::str::FromStr;
#[async_trait::async_trait(?Send)]
impl PerformCrud for EditSite {
let data: &EditSite = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
// Make sure user is an admin
is_admin(&local_user_view)?;
- let local_site = blocking(context.pool(), Site::read_local).await??;
-
- let sidebar = diesel_option_overwrite(&data.sidebar);
- let description = diesel_option_overwrite(&data.description);
- let application_question = diesel_option_overwrite(&data.application_question);
- let legal_information = diesel_option_overwrite(&data.legal_information);
- let icon = diesel_option_overwrite_to_url(&data.icon)?;
- let banner = diesel_option_overwrite_to_url(&data.banner)?;
+ let slur_regex = local_site_to_slur_regex(&local_site);
- check_slurs_opt(&data.name, &context.settings().slur_regex())?;
- check_slurs_opt(&data.description, &context.settings().slur_regex())?;
+ check_slurs_opt(&data.name, &slur_regex)?;
+ check_slurs_opt(&data.description, &slur_regex)?;
- if let Some(Some(desc)) = &description {
+ if let Some(desc) = &data.description {
site_description_length_check(desc)?;
}
- // Make sure if applications are required, that there is an application questionnaire
- if data.require_application.unwrap_or(false)
- && application_question.as_ref().unwrap_or(&None).is_none()
- {
- return Err(LemmyError::from_message("application_question_required"));
- }
+ let application_question = diesel_option_overwrite(&data.application_question);
+ check_application_question(&application_question, &data.require_application)?;
if let Some(default_post_listing_type) = &data.default_post_listing_type {
// only allow all or local as default listing types
}
}
- let site_id = local_site.id;
+ let site_id = local_site.site_id;
if let Some(discussion_languages) = data.discussion_languages.clone() {
blocking(context.pool(), move |conn| {
SiteLanguage::update(conn, discussion_languages.clone(), site_id)
.await??;
}
- let site_form = SiteForm {
- name: data.name.to_owned().unwrap_or(local_site.name),
- sidebar,
- description,
- icon,
- banner,
- updated: Some(naive_now()),
- enable_downvotes: data.enable_downvotes,
- open_registration: data.open_registration,
- enable_nsfw: data.enable_nsfw,
- community_creation_admin_only: data.community_creation_admin_only,
- require_email_verification: data.require_email_verification,
- require_application: data.require_application,
- application_question,
- private_instance: data.private_instance,
- default_theme: data.default_theme.clone(),
- default_post_listing_type: data.default_post_listing_type.clone(),
- legal_information,
- application_email_admins: data.application_email_admins,
- hide_modlog_mod_names: data.hide_modlog_mod_names,
- ..SiteForm::default()
- };
-
- let update_site = blocking(context.pool(), move |conn| {
- Site::update(conn, local_site.id, &site_form)
+ let name = data.name.to_owned();
+ let site_form = SiteUpdateForm::builder()
+ .name(name)
+ .sidebar(diesel_option_overwrite(&data.sidebar))
+ .description(diesel_option_overwrite(&data.description))
+ .icon(diesel_option_overwrite_to_url(&data.icon)?)
+ .banner(diesel_option_overwrite_to_url(&data.banner)?)
+ .updated(Some(Some(naive_now())))
+ .build();
+
+ blocking(context.pool(), move |conn| {
+ Site::update(conn, site_id, &site_form)
+ })
+ .await
+ // Ignore errors for all these, so as to not throw errors if no update occurs
+ // Diesel will throw an error for empty update forms
+ .ok();
+
+ let local_site_form = LocalSiteUpdateForm::builder()
+ .enable_downvotes(data.enable_downvotes)
+ .open_registration(data.open_registration)
+ .enable_nsfw(data.enable_nsfw)
+ .community_creation_admin_only(data.community_creation_admin_only)
+ .require_email_verification(data.require_email_verification)
+ .require_application(data.require_application)
+ .application_question(application_question)
+ .private_instance(data.private_instance)
+ .default_theme(data.default_theme.clone())
+ .default_post_listing_type(data.default_post_listing_type.clone())
+ .legal_information(diesel_option_overwrite(&data.legal_information))
+ .application_email_admins(data.application_email_admins)
+ .hide_modlog_mod_names(data.hide_modlog_mod_names)
+ .updated(Some(Some(naive_now())))
+ .slur_filter_regex(diesel_option_overwrite(&data.slur_filter_regex))
+ .actor_name_max_length(data.actor_name_max_length)
+ .federation_enabled(data.federation_enabled)
+ .federation_debug(data.federation_debug)
+ .federation_strict_allowlist(data.federation_strict_allowlist)
+ .federation_http_fetch_retry_limit(data.federation_http_fetch_retry_limit)
+ .federation_worker_count(data.federation_worker_count)
+ .captcha_enabled(data.captcha_enabled)
+ .captcha_difficulty(data.captcha_difficulty.to_owned())
+ .build();
+
+ let update_local_site = blocking(context.pool(), move |conn| {
+ LocalSite::update(conn, &local_site_form)
})
- .await?
- .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_site"))?;
+ .await
+ .ok();
+
+ let local_site_rate_limit_form = LocalSiteRateLimitUpdateForm::builder()
+ .message(data.rate_limit_message)
+ .message_per_second(data.rate_limit_message_per_second)
+ .post(data.rate_limit_post)
+ .post_per_second(data.rate_limit_post_per_second)
+ .register(data.rate_limit_register)
+ .register_per_second(data.rate_limit_register_per_second)
+ .image(data.rate_limit_image)
+ .image_per_second(data.rate_limit_image_per_second)
+ .comment(data.rate_limit_comment)
+ .comment_per_second(data.rate_limit_comment_per_second)
+ .search(data.rate_limit_search)
+ .search_per_second(data.rate_limit_search_per_second)
+ .build();
+
+ blocking(context.pool(), move |conn| {
+ LocalSiteRateLimit::update(conn, &local_site_rate_limit_form)
+ })
+ .await
+ .ok();
+
+ // Replace the blocked and allowed instances
+ let allowed = data.allowed_instances.to_owned();
+ blocking(context.pool(), move |conn| {
+ FederationAllowList::replace(conn, allowed)
+ })
+ .await??;
+ let blocked = data.blocked_instances.to_owned();
+ blocking(context.pool(), move |conn| {
+ FederationBlockList::replace(conn, blocked)
+ })
+ .await??;
// TODO can't think of a better way to do this.
// If the server suddenly requires email verification, or required applications, no old users
// will be able to log in. It really only wants this to be a requirement for NEW signups.
// So if it was set from false, to true, you need to update all current users columns to be verified.
- if !local_site.require_application && update_site.require_application {
+ let new_require_application = update_local_site
+ .as_ref()
+ .map(|ols| {
+ ols
+ .as_ref()
+ .map(|ls| ls.require_application)
+ .unwrap_or(false)
+ })
+ .unwrap_or(false);
+ if !local_site.require_application && new_require_application {
blocking(context.pool(), move |conn| {
LocalUser::set_all_users_registration_applications_accepted(conn)
})
.map_err(|e| LemmyError::from_error_message(e, "couldnt_set_all_registrations_accepted"))?;
}
- if !local_site.require_email_verification && update_site.require_email_verification {
+ let new_require_email_verification = update_local_site
+ .as_ref()
+ .map(|ols| {
+ ols
+ .as_ref()
+ .map(|ls| ls.require_email_verification)
+ .unwrap_or(false)
+ })
+ .unwrap_or(false);
+ if !local_site.require_email_verification && new_require_email_verification {
blocking(context.pool(), move |conn| {
LocalUser::set_all_users_email_verified(conn)
})
utils::{
blocking,
honeypot_check,
+ local_site_to_slur_regex,
password_length_check,
send_new_applicant_email_to_admins,
send_verification_email,
use lemmy_db_schema::{
aggregates::structs::PersonAggregates,
source::{
- local_user::{LocalUser, LocalUserForm},
- person::{Person, PersonForm},
- registration_application::{RegistrationApplication, RegistrationApplicationForm},
- site::Site,
+ local_user::{LocalUser, LocalUserInsertForm},
+ person::{Person, PersonInsertForm},
+ registration_application::{RegistrationApplication, RegistrationApplicationInsertForm},
},
traits::Crud,
};
-use lemmy_db_views::structs::LocalUserView;
+use lemmy_db_views::structs::{LocalUserView, SiteView};
use lemmy_db_views_actor::structs::PersonViewSafe;
use lemmy_utils::{
claims::Claims,
) -> Result<LoginResponse, LemmyError> {
let data: &Register = self;
- // no email verification, or applications if the site is not setup yet
- let (mut email_verification, mut require_application) = (false, false);
+ let site_view = blocking(context.pool(), SiteView::read_local).await??;
+ let local_site = site_view.local_site;
- // Make sure site has open registration
- let site = blocking(context.pool(), Site::read_local).await?;
- if let Ok(site) = &site {
- if !site.open_registration {
- return Err(LemmyError::from_message("registration_closed"));
- }
- email_verification = site.require_email_verification;
- require_application = site.require_application;
+ if !local_site.open_registration {
+ return Err(LemmyError::from_message("registration_closed"));
}
password_length_check(&data.password)?;
honeypot_check(&data.honeypot)?;
- if email_verification && data.email.is_none() {
+ if local_site.require_email_verification && data.email.is_none() {
return Err(LemmyError::from_message("email_required"));
}
- if require_application && data.answer.is_none() {
+ if local_site.require_application && data.answer.is_none() {
return Err(LemmyError::from_message(
"registration_application_answer_required",
));
.await??;
// If its not the admin, check the captcha
- if !no_admins && context.settings().captcha.enabled {
+ if !no_admins && local_site.captcha_enabled {
let check = context
.chat_server()
.send(CheckCaptcha {
}
}
- let slur_regex = &context.settings().slur_regex();
- check_slurs(&data.username, slur_regex)?;
- check_slurs_opt(&data.answer, slur_regex)?;
+ let slur_regex = local_site_to_slur_regex(&local_site);
+ check_slurs(&data.username, &slur_regex)?;
+ check_slurs_opt(&data.answer, &slur_regex)?;
let actor_keypair = generate_actor_keypair()?;
- if !is_valid_actor_name(&data.username, context.settings().actor_name_max_length) {
+ if !is_valid_actor_name(&data.username, local_site.actor_name_max_length as usize) {
return Err(LemmyError::from_message("invalid_username"));
}
let actor_id = generate_local_apub_endpoint(
// We have to create both a person, and local_user
// Register the new person
- let person_form = PersonForm {
- name: data.username.to_owned(),
- actor_id: Some(actor_id.clone()),
- private_key: Some(Some(actor_keypair.private_key)),
- public_key: Some(actor_keypair.public_key),
- inbox_url: Some(generate_inbox_url(&actor_id)?),
- shared_inbox_url: Some(Some(generate_shared_inbox_url(&actor_id)?)),
- admin: Some(no_admins),
- ..PersonForm::default()
- };
+ let person_form = PersonInsertForm::builder()
+ .name(data.username.to_owned())
+ .actor_id(Some(actor_id.clone()))
+ .private_key(Some(actor_keypair.private_key))
+ .public_key(actor_keypair.public_key)
+ .inbox_url(Some(generate_inbox_url(&actor_id)?))
+ .shared_inbox_url(Some(generate_shared_inbox_url(&actor_id)?))
+ .admin(Some(no_admins))
+ .instance_id(site_view.site.instance_id)
+ .build();
// insert the person
let inserted_person = blocking(context.pool(), move |conn| {
.map_err(|e| LemmyError::from_error_message(e, "user_already_exists"))?;
// Create the local user
- let local_user_form = LocalUserForm {
- person_id: Some(inserted_person.id),
- email: Some(data.email.as_deref().map(|s| s.to_lowercase())),
- password_encrypted: Some(data.password.to_string()),
- show_nsfw: Some(data.show_nsfw),
- email_verified: Some(false),
- ..LocalUserForm::default()
- };
+ let local_user_form = LocalUserInsertForm::builder()
+ .person_id(inserted_person.id)
+ .email(data.email.as_deref().map(|s| s.to_lowercase()))
+ .password_encrypted(data.password.to_string())
+ .show_nsfw(Some(data.show_nsfw))
+ .build();
let inserted_local_user = match blocking(context.pool(), move |conn| {
- LocalUser::register(conn, &local_user_form)
+ LocalUser::create(conn, &local_user_form)
})
.await?
{
}
};
- if require_application {
+ if local_site.require_application {
// Create the registration application
- let form = RegistrationApplicationForm {
- local_user_id: Some(inserted_local_user.id),
+ let form = RegistrationApplicationInsertForm {
+ local_user_id: inserted_local_user.id,
// We already made sure answer was not null above
- answer: data.answer.to_owned(),
- ..RegistrationApplicationForm::default()
+ answer: data.answer.to_owned().expect("must have an answer"),
};
blocking(context.pool(), move |conn| {
}
// Email the admins
- if site.map(|s| s.application_email_admins).unwrap_or(false) {
+ if local_site.application_email_admins {
send_new_applicant_email_to_admins(&data.username, context.pool(), context.settings())
.await?;
}
};
// Log the user in directly if email verification and application aren't required
- if !require_application && !email_verification {
+ if !local_site.require_application && !local_site.require_email_verification {
login_response.jwt = Some(
Claims::jwt(
inserted_local_user.id.0,
.into(),
);
} else {
- if email_verification {
+ if local_site.require_email_verification {
let local_user_view = LocalUserView {
local_user: inserted_local_user,
person: inserted_person,
.email
.clone()
.expect("email was provided");
+
send_verification_email(&local_user_view, &email, context.pool(), context.settings())
.await?;
login_response.verify_email_sent = true;
}
- if require_application {
+ if local_site.require_application {
login_response.registration_created = true;
}
}
utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
use lemmy_apub::{fetcher::resolve_actor_identifier, objects::person::ApubPerson};
-use lemmy_db_schema::{source::person::Person, utils::post_to_comment_sort_type};
+use lemmy_db_schema::{
+ source::{local_site::LocalSite, person::Person},
+ utils::post_to_comment_sort_type,
+};
use lemmy_db_views::{comment_view::CommentQuery, post_view::PostQuery};
use lemmy_db_views_actor::structs::{CommunityModeratorView, PersonViewSafe};
use lemmy_utils::{error::LemmyError, ConnectionId};
let local_user_view =
get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
- check_private_instance(&local_user_view, context.pool()).await?;
+ let local_site = blocking(context.pool(), LocalSite::read).await??;
+
+ check_private_instance(&local_user_view, &local_site)?;
let person_details_id = match data.person_id {
Some(id) => id,
verify_person_in_community,
},
activity_lists::AnnouncableActivities,
+ check_apub_id_valid,
+ fetch_local_site_data,
local_instance,
objects::{community::ApubCommunity, instance::remote_instance_inboxes, person::ApubPerson},
protocol::activities::block::block_user::BlockUser,
CommunityPersonBanForm,
},
moderator::{ModBan, ModBanForm, ModBanFromCommunity, ModBanFromCommunityForm},
- person::Person,
+ person::{Person, PersonUpdateForm},
},
traits::{Bannable, Crud, Followable},
};
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
+
verify_is_public(&self.to, &self.cc)?;
match self
.target
match target {
SiteOrCommunity::Site(_site) => {
let blocked_person = blocking(context.pool(), move |conn| {
- Person::ban_person(conn, blocked_person.id, true, expires)
+ Person::update(
+ conn,
+ blocked_person.id,
+ &PersonUpdateForm::builder()
+ .banned(Some(true))
+ .ban_expires(Some(expires))
+ .build(),
+ )
})
.await??;
if self.remove_data.unwrap_or(false) {
verify_is_public,
},
activity_lists::AnnouncableActivities,
+ check_apub_id_valid,
+ fetch_local_site_data,
local_instance,
objects::{community::ApubCommunity, instance::remote_instance_inboxes, person::ApubPerson},
protocol::activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
source::{
community::{CommunityPersonBan, CommunityPersonBanForm},
moderator::{ModBan, ModBanForm, ModBanFromCommunity, ModBanFromCommunityForm},
- person::Person,
+ person::{Person, PersonUpdateForm},
},
traits::{Bannable, Crud},
};
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
+
verify_is_public(&self.to, &self.cc)?;
verify_domains_match(self.actor.inner(), self.object.actor.inner())?;
self.object.verify(context, request_counter).await?;
{
SiteOrCommunity::Site(_site) => {
let blocked_person = blocking(context.pool(), move |conn| {
- Person::ban_person(conn, blocked_person.id, false, expires)
+ Person::update(
+ conn,
+ blocked_person.id,
+ &PersonUpdateForm::builder()
+ .banned(Some(false))
+ .ban_expires(Some(expires))
+ .build(),
+ )
})
.await??;
verify_person_in_community,
},
activity_lists::AnnouncableActivities,
+ check_apub_id_valid,
+ fetch_local_site_data,
generate_moderators_url,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
+
verify_is_public(&self.to, &self.cc)?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
use crate::{
activities::{generate_activity_id, send_lemmy_activity, verify_is_public},
activity_lists::AnnouncableActivities,
+ check_apub_id_valid,
+ fetch_local_site_data,
insert_activity,
objects::community::ApubCommunity,
protocol::{
};
use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
use activitystreams_kinds::{activity::AnnounceType, public};
+use lemmy_api_common::utils::blocking;
use lemmy_utils::error::LemmyError;
use lemmy_websocket::LemmyContext;
use tracing::debug;
#[tracing::instrument(skip_all)]
async fn verify(
&self,
- _context: &Data<LemmyContext>,
+ context: &Data<LemmyContext>,
_request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
+
verify_is_public(&self.to, &self.cc)?;
Ok(())
}
verify_person_in_community,
},
activity_lists::AnnouncableActivities,
+ check_apub_id_valid,
+ fetch_local_site_data,
generate_moderators_url,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
+
verify_is_public(&self.to, &self.cc)?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
use crate::{
activities::{generate_activity_id, send_lemmy_activity, verify_person_in_community},
+ check_apub_id_valid,
+ fetch_local_site_data,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::activities::community::report::Report,
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
+
let community = self.to[0]
.dereference(context, local_instance(context), request_counter)
.await?;
verify_person_in_community,
},
activity_lists::AnnouncableActivities,
+ check_apub_id_valid,
+ fetch_local_site_data,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::activities::community::update::UpdateCommunity,
};
use activitystreams_kinds::{activity::UpdateType, public};
use lemmy_api_common::utils::blocking;
-use lemmy_db_schema::{
- source::community::{Community, CommunityForm},
- traits::Crud,
-};
+use lemmy_db_schema::{source::community::Community, traits::Crud};
use lemmy_utils::error::LemmyError;
use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
use url::Url;
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
verify_is_public(&self.to, &self.cc)?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
) -> Result<(), LemmyError> {
let community = self.get_community(context, request_counter).await?;
- let updated_community = self.object.into_form();
- let cf = CommunityForm {
- name: updated_community.name,
- title: updated_community.title,
- description: updated_community.description,
- nsfw: updated_community.nsfw,
- // TODO: icon and banner would be hosted on the other instance, ideally we would copy it to ours
- icon: updated_community.icon,
- banner: updated_community.banner,
- ..CommunityForm::default()
- };
+ let community_update_form = self.object.into_update_form();
+
let updated_community = blocking(context.pool(), move |conn| {
- Community::update(conn, community.id, &cf)
+ Community::update(conn, community.id, &community_update_form)
})
.await??;
verify_person_in_community,
},
activity_lists::AnnouncableActivities,
+ check_apub_id_valid,
+ fetch_local_site_data,
local_instance,
mentions::MentionOrValue,
objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson},
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
+
verify_is_public(&self.to, &self.cc)?;
let post = self.object.get_parents(context, request_counter).await?.0;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community,
},
activity_lists::AnnouncableActivities,
+ check_apub_id_valid,
+ fetch_local_site_data,
objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
protocol::activities::{create_or_update::post::CreateOrUpdatePost, CreateOrUpdateType},
ActorType,
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
verify_is_public(&self.to, &self.cc)?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
use crate::{
activities::{generate_activity_id, send_lemmy_activity, verify_person},
+ check_apub_id_valid,
+ fetch_local_site_data,
objects::{person::ApubPerson, private_message::ApubPrivateMessage},
protocol::activities::{
create_or_update::private_message::CreateOrUpdatePrivateMessage,
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
+
verify_person(&self.actor, context, request_counter).await?;
verify_domains_match(self.actor.inner(), self.object.id.inner())?;
verify_domains_match(self.to[0].inner(), self.object.to[0].inner())?;
deletion::{receive_delete_action, verify_delete_activity, DeletableObjects},
generate_activity_id,
},
+ check_apub_id_valid,
+ fetch_local_site_data,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::{activities::deletion::delete::Delete, IdOrNestedObject},
use lemmy_api_common::utils::blocking;
use lemmy_db_schema::{
source::{
- comment::Comment,
- community::Community,
+ comment::{Comment, CommentUpdateForm},
+ community::{Community, CommunityUpdateForm},
moderator::{
ModRemoveComment,
ModRemoveCommentForm,
ModRemovePost,
ModRemovePostForm,
},
- post::Post,
+ post::{Post, PostUpdateForm},
},
traits::Crud,
};
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
verify_delete_activity(self, self.summary.is_some(), context, request_counter).await?;
Ok(())
}
})
.await??;
let deleted_community = blocking(context.pool(), move |conn| {
- Community::update_removed(conn, community.id, true)
+ Community::update(
+ conn,
+ community.id,
+ &CommunityUpdateForm::builder().removed(Some(true)).build(),
+ )
})
.await??;
})
.await??;
let removed_post = blocking(context.pool(), move |conn| {
- Post::update_removed(conn, post.id, true)
+ Post::update(
+ conn,
+ post.id,
+ &PostUpdateForm::builder().removed(Some(true)).build(),
+ )
})
.await??;
})
.await??;
let removed_comment = blocking(context.pool(), move |conn| {
- Comment::update_removed(conn, comment.id, true)
+ Comment::update(
+ conn,
+ comment.id,
+ &CommentUpdateForm::builder().removed(Some(true)).build(),
+ )
})
.await??;
use crate::{
activities::{generate_activity_id, send_lemmy_activity, verify_is_public, verify_person},
+ check_apub_id_valid,
+ fetch_local_site_data,
local_instance,
objects::{instance::remote_instance_inboxes, person::ApubPerson},
protocol::activities::deletion::delete_user::DeleteUser,
utils::verify_urls_match,
};
use activitystreams_kinds::{activity::DeleteType, public};
-use lemmy_api_common::utils::delete_user_account;
+use lemmy_api_common::utils::{blocking, delete_user_account};
use lemmy_utils::error::LemmyError;
use lemmy_websocket::LemmyContext;
use url::Url;
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
verify_is_public(&self.to, &[])?;
verify_person(&self.actor, context, request_counter).await?;
verify_urls_match(self.actor.inner(), self.object.inner())?;
use lemmy_api_common::utils::blocking;
use lemmy_db_schema::{
source::{
- comment::Comment,
- community::Community,
+ comment::{Comment, CommentUpdateForm},
+ community::{Community, CommunityUpdateForm},
person::Person,
- post::Post,
- private_message::PrivateMessage,
+ post::{Post, PostUpdateForm},
+ private_message::{PrivateMessage, PrivateMessageUpdateForm},
},
traits::Crud,
};
}
let community = blocking(context.pool(), move |conn| {
- Community::update_deleted(conn, community.id, deleted)
+ Community::update(
+ conn,
+ community.id,
+ &CommunityUpdateForm::builder()
+ .deleted(Some(deleted))
+ .build(),
+ )
})
.await??;
send_community_ws_message(
DeletableObjects::Post(post) => {
if deleted != post.deleted {
let deleted_post = blocking(context.pool(), move |conn| {
- Post::update_deleted(conn, post.id, deleted)
+ Post::update(
+ conn,
+ post.id,
+ &PostUpdateForm::builder().deleted(Some(deleted)).build(),
+ )
})
.await??;
send_post_ws_message(
DeletableObjects::Comment(comment) => {
if deleted != comment.deleted {
let deleted_comment = blocking(context.pool(), move |conn| {
- Comment::update_deleted(conn, comment.id, deleted)
+ Comment::update(
+ conn,
+ comment.id,
+ &CommentUpdateForm::builder().deleted(Some(deleted)).build(),
+ )
})
.await??;
send_comment_ws_message_simple(
}
DeletableObjects::PrivateMessage(pm) => {
let deleted_private_message = blocking(context.pool(), move |conn| {
- PrivateMessage::update_deleted(conn, pm.id, deleted)
+ PrivateMessage::update(
+ conn,
+ pm.id,
+ &PrivateMessageUpdateForm::builder()
+ .deleted(Some(deleted))
+ .build(),
+ )
})
.await??;
deletion::{receive_delete_action, verify_delete_activity, DeletableObjects},
generate_activity_id,
},
+ check_apub_id_valid,
+ fetch_local_site_data,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
use lemmy_api_common::utils::blocking;
use lemmy_db_schema::{
source::{
- comment::Comment,
- community::Community,
+ comment::{Comment, CommentUpdateForm},
+ community::{Community, CommunityUpdateForm},
moderator::{
ModRemoveComment,
ModRemoveCommentForm,
ModRemovePost,
ModRemovePostForm,
},
- post::Post,
+ post::{Post, PostUpdateForm},
},
traits::Crud,
};
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
self.object.verify(context, request_counter).await?;
verify_delete_activity(
&self.object,
})
.await??;
let deleted_community = blocking(context.pool(), move |conn| {
- Community::update_removed(conn, community.id, false)
+ Community::update(
+ conn,
+ community.id,
+ &CommunityUpdateForm::builder().removed(Some(false)).build(),
+ )
})
.await??;
send_community_ws_message(deleted_community.id, EditCommunity, None, None, context).await?;
})
.await??;
let removed_post = blocking(context.pool(), move |conn| {
- Post::update_removed(conn, post.id, false)
+ Post::update(
+ conn,
+ post.id,
+ &PostUpdateForm::builder().removed(Some(false)).build(),
+ )
})
.await??;
send_post_ws_message(removed_post.id, EditPost, None, None, context).await?;
})
.await??;
let removed_comment = blocking(context.pool(), move |conn| {
- Comment::update_removed(conn, comment.id, false)
+ Comment::update(
+ conn,
+ comment.id,
+ &CommentUpdateForm::builder().removed(Some(false)).build(),
+ )
})
.await??;
send_comment_ws_message_simple(removed_comment.id, EditComment, context).await?;
use crate::{
activities::{generate_activity_id, send_lemmy_activity},
+ check_apub_id_valid,
+ fetch_local_site_data,
local_instance,
protocol::activities::following::{accept::AcceptFollowCommunity, follow::FollowCommunity},
ActorType,
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
+
verify_urls_match(self.actor.inner(), self.object.object.inner())?;
self.object.verify(context, request_counter).await?;
Ok(())
verify_person,
verify_person_in_community,
},
+ check_apub_id_valid,
+ fetch_local_site_data,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::activities::following::{accept::AcceptFollowCommunity, follow::FollowCommunity},
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
verify_person(&self.actor, context, request_counter).await?;
let community = self
.object
use crate::{
activities::{generate_activity_id, send_lemmy_activity, verify_person},
+ check_apub_id_valid,
+ fetch_local_site_data,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::activities::following::{follow::FollowCommunity, undo_follow::UndoFollowCommunity},
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
verify_urls_match(self.actor.inner(), self.object.actor.inner())?;
verify_person(&self.actor, context, request_counter).await?;
self.object.verify(context, request_counter).await?;
use activitystreams_kinds::public;
use anyhow::anyhow;
use lemmy_api_common::utils::blocking;
-use lemmy_db_schema::{newtypes::CommunityId, source::community::Community};
+use lemmy_db_schema::{
+ newtypes::CommunityId,
+ source::{community::Community, local_site::LocalSite},
+};
use lemmy_db_views_actor::structs::{CommunityPersonBanView, CommunityView};
use lemmy_utils::error::LemmyError;
use lemmy_websocket::LemmyContext;
ActorT: Actor + ActorType,
Activity: ActivityHandler<Error = LemmyError>,
{
- if !context.settings().federation.enabled {
+ let federation_enabled = blocking(context.pool(), &LocalSite::read)
+ .await?
+ .map(|l| l.federation_enabled)
+ .unwrap_or(false);
+ if !federation_enabled {
return Ok(());
}
+
info!("Sending activity {}", activity.id().to_string());
let activity = WithContext::new(activity, CONTEXT.deref().clone());
voting::{undo_vote_comment, undo_vote_post},
},
activity_lists::AnnouncableActivities,
+ check_apub_id_valid,
+ fetch_local_site_data,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::activities::voting::{
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
verify_urls_match(self.actor.inner(), self.object.actor.inner())?;
voting::{vote_comment, vote_post},
},
activity_lists::AnnouncableActivities,
+ check_apub_id_valid,
+ fetch_local_site_data,
local_instance,
objects::{community::ApubCommunity, person::ApubPerson},
protocol::activities::voting::vote::{Vote, VoteType},
use lemmy_api_common::utils::blocking;
use lemmy_db_schema::{
newtypes::CommunityId,
- source::{community::Community, post::Post, site::Site},
+ source::{community::Community, local_site::LocalSite, post::Post},
traits::Crud,
};
use lemmy_utils::error::LemmyError;
context: &Data<LemmyContext>,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ check_apub_id_valid(self.id(), &local_site_data, context.settings())
+ .map_err(LemmyError::from_message)?;
let community = self.get_community(context, request_counter).await?;
verify_person_in_community(&self.actor, &community, context, request_counter).await?;
- let site = blocking(context.pool(), Site::read_local).await??;
- if self.kind == VoteType::Dislike && !site.enable_downvotes {
+ let enable_downvotes = blocking(context.pool(), LocalSite::read)
+ .await?
+ .map(|l| l.enable_downvotes)
+ .unwrap_or(true);
+ if self.kind == VoteType::Dislike && !enable_downvotes {
return Err(anyhow!("Downvotes disabled").into());
}
Ok(())
use lemmy_db_schema::{
source::{
community::Community,
- person::{Person, PersonForm},
+ instance::Instance,
+ person::{Person, PersonInsertForm},
site::Site,
},
traits::Crud,
let community = parse_lemmy_community(&context).await;
let community_id = community.id;
- let old_mod = PersonForm {
- name: "holly".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let old_mod = PersonInsertForm::builder()
+ .name("holly".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
+
let old_mod = Person::create(conn, &old_mod).unwrap();
let community_moderator_form = CommunityModeratorForm {
community_id: community.id,
Person::delete(conn, new_mod.id).unwrap();
Community::delete(conn, community_context.0.id).unwrap();
Site::delete(conn, site.id).unwrap();
+ Instance::delete(conn, inserted_instance.id).unwrap();
}
}
use activitypub_federation::{core::object_id::ObjectId, traits::ApubObject};
use anyhow::anyhow;
use itertools::Itertools;
-use lemmy_db_schema::newtypes::DbUrl;
+use lemmy_api_common::utils::blocking;
+use lemmy_db_schema::{newtypes::DbUrl, source::local_site::LocalSite};
use lemmy_utils::error::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
);
debug!("Fetching webfinger url: {}", &fetch_url);
+ let local_site = blocking(context.pool(), LocalSite::read).await?;
+ let http_fetch_retry_limit = local_site
+ .as_ref()
+ .map(|l| l.federation_http_fetch_retry_limit)
+ .unwrap_or(25);
+
*request_counter += 1;
- if *request_counter > context.settings().federation.http_fetch_retry_limit {
+ if *request_counter > http_fetch_retry_limit {
return Err(LemmyError::from_message("Request retry limit reached"));
}
web,
};
use http_signature_normalization_actix::digest::middleware::VerifyDigest;
-use lemmy_utils::settings::structs::Settings;
use sha2::{Digest, Sha256};
-pub fn config(cfg: &mut web::ServiceConfig, settings: &Settings) {
- if settings.federation.enabled {
- println!("federation enabled, host is {}", settings.hostname);
+pub fn config(cfg: &mut web::ServiceConfig) {
+ cfg
+ .route("/", web::get().to(get_apub_site_http))
+ .route("/site_outbox", web::get().to(get_apub_site_outbox))
+ .route(
+ "/c/{community_name}",
+ web::get().to(get_apub_community_http),
+ )
+ .route(
+ "/c/{community_name}/followers",
+ web::get().to(get_apub_community_followers),
+ )
+ .route(
+ "/c/{community_name}/outbox",
+ web::get().to(get_apub_community_outbox),
+ )
+ .route(
+ "/c/{community_name}/moderators",
+ web::get().to(get_apub_community_moderators),
+ )
+ .route("/u/{user_name}", web::get().to(get_apub_person_http))
+ .route(
+ "/u/{user_name}/outbox",
+ web::get().to(get_apub_person_outbox),
+ )
+ .route("/post/{post_id}", web::get().to(get_apub_post))
+ .route("/comment/{comment_id}", web::get().to(get_apub_comment))
+ .route("/activities/{type_}/{id}", web::get().to(get_activity));
- cfg
- .route("/", web::get().to(get_apub_site_http))
- .route("/site_outbox", web::get().to(get_apub_site_outbox))
- .route(
- "/c/{community_name}",
- web::get().to(get_apub_community_http),
- )
- .route(
- "/c/{community_name}/followers",
- web::get().to(get_apub_community_followers),
- )
- .route(
- "/c/{community_name}/outbox",
- web::get().to(get_apub_community_outbox),
- )
- .route(
- "/c/{community_name}/moderators",
- web::get().to(get_apub_community_moderators),
- )
- .route("/u/{user_name}", web::get().to(get_apub_person_http))
- .route(
- "/u/{user_name}/outbox",
- web::get().to(get_apub_person_outbox),
- )
- .route("/post/{post_id}", web::get().to(get_apub_post))
- .route("/comment/{comment_id}", web::get().to(get_apub_comment))
- .route("/activities/{type_}/{id}", web::get().to(get_activity));
-
- cfg.service(
- web::scope("")
- .wrap(VerifyDigest::new(Sha256::new()))
- .guard(InboxRequestGuard)
- .route("/c/{community_name}/inbox", web::post().to(community_inbox))
- .route("/u/{user_name}/inbox", web::post().to(person_inbox))
- .route("/inbox", web::post().to(shared_inbox))
- .route("/site_inbox", web::post().to(get_apub_site_inbox)),
- );
- }
+ cfg.service(
+ web::scope("")
+ .wrap(VerifyDigest::new(Sha256::new()))
+ .guard(InboxRequestGuard)
+ .route("/c/{community_name}/inbox", web::post().to(community_inbox))
+ .route("/u/{user_name}/inbox", web::post().to(person_inbox))
+ .route("/inbox", web::post().to(shared_inbox))
+ .route("/site_inbox", web::post().to(get_apub_site_inbox)),
+ );
}
/// Without this, things like webfinger or RSS feeds stop working, as all requests seem to get
use activitypub_federation::{deser::context::WithContext, traits::ApubObject};
use actix_web::{web, HttpRequest, HttpResponse};
use lemmy_api_common::utils::blocking;
-use lemmy_db_schema::source::site::Site;
+use lemmy_db_views::structs::SiteView;
use lemmy_utils::error::LemmyError;
use lemmy_websocket::LemmyContext;
use url::Url;
pub(crate) async fn get_apub_site_http(
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, LemmyError> {
- let site: ApubSite = blocking(context.pool(), Site::read_local).await??.into();
+ let site: ApubSite = blocking(context.pool(), SiteView::read_local)
+ .await??
+ .site
+ .into();
let apub = site.into_apub(&context).await?;
Ok(create_apub_response(&apub))
LocalInstance,
};
use anyhow::Context;
+use diesel::PgConnection;
use lemmy_api_common::utils::blocking;
-use lemmy_db_schema::{newtypes::DbUrl, source::activity::Activity, utils::DbPool};
-use lemmy_utils::{
- error::LemmyError,
- location_info,
- settings::{structs::Settings, SETTINGS},
+use lemmy_db_schema::{
+ newtypes::DbUrl,
+ source::{activity::Activity, instance::Instance, local_site::LocalSite},
+ utils::DbPool,
};
+use lemmy_utils::{error::LemmyError, location_info, settings::structs::Settings};
use lemmy_websocket::LemmyContext;
use once_cell::sync::{Lazy, OnceCell};
use url::{ParseError, Url};
});
// TODO: store this in context? but its only used in this crate, no need to expose it elsewhere
+// TODO this singleton needs to be redone to account for live data.
fn local_instance(context: &LemmyContext) -> &'static LocalInstance {
static LOCAL_INSTANCE: OnceCell<LocalInstance> = OnceCell::new();
LOCAL_INSTANCE.get_or_init(|| {
+ let conn = &mut context
+ .pool()
+ .get()
+ .expect("getting connection for LOCAL_INSTANCE init");
+ // Local site may be missing
+ let local_site = &LocalSite::read(conn);
+ let worker_count = local_site
+ .as_ref()
+ .map(|l| l.federation_worker_count)
+ .unwrap_or(64) as u64;
+ let http_fetch_retry_limit = local_site
+ .as_ref()
+ .map(|l| l.federation_http_fetch_retry_limit)
+ .unwrap_or(25);
+ let federation_debug = local_site
+ .as_ref()
+ .map(|l| l.federation_debug)
+ .unwrap_or(true);
+
let settings = InstanceSettings::builder()
- .http_fetch_retry_limit(context.settings().federation.http_fetch_retry_limit)
- .worker_count(context.settings().federation.worker_count)
- .debug(context.settings().federation.debug)
+ .http_fetch_retry_limit(http_fetch_retry_limit)
+ .worker_count(worker_count)
+ .debug(federation_debug)
// TODO No idea why, but you can't pass context.settings() to the verify_url_function closure
// without the value getting captured.
- .verify_url_function(|url| check_apub_id_valid(url, &SETTINGS))
.http_signature_compat(true)
.build()
.expect("configure federation");
///
/// `use_strict_allowlist` should be true only when parsing a remote community, or when parsing a
/// post/comment in a local community.
-#[tracing::instrument(skip(settings))]
-fn check_apub_id_valid(apub_id: &Url, settings: &Settings) -> Result<(), &'static str> {
+#[tracing::instrument(skip(settings, local_site_data))]
+// TODO This function needs to be called by incoming activities
+fn check_apub_id_valid(
+ apub_id: &Url,
+ local_site_data: &LocalSiteData,
+ settings: &Settings,
+) -> Result<(), &'static str> {
let domain = apub_id.domain().expect("apud id has domain").to_string();
let local_instance = settings
.get_hostname_without_port()
return Ok(());
}
- if !settings.federation.enabled {
+ if !local_site_data
+ .local_site
+ .as_ref()
+ .map(|l| l.federation_enabled)
+ .unwrap_or(true)
+ {
return Err("Federation disabled");
}
return Err("Invalid protocol scheme");
}
- if let Some(blocked) = settings.to_owned().federation.blocked_instances {
+ if let Some(blocked) = local_site_data.blocked_instances.as_ref() {
if blocked.contains(&domain) {
return Err("Domain is blocked");
}
}
- if let Some(allowed) = settings.to_owned().federation.allowed_instances {
+ if let Some(allowed) = local_site_data.allowed_instances.as_ref() {
if !allowed.contains(&domain) {
return Err("Domain is not in allowlist");
}
Ok(())
}
-#[tracing::instrument(skip(settings))]
+#[derive(Clone)]
+pub(crate) struct LocalSiteData {
+ local_site: Option<LocalSite>,
+ allowed_instances: Option<Vec<String>>,
+ blocked_instances: Option<Vec<String>>,
+}
+
+pub(crate) fn fetch_local_site_data(
+ conn: &mut PgConnection,
+) -> Result<LocalSiteData, diesel::result::Error> {
+ // LocalSite may be missing
+ let local_site = LocalSite::read(conn).ok();
+ let allowed = Instance::allowlist(conn)?;
+ let blocked = Instance::blocklist(conn)?;
+
+ // These can return empty vectors, so convert them to options
+ let allowed_instances = (!allowed.is_empty()).then(|| allowed);
+ let blocked_instances = (!blocked.is_empty()).then(|| blocked);
+
+ Ok(LocalSiteData {
+ local_site,
+ allowed_instances,
+ blocked_instances,
+ })
+}
+
+#[tracing::instrument(skip(settings, local_site_data))]
pub(crate) fn check_apub_id_valid_with_strictness(
apub_id: &Url,
is_strict: bool,
+ local_site_data: &LocalSiteData,
settings: &Settings,
) -> Result<(), LemmyError> {
- check_apub_id_valid(apub_id, settings).map_err(LemmyError::from_message)?;
+ check_apub_id_valid(apub_id, local_site_data, settings).map_err(LemmyError::from_message)?;
let domain = apub_id.domain().expect("apud id has domain").to_string();
let local_instance = settings
.get_hostname_without_port()
return Ok(());
}
- if let Some(mut allowed) = settings.to_owned().federation.allowed_instances {
+ if let Some(allowed) = local_site_data.allowed_instances.as_ref() {
// Only check allowlist if this is a community, or strict allowlist is enabled.
- let strict_allowlist = settings.to_owned().federation.strict_allowlist;
+ let strict_allowlist = local_site_data
+ .local_site
+ .as_ref()
+ .map(|l| l.federation_strict_allowlist)
+ .unwrap_or(true);
if is_strict || strict_allowlist {
// need to allow this explicitly because apub receive might contain objects from our local
// instance.
- allowed.push(local_instance);
+ let mut allowed_and_local = allowed.to_owned();
+ allowed_and_local.push(local_instance);
- if !allowed.contains(&domain) {
+ if !allowed_and_local.contains(&domain) {
return Err(LemmyError::from_message(
"Federation forbidden by strict allowlist",
));
let ap_id = ap_id.to_owned().into();
Ok(
blocking(pool, move |conn| {
- Activity::insert(conn, ap_id, activity, local, sensitive)
+ Activity::insert(conn, ap_id, activity, local, Some(sensitive))
})
.await??,
)
use crate::{
activities::{verify_is_public, verify_person_in_community},
check_apub_id_valid_with_strictness,
+ fetch_local_site_data,
local_instance,
mentions::collect_non_local_mentions,
objects::{read_from_string_or_source, verify_is_remote_object},
};
use activitystreams_kinds::{object::NoteType, public};
use chrono::NaiveDateTime;
-use lemmy_api_common::utils::blocking;
+use lemmy_api_common::utils::{blocking, local_site_opt_to_slur_regex};
use lemmy_db_schema::{
source::{
- comment::{Comment, CommentForm},
+ comment::{Comment, CommentInsertForm, CommentUpdateForm},
community::Community,
+ local_site::LocalSite,
person::Person,
post::Post,
},
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
if !self.deleted {
blocking(context.pool(), move |conn| {
- Comment::update_deleted(conn, self.id, true)
+ let form = CommentUpdateForm::builder().deleted(Some(true)).build();
+ Comment::update(conn, self.id, &form)
})
.await??;
}
Community::read(conn, community_id)
})
.await??;
- check_apub_id_valid_with_strictness(note.id.inner(), community.local, context.settings())?;
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+
+ check_apub_id_valid_with_strictness(
+ note.id.inner(),
+ community.local,
+ &local_site_data,
+ context.settings(),
+ )?;
verify_is_remote_object(note.id.inner(), context.settings())?;
verify_person_in_community(
¬e.attributed_to,
let (post, parent_comment) = note.get_parents(context, request_counter).await?;
let content = read_from_string_or_source(¬e.content, ¬e.media_type, ¬e.source);
- let content_slurs_removed = remove_slurs(&content, &context.settings().slur_regex());
+
+ let local_site = blocking(context.pool(), LocalSite::read).await?.ok();
+ let slur_regex = &local_site_opt_to_slur_regex(&local_site);
+ let content_slurs_removed = remove_slurs(&content, slur_regex);
let language_id = LanguageTag::to_language_id_single(note.language, context.pool()).await?;
- let form = CommentForm {
+ let form = CommentInsertForm {
creator_id: creator.id,
post_id: post.id,
content: content_slurs_removed,
Community::delete(conn, data.1.id).unwrap();
Person::delete(conn, data.0.id).unwrap();
Site::delete(conn, data.3.id).unwrap();
+ LocalSite::delete(conn).unwrap();
}
#[actix_rt::test]
use crate::{
check_apub_id_valid_with_strictness,
collections::{community_moderators::ApubCommunityModerators, CommunityContext},
+ fetch_local_site_data,
generate_moderators_url,
generate_outbox_url,
local_instance,
use itertools::Itertools;
use lemmy_api_common::utils::blocking;
use lemmy_db_schema::{
- source::{actor_language::CommunityLanguage, community::Community},
- traits::ApubActor,
+ source::{
+ actor_language::CommunityLanguage,
+ community::{Community, CommunityUpdateForm},
+ instance::Instance,
+ },
+ traits::{ApubActor, Crud},
};
use lemmy_db_views_actor::structs::CommunityFollowerView;
use lemmy_utils::{
#[tracing::instrument(skip_all)]
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
blocking(context.pool(), move |conn| {
- Community::update_deleted(conn, self.id, true)
+ let form = CommunityUpdateForm::builder().deleted(Some(true)).build();
+ Community::update(conn, self.id, &form)
})
.await??;
Ok(())
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<ApubCommunity, LemmyError> {
- let form = Group::into_form(group.clone());
+ let apub_id = group.id.inner().to_owned();
+ let instance = blocking(context.pool(), move |conn| {
+ Instance::create_from_actor_id(conn, &apub_id)
+ })
+ .await??;
+
+ let form = Group::into_insert_form(group.clone(), instance.id);
let languages = LanguageTag::to_language_id_multiple(group.language, context.pool()).await?;
let community: ApubCommunity = blocking(context.pool(), move |conn| {
- let community = Community::upsert(conn, &form)?;
+ let community = Community::create(conn, &form)?;
CommunityLanguage::update(conn, languages, community.id)?;
Ok::<Community, diesel::result::Error>(community)
})
) -> Result<Vec<Url>, LemmyError> {
let id = self.id;
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
let follows = blocking(context.pool(), move |conn| {
CommunityFollowerView::for_community(conn, id)
})
.unique()
.filter(|inbox: &Url| inbox.host_str() != Some(&context.settings().hostname))
// Don't send to blocked instances
- .filter(|inbox| check_apub_id_valid_with_strictness(inbox, false, context.settings()).is_ok())
+ .filter(|inbox| {
+ check_apub_id_valid_with_strictness(inbox, false, &local_site_data, context.settings())
+ .is_ok()
+ })
.collect();
Ok(inboxes)
use crate::{
check_apub_id_valid_with_strictness,
+ fetch_local_site_data,
local_instance,
objects::read_from_string_or_source_opt,
protocol::{
utils::verify_domains_match,
};
use chrono::NaiveDateTime;
-use lemmy_api_common::utils::blocking;
+use lemmy_api_common::utils::{blocking, local_site_opt_to_slur_regex};
use lemmy_db_schema::{
source::{
actor_language::SiteLanguage,
- site::{Site, SiteForm},
+ instance::Instance as DbInstance,
+ site::{Site, SiteInsertForm},
},
+ traits::Crud,
utils::{naive_now, DbPool},
};
use lemmy_utils::{
data: &Self::DataType,
_request_counter: &mut i32,
) -> Result<(), LemmyError> {
- check_apub_id_valid_with_strictness(apub.id.inner(), true, data.settings())?;
+ let local_site_data = blocking(data.pool(), fetch_local_site_data).await??;
+
+ check_apub_id_valid_with_strictness(apub.id.inner(), true, &local_site_data, data.settings())?;
verify_domains_match(expected_domain, apub.id.inner())?;
- let slur_regex = &data.settings().slur_regex();
+ let slur_regex = &local_site_opt_to_slur_regex(&local_site_data.local_site);
+
check_slurs(&apub.name, slur_regex)?;
check_slurs_opt(&apub.summary, slur_regex)?;
Ok(())
data: &Self::DataType,
_request_counter: &mut i32,
) -> Result<Self, LemmyError> {
- let site_form = SiteForm {
+ let apub_id = apub.id.inner().to_owned();
+ let instance = blocking(data.pool(), move |conn| {
+ DbInstance::create_from_actor_id(conn, &apub_id)
+ })
+ .await??;
+
+ let site_form = SiteInsertForm {
name: apub.name.clone(),
- sidebar: Some(read_from_string_or_source_opt(
- &apub.content,
- &None,
- &apub.source,
- )),
+ sidebar: read_from_string_or_source_opt(&apub.content, &None, &apub.source),
updated: apub.updated.map(|u| u.clone().naive_local()),
- icon: Some(apub.icon.clone().map(|i| i.url.into())),
- banner: Some(apub.image.clone().map(|i| i.url.into())),
- description: Some(apub.summary.clone()),
+ icon: apub.icon.clone().map(|i| i.url.into()),
+ banner: apub.image.clone().map(|i| i.url.into()),
+ description: apub.summary.clone(),
actor_id: Some(apub.id.clone().into()),
last_refreshed_at: Some(naive_now()),
inbox_url: Some(apub.inbox.clone().into()),
public_key: Some(apub.public_key.public_key_pem.clone()),
- ..SiteForm::default()
+ private_key: None,
+ instance_id: instance.id,
};
let languages = LanguageTag::to_language_id_multiple(apub.language, data.pool()).await?;
let site = blocking(data.pool(), move |conn| {
- let site = Site::upsert(conn, &site_form)?;
+ let site = Site::create(conn, &site_form)?;
SiteLanguage::update(conn, languages, site.id)?;
Ok::<Site, diesel::result::Error>(site)
})
};
use lemmy_utils::{
error::LemmyError,
- rate_limit::{rate_limiter::RateLimiter, RateLimit},
+ rate_limit::{rate_limiter::RateLimiter, RateLimit, RateLimitConfig},
settings::SETTINGS,
};
use lemmy_websocket::{chat_server::ChatServer, LemmyContext};
// call this to run migrations
establish_unpooled_connection();
let settings = SETTINGS.to_owned();
- let rate_limiter = RateLimit {
- rate_limiter: Arc::new(Mutex::new(RateLimiter::default())),
- rate_limit_config: settings.rate_limit.to_owned().unwrap_or_default(),
- };
let client = Client::builder()
.user_agent(build_user_agent(&settings))
.build()
async fn x() -> Result<String, LemmyError> {
Ok("".to_string())
}
+
+ let rate_limit_config = RateLimitConfig::builder().build();
+
+ let rate_limiter = RateLimit {
+ rate_limiter: Arc::new(Mutex::new(RateLimiter::default())),
+ rate_limit_config,
+ };
+
let chat_server = ChatServer::startup(
pool.clone(),
rate_limiter,
use crate::{
check_apub_id_valid_with_strictness,
+ fetch_local_site_data,
generate_outbox_url,
objects::{instance::fetch_instance_actor_for_object, read_from_string_or_source_opt},
protocol::{
utils::verify_domains_match,
};
use chrono::NaiveDateTime;
-use lemmy_api_common::utils::blocking;
+use lemmy_api_common::utils::{blocking, local_site_opt_to_slur_regex};
use lemmy_db_schema::{
- source::person::{Person as DbPerson, PersonForm},
- traits::ApubActor,
+ source::{
+ instance::Instance,
+ person::{Person as DbPerson, PersonInsertForm, PersonUpdateForm},
+ },
+ traits::{ApubActor, Crud},
utils::naive_now,
};
use lemmy_utils::{
#[tracing::instrument(skip_all)]
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
blocking(context.pool(), move |conn| {
- DbPerson::update_deleted(conn, self.id, true)
+ let form = PersonUpdateForm::builder().deleted(Some(true)).build();
+ DbPerson::update(conn, self.id, &form)
})
.await??;
Ok(())
context: &LemmyContext,
_request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_domains_match(person.id.inner(), expected_domain)?;
- check_apub_id_valid_with_strictness(person.id.inner(), false, context.settings())?;
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+ let slur_regex = &local_site_opt_to_slur_regex(&local_site_data.local_site);
- let slur_regex = &context.settings().slur_regex();
check_slurs(&person.preferred_username, slur_regex)?;
check_slurs_opt(&person.name, slur_regex)?;
+
+ verify_domains_match(person.id.inner(), expected_domain)?;
+ check_apub_id_valid_with_strictness(
+ person.id.inner(),
+ false,
+ &local_site_data,
+ context.settings(),
+ )?;
+
let bio = read_from_string_or_source_opt(&person.summary, &None, &person.source);
check_slurs_opt(&bio, slur_regex)?;
Ok(())
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<ApubPerson, LemmyError> {
- let person_form = PersonForm {
+ let apub_id = person.id.inner().to_owned();
+ let instance = blocking(context.pool(), move |conn| {
+ Instance::create_from_actor_id(conn, &apub_id)
+ })
+ .await??;
+
+ let person_form = PersonInsertForm {
name: person.preferred_username,
- display_name: Some(person.name),
+ display_name: person.name,
banned: None,
ban_expires: None,
deleted: None,
- avatar: Some(person.icon.map(|i| i.url.into())),
- banner: Some(person.image.map(|i| i.url.into())),
+ avatar: person.icon.map(|i| i.url.into()),
+ banner: person.image.map(|i| i.url.into()),
published: person.published.map(|u| u.naive_local()),
updated: person.updated.map(|u| u.naive_local()),
actor_id: Some(person.id.into()),
- bio: Some(read_from_string_or_source_opt(
- &person.summary,
- &None,
- &person.source,
- )),
+ bio: read_from_string_or_source_opt(&person.summary, &None, &person.source),
local: Some(false),
admin: Some(false),
bot_account: Some(person.kind == UserTypes::Service),
private_key: None,
- public_key: Some(person.public_key.public_key_pem),
+ public_key: person.public_key.public_key_pem,
last_refreshed_at: Some(naive_now()),
inbox_url: Some(person.inbox.into()),
- shared_inbox_url: Some(person.endpoints.map(|e| e.shared_inbox.into())),
- matrix_user_id: Some(person.matrix_user_id),
+ shared_inbox_url: person.endpoints.map(|e| e.shared_inbox.into()),
+ matrix_user_id: person.matrix_user_id,
+ instance_id: instance.id,
};
let person = blocking(context.pool(), move |conn| {
- DbPerson::upsert(conn, &person_form)
+ DbPerson::create(conn, &person_form)
})
.await??;
#[serial]
async fn test_parse_lemmy_person() {
let context = init_context();
- let conn = &mut context.pool().get().unwrap();
let (person, site) = parse_lemmy_person(&context).await;
assert_eq!(person.display_name, Some("Jean-Luc Picard".to_string()));
assert!(!person.local);
assert_eq!(person.bio.as_ref().unwrap().len(), 39);
- DbPerson::delete(conn, person.id).unwrap();
- Site::delete(conn, site.id).unwrap();
+ cleanup((person, site), &context);
}
#[actix_rt::test]
#[serial]
async fn test_parse_pleroma_person() {
let context = init_context();
- let conn = &mut context.pool().get().unwrap();
// create and parse a fake pleroma instance actor, to avoid network request during test
let mut json: Instance = file_to_json_object("assets/lemmy/objects/instance.json").unwrap();
assert_eq!(request_counter, 0);
assert_eq!(person.bio.as_ref().unwrap().len(), 873);
- DbPerson::delete(conn, person.id).unwrap();
- Site::delete(conn, site.id).unwrap();
+ cleanup((person, site), &context);
+ }
+
+ fn cleanup(data: (ApubPerson, ApubSite), context: &LemmyContext) {
+ let conn = &mut context.pool().get().unwrap();
+ DbPerson::delete(conn, data.0.id).unwrap();
+ Site::delete(conn, data.1.id).unwrap();
}
}
use crate::{
activities::{verify_is_public, verify_person_in_community},
check_apub_id_valid_with_strictness,
+ fetch_local_site_data,
local_instance,
objects::{read_from_string_or_source_opt, verify_is_remote_object},
protocol::{
};
use activitystreams_kinds::public;
use chrono::NaiveDateTime;
-use lemmy_api_common::{request::fetch_site_data, utils::blocking};
+use lemmy_api_common::{
+ request::fetch_site_data,
+ utils::{blocking, local_site_opt_to_slur_regex},
+};
use lemmy_db_schema::{
self,
source::{
community::Community,
+ local_site::LocalSite,
moderator::{ModLockPost, ModLockPostForm, ModStickyPost, ModStickyPostForm},
person::Person,
- post::{Post, PostForm},
+ post::{Post, PostInsertForm, PostUpdateForm},
},
traits::Crud,
};
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
if !self.deleted {
blocking(context.pool(), move |conn| {
- Post::update_deleted(conn, self.id, true)
+ let form = PostUpdateForm::builder().deleted(Some(true)).build();
+ Post::update(conn, self.id, &form)
})
.await??;
}
verify_is_remote_object(page.id.inner(), context.settings())?;
};
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+
let community = page.extract_community(context, request_counter).await?;
- check_apub_id_valid_with_strictness(page.id.inner(), community.local, context.settings())?;
+ check_apub_id_valid_with_strictness(
+ page.id.inner(),
+ community.local,
+ &local_site_data,
+ context.settings(),
+ )?;
verify_person_in_community(&page.creator()?, &community, context, request_counter).await?;
- check_slurs(&page.name, &context.settings().slur_regex())?;
+
+ let slur_regex = &local_site_opt_to_slur_regex(&local_site_data.local_site);
+ check_slurs(&page.name, slur_regex)?;
+
verify_domains_match(page.creator()?.inner(), page.id.inner())?;
verify_is_public(&page.to, &page.cc)?;
Ok(())
(None, page.image.map(|i| i.url.into()))
};
let (embed_title, embed_description, embed_video_url) = metadata_res
- .map(|u| (Some(u.title), Some(u.description), Some(u.embed_video_url)))
+ .map(|u| (u.title, u.description, u.embed_video_url))
.unwrap_or_default();
+ let local_site = blocking(context.pool(), LocalSite::read).await?.ok();
+ let slur_regex = &local_site_opt_to_slur_regex(&local_site);
+
let body_slurs_removed =
read_from_string_or_source_opt(&page.content, &page.media_type, &page.source)
- .map(|s| Some(remove_slurs(&s, &context.settings().slur_regex())));
+ .map(|s| remove_slurs(&s, slur_regex));
let language_id = LanguageTag::to_language_id_single(page.language, context.pool()).await?;
- PostForm {
+ PostInsertForm {
name: page.name.clone(),
- url: Some(url.map(Into::into)),
+ url: url.map(Into::into),
body: body_slurs_removed,
creator_id: creator.id,
community_id: community.id,
embed_title,
embed_description,
embed_video_url,
- thumbnail_url: Some(thumbnail_url),
+ thumbnail_url,
ap_id: Some(page.id.clone().into()),
local: Some(false),
language_id,
}
} else {
// if is mod action, only update locked/stickied fields, nothing else
- PostForm {
- name: page.name.clone(),
- creator_id: creator.id,
- community_id: community.id,
- locked: page.comments_enabled.map(|e| !e),
- stickied: page.stickied,
- updated: page.updated.map(|u| u.naive_local()),
- ap_id: Some(page.id.clone().into()),
- ..Default::default()
- }
+ PostInsertForm::builder()
+ .name(page.name.clone())
+ .creator_id(creator.id)
+ .community_id(community.id)
+ .ap_id(Some(page.id.clone().into()))
+ .locked(page.comments_enabled.map(|e| !e))
+ .stickied(page.stickied)
+ .updated(page.updated.map(|u| u.naive_local()))
+ .build()
};
// read existing, local post if any (for generating mod log)
.dereference_local(context)
.await;
- let post = blocking(context.pool(), move |conn| Post::upsert(conn, &form)).await??;
+ let post = blocking(context.pool(), move |conn| Post::create(conn, &form)).await??;
// write mod log entries for sticky/lock
if Page::is_stickied_changed(&old_post, &page.stickied) {
use crate::{
check_apub_id_valid_with_strictness,
+ fetch_local_site_data,
local_instance,
objects::read_from_string_or_source,
protocol::{
use lemmy_db_schema::{
source::{
person::Person,
- private_message::{PrivateMessage, PrivateMessageForm},
+ private_message::{PrivateMessage, PrivateMessageInsertForm},
},
traits::Crud,
};
) -> Result<(), LemmyError> {
verify_domains_match(note.id.inner(), expected_domain)?;
verify_domains_match(note.attributed_to.inner(), note.id.inner())?;
- check_apub_id_valid_with_strictness(note.id.inner(), false, context.settings())?;
+
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+
+ check_apub_id_valid_with_strictness(
+ note.id.inner(),
+ false,
+ &local_site_data,
+ context.settings(),
+ )?;
let person = note
.attributed_to
.dereference(context, local_instance(context), request_counter)
.await?;
check_person_block(creator.id, recipient.id, context.pool()).await?;
- let form = PrivateMessageForm {
+ let form = PrivateMessageInsertForm {
creator_id: creator.id,
recipient_id: recipient.id,
content: read_from_string_or_source(¬e.content, &None, ¬e.source),
local: Some(false),
};
let pm = blocking(context.pool(), move |conn| {
- PrivateMessage::upsert(conn, &form)
+ PrivateMessage::create(conn, &form)
})
.await??;
Ok(pm.into())
community_moderators::ApubCommunityModerators,
community_outbox::ApubCommunityOutbox,
},
+ fetch_local_site_data,
objects::{community::ApubCommunity, read_from_string_or_source_opt},
protocol::{
objects::{Endpoints, LanguageTag},
};
use activitystreams_kinds::actor::GroupType;
use chrono::{DateTime, FixedOffset};
-use lemmy_db_schema::{source::community::CommunityForm, utils::naive_now};
+use lemmy_api_common::utils::{blocking, local_site_opt_to_slur_regex};
+use lemmy_db_schema::{
+ newtypes::InstanceId,
+ source::community::{CommunityInsertForm, CommunityUpdateForm},
+ utils::naive_now,
+};
use lemmy_utils::{
error::LemmyError,
utils::{check_slurs, check_slurs_opt},
expected_domain: &Url,
context: &LemmyContext,
) -> Result<(), LemmyError> {
- check_apub_id_valid_with_strictness(self.id.inner(), true, context.settings())?;
+ let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
+
+ check_apub_id_valid_with_strictness(
+ self.id.inner(),
+ true,
+ &local_site_data,
+ context.settings(),
+ )?;
verify_domains_match(expected_domain, self.id.inner())?;
- let slur_regex = &context.settings().slur_regex();
+ let slur_regex = &local_site_opt_to_slur_regex(&local_site_data.local_site);
+
check_slurs(&self.preferred_username, slur_regex)?;
check_slurs_opt(&self.name, slur_regex)?;
let description = read_from_string_or_source_opt(&self.summary, &None, &self.source);
Ok(())
}
- pub(crate) fn into_form(self) -> CommunityForm {
- CommunityForm {
+ pub(crate) fn into_insert_form(self, instance_id: InstanceId) -> CommunityInsertForm {
+ CommunityInsertForm {
name: self.preferred_username.clone(),
title: self.name.unwrap_or(self.preferred_username),
+ description: read_from_string_or_source_opt(&self.summary, &None, &self.source),
+ removed: None,
+ published: self.published.map(|u| u.naive_local()),
+ updated: self.updated.map(|u| u.naive_local()),
+ deleted: None,
+ nsfw: Some(self.sensitive.unwrap_or(false)),
+ actor_id: Some(self.id.into()),
+ local: Some(false),
+ private_key: None,
+ hidden: Some(false),
+ public_key: self.public_key.public_key_pem,
+ last_refreshed_at: Some(naive_now()),
+ icon: self.icon.map(|i| i.url.into()),
+ banner: self.image.map(|i| i.url.into()),
+ followers_url: Some(self.followers.into()),
+ inbox_url: Some(self.inbox.into()),
+ shared_inbox_url: self.endpoints.map(|e| e.shared_inbox.into()),
+ posting_restricted_to_mods: self.posting_restricted_to_mods,
+ instance_id,
+ }
+ }
+
+ pub(crate) fn into_update_form(self) -> CommunityUpdateForm {
+ CommunityUpdateForm {
+ title: Some(self.name.unwrap_or(self.preferred_username)),
description: Some(read_from_string_or_source_opt(
&self.summary,
&None,
)),
removed: None,
published: self.published.map(|u| u.naive_local()),
- updated: self.updated.map(|u| u.naive_local()),
+ updated: Some(self.updated.map(|u| u.naive_local())),
deleted: None,
nsfw: Some(self.sensitive.unwrap_or(false)),
actor_id: Some(self.id.into()),
regex = { version = "1.6.0", optional = true }
once_cell = { version = "1.15.0", optional = true }
diesel_ltree = "0.3.0"
+typed-builder = "0.10.0"
[dev-dependencies]
serial_test = "0.9.0"
+
use crate::{
aggregates::comment_aggregates::CommentAggregates,
source::{
- comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
- community::{Community, CommunityForm},
- person::{Person, PersonForm},
- post::{Post, PostForm},
+ comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm},
+ community::{Community, CommunityInsertForm},
+ instance::Instance,
+ person::{Person, PersonInsertForm},
+ post::{Post, PostInsertForm},
},
traits::{Crud, Likeable},
utils::establish_unpooled_connection,
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "thommy_comment_agg".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("thommy_comment_agg".into())
+ .public_key("pubkey".into())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let another_person = PersonForm {
- name: "jerry_comment_agg".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let another_person = PersonInsertForm::builder()
+ .name("jerry_comment_agg".into())
+ .public_key("pubkey".into())
+ .instance_id(inserted_instance.id)
+ .build();
let another_inserted_person = Person::create(conn, &another_person).unwrap();
- let new_community = CommunityForm {
- name: "TIL_comment_agg".into(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("TIL_comment_agg".into())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
- let new_post = PostForm {
- name: "A test post".into(),
- creator_id: inserted_person.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("A test post".into())
+ .creator_id(inserted_person.id)
+ .community_id(inserted_community.id)
+ .build();
let inserted_post = Post::create(conn, &new_post).unwrap();
- let comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_comment = Comment::create(conn, &comment_form, None).unwrap();
- let child_comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let child_comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let _inserted_child_comment =
Comment::create(conn, &child_comment_form, Some(&inserted_comment.path)).unwrap();
// Delete the community
let community_num_deleted = Community::delete(conn, inserted_community.id).unwrap();
assert_eq!(1, community_num_deleted);
+
+ Instance::delete(conn, inserted_instance.id).unwrap();
}
}
use crate::{
aggregates::community_aggregates::CommunityAggregates,
source::{
- comment::{Comment, CommentForm},
- community::{Community, CommunityFollower, CommunityFollowerForm, CommunityForm},
- person::{Person, PersonForm},
- post::{Post, PostForm},
+ comment::{Comment, CommentInsertForm},
+ community::{Community, CommunityFollower, CommunityFollowerForm, CommunityInsertForm},
+ instance::Instance,
+ person::{Person, PersonInsertForm},
+ post::{Post, PostInsertForm},
},
traits::{Crud, Followable},
utils::establish_unpooled_connection,
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "thommy_community_agg".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("thommy_community_agg".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let another_person = PersonForm {
- name: "jerry_community_agg".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let another_person = PersonInsertForm::builder()
+ .name("jerry_community_agg".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let another_inserted_person = Person::create(conn, &another_person).unwrap();
- let new_community = CommunityForm {
- name: "TIL_community_agg".into(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("TIL_community_agg".into())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
- let another_community = CommunityForm {
- name: "TIL_community_agg_2".into(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let another_community = CommunityInsertForm::builder()
+ .name("TIL_community_agg_2".into())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let another_inserted_community = Community::create(conn, &another_community).unwrap();
CommunityFollower::follow(conn, &another_community_follow).unwrap();
- let new_post = PostForm {
- name: "A test post".into(),
- creator_id: inserted_person.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("A test post".into())
+ .creator_id(inserted_person.id)
+ .community_id(inserted_community.id)
+ .build();
let inserted_post = Post::create(conn, &new_post).unwrap();
- let comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_comment = Comment::create(conn, &comment_form, None).unwrap();
- let child_comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let child_comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let _inserted_child_comment =
Comment::create(conn, &child_comment_form, Some(&inserted_comment.path)).unwrap();
use crate::{
aggregates::person_aggregates::PersonAggregates,
source::{
- comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
- community::{Community, CommunityForm},
- person::{Person, PersonForm},
- post::{Post, PostForm, PostLike, PostLikeForm},
+ comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm},
+ community::{Community, CommunityInsertForm},
+ instance::Instance,
+ person::{Person, PersonInsertForm},
+ post::{Post, PostInsertForm, PostLike, PostLikeForm},
},
traits::{Crud, Likeable},
utils::establish_unpooled_connection,
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "thommy_user_agg".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("thommy_user_agg".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let another_person = PersonForm {
- name: "jerry_user_agg".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let another_person = PersonInsertForm::builder()
+ .name("jerry_user_agg".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let another_inserted_person = Person::create(conn, &another_person).unwrap();
- let new_community = CommunityForm {
- name: "TIL_site_agg".into(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("TIL_site_agg".into())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
- let new_post = PostForm {
- name: "A test post".into(),
- creator_id: inserted_person.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("A test post".into())
+ .creator_id(inserted_person.id)
+ .community_id(inserted_community.id)
+ .build();
let inserted_post = Post::create(conn, &new_post).unwrap();
let _inserted_post_like = PostLike::like(conn, &post_like).unwrap();
- let comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_comment = Comment::create(conn, &comment_form, None).unwrap();
let _inserted_comment_like = CommentLike::like(conn, &comment_like).unwrap();
- let child_comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let child_comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_child_comment =
Comment::create(conn, &child_comment_form, Some(&inserted_comment.path)).unwrap();
// Should be none found
let after_delete = PersonAggregates::read(conn, inserted_person.id);
assert!(after_delete.is_err());
+
+ Instance::delete(conn, inserted_instance.id).unwrap();
}
}
use crate::{
aggregates::post_aggregates::PostAggregates,
source::{
- comment::{Comment, CommentForm},
- community::{Community, CommunityForm},
- person::{Person, PersonForm},
- post::{Post, PostForm, PostLike, PostLikeForm},
+ comment::{Comment, CommentInsertForm},
+ community::{Community, CommunityInsertForm},
+ instance::Instance,
+ person::{Person, PersonInsertForm},
+ post::{Post, PostInsertForm, PostLike, PostLikeForm},
},
traits::{Crud, Likeable},
utils::establish_unpooled_connection,
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "thommy_community_agg".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("thommy_community_agg".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let another_person = PersonForm {
- name: "jerry_community_agg".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let another_person = PersonInsertForm::builder()
+ .name("jerry_community_agg".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let another_inserted_person = Person::create(conn, &another_person).unwrap();
- let new_community = CommunityForm {
- name: "TIL_community_agg".into(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("TIL_community_agg".into())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
- let new_post = PostForm {
- name: "A test post".into(),
- creator_id: inserted_person.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("A test post".into())
+ .creator_id(inserted_person.id)
+ .community_id(inserted_community.id)
+ .build();
let inserted_post = Post::create(conn, &new_post).unwrap();
- let comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_comment = Comment::create(conn, &comment_form, None).unwrap();
- let child_comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let child_comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_child_comment =
Comment::create(conn, &child_comment_form, Some(&inserted_comment.path)).unwrap();
// Should be none found, since the creator was deleted
let after_delete = PostAggregates::read(conn, inserted_post.id);
assert!(after_delete.is_err());
+
+ Instance::delete(conn, inserted_instance.id).unwrap();
}
}
use crate::{
aggregates::site_aggregates::SiteAggregates,
source::{
- comment::{Comment, CommentForm},
- community::{Community, CommunityForm},
- person::{Person, PersonForm},
- post::{Post, PostForm},
- site::{Site, SiteForm},
+ comment::{Comment, CommentInsertForm},
+ community::{Community, CommunityInsertForm},
+ instance::Instance,
+ person::{Person, PersonInsertForm},
+ post::{Post, PostInsertForm},
+ site::{Site, SiteInsertForm},
},
traits::Crud,
utils::establish_unpooled_connection,
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "thommy_site_agg".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("thommy_site_agg".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let site_form = SiteForm {
- name: "test_site".into(),
- public_key: Some("pubkey".to_string()),
- ..Default::default()
- };
+ let site_form = SiteInsertForm::builder()
+ .name("test_site".into())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_site = Site::create(conn, &site_form).unwrap();
- let new_community = CommunityForm {
- name: "TIL_site_agg".into(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("TIL_site_agg".into())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
- let new_post = PostForm {
- name: "A test post".into(),
- creator_id: inserted_person.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("A test post".into())
+ .creator_id(inserted_person.id)
+ .community_id(inserted_community.id)
+ .build();
// Insert two of those posts
let inserted_post = Post::create(conn, &new_post).unwrap();
let _inserted_post_again = Post::create(conn, &new_post).unwrap();
- let comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
// Insert two of those comments
let inserted_comment = Comment::create(conn, &comment_form, None).unwrap();
- let child_comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let child_comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let _inserted_child_comment =
Comment::create(conn, &child_comment_form, Some(&inserted_comment.path)).unwrap();
Site::delete(conn, inserted_site.id).unwrap();
let after_delete_site = SiteAggregates::read(conn);
assert!(after_delete_site.is_err());
+
+ Instance::delete(conn, inserted_instance.id).unwrap();
}
}
use serde_json::Value;
impl Crud for Activity {
- type Form = ActivityForm;
+ type InsertForm = ActivityInsertForm;
+ type UpdateForm = ActivityUpdateForm;
type IdType = i32;
fn read(conn: &mut PgConnection, activity_id: i32) -> Result<Self, Error> {
use crate::schema::activity::dsl::*;
activity.find(activity_id).first::<Self>(conn)
}
- fn create(conn: &mut PgConnection, new_activity: &ActivityForm) -> Result<Self, Error> {
+ fn create(conn: &mut PgConnection, new_activity: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::activity::dsl::*;
insert_into(activity)
.values(new_activity)
fn update(
conn: &mut PgConnection,
activity_id: i32,
- new_activity: &ActivityForm,
+ new_activity: &Self::UpdateForm,
) -> Result<Self, Error> {
use crate::schema::activity::dsl::*;
diesel::update(activity.find(activity_id))
impl Activity {
/// Returns true if the insert was successful
+ // TODO this should probably just be changed to an upsert on_conflict, rather than an error
pub fn insert(
conn: &mut PgConnection,
ap_id: DbUrl,
data: Value,
local: bool,
- sensitive: bool,
+ sensitive: Option<bool>,
) -> Result<bool, Error> {
- let activity_form = ActivityForm {
+ let activity_form = ActivityInsertForm {
ap_id,
data,
local: Some(local),
use crate::{
newtypes::DbUrl,
source::{
- activity::{Activity, ActivityForm},
- person::{Person, PersonForm},
+ activity::{Activity, ActivityInsertForm},
+ instance::Instance,
+ person::{Person, PersonInsertForm},
},
utils::establish_unpooled_connection,
};
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let creator_form = PersonForm {
- name: "activity_creator_pm".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let creator_form = PersonInsertForm::builder()
+ .name("activity_creator_ pm".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_creator = Person::create(conn, &creator_form).unwrap();
}"#,
)
.unwrap();
- let activity_form = ActivityForm {
+ let activity_form = ActivityInsertForm {
ap_id: ap_id.clone(),
data: test_json.to_owned(),
local: Some(true),
- sensitive: false,
+ sensitive: Some(false),
updated: None,
};
impl SiteLanguage {
pub fn read_local(conn: &mut PgConnection) -> Result<Vec<LanguageId>, Error> {
- use crate::schema::{site, site_language::dsl::*};
- // TODO: remove this subquery once site.local column is added
- let subquery = crate::schema::site::dsl::site
- .order_by(site::id)
- .select(site::id)
- .limit(1)
- .into_boxed();
- site_language
- .filter(site_id.eq_any(subquery))
- .select(language_id)
+ use crate::schema::{local_site, site, site_language};
+ site::table
+ .inner_join(local_site::table)
+ .inner_join(site_language::table)
+ .select(site_language::language_id)
.load(conn)
}
use crate::{
impls::actor_language::*,
source::{
- community::{Community, CommunityForm},
- local_user::{LocalUser, LocalUserForm},
- person::{Person, PersonForm},
- site::{Site, SiteForm},
+ community::{Community, CommunityInsertForm},
+ instance::Instance,
+ local_site::{LocalSite, LocalSiteInsertForm},
+ local_user::{LocalUser, LocalUserInsertForm},
+ person::{Person, PersonInsertForm},
+ site::{Site, SiteInsertForm},
},
traits::Crud,
utils::establish_unpooled_connection,
]
}
- fn create_test_site(conn: &mut PgConnection) -> Site {
- let site_form = SiteForm {
- name: "test site".to_string(),
- ..Default::default()
- };
- Site::create(conn, &site_form).unwrap()
+ fn create_test_site(conn: &mut PgConnection) -> (Site, Instance) {
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let site_form = SiteInsertForm::builder()
+ .name("test site".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
+ let site = Site::create(conn, &site_form).unwrap();
+
+ // Create a local site, since this is necessary for local languages
+ let local_site_form = LocalSiteInsertForm::builder().site_id(site.id).build();
+ LocalSite::create(conn, &local_site_form).unwrap();
+
+ (site, inserted_instance)
}
#[test]
fn test_site_languages() {
let conn = &mut establish_unpooled_connection();
- let site = create_test_site(conn);
+ let (site, instance) = create_test_site(conn);
let site_languages1 = SiteLanguage::read_local(conn).unwrap();
// site is created with all languages
assert_eq!(184, site_languages1.len());
assert_eq!(test_langs, site_languages2);
Site::delete(conn, site.id).unwrap();
+ Instance::delete(conn, instance.id).unwrap();
+ LocalSite::delete(conn).unwrap();
}
#[test]
fn test_user_languages() {
let conn = &mut establish_unpooled_connection();
- let site = create_test_site(conn);
+ let (site, instance) = create_test_site(conn);
let test_langs = test_langs1(conn);
SiteLanguage::update(conn, test_langs.clone(), site.id).unwrap();
- let person_form = PersonForm {
- name: "my test person".to_string(),
- public_key: Some("pubkey".to_string()),
- ..Default::default()
- };
+ let person_form = PersonInsertForm::builder()
+ .name("my test person".to_string())
+ .public_key("pubkey".to_string())
+ .instance_id(instance.id)
+ .build();
let person = Person::create(conn, &person_form).unwrap();
- let local_user_form = LocalUserForm {
- person_id: Some(person.id),
- password_encrypted: Some("my_pw".to_string()),
- ..Default::default()
- };
+ let local_user_form = LocalUserInsertForm::builder()
+ .person_id(person.id)
+ .password_encrypted("my_pw".to_string())
+ .build();
+
let local_user = LocalUser::create(conn, &local_user_form).unwrap();
let local_user_langs1 = LocalUserLanguage::read(conn, local_user.id).unwrap();
Person::delete(conn, person.id).unwrap();
LocalUser::delete(conn, local_user.id).unwrap();
Site::delete(conn, site.id).unwrap();
+ LocalSite::delete(conn).unwrap();
+ Instance::delete(conn, instance.id).unwrap();
}
#[test]
#[serial]
fn test_community_languages() {
let conn = &mut establish_unpooled_connection();
- let site = create_test_site(conn);
+ let (site, instance) = create_test_site(conn);
let test_langs = test_langs1(conn);
SiteLanguage::update(conn, test_langs.clone(), site.id).unwrap();
- let community_form = CommunityForm {
- name: "test community".to_string(),
- title: "test community".to_string(),
- public_key: Some("pubkey".to_string()),
- ..Default::default()
- };
+ let read_site_langs = SiteLanguage::read(conn, site.id).unwrap();
+ assert_eq!(test_langs, read_site_langs);
+
+ // Test the local ones are the same
+ let read_local_site_langs = SiteLanguage::read_local(conn).unwrap();
+ assert_eq!(test_langs, read_local_site_langs);
+
+ let community_form = CommunityInsertForm::builder()
+ .name("test community".to_string())
+ .title("test community".to_string())
+ .public_key("pubkey".to_string())
+ .instance_id(instance.id)
+ .build();
let community = Community::create(conn, &community_form).unwrap();
let community_langs1 = CommunityLanguage::read(conn, community.id).unwrap();
+
// community is initialized with site languages
assert_eq!(test_langs, community_langs1);
let community_langs3 = CommunityLanguage::read(conn, community.id).unwrap();
assert_eq!(test_langs2, community_langs3);
- Site::delete(conn, site.id).unwrap();
Community::delete(conn, community.id).unwrap();
+ Site::delete(conn, site.id).unwrap();
+ LocalSite::delete(conn).unwrap();
+ Instance::delete(conn, instance.id).unwrap();
}
#[test]
#[serial]
fn test_default_post_language() {
let conn = &mut establish_unpooled_connection();
+ let (site, instance) = create_test_site(conn);
let test_langs = test_langs1(conn);
let test_langs2 = test_langs2(conn);
- let community_form = CommunityForm {
- name: "test community".to_string(),
- title: "test community".to_string(),
- public_key: Some("pubkey".to_string()),
- ..Default::default()
- };
+ let community_form = CommunityInsertForm::builder()
+ .name("test community".to_string())
+ .title("test community".to_string())
+ .public_key("pubkey".to_string())
+ .instance_id(instance.id)
+ .build();
let community = Community::create(conn, &community_form).unwrap();
CommunityLanguage::update(conn, test_langs, community.id).unwrap();
- let person_form = PersonForm {
- name: "my test person".to_string(),
- public_key: Some("pubkey".to_string()),
- ..Default::default()
- };
+ let person_form = PersonInsertForm::builder()
+ .name("my test person".to_string())
+ .public_key("pubkey".to_string())
+ .instance_id(instance.id)
+ .build();
let person = Person::create(conn, &person_form).unwrap();
- let local_user_form = LocalUserForm {
- person_id: Some(person.id),
- password_encrypted: Some("my_pw".to_string()),
- ..Default::default()
- };
+ let local_user_form = LocalUserInsertForm::builder()
+ .person_id(person.id)
+ .password_encrypted("my_pw".to_string())
+ .build();
let local_user = LocalUser::create(conn, &local_user_form).unwrap();
LocalUserLanguage::update(conn, test_langs2, local_user.id).unwrap();
Person::delete(conn, person.id).unwrap();
Community::delete(conn, community.id).unwrap();
LocalUser::delete(conn, local_user.id).unwrap();
+ Site::delete(conn, site.id).unwrap();
+ LocalSite::delete(conn).unwrap();
+ Instance::delete(conn, instance.id).unwrap();
}
}
newtypes::{CommentId, DbUrl, PersonId},
source::comment::{
Comment,
- CommentForm,
+ CommentInsertForm,
CommentLike,
CommentLikeForm,
CommentSaved,
CommentSavedForm,
+ CommentUpdateForm,
},
traits::{Crud, DeleteableOrRemoveable, Likeable, Saveable},
utils::naive_now,
use url::Url;
impl Comment {
- pub fn update_ap_id(
- conn: &mut PgConnection,
- comment_id: CommentId,
- apub_id: DbUrl,
- ) -> Result<Self, Error> {
- use crate::schema::comment::dsl::*;
-
- diesel::update(comment.find(comment_id))
- .set(ap_id.eq(apub_id))
- .get_result::<Self>(conn)
- }
-
pub fn permadelete_for_creator(
conn: &mut PgConnection,
for_creator_id: PersonId,
.get_results::<Self>(conn)
}
- pub fn update_deleted(
- conn: &mut PgConnection,
- comment_id: CommentId,
- new_deleted: bool,
- ) -> Result<Self, Error> {
- use crate::schema::comment::dsl::*;
- diesel::update(comment.find(comment_id))
- .set((deleted.eq(new_deleted), updated.eq(naive_now())))
- .get_result::<Self>(conn)
- }
-
- pub fn update_removed(
- conn: &mut PgConnection,
- comment_id: CommentId,
- new_removed: bool,
- ) -> Result<Self, Error> {
- use crate::schema::comment::dsl::*;
- diesel::update(comment.find(comment_id))
- .set((removed.eq(new_removed), updated.eq(naive_now())))
- .get_result::<Self>(conn)
- }
-
pub fn update_removed_for_creator(
conn: &mut PgConnection,
for_creator_id: PersonId,
pub fn create(
conn: &mut PgConnection,
- comment_form: &CommentForm,
+ comment_form: &CommentInsertForm,
parent_path: Option<&Ltree>,
) -> Result<Comment, Error> {
use crate::schema::comment::dsl::*;
}
impl Crud for Comment {
- type Form = CommentForm;
+ type InsertForm = CommentInsertForm;
+ type UpdateForm = CommentUpdateForm;
type IdType = CommentId;
fn read(conn: &mut PgConnection, comment_id: CommentId) -> Result<Self, Error> {
use crate::schema::comment::dsl::*;
}
/// This is unimplemented, use [[Comment::create]]
- fn create(_conn: &mut PgConnection, _comment_form: &CommentForm) -> Result<Self, Error> {
+ fn create(_conn: &mut PgConnection, _comment_form: &Self::InsertForm) -> Result<Self, Error> {
unimplemented!();
}
fn update(
conn: &mut PgConnection,
comment_id: CommentId,
- comment_form: &CommentForm,
+ comment_form: &Self::UpdateForm,
) -> Result<Self, Error> {
use crate::schema::comment::dsl::*;
diesel::update(comment.find(comment_id))
newtypes::LanguageId,
source::{
comment::*,
- community::{Community, CommunityForm},
- person::{Person, PersonForm},
+ community::{Community, CommunityInsertForm},
+ instance::Instance,
+ person::{Person, PersonInsertForm},
post::*,
},
traits::{Crud, Likeable, Saveable},
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "terry".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("terry".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let new_community = CommunityForm {
- name: "test community".to_string(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("test community".to_string())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
- let new_post = PostForm {
- name: "A test post".into(),
- creator_id: inserted_person.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("A test post".into())
+ .creator_id(inserted_person.id)
+ .community_id(inserted_community.id)
+ .build();
let inserted_post = Post::create(conn, &new_post).unwrap();
- let comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_comment = Comment::create(conn, &comment_form, None).unwrap();
language_id: LanguageId::default(),
};
- let child_comment_form = CommentForm {
- content: "A child comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- // path: Some(text2ltree(inserted_comment.id),
- ..CommentForm::default()
- };
+ let child_comment_form = CommentInsertForm::builder()
+ .content("A child comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_child_comment =
Comment::create(conn, &child_comment_form, Some(&inserted_comment.path)).unwrap();
published: inserted_comment_saved.published,
};
+ let comment_update_form = CommentUpdateForm::builder()
+ .content(Some("A test comment".into()))
+ .build();
+
+ let updated_comment = Comment::update(conn, inserted_comment.id, &comment_update_form).unwrap();
+
let read_comment = Comment::read(conn, inserted_comment.id).unwrap();
- let updated_comment = Comment::update(conn, inserted_comment.id, &comment_form).unwrap();
let like_removed = CommentLike::remove(conn, inserted_person.id, inserted_comment.id).unwrap();
let saved_removed = CommentSaved::unsave(conn, &comment_saved_form).unwrap();
let num_deleted = Comment::delete(conn, inserted_comment.id).unwrap();
Post::delete(conn, inserted_post.id).unwrap();
Community::delete(conn, inserted_community.id).unwrap();
Person::delete(conn, inserted_person.id).unwrap();
+ Instance::delete(conn, inserted_instance.id).unwrap();
assert_eq!(expected_comment, read_comment);
assert_eq!(expected_comment, inserted_comment);
use diesel::{dsl::*, result::Error, *};
impl Crud for CommentReply {
- type Form = CommentReplyForm;
+ type InsertForm = CommentReplyInsertForm;
+ type UpdateForm = CommentReplyUpdateForm;
type IdType = CommentReplyId;
fn read(conn: &mut PgConnection, comment_reply_id: CommentReplyId) -> Result<Self, Error> {
use crate::schema::comment_reply::dsl::*;
comment_reply.find(comment_reply_id).first::<Self>(conn)
}
- fn create(conn: &mut PgConnection, comment_reply_form: &CommentReplyForm) -> Result<Self, Error> {
+ fn create(conn: &mut PgConnection, comment_reply_form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::comment_reply::dsl::*;
// since the return here isnt utilized, we dont need to do an update
// but get_result doesnt return the existing row here
fn update(
conn: &mut PgConnection,
comment_reply_id: CommentReplyId,
- comment_reply_form: &CommentReplyForm,
+ comment_reply_form: &Self::UpdateForm,
) -> Result<Self, Error> {
use crate::schema::comment_reply::dsl::*;
diesel::update(comment_reply.find(comment_reply_id))
}
impl CommentReply {
- pub fn update_read(
- conn: &mut PgConnection,
- comment_reply_id: CommentReplyId,
- new_read: bool,
- ) -> Result<CommentReply, Error> {
- use crate::schema::comment_reply::dsl::*;
- diesel::update(comment_reply.find(comment_reply_id))
- .set(read.eq(new_read))
- .get_result::<Self>(conn)
- }
-
pub fn mark_all_as_read(
conn: &mut PgConnection,
for_recipient_id: PersonId,
source::{
comment::*,
comment_reply::*,
- community::{Community, CommunityForm},
+ community::{Community, CommunityInsertForm},
+ instance::Instance,
person::*,
post::*,
},
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "terrylake".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("terrylake".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let recipient_form = PersonForm {
- name: "terrylakes recipient".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let recipient_form = PersonInsertForm::builder()
+ .name("terrylakes recipient".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_recipient = Person::create(conn, &recipient_form).unwrap();
- let new_community = CommunityForm {
- name: "test community lake".to_string(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("test community lake".to_string())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
- let new_post = PostForm {
- name: "A test post".into(),
- creator_id: inserted_person.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("A test post".into())
+ .creator_id(inserted_person.id)
+ .community_id(inserted_community.id)
+ .build();
let inserted_post = Post::create(conn, &new_post).unwrap();
- let comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_comment = Comment::create(conn, &comment_form, None).unwrap();
- let comment_reply_form = CommentReplyForm {
+ let comment_reply_form = CommentReplyInsertForm {
recipient_id: inserted_recipient.id,
comment_id: inserted_comment.id,
read: None,
};
let read_reply = CommentReply::read(conn, inserted_reply.id).unwrap();
- let updated_reply = CommentReply::update(conn, inserted_reply.id, &comment_reply_form).unwrap();
+
+ let comment_reply_update_form = CommentReplyUpdateForm { read: Some(false) };
+ let updated_reply =
+ CommentReply::update(conn, inserted_reply.id, &comment_reply_update_form).unwrap();
+
Comment::delete(conn, inserted_comment.id).unwrap();
Post::delete(conn, inserted_post.id).unwrap();
Community::delete(conn, inserted_community.id).unwrap();
Person::delete(conn, inserted_person.id).unwrap();
Person::delete(conn, inserted_recipient.id).unwrap();
+ Instance::delete(conn, inserted_instance.id).unwrap();
assert_eq!(expected_reply, read_reply);
assert_eq!(expected_reply, inserted_reply);
Community,
CommunityFollower,
CommunityFollowerForm,
- CommunityForm,
+ CommunityInsertForm,
CommunityModerator,
CommunityModeratorForm,
CommunityPersonBan,
CommunityPersonBanForm,
CommunitySafe,
+ CommunityUpdateForm,
},
},
traits::{ApubActor, Bannable, Crud, DeleteableOrRemoveable, Followable, Joinable},
- utils::{functions::lower, naive_now},
+ utils::functions::lower,
SubscribedType,
};
use diesel::{
banner,
hidden,
posting_restricted_to_mods,
+ instance_id,
);
impl ToSafe for Community {
banner,
hidden,
posting_restricted_to_mods,
+ instance_id,
)
}
}
}
impl Crud for Community {
- type Form = CommunityForm;
+ type InsertForm = CommunityInsertForm;
+ type UpdateForm = CommunityUpdateForm;
type IdType = CommunityId;
fn read(conn: &mut PgConnection, community_id: CommunityId) -> Result<Self, Error> {
use crate::schema::community::dsl::*;
diesel::delete(community.find(community_id)).execute(conn)
}
- fn create(conn: &mut PgConnection, new_community: &CommunityForm) -> Result<Self, Error> {
+ fn create(conn: &mut PgConnection, form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::community::dsl::*;
let community_ = insert_into(community)
- .values(new_community)
+ .values(form)
+ .on_conflict(actor_id)
+ .do_update()
+ .set(form)
.get_result::<Self>(conn)?;
let site_languages = SiteLanguage::read_local(conn);
fn update(
conn: &mut PgConnection,
community_id: CommunityId,
- new_community: &CommunityForm,
+ form: &Self::UpdateForm,
) -> Result<Self, Error> {
use crate::schema::community::dsl::*;
diesel::update(community.find(community_id))
- .set(new_community)
- .get_result::<Self>(conn)
- }
-}
-
-impl Community {
- pub fn update_deleted(
- conn: &mut PgConnection,
- community_id: CommunityId,
- new_deleted: bool,
- ) -> Result<Community, Error> {
- use crate::schema::community::dsl::*;
- diesel::update(community.find(community_id))
- .set((deleted.eq(new_deleted), updated.eq(naive_now())))
- .get_result::<Self>(conn)
- }
-
- pub fn update_removed(
- conn: &mut PgConnection,
- community_id: CommunityId,
- new_removed: bool,
- ) -> Result<Community, Error> {
- use crate::schema::community::dsl::*;
- diesel::update(community.find(community_id))
- .set((removed.eq(new_removed), updated.eq(naive_now())))
- .get_result::<Self>(conn)
- }
-
- pub fn distinct_federated_communities(conn: &mut PgConnection) -> Result<Vec<DbUrl>, Error> {
- use crate::schema::community::dsl::*;
- community.select(actor_id).distinct().load::<DbUrl>(conn)
- }
-
- pub fn upsert(
- conn: &mut PgConnection,
- community_form: &CommunityForm,
- ) -> Result<Community, Error> {
- use crate::schema::community::dsl::*;
- insert_into(community)
- .values(community_form)
- .on_conflict(actor_id)
- .do_update()
- .set(community_form)
- .get_result::<Self>(conn)
- }
-
- pub fn remove_avatar_and_banner(
- conn: &mut PgConnection,
- community_id: CommunityId,
- ) -> Result<Self, Error> {
- use crate::schema::community::dsl::*;
- diesel::update(community.find(community_id))
- .set((
- icon.eq::<Option<String>>(None),
- banner.eq::<Option<String>>(None),
- ))
+ .set(form)
.get_result::<Self>(conn)
}
}
#[cfg(test)]
mod tests {
use crate::{
- source::{community::*, person::*},
+ source::{community::*, instance::Instance, person::*},
traits::{Bannable, Crud, Followable, Joinable},
utils::establish_unpooled_connection,
};
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "bobbee".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("bobbee".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let new_community = CommunityForm {
- name: "TIL".into(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("TIL".into())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
shared_inbox_url: None,
hidden: false,
posting_restricted_to_mods: false,
+ instance_id: inserted_instance.id,
};
let community_follower_form = CommunityFollowerForm {
};
let read_community = Community::read(conn, inserted_community.id).unwrap();
- let updated_community = Community::update(conn, inserted_community.id, &new_community).unwrap();
+
+ let update_community_form = CommunityUpdateForm::builder()
+ .title(Some("nada".to_owned()))
+ .build();
+ let updated_community =
+ Community::update(conn, inserted_community.id, &update_community_form).unwrap();
+
let ignored_community = CommunityFollower::unfollow(conn, &community_follower_form).unwrap();
let left_community = CommunityModerator::leave(conn, &community_moderator_form).unwrap();
let unban = CommunityPersonBan::unban(conn, &community_person_ban_form).unwrap();
let num_deleted = Community::delete(conn, inserted_community.id).unwrap();
Person::delete(conn, inserted_person.id).unwrap();
+ Instance::delete(conn, inserted_instance.id).unwrap();
assert_eq!(expected_community, read_community);
assert_eq!(expected_community, inserted_community);
-use crate::{newtypes::LocalUserId, source::email_verification::*, traits::Crud};
+use crate::{newtypes::LocalUserId, source::email_verification::*};
use diesel::{
dsl::*,
insert_into,
RunQueryDsl,
};
-impl Crud for EmailVerification {
- type Form = EmailVerificationForm;
- type IdType = i32;
- fn create(conn: &mut PgConnection, form: &EmailVerificationForm) -> Result<Self, Error> {
+impl EmailVerification {
+ pub fn create(conn: &mut PgConnection, form: &EmailVerificationForm) -> Result<Self, Error> {
use crate::schema::email_verification::dsl::*;
insert_into(email_verification)
.values(form)
.get_result::<Self>(conn)
}
- fn read(conn: &mut PgConnection, id_: i32) -> Result<Self, Error> {
- use crate::schema::email_verification::dsl::*;
- email_verification.find(id_).first::<Self>(conn)
- }
-
- fn update(
- conn: &mut PgConnection,
- id_: i32,
- form: &EmailVerificationForm,
- ) -> Result<Self, Error> {
- use crate::schema::email_verification::dsl::*;
- diesel::update(email_verification.find(id_))
- .set(form)
- .get_result::<Self>(conn)
- }
-
- fn delete(conn: &mut PgConnection, id_: i32) -> Result<usize, Error> {
- use crate::schema::email_verification::dsl::*;
- diesel::delete(email_verification.find(id_)).execute(conn)
- }
-}
-
-impl EmailVerification {
pub fn read_for_token(conn: &mut PgConnection, token: &str) -> Result<Self, Error> {
use crate::schema::email_verification::dsl::*;
email_verification
--- /dev/null
+use crate::{
+ schema::federation_allowlist,
+ source::{
+ federation_allowlist::{FederationAllowList, FederationAllowListForm},
+ instance::Instance,
+ },
+};
+use diesel::{dsl::*, result::Error, *};
+
+impl FederationAllowList {
+ pub fn replace(conn: &mut PgConnection, list_opt: Option<Vec<String>>) -> Result<(), Error> {
+ conn.build_transaction().read_write().run(|conn| {
+ if let Some(list) = list_opt {
+ Self::clear(conn)?;
+
+ for domain in list {
+ // Upsert all of these as instances
+ let instance = Instance::create(conn, &domain)?;
+
+ let form = FederationAllowListForm {
+ instance_id: instance.id,
+ updated: None,
+ };
+ insert_into(federation_allowlist::table)
+ .values(form)
+ .get_result::<Self>(conn)?;
+ }
+ Ok(())
+ } else {
+ Ok(())
+ }
+ })
+ }
+
+ pub fn clear(conn: &mut PgConnection) -> Result<usize, Error> {
+ diesel::delete(federation_allowlist::table).execute(conn)
+ }
+}
+#[cfg(test)]
+mod tests {
+ use crate::{
+ source::{federation_allowlist::FederationAllowList, instance::Instance},
+ utils::establish_unpooled_connection,
+ };
+ use serial_test::serial;
+
+ #[test]
+ #[serial]
+ fn test_allowlist_insert_and_clear() {
+ let conn = &mut establish_unpooled_connection();
+ let allowed = Some(vec![
+ "tld1.xyz".to_string(),
+ "tld2.xyz".to_string(),
+ "tld3.xyz".to_string(),
+ ]);
+
+ FederationAllowList::replace(conn, allowed).unwrap();
+
+ let allows = Instance::allowlist(conn).unwrap();
+
+ assert_eq!(3, allows.len());
+ assert_eq!(
+ vec![
+ "tld1.xyz".to_string(),
+ "tld2.xyz".to_string(),
+ "tld3.xyz".to_string()
+ ],
+ allows
+ );
+
+ // Now test clearing them via Some(empty vec)
+ let clear_allows = Some(Vec::new());
+
+ FederationAllowList::replace(conn, clear_allows).unwrap();
+ let allows = Instance::allowlist(conn).unwrap();
+
+ assert_eq!(0, allows.len());
+
+ Instance::delete_all(conn).unwrap();
+ }
+}
--- /dev/null
+use crate::{
+ schema::federation_blocklist,
+ source::{
+ federation_blocklist::{FederationBlockList, FederationBlockListForm},
+ instance::Instance,
+ },
+};
+use diesel::{dsl::*, result::Error, *};
+
+impl FederationBlockList {
+ pub fn replace(conn: &mut PgConnection, list_opt: Option<Vec<String>>) -> Result<(), Error> {
+ conn.build_transaction().read_write().run(|conn| {
+ if let Some(list) = list_opt {
+ Self::clear(conn)?;
+
+ for domain in list {
+ // Upsert all of these as instances
+ let instance = Instance::create(conn, &domain)?;
+
+ let form = FederationBlockListForm {
+ instance_id: instance.id,
+ updated: None,
+ };
+ insert_into(federation_blocklist::table)
+ .values(form)
+ .get_result::<Self>(conn)?;
+ }
+ Ok(())
+ } else {
+ Ok(())
+ }
+ })
+ }
+
+ pub fn clear(conn: &mut PgConnection) -> Result<usize, Error> {
+ diesel::delete(federation_blocklist::table).execute(conn)
+ }
+}
--- /dev/null
+use crate::{
+ newtypes::InstanceId,
+ schema::{federation_allowlist, federation_blocklist, instance},
+ source::instance::{Instance, InstanceForm},
+ utils::naive_now,
+};
+use diesel::{dsl::*, result::Error, *};
+use lemmy_utils::utils::generate_domain_url;
+use url::Url;
+
+impl Instance {
+ fn create_from_form(conn: &mut PgConnection, form: &InstanceForm) -> Result<Self, Error> {
+ // Do upsert on domain name conflict
+ insert_into(instance::table)
+ .values(form)
+ .on_conflict(instance::domain)
+ .do_update()
+ .set(form)
+ .get_result::<Self>(conn)
+ }
+ pub fn create(conn: &mut PgConnection, domain: &str) -> Result<Self, Error> {
+ let form = InstanceForm {
+ domain: domain.to_string(),
+ updated: Some(naive_now()),
+ };
+ Self::create_from_form(conn, &form)
+ }
+ pub fn create_from_actor_id(conn: &mut PgConnection, actor_id: &Url) -> Result<Self, Error> {
+ let domain = &generate_domain_url(actor_id).expect("actor id missing a domain");
+ Self::create(conn, domain)
+ }
+ pub fn delete(conn: &mut PgConnection, instance_id: InstanceId) -> Result<usize, Error> {
+ diesel::delete(instance::table.find(instance_id)).execute(conn)
+ }
+ pub fn delete_all(conn: &mut PgConnection) -> Result<usize, Error> {
+ diesel::delete(instance::table).execute(conn)
+ }
+ pub fn allowlist(conn: &mut PgConnection) -> Result<Vec<String>, Error> {
+ instance::table
+ .inner_join(federation_allowlist::table)
+ .select(instance::domain)
+ .load::<String>(conn)
+ }
+
+ pub fn blocklist(conn: &mut PgConnection) -> Result<Vec<String>, Error> {
+ instance::table
+ .inner_join(federation_blocklist::table)
+ .select(instance::domain)
+ .load::<String>(conn)
+ }
+
+ pub fn linked(conn: &mut PgConnection) -> Result<Vec<String>, Error> {
+ instance::table
+ .left_join(federation_blocklist::table)
+ .filter(federation_blocklist::id.is_null())
+ .select(instance::domain)
+ .load::<String>(conn)
+ }
+}
--- /dev/null
+use crate::{schema::local_site::dsl::*, source::local_site::*};
+use diesel::{dsl::*, result::Error, *};
+
+impl LocalSite {
+ pub fn create(conn: &mut PgConnection, form: &LocalSiteInsertForm) -> Result<Self, Error> {
+ insert_into(local_site)
+ .values(form)
+ .get_result::<Self>(conn)
+ }
+ pub fn read(conn: &mut PgConnection) -> Result<Self, Error> {
+ local_site.first::<Self>(conn)
+ }
+ pub fn update(conn: &mut PgConnection, form: &LocalSiteUpdateForm) -> Result<Self, Error> {
+ diesel::update(local_site)
+ .set(form)
+ .get_result::<Self>(conn)
+ }
+ pub fn delete(conn: &mut PgConnection) -> Result<usize, Error> {
+ diesel::delete(local_site).execute(conn)
+ }
+}
--- /dev/null
+use crate::{schema::local_site_rate_limit, source::local_site_rate_limit::*};
+use diesel::{dsl::*, result::Error, *};
+
+impl LocalSiteRateLimit {
+ pub fn read(conn: &mut PgConnection) -> Result<Self, Error> {
+ local_site_rate_limit::table.first::<Self>(conn)
+ }
+
+ pub fn create(
+ conn: &mut PgConnection,
+ form: &LocalSiteRateLimitInsertForm,
+ ) -> Result<Self, Error> {
+ insert_into(local_site_rate_limit::table)
+ .values(form)
+ .get_result::<Self>(conn)
+ }
+ pub fn update(
+ conn: &mut PgConnection,
+ form: &LocalSiteRateLimitUpdateForm,
+ ) -> Result<Self, Error> {
+ diesel::update(local_site_rate_limit::table)
+ .set(form)
+ .get_result::<Self>(conn)
+ }
+}
schema::local_user::dsl::*,
source::{
actor_language::{LocalUserLanguage, SiteLanguage},
- local_user::{LocalUser, LocalUserForm},
+ local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
},
traits::Crud,
utils::naive_now,
}
impl LocalUser {
- pub fn register(conn: &mut PgConnection, form: &LocalUserForm) -> Result<Self, Error> {
- let mut edited_user = form.clone();
- let password_hash = form
- .password_encrypted
- .as_ref()
- .map(|p| hash(p, DEFAULT_COST).expect("Couldn't hash password"));
- edited_user.password_encrypted = password_hash;
-
- Self::create(conn, &edited_user)
- }
-
pub fn update_password(
conn: &mut PgConnection,
local_user_id: LocalUserId,
}
impl Crud for LocalUser {
- type Form = LocalUserForm;
+ type InsertForm = LocalUserInsertForm;
+ type UpdateForm = LocalUserUpdateForm;
type IdType = LocalUserId;
fn read(conn: &mut PgConnection, local_user_id: LocalUserId) -> Result<Self, Error> {
local_user.find(local_user_id).first::<Self>(conn)
fn delete(conn: &mut PgConnection, local_user_id: LocalUserId) -> Result<usize, Error> {
diesel::delete(local_user.find(local_user_id)).execute(conn)
}
- fn create(conn: &mut PgConnection, form: &LocalUserForm) -> Result<Self, Error> {
+ fn create(conn: &mut PgConnection, form: &Self::InsertForm) -> Result<Self, Error> {
+ let mut form_with_encrypted_password = form.clone();
+ let password_hash =
+ hash(&form.password_encrypted, DEFAULT_COST).expect("Couldn't hash password");
+ form_with_encrypted_password.password_encrypted = password_hash;
+
let local_user_ = insert_into(local_user)
- .values(form)
+ .values(form_with_encrypted_password)
.get_result::<Self>(conn)?;
let site_languages = SiteLanguage::read_local(conn);
fn update(
conn: &mut PgConnection,
local_user_id: LocalUserId,
- form: &LocalUserForm,
+ form: &Self::UpdateForm,
) -> Result<Self, Error> {
diesel::update(local_user.find(local_user_id))
.set(form)
pub mod community;
pub mod community_block;
pub mod email_verification;
+pub mod federation_allowlist;
+pub mod federation_blocklist;
+pub mod instance;
pub mod language;
+pub mod local_site;
+pub mod local_site_rate_limit;
pub mod local_user;
pub mod moderator;
pub mod password_reset_request;
use crate::{source::moderator::*, traits::Crud};
use diesel::{dsl::*, result::Error, *};
+// TODO grep for ..xxxDefault()
+
impl Crud for ModRemovePost {
- type Form = ModRemovePostForm;
+ type InsertForm = ModRemovePostForm;
+ type UpdateForm = ModRemovePostForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_remove_post::dsl::*;
}
impl Crud for ModLockPost {
- type Form = ModLockPostForm;
+ type InsertForm = ModLockPostForm;
+ type UpdateForm = ModLockPostForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_lock_post::dsl::*;
}
impl Crud for ModStickyPost {
- type Form = ModStickyPostForm;
+ type InsertForm = ModStickyPostForm;
+ type UpdateForm = ModStickyPostForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_sticky_post::dsl::*;
}
impl Crud for ModRemoveComment {
- type Form = ModRemoveCommentForm;
+ type InsertForm = ModRemoveCommentForm;
+ type UpdateForm = ModRemoveCommentForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_remove_comment::dsl::*;
}
impl Crud for ModRemoveCommunity {
- type Form = ModRemoveCommunityForm;
+ type InsertForm = ModRemoveCommunityForm;
+ type UpdateForm = ModRemoveCommunityForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_remove_community::dsl::*;
}
impl Crud for ModBanFromCommunity {
- type Form = ModBanFromCommunityForm;
+ type InsertForm = ModBanFromCommunityForm;
+ type UpdateForm = ModBanFromCommunityForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_ban_from_community::dsl::*;
}
impl Crud for ModBan {
- type Form = ModBanForm;
+ type InsertForm = ModBanForm;
+ type UpdateForm = ModBanForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_ban::dsl::*;
}
impl Crud for ModHideCommunity {
- type Form = ModHideCommunityForm;
+ type InsertForm = ModHideCommunityForm;
+ type UpdateForm = ModHideCommunityForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
}
impl Crud for ModAddCommunity {
- type Form = ModAddCommunityForm;
+ type InsertForm = ModAddCommunityForm;
+ type UpdateForm = ModAddCommunityForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_add_community::dsl::*;
}
impl Crud for ModTransferCommunity {
- type Form = ModTransferCommunityForm;
+ type InsertForm = ModTransferCommunityForm;
+ type UpdateForm = ModTransferCommunityForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_transfer_community::dsl::*;
}
impl Crud for ModAdd {
- type Form = ModAddForm;
+ type InsertForm = ModAddForm;
+ type UpdateForm = ModAddForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_add::dsl::*;
}
impl Crud for AdminPurgePerson {
- type Form = AdminPurgePersonForm;
+ type InsertForm = AdminPurgePersonForm;
+ type UpdateForm = AdminPurgePersonForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::admin_purge_person::dsl::*;
admin_purge_person.find(from_id).first::<Self>(conn)
}
- fn create(conn: &mut PgConnection, form: &Self::Form) -> Result<Self, Error> {
+ fn create(conn: &mut PgConnection, form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::admin_purge_person::dsl::*;
insert_into(admin_purge_person)
.values(form)
.get_result::<Self>(conn)
}
- fn update(conn: &mut PgConnection, from_id: i32, form: &Self::Form) -> Result<Self, Error> {
+ fn update(conn: &mut PgConnection, from_id: i32, form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::admin_purge_person::dsl::*;
diesel::update(admin_purge_person.find(from_id))
.set(form)
}
impl Crud for AdminPurgeCommunity {
- type Form = AdminPurgeCommunityForm;
+ type InsertForm = AdminPurgeCommunityForm;
+ type UpdateForm = AdminPurgeCommunityForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::admin_purge_community::dsl::*;
admin_purge_community.find(from_id).first::<Self>(conn)
}
- fn create(conn: &mut PgConnection, form: &Self::Form) -> Result<Self, Error> {
+ fn create(conn: &mut PgConnection, form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::admin_purge_community::dsl::*;
insert_into(admin_purge_community)
.values(form)
.get_result::<Self>(conn)
}
- fn update(conn: &mut PgConnection, from_id: i32, form: &Self::Form) -> Result<Self, Error> {
+ fn update(conn: &mut PgConnection, from_id: i32, form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::admin_purge_community::dsl::*;
diesel::update(admin_purge_community.find(from_id))
.set(form)
}
impl Crud for AdminPurgePost {
- type Form = AdminPurgePostForm;
+ type InsertForm = AdminPurgePostForm;
+ type UpdateForm = AdminPurgePostForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::admin_purge_post::dsl::*;
admin_purge_post.find(from_id).first::<Self>(conn)
}
- fn create(conn: &mut PgConnection, form: &Self::Form) -> Result<Self, Error> {
+ fn create(conn: &mut PgConnection, form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::admin_purge_post::dsl::*;
insert_into(admin_purge_post)
.values(form)
.get_result::<Self>(conn)
}
- fn update(conn: &mut PgConnection, from_id: i32, form: &Self::Form) -> Result<Self, Error> {
+ fn update(conn: &mut PgConnection, from_id: i32, form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::admin_purge_post::dsl::*;
diesel::update(admin_purge_post.find(from_id))
.set(form)
}
impl Crud for AdminPurgeComment {
- type Form = AdminPurgeCommentForm;
+ type InsertForm = AdminPurgeCommentForm;
+ type UpdateForm = AdminPurgeCommentForm;
type IdType = i32;
fn read(conn: &mut PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::admin_purge_comment::dsl::*;
admin_purge_comment.find(from_id).first::<Self>(conn)
}
- fn create(conn: &mut PgConnection, form: &Self::Form) -> Result<Self, Error> {
+ fn create(conn: &mut PgConnection, form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::admin_purge_comment::dsl::*;
insert_into(admin_purge_comment)
.values(form)
.get_result::<Self>(conn)
}
- fn update(conn: &mut PgConnection, from_id: i32, form: &Self::Form) -> Result<Self, Error> {
+ fn update(conn: &mut PgConnection, from_id: i32, form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::admin_purge_comment::dsl::*;
diesel::update(admin_purge_comment.find(from_id))
.set(form)
#[cfg(test)]
mod tests {
use crate::{
- source::{comment::*, community::*, moderator::*, person::*, post::*},
+ source::{comment::*, community::*, instance::Instance, moderator::*, person::*, post::*},
traits::Crud,
utils::establish_unpooled_connection,
};
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_mod = PersonForm {
- name: "the mod".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_mod = PersonInsertForm::builder()
+ .name("the mod".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_mod = Person::create(conn, &new_mod).unwrap();
- let new_person = PersonForm {
- name: "jim2".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let new_person = PersonInsertForm::builder()
+ .name("jim2".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let new_community = CommunityForm {
- name: "mod_community".to_string(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("mod_community".to_string())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
- let new_post = PostForm {
- name: "A test post thweep".into(),
- creator_id: inserted_person.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("A test post thweep".into())
+ .creator_id(inserted_person.id)
+ .community_id(inserted_community.id)
+ .build();
let inserted_post = Post::create(conn, &new_post).unwrap();
- let comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_comment = Comment::create(conn, &comment_form, None).unwrap();
Community::delete(conn, inserted_community.id).unwrap();
Person::delete(conn, inserted_person.id).unwrap();
Person::delete(conn, inserted_mod.id).unwrap();
+ Instance::delete(conn, inserted_instance.id).unwrap();
assert_eq!(expected_mod_remove_post, read_mod_remove_post);
assert_eq!(expected_mod_lock_post, read_mod_lock_post);
use sha2::{Digest, Sha256};
impl Crud for PasswordResetRequest {
- type Form = PasswordResetRequestForm;
+ type InsertForm = PasswordResetRequestForm;
+ type UpdateForm = PasswordResetRequestForm;
type IdType = i32;
fn read(conn: &mut PgConnection, password_reset_request_id: i32) -> Result<Self, Error> {
password_reset_request
mod tests {
use crate::{
source::{
- local_user::{LocalUser, LocalUserForm},
+ instance::Instance,
+ local_user::{LocalUser, LocalUserInsertForm},
password_reset_request::PasswordResetRequest,
person::*,
},
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "thommy prw".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("thommy prw".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let new_local_user = LocalUserForm {
- person_id: Some(inserted_person.id),
- password_encrypted: Some("pass".to_string()),
- ..LocalUserForm::default()
- };
+ let new_local_user = LocalUserInsertForm::builder()
+ .person_id(inserted_person.id)
+ .password_encrypted("pass".to_string())
+ .build();
let inserted_local_user = LocalUser::create(conn, &new_local_user).unwrap();
let read_password_reset_request = PasswordResetRequest::read_from_token(conn, token).unwrap();
let num_deleted = Person::delete(conn, inserted_person.id).unwrap();
+ Instance::delete(conn, inserted_instance.id).unwrap();
assert_eq!(expected_password_reset_request, read_password_reset_request);
assert_eq!(
use crate::{
newtypes::{DbUrl, PersonId},
schema::person::dsl::*,
- source::person::{Person, PersonForm},
+ source::person::{Person, PersonInsertForm, PersonUpdateForm},
traits::{ApubActor, Crud},
utils::{functions::lower, naive_now},
};
admin,
bot_account,
ban_expires,
+ instance_id,
);
impl ToSafe for Person {
admin,
bot_account,
ban_expires,
+ instance_id,
)
}
}
}
impl Crud for Person {
- type Form = PersonForm;
+ type InsertForm = PersonInsertForm;
+ type UpdateForm = PersonUpdateForm;
type IdType = PersonId;
fn read(conn: &mut PgConnection, person_id: PersonId) -> Result<Self, Error> {
person
fn delete(conn: &mut PgConnection, person_id: PersonId) -> Result<usize, Error> {
diesel::delete(person.find(person_id)).execute(conn)
}
- fn create(conn: &mut PgConnection, form: &PersonForm) -> Result<Self, Error> {
- insert_into(person).values(form).get_result::<Self>(conn)
+ fn create(conn: &mut PgConnection, form: &PersonInsertForm) -> Result<Self, Error> {
+ insert_into(person)
+ .values(form)
+ .on_conflict(actor_id)
+ .do_update()
+ .set(form)
+ .get_result::<Self>(conn)
}
fn update(
conn: &mut PgConnection,
person_id: PersonId,
- form: &PersonForm,
+ form: &PersonUpdateForm,
) -> Result<Self, Error> {
diesel::update(person.find(person_id))
.set(form)
}
impl Person {
- pub fn ban_person(
- conn: &mut PgConnection,
- person_id: PersonId,
- ban: bool,
- expires: Option<chrono::NaiveDateTime>,
- ) -> Result<Self, Error> {
- diesel::update(person.find(person_id))
- .set((banned.eq(ban), ban_expires.eq(expires)))
- .get_result::<Self>(conn)
- }
-
- pub fn add_admin(
- conn: &mut PgConnection,
- person_id: PersonId,
- added: bool,
- ) -> Result<Self, Error> {
- diesel::update(person.find(person_id))
- .set(admin.eq(added))
- .get_result::<Self>(conn)
- }
-
- pub fn mark_as_updated(conn: &mut PgConnection, person_id: PersonId) -> Result<Person, Error> {
- diesel::update(person.find(person_id))
- .set((last_refreshed_at.eq(naive_now()),))
- .get_result::<Self>(conn)
- }
-
pub fn delete_account(conn: &mut PgConnection, person_id: PersonId) -> Result<Person, Error> {
use crate::schema::local_user;
))
.get_result::<Self>(conn)
}
-
- pub fn upsert(conn: &mut PgConnection, person_form: &PersonForm) -> Result<Person, Error> {
- insert_into(person)
- .values(person_form)
- .on_conflict(actor_id)
- .do_update()
- .set(person_form)
- .get_result::<Self>(conn)
- }
-
- pub fn update_deleted(
- conn: &mut PgConnection,
- person_id: PersonId,
- new_deleted: bool,
- ) -> Result<Person, Error> {
- use crate::schema::person::dsl::*;
- diesel::update(person.find(person_id))
- .set(deleted.eq(new_deleted))
- .get_result::<Self>(conn)
- }
-
- pub fn leave_admin(conn: &mut PgConnection, person_id: PersonId) -> Result<Self, Error> {
- diesel::update(person.find(person_id))
- .set(admin.eq(false))
- .get_result::<Self>(conn)
- }
-
- pub fn remove_avatar_and_banner(
- conn: &mut PgConnection,
- person_id: PersonId,
- ) -> Result<Self, Error> {
- diesel::update(person.find(person_id))
- .set((
- avatar.eq::<Option<String>>(None),
- banner.eq::<Option<String>>(None),
- ))
- .get_result::<Self>(conn)
- }
}
pub fn is_banned(banned_: bool, expires: Option<chrono::NaiveDateTime>) -> bool {
#[cfg(test)]
mod tests {
- use crate::{source::person::*, traits::Crud, utils::establish_unpooled_connection};
+ use crate::{
+ source::{instance::Instance, person::*},
+ traits::Crud,
+ utils::establish_unpooled_connection,
+ };
use serial_test::serial;
#[test]
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "holly".into(),
- public_key: Some("nada".to_owned()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("holly".into())
+ .public_key("nada".to_owned())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
+ instance_id: inserted_instance.id,
};
let read_person = Person::read(conn, inserted_person.id).unwrap();
- let updated_person = Person::update(conn, inserted_person.id, &new_person).unwrap();
+
+ let update_person_form = PersonUpdateForm::builder()
+ .actor_id(Some(inserted_person.actor_id.to_owned()))
+ .build();
+ let updated_person = Person::update(conn, inserted_person.id, &update_person_form).unwrap();
+
let num_deleted = Person::delete(conn, inserted_person.id).unwrap();
+ Instance::delete(conn, inserted_instance.id).unwrap();
assert_eq!(expected_person, read_person);
assert_eq!(expected_person, inserted_person);
use diesel::{dsl::*, result::Error, *};
impl Crud for PersonMention {
- type Form = PersonMentionForm;
+ type InsertForm = PersonMentionInsertForm;
+ type UpdateForm = PersonMentionUpdateForm;
type IdType = PersonMentionId;
fn read(conn: &mut PgConnection, person_mention_id: PersonMentionId) -> Result<Self, Error> {
use crate::schema::person_mention::dsl::*;
fn create(
conn: &mut PgConnection,
- person_mention_form: &PersonMentionForm,
+ person_mention_form: &Self::InsertForm,
) -> Result<Self, Error> {
use crate::schema::person_mention::dsl::*;
// since the return here isnt utilized, we dont need to do an update
fn update(
conn: &mut PgConnection,
person_mention_id: PersonMentionId,
- person_mention_form: &PersonMentionForm,
+ person_mention_form: &Self::UpdateForm,
) -> Result<Self, Error> {
use crate::schema::person_mention::dsl::*;
diesel::update(person_mention.find(person_mention_id))
}
impl PersonMention {
- pub fn update_read(
- conn: &mut PgConnection,
- person_mention_id: PersonMentionId,
- new_read: bool,
- ) -> Result<PersonMention, Error> {
- use crate::schema::person_mention::dsl::*;
- diesel::update(person_mention.find(person_mention_id))
- .set(read.eq(new_read))
- .get_result::<Self>(conn)
- }
-
pub fn mark_all_as_read(
conn: &mut PgConnection,
for_recipient_id: PersonId,
.set(read.eq(true))
.get_results::<Self>(conn)
}
+
pub fn read_by_comment_and_person(
conn: &mut PgConnection,
for_comment_id: CommentId,
use crate::{
source::{
comment::*,
- community::{Community, CommunityForm},
+ community::{Community, CommunityInsertForm},
+ instance::Instance,
person::*,
person_mention::*,
post::*,
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "terrylake".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("terrylake".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let recipient_form = PersonForm {
- name: "terrylakes recipient".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let recipient_form = PersonInsertForm::builder()
+ .name("terrylakes recipient".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_recipient = Person::create(conn, &recipient_form).unwrap();
- let new_community = CommunityForm {
- name: "test community lake".to_string(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("test community lake".to_string())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
- let new_post = PostForm {
- name: "A test post".into(),
- creator_id: inserted_person.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("A test post".into())
+ .creator_id(inserted_person.id)
+ .community_id(inserted_community.id)
+ .build();
let inserted_post = Post::create(conn, &new_post).unwrap();
- let comment_form = CommentForm {
- content: "A test comment".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form = CommentInsertForm::builder()
+ .content("A test comment".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_comment = Comment::create(conn, &comment_form, None).unwrap();
- let person_mention_form = PersonMentionForm {
+ let person_mention_form = PersonMentionInsertForm {
recipient_id: inserted_recipient.id,
comment_id: inserted_comment.id,
read: None,
};
let read_mention = PersonMention::read(conn, inserted_mention.id).unwrap();
+
+ let person_mention_update_form = PersonMentionUpdateForm { read: Some(false) };
let updated_mention =
- PersonMention::update(conn, inserted_mention.id, &person_mention_form).unwrap();
+ PersonMention::update(conn, inserted_mention.id, &person_mention_update_form).unwrap();
Comment::delete(conn, inserted_comment.id).unwrap();
Post::delete(conn, inserted_post.id).unwrap();
Community::delete(conn, inserted_community.id).unwrap();
Person::delete(conn, inserted_person.id).unwrap();
Person::delete(conn, inserted_recipient.id).unwrap();
+ Instance::delete(conn, inserted_instance.id).unwrap();
assert_eq!(expected_mention, read_mention);
assert_eq!(expected_mention, inserted_mention);
newtypes::{CommunityId, DbUrl, PersonId, PostId},
source::post::{
Post,
- PostForm,
+ PostInsertForm,
PostLike,
PostLikeForm,
PostRead,
PostReadForm,
PostSaved,
PostSavedForm,
+ PostUpdateForm,
},
traits::{Crud, DeleteableOrRemoveable, Likeable, Readable, Saveable},
utils::{naive_now, FETCH_LIMIT_MAX},
use url::Url;
impl Crud for Post {
- type Form = PostForm;
+ type InsertForm = PostInsertForm;
+ type UpdateForm = PostUpdateForm;
type IdType = PostId;
fn read(conn: &mut PgConnection, post_id: PostId) -> Result<Self, Error> {
use crate::schema::post::dsl::*;
diesel::delete(post.find(post_id)).execute(conn)
}
- fn create(conn: &mut PgConnection, new_post: &PostForm) -> Result<Self, Error> {
+ fn create(conn: &mut PgConnection, form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::post::dsl::*;
- insert_into(post).values(new_post).get_result::<Self>(conn)
+ insert_into(post)
+ .values(form)
+ .on_conflict(ap_id)
+ .do_update()
+ .set(form)
+ .get_result::<Self>(conn)
}
- fn update(conn: &mut PgConnection, post_id: PostId, new_post: &PostForm) -> Result<Self, Error> {
+ fn update(
+ conn: &mut PgConnection,
+ post_id: PostId,
+ new_post: &Self::UpdateForm,
+ ) -> Result<Self, Error> {
use crate::schema::post::dsl::*;
diesel::update(post.find(post_id))
.set(new_post)
.load::<Self>(conn)
}
- pub fn update_ap_id(
- conn: &mut PgConnection,
- post_id: PostId,
- apub_id: DbUrl,
- ) -> Result<Self, Error> {
- use crate::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: &mut PgConnection,
for_creator_id: PersonId,
.get_results::<Self>(conn)
}
- pub fn update_deleted(
- conn: &mut PgConnection,
- post_id: PostId,
- new_deleted: bool,
- ) -> Result<Self, Error> {
- use crate::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: &mut PgConnection,
- post_id: PostId,
- new_removed: bool,
- ) -> Result<Self, Error> {
- use crate::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(
conn: &mut PgConnection,
for_creator_id: PersonId,
.get_results::<Self>(conn)
}
- pub fn update_locked(
- conn: &mut PgConnection,
- post_id: PostId,
- new_locked: bool,
- ) -> Result<Self, Error> {
- use crate::schema::post::dsl::*;
- diesel::update(post.find(post_id))
- .set(locked.eq(new_locked))
- .get_result::<Self>(conn)
- }
-
- pub fn update_stickied(
- conn: &mut PgConnection,
- post_id: PostId,
- new_stickied: bool,
- ) -> Result<Self, Error> {
- use crate::schema::post::dsl::*;
- diesel::update(post.find(post_id))
- .set(stickied.eq(new_stickied))
- .get_result::<Self>(conn)
- }
-
pub fn is_post_creator(person_id: PersonId, post_creator_id: PersonId) -> bool {
person_id == post_creator_id
}
- pub fn upsert(conn: &mut 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 fn read_from_apub_id(conn: &mut PgConnection, object_id: Url) -> Result<Option<Self>, Error> {
use crate::schema::post::dsl::*;
let object_id: DbUrl = object_id.into();
mod tests {
use crate::{
source::{
- community::{Community, CommunityForm},
+ community::{Community, CommunityInsertForm},
+ instance::Instance,
person::*,
post::*,
},
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "jim".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("jim".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let new_community = CommunityForm {
- name: "test community_3".to_string(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("test community_3".to_string())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
- let new_post = PostForm {
- name: "A test post".into(),
- creator_id: inserted_person.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("A test post".into())
+ .creator_id(inserted_person.id)
+ .community_id(inserted_community.id)
+ .build();
let inserted_post = Post::create(conn, &new_post).unwrap();
};
let read_post = Post::read(conn, inserted_post.id).unwrap();
- let updated_post = Post::update(conn, inserted_post.id, &new_post).unwrap();
+
+ let new_post_update = PostUpdateForm::builder()
+ .name(Some("A test post".into()))
+ .build();
+ let updated_post = Post::update(conn, inserted_post.id, &new_post_update).unwrap();
+
let like_removed = PostLike::remove(conn, inserted_person.id, inserted_post.id).unwrap();
let saved_removed = PostSaved::unsave(conn, &post_saved_form).unwrap();
let read_removed = PostRead::mark_as_unread(conn, &post_read_form).unwrap();
let num_deleted = Post::delete(conn, inserted_post.id).unwrap();
Community::delete(conn, inserted_community.id).unwrap();
Person::delete(conn, inserted_person.id).unwrap();
+ Instance::delete(conn, inserted_instance.id).unwrap();
assert_eq!(expected_post, read_post);
assert_eq!(expected_post, inserted_post);
newtypes::{DbUrl, PersonId, PrivateMessageId},
source::private_message::*,
traits::{Crud, DeleteableOrRemoveable},
- utils::naive_now,
};
use diesel::{dsl::*, result::Error, *};
use lemmy_utils::error::LemmyError;
use url::Url;
impl Crud for PrivateMessage {
- type Form = PrivateMessageForm;
+ type InsertForm = PrivateMessageInsertForm;
+ type UpdateForm = PrivateMessageUpdateForm;
type IdType = PrivateMessageId;
fn read(conn: &mut PgConnection, private_message_id: PrivateMessageId) -> Result<Self, Error> {
use crate::schema::private_message::dsl::*;
private_message.find(private_message_id).first::<Self>(conn)
}
- fn create(
- conn: &mut PgConnection,
- private_message_form: &PrivateMessageForm,
- ) -> Result<Self, Error> {
+ fn create(conn: &mut PgConnection, form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::private_message::dsl::*;
insert_into(private_message)
- .values(private_message_form)
+ .values(form)
+ .on_conflict(ap_id)
+ .do_update()
+ .set(form)
.get_result::<Self>(conn)
}
fn update(
conn: &mut PgConnection,
private_message_id: PrivateMessageId,
- private_message_form: &PrivateMessageForm,
+ form: &Self::UpdateForm,
) -> Result<Self, Error> {
use crate::schema::private_message::dsl::*;
diesel::update(private_message.find(private_message_id))
- .set(private_message_form)
+ .set(form)
.get_result::<Self>(conn)
}
fn delete(conn: &mut PgConnection, pm_id: Self::IdType) -> Result<usize, Error> {
}
impl PrivateMessage {
- pub fn update_ap_id(
- conn: &mut PgConnection,
- private_message_id: PrivateMessageId,
- apub_id: DbUrl,
- ) -> Result<PrivateMessage, Error> {
- use crate::schema::private_message::dsl::*;
-
- diesel::update(private_message.find(private_message_id))
- .set(ap_id.eq(apub_id))
- .get_result::<Self>(conn)
- }
-
- pub fn update_content(
- conn: &mut PgConnection,
- private_message_id: PrivateMessageId,
- new_content: &str,
- ) -> Result<PrivateMessage, Error> {
- use crate::schema::private_message::dsl::*;
- diesel::update(private_message.find(private_message_id))
- .set((content.eq(new_content), updated.eq(naive_now())))
- .get_result::<Self>(conn)
- }
-
- pub fn update_deleted(
- conn: &mut PgConnection,
- private_message_id: PrivateMessageId,
- new_deleted: bool,
- ) -> Result<PrivateMessage, Error> {
- use crate::schema::private_message::dsl::*;
- diesel::update(private_message.find(private_message_id))
- .set(deleted.eq(new_deleted))
- .get_result::<Self>(conn)
- }
-
- pub fn update_read(
- conn: &mut PgConnection,
- private_message_id: PrivateMessageId,
- new_read: bool,
- ) -> Result<PrivateMessage, Error> {
- use crate::schema::private_message::dsl::*;
- diesel::update(private_message.find(private_message_id))
- .set(read.eq(new_read))
- .get_result::<Self>(conn)
- }
-
pub fn mark_all_as_read(
conn: &mut PgConnection,
for_recipient_id: PersonId,
.get_results::<Self>(conn)
}
- pub fn upsert(
- conn: &mut PgConnection,
- private_message_form: &PrivateMessageForm,
- ) -> Result<PrivateMessage, Error> {
- use crate::schema::private_message::dsl::*;
- insert_into(private_message)
- .values(private_message_form)
- .on_conflict(ap_id)
- .do_update()
- .set(private_message_form)
- .get_result::<Self>(conn)
- }
-
pub fn read_from_apub_id(
conn: &mut PgConnection,
object_id: Url,
#[cfg(test)]
mod tests {
use crate::{
- source::{person::*, private_message::*},
+ source::{instance::Instance, person::*, private_message::*},
traits::Crud,
utils::establish_unpooled_connection,
};
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let creator_form = PersonForm {
- name: "creator_pm".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let creator_form = PersonInsertForm::builder()
+ .name("creator_pm".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_creator = Person::create(conn, &creator_form).unwrap();
- let recipient_form = PersonForm {
- name: "recipient_pm".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let recipient_form = PersonInsertForm::builder()
+ .name("recipient_pm".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_recipient = Person::create(conn, &recipient_form).unwrap();
- let private_message_form = PrivateMessageForm {
- content: "A test private message".into(),
- creator_id: inserted_creator.id,
- recipient_id: inserted_recipient.id,
- ..PrivateMessageForm::default()
- };
+ let private_message_form = PrivateMessageInsertForm::builder()
+ .content("A test private message".into())
+ .creator_id(inserted_creator.id)
+ .recipient_id(inserted_recipient.id)
+ .build();
let inserted_private_message = PrivateMessage::create(conn, &private_message_form).unwrap();
};
let read_private_message = PrivateMessage::read(conn, inserted_private_message.id).unwrap();
- let updated_private_message =
- PrivateMessage::update(conn, inserted_private_message.id, &private_message_form).unwrap();
- let deleted_private_message =
- PrivateMessage::update_deleted(conn, inserted_private_message.id, true).unwrap();
- let marked_read_private_message =
- PrivateMessage::update_read(conn, inserted_private_message.id, true).unwrap();
+
+ let private_message_update_form = PrivateMessageUpdateForm::builder()
+ .content(Some("A test private message".into()))
+ .build();
+ let updated_private_message = PrivateMessage::update(
+ conn,
+ inserted_private_message.id,
+ &private_message_update_form,
+ )
+ .unwrap();
+
+ let deleted_private_message = PrivateMessage::update(
+ conn,
+ inserted_private_message.id,
+ &PrivateMessageUpdateForm::builder()
+ .deleted(Some(true))
+ .build(),
+ )
+ .unwrap();
+ let marked_read_private_message = PrivateMessage::update(
+ conn,
+ inserted_private_message.id,
+ &PrivateMessageUpdateForm::builder().read(Some(true)).build(),
+ )
+ .unwrap();
Person::delete(conn, inserted_creator.id).unwrap();
Person::delete(conn, inserted_recipient.id).unwrap();
+ Instance::delete(conn, inserted_instance.id).unwrap();
assert_eq!(expected_private_message, read_private_message);
assert_eq!(expected_private_message, updated_private_message);
use diesel::{insert_into, result::Error, ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl};
impl Crud for RegistrationApplication {
- type Form = RegistrationApplicationForm;
+ type InsertForm = RegistrationApplicationInsertForm;
+ type UpdateForm = RegistrationApplicationUpdateForm;
type IdType = i32;
- fn create(conn: &mut PgConnection, form: &Self::Form) -> Result<Self, Error> {
+ fn create(conn: &mut PgConnection, form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::registration_application::dsl::*;
insert_into(registration_application)
.values(form)
registration_application.find(id_).first::<Self>(conn)
}
- fn update(conn: &mut PgConnection, id_: Self::IdType, form: &Self::Form) -> Result<Self, Error> {
+ fn update(
+ conn: &mut PgConnection,
+ id_: Self::IdType,
+ form: &Self::UpdateForm,
+ ) -> Result<Self, Error> {
use crate::schema::registration_application::dsl::*;
diesel::update(registration_application.find(id_))
.set(form)
use url::Url;
impl Crud for Site {
- type Form = SiteForm;
+ type InsertForm = SiteInsertForm;
+ type UpdateForm = SiteUpdateForm;
type IdType = SiteId;
fn read(conn: &mut PgConnection, _site_id: SiteId) -> Result<Self, Error> {
use crate::schema::site::dsl::*;
site.first::<Self>(conn)
}
- fn create(conn: &mut PgConnection, new_site: &SiteForm) -> Result<Self, Error> {
+ fn create(conn: &mut PgConnection, form: &Self::InsertForm) -> Result<Self, Error> {
use crate::schema::site::dsl::*;
+
let site_ = insert_into(site)
- .values(new_site)
+ .values(form)
+ .on_conflict(actor_id)
+ .do_update()
+ .set(form)
.get_result::<Self>(conn)?;
// initialize with all languages
Ok(site_)
}
- fn update(conn: &mut PgConnection, site_id: SiteId, new_site: &SiteForm) -> Result<Self, Error> {
+ fn update(
+ conn: &mut PgConnection,
+ site_id: SiteId,
+ new_site: &Self::UpdateForm,
+ ) -> Result<Self, Error> {
use crate::schema::site::dsl::*;
diesel::update(site.find(site_id))
.set(new_site)
}
impl Site {
- pub fn read_local(conn: &mut PgConnection) -> Result<Self, Error> {
- use crate::schema::site::dsl::*;
- site.order_by(id).first::<Self>(conn)
- }
-
- pub fn upsert(conn: &mut PgConnection, site_form: &SiteForm) -> Result<Site, Error> {
- use crate::schema::site::dsl::*;
- insert_into(site)
- .values(site_form)
- .on_conflict(actor_id)
- .do_update()
- .set(site_form)
- .get_result::<Self>(conn)
- }
-
pub fn read_from_apub_id(conn: &mut PgConnection, object_id: Url) -> Result<Option<Self>, Error> {
use crate::schema::site::dsl::*;
let object_id: DbUrl = object_id.into();
)
}
+ // TODO this needs fixed
pub fn read_remote_sites(conn: &mut PgConnection) -> Result<Vec<Self>, Error> {
use crate::schema::site::dsl::*;
site.order_by(id).offset(1).get_results::<Self>(conn)
+#![recursion_limit = "256"]
+
#[cfg(feature = "full")]
#[macro_use]
extern crate diesel;
#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct CommentReplyId(i32);
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
+pub struct InstanceId(i32);
+
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
+pub struct LocalSiteId(i32);
+
#[repr(transparent)]
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
#[cfg_attr(feature = "full", derive(AsExpression, FromSqlRow))]
shared_inbox_url -> Nullable<Varchar>,
hidden -> Bool,
posting_restricted_to_mods -> Bool,
+ instance_id -> Int4,
}
}
admin -> Bool,
bot_account -> Bool,
ban_expires -> Nullable<Timestamp>,
+ instance_id -> Int4,
}
}
sidebar -> Nullable<Text>,
published -> Timestamp,
updated -> Nullable<Timestamp>,
- enable_downvotes -> Bool,
- open_registration -> Bool,
- enable_nsfw -> Bool,
icon -> Nullable<Varchar>,
banner -> Nullable<Varchar>,
description -> Nullable<Text>,
- community_creation_admin_only -> Bool,
- require_email_verification -> Bool,
- require_application -> Bool,
- application_question -> Nullable<Text>,
- private_instance -> Bool,
actor_id -> Text,
last_refreshed_at -> Timestamp,
inbox_url -> Text,
private_key -> Nullable<Text>,
public_key -> Text,
- default_theme -> Text,
- default_post_listing_type -> Text,
- legal_information -> Nullable<Text>,
- application_email_admins -> Bool,
- hide_modlog_mod_names -> Bool,
+ instance_id -> Int4,
}
}
}
}
+table! {
+ instance(id) {
+ id -> Int4,
+ domain -> Text,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ }
+}
+
+table! {
+ federation_allowlist(id) {
+ id -> Int4,
+ instance_id -> Int4,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ }
+}
+
+table! {
+ federation_blocklist(id) {
+ id -> Int4,
+ instance_id -> Int4,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ }
+}
+
+table! {
+ local_site(id) {
+ id -> Int4,
+ site_id -> Int4,
+ site_setup -> Bool,
+ enable_downvotes -> Bool,
+ open_registration -> Bool,
+ enable_nsfw -> Bool,
+ community_creation_admin_only -> Bool,
+ require_email_verification -> Bool,
+ require_application -> Bool,
+ application_question -> Nullable<Text>,
+ private_instance -> Bool,
+ default_theme -> Text,
+ default_post_listing_type -> Text,
+ legal_information -> Nullable<Text>,
+ hide_modlog_mod_names -> Bool,
+ application_email_admins -> Bool,
+ slur_filter_regex -> Nullable<Text>,
+ actor_name_max_length -> Int4,
+ federation_enabled -> Bool,
+ federation_debug -> Bool,
+ federation_strict_allowlist -> Bool,
+ federation_http_fetch_retry_limit -> Int4,
+ federation_worker_count -> Int4,
+ captcha_enabled -> Bool,
+ captcha_difficulty -> Text,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ }
+}
+
+table! {
+ local_site_rate_limit(id) {
+ id -> Int4,
+ local_site_id -> Int4,
+ message -> Int4,
+ message_per_second-> Int4,
+ post -> Int4,
+ post_per_second -> Int4,
+ register -> Int4,
+ register_per_second -> Int4,
+ image -> Int4,
+ image_per_second -> Int4,
+ comment -> Int4,
+ comment_per_second -> Int4,
+ search -> Int4,
+ search_per_second -> Int4,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ }
+}
+
joinable!(person_block -> person (person_id));
joinable!(comment -> person (creator_id));
joinable!(admin_purge_post -> community (community_id));
joinable!(admin_purge_post -> person (admin_person_id));
+joinable!(site -> instance (instance_id));
+joinable!(person -> instance (instance_id));
+joinable!(community -> instance (instance_id));
+joinable!(federation_allowlist -> instance (instance_id));
+joinable!(federation_blocklist -> instance (instance_id));
+joinable!(local_site -> site (site_id));
+joinable!(local_site_rate_limit -> local_site (local_site_id));
+
allow_tables_to_appear_in_same_query!(
activity,
comment,
local_user_language,
site_language,
community_language,
+ instance,
+ federation_allowlist,
+ federation_blocklist,
+ local_site,
+ local_site_rate_limit,
);
pub sensitive: Option<bool>,
}
-#[derive(Insertable, AsChangeset)]
+#[derive(Insertable)]
#[diesel(table_name = activity)]
-pub struct ActivityForm {
+pub struct ActivityInsertForm {
pub data: Value,
pub local: Option<bool>,
pub updated: Option<chrono::NaiveDateTime>,
pub ap_id: DbUrl,
- pub sensitive: bool,
+ pub sensitive: Option<bool>,
+}
+
+#[derive(AsChangeset)]
+#[diesel(table_name = activity)]
+pub struct ActivityUpdateForm {
+ pub data: Option<Value>,
+ pub local: Option<bool>,
+ pub updated: Option<Option<chrono::NaiveDateTime>>,
+ pub sensitive: Option<Option<bool>>,
}
use crate::newtypes::{CommentId, DbUrl, LanguageId, LtreeDef, PersonId, PostId};
use diesel_ltree::Ltree;
use serde::{Deserialize, Serialize};
+use typed_builder::TypedBuilder;
#[cfg(feature = "full")]
use crate::schema::{comment, comment_like, comment_saved};
pub language_id: LanguageId,
}
-#[derive(Clone, Default)]
+#[derive(Debug, Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
#[cfg_attr(feature = "full", diesel(table_name = comment))]
-pub struct CommentForm {
+pub struct CommentInsertForm {
+ #[builder(!default)]
pub creator_id: PersonId,
+ #[builder(!default)]
pub post_id: PostId,
+ #[builder(!default)]
pub content: String,
pub removed: Option<bool>,
pub published: Option<chrono::NaiveDateTime>,
pub language_id: Option<LanguageId>,
}
+#[derive(Debug, Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
+#[cfg_attr(feature = "full", derive(AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = comment))]
+pub struct CommentUpdateForm {
+ pub content: Option<String>,
+ pub removed: Option<bool>,
+ // Don't use a default naive_now here, because the create function does a lot of comment updates
+ pub updated: Option<Option<chrono::NaiveDateTime>>,
+ pub deleted: Option<bool>,
+ pub ap_id: Option<DbUrl>,
+ pub local: Option<bool>,
+ pub distinguished: Option<bool>,
+ pub language_id: Option<LanguageId>,
+}
+
#[derive(PartialEq, Eq, Debug, Clone)]
#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
#[cfg_attr(feature = "full", diesel(table_name = comment_reply))]
-pub struct CommentReplyForm {
+pub struct CommentReplyInsertForm {
pub recipient_id: PersonId,
pub comment_id: CommentId,
pub read: Option<bool>,
}
+
+#[cfg_attr(feature = "full", derive(AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = comment_reply))]
+pub struct CommentReplyUpdateForm {
+ pub read: Option<bool>,
+}
-use crate::newtypes::{CommunityId, DbUrl, PersonId};
+use crate::newtypes::{CommunityId, DbUrl, InstanceId, PersonId};
use serde::{Deserialize, Serialize};
+use typed_builder::TypedBuilder;
#[cfg(feature = "full")]
use crate::schema::{community, community_follower, community_moderator, community_person_ban};
pub shared_inbox_url: Option<DbUrl>,
pub hidden: bool,
pub posting_restricted_to_mods: bool,
+ pub instance_id: InstanceId,
}
/// A safe representation of community, without the sensitive info
pub banner: Option<DbUrl>,
pub hidden: bool,
pub posting_restricted_to_mods: bool,
+ pub instance_id: InstanceId,
}
-#[derive(Debug, Default)]
+#[derive(Debug, Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
#[cfg_attr(feature = "full", diesel(table_name = community))]
-pub struct CommunityForm {
+pub struct CommunityInsertForm {
+ #[builder(!default)]
pub name: String,
+ #[builder(!default)]
pub title: String,
- pub description: Option<Option<String>>,
+ pub description: Option<String>,
pub removed: Option<bool>,
pub published: Option<chrono::NaiveDateTime>,
pub updated: Option<chrono::NaiveDateTime>,
pub nsfw: Option<bool>,
pub actor_id: Option<DbUrl>,
pub local: Option<bool>,
- pub private_key: Option<Option<String>>,
+ pub private_key: Option<String>,
+ pub public_key: String,
+ pub last_refreshed_at: Option<chrono::NaiveDateTime>,
+ pub icon: Option<DbUrl>,
+ pub banner: Option<DbUrl>,
+ pub followers_url: Option<DbUrl>,
+ pub inbox_url: Option<DbUrl>,
+ pub shared_inbox_url: Option<DbUrl>,
+ pub hidden: Option<bool>,
+ pub posting_restricted_to_mods: Option<bool>,
+ #[builder(!default)]
+ pub instance_id: InstanceId,
+}
+
+#[derive(Debug, Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
+#[cfg_attr(feature = "full", derive(AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = community))]
+pub struct CommunityUpdateForm {
+ pub title: Option<String>,
+ pub description: Option<Option<String>>,
+ pub removed: Option<bool>,
+ pub published: Option<chrono::NaiveDateTime>,
+ pub updated: Option<Option<chrono::NaiveDateTime>>,
+ pub deleted: Option<bool>,
+ pub nsfw: Option<bool>,
+ pub actor_id: Option<DbUrl>,
+ pub local: Option<bool>,
pub public_key: Option<String>,
+ pub private_key: Option<Option<String>>,
pub last_refreshed_at: Option<chrono::NaiveDateTime>,
pub icon: Option<Option<DbUrl>>,
pub banner: Option<Option<DbUrl>>,
--- /dev/null
+use crate::newtypes::InstanceId;
+use serde::{Deserialize, Serialize};
+use std::fmt::Debug;
+
+#[cfg(feature = "full")]
+use crate::schema::federation_allowlist;
+
+#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(
+ feature = "full",
+ diesel(belongs_to(crate::source::instance::Instance))
+)]
+#[cfg_attr(feature = "full", diesel(table_name = federation_allowlist))]
+pub struct FederationAllowList {
+ pub id: i32,
+ pub instance_id: InstanceId,
+ pub published: chrono::NaiveDateTime,
+ pub updated: Option<chrono::NaiveDateTime>,
+}
+
+#[derive(Clone, Default)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = federation_allowlist))]
+pub struct FederationAllowListForm {
+ pub instance_id: InstanceId,
+ pub updated: Option<chrono::NaiveDateTime>,
+}
--- /dev/null
+use crate::newtypes::InstanceId;
+use serde::{Deserialize, Serialize};
+use std::fmt::Debug;
+
+#[cfg(feature = "full")]
+use crate::schema::federation_blocklist;
+
+#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(
+ feature = "full",
+ diesel(belongs_to(crate::source::instance::Instance))
+)]
+#[cfg_attr(feature = "full", diesel(table_name = federation_blocklist))]
+pub struct FederationBlockList {
+ pub id: i32,
+ pub instance_id: InstanceId,
+ pub published: chrono::NaiveDateTime,
+ pub updated: Option<chrono::NaiveDateTime>,
+}
+
+#[derive(Clone, Default)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = federation_blocklist))]
+pub struct FederationBlockListForm {
+ pub instance_id: InstanceId,
+ pub updated: Option<chrono::NaiveDateTime>,
+}
--- /dev/null
+use crate::newtypes::InstanceId;
+use std::fmt::Debug;
+
+#[cfg(feature = "full")]
+use crate::schema::instance;
+
+#[derive(PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", diesel(table_name = instance))]
+pub struct Instance {
+ pub id: InstanceId,
+ pub domain: String,
+ pub published: chrono::NaiveDateTime,
+ pub updated: Option<chrono::NaiveDateTime>,
+}
+
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = instance))]
+pub struct InstanceForm {
+ pub domain: String,
+ pub updated: Option<chrono::NaiveDateTime>,
+}
--- /dev/null
+use crate::newtypes::{LocalSiteId, SiteId};
+use serde::{Deserialize, Serialize};
+use typed_builder::TypedBuilder;
+
+#[cfg(feature = "full")]
+use crate::schema::local_site;
+
+#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", diesel(table_name = local_site))]
+#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::site::Site)))]
+pub struct LocalSite {
+ pub id: LocalSiteId,
+ pub site_id: SiteId,
+ pub site_setup: bool,
+ pub enable_downvotes: bool,
+ pub open_registration: bool,
+ pub enable_nsfw: bool,
+ pub community_creation_admin_only: bool,
+ pub require_email_verification: bool,
+ pub require_application: bool,
+ pub application_question: Option<String>,
+ pub private_instance: bool,
+ pub default_theme: String,
+ pub default_post_listing_type: String,
+ pub legal_information: Option<String>,
+ pub hide_modlog_mod_names: bool,
+ pub application_email_admins: bool,
+ pub slur_filter_regex: Option<String>,
+ pub actor_name_max_length: i32,
+ pub federation_enabled: bool,
+ pub federation_debug: bool,
+ pub federation_strict_allowlist: bool,
+ pub federation_http_fetch_retry_limit: i32,
+ pub federation_worker_count: i32,
+ pub captcha_enabled: bool,
+ pub captcha_difficulty: String,
+ pub published: chrono::NaiveDateTime,
+ pub updated: Option<chrono::NaiveDateTime>,
+}
+
+#[derive(Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
+#[cfg_attr(feature = "full", derive(Insertable))]
+#[cfg_attr(feature = "full", diesel(table_name = local_site))]
+pub struct LocalSiteInsertForm {
+ #[builder(!default)]
+ pub site_id: SiteId,
+ pub site_setup: Option<bool>,
+ pub enable_downvotes: Option<bool>,
+ pub open_registration: Option<bool>,
+ pub enable_nsfw: Option<bool>,
+ pub community_creation_admin_only: Option<bool>,
+ pub require_email_verification: Option<bool>,
+ pub require_application: Option<bool>,
+ pub application_question: Option<String>,
+ pub private_instance: Option<bool>,
+ pub default_theme: Option<String>,
+ pub default_post_listing_type: Option<String>,
+ pub legal_information: Option<String>,
+ pub hide_modlog_mod_names: Option<bool>,
+ pub application_email_admins: Option<bool>,
+ pub slur_filter_regex: Option<String>,
+ pub actor_name_max_length: Option<i32>,
+ pub federation_enabled: Option<bool>,
+ pub federation_debug: Option<bool>,
+ pub federation_strict_allowlist: Option<bool>,
+ pub federation_http_fetch_retry_limit: Option<i32>,
+ pub federation_worker_count: Option<i32>,
+ pub captcha_enabled: Option<bool>,
+ pub captcha_difficulty: Option<String>,
+}
+
+#[derive(Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
+#[cfg_attr(feature = "full", derive(AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = local_site))]
+pub struct LocalSiteUpdateForm {
+ pub site_setup: Option<bool>,
+ pub enable_downvotes: Option<bool>,
+ pub open_registration: Option<bool>,
+ pub enable_nsfw: Option<bool>,
+ pub community_creation_admin_only: Option<bool>,
+ pub require_email_verification: Option<bool>,
+ pub require_application: Option<bool>,
+ pub application_question: Option<Option<String>>,
+ pub private_instance: Option<bool>,
+ pub default_theme: Option<String>,
+ pub default_post_listing_type: Option<String>,
+ pub legal_information: Option<Option<String>>,
+ pub hide_modlog_mod_names: Option<bool>,
+ pub application_email_admins: Option<bool>,
+ pub slur_filter_regex: Option<Option<String>>,
+ pub actor_name_max_length: Option<i32>,
+ pub federation_enabled: Option<bool>,
+ pub federation_debug: Option<bool>,
+ pub federation_strict_allowlist: Option<bool>,
+ pub federation_http_fetch_retry_limit: Option<i32>,
+ pub federation_worker_count: Option<i32>,
+ pub captcha_enabled: Option<bool>,
+ pub captcha_difficulty: Option<String>,
+ pub updated: Option<Option<chrono::NaiveDateTime>>,
+}
--- /dev/null
+use crate::newtypes::LocalSiteId;
+use serde::{Deserialize, Serialize};
+use typed_builder::TypedBuilder;
+
+#[cfg(feature = "full")]
+use crate::schema::local_site_rate_limit;
+
+#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", diesel(table_name = local_site_rate_limit))]
+#[cfg_attr(
+ feature = "full",
+ diesel(belongs_to(crate::source::local_site::LocalSite))
+)]
+pub struct LocalSiteRateLimit {
+ pub id: i32,
+ pub local_site_id: LocalSiteId,
+ pub message: i32,
+ pub message_per_second: i32,
+ pub post: i32,
+ pub post_per_second: i32,
+ pub register: i32,
+ pub register_per_second: i32,
+ pub image: i32,
+ pub image_per_second: i32,
+ pub comment: i32,
+ pub comment_per_second: i32,
+ pub search: i32,
+ pub search_per_second: i32,
+ pub published: chrono::NaiveDateTime,
+ pub updated: Option<chrono::NaiveDateTime>,
+}
+
+#[derive(Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
+#[cfg_attr(feature = "full", derive(Insertable))]
+#[cfg_attr(feature = "full", diesel(table_name = local_site_rate_limit))]
+pub struct LocalSiteRateLimitInsertForm {
+ #[builder(!default)]
+ pub local_site_id: LocalSiteId,
+ pub message: Option<i32>,
+ pub message_per_second: Option<i32>,
+ pub post: Option<i32>,
+ pub post_per_second: Option<i32>,
+ pub register: Option<i32>,
+ pub register_per_second: Option<i32>,
+ pub image: Option<i32>,
+ pub image_per_second: Option<i32>,
+ pub comment: Option<i32>,
+ pub comment_per_second: Option<i32>,
+ pub search: Option<i32>,
+ pub search_per_second: Option<i32>,
+}
+
+#[derive(Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
+#[cfg_attr(feature = "full", derive(AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = local_site_rate_limit))]
+pub struct LocalSiteRateLimitUpdateForm {
+ pub message: Option<i32>,
+ pub message_per_second: Option<i32>,
+ pub post: Option<i32>,
+ pub post_per_second: Option<i32>,
+ pub register: Option<i32>,
+ pub register_per_second: Option<i32>,
+ pub image: Option<i32>,
+ pub image_per_second: Option<i32>,
+ pub comment: Option<i32>,
+ pub comment_per_second: Option<i32>,
+ pub search: Option<i32>,
+ pub search_per_second: Option<i32>,
+ pub updated: Option<Option<chrono::NaiveDateTime>>,
+}
use crate::newtypes::{LocalUserId, PersonId};
use serde::{Deserialize, Serialize};
+use typed_builder::TypedBuilder;
#[cfg(feature = "full")]
use crate::schema::local_user;
pub accepted_application: bool,
}
-// TODO redo these, check table defaults
-#[derive(Clone, Default)]
-#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
-#[cfg_attr(feature = "full", diesel(table_name = local_user))]
-pub struct LocalUserForm {
- pub person_id: Option<PersonId>,
- pub password_encrypted: Option<String>,
- pub email: Option<Option<String>>,
- pub show_nsfw: Option<bool>,
- pub theme: Option<String>,
- pub default_sort_type: Option<i16>,
- pub default_listing_type: Option<i16>,
- pub interface_language: Option<String>,
- pub show_avatars: Option<bool>,
- pub send_notifications_to_email: Option<bool>,
- pub show_bot_accounts: Option<bool>,
- pub show_scores: Option<bool>,
- pub show_read_posts: Option<bool>,
- pub show_new_post_notifs: Option<bool>,
- pub email_verified: Option<bool>,
- pub accepted_application: Option<bool>,
-}
-
/// A local user view that removes password encrypted
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
pub email_verified: bool,
pub accepted_application: bool,
}
+
+#[derive(Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
+#[cfg_attr(feature = "full", derive(Insertable))]
+#[cfg_attr(feature = "full", diesel(table_name = local_user))]
+pub struct LocalUserInsertForm {
+ #[builder(!default)]
+ pub person_id: PersonId,
+ #[builder(!default)]
+ pub password_encrypted: String,
+ pub email: Option<String>,
+ pub show_nsfw: Option<bool>,
+ pub theme: Option<String>,
+ pub default_sort_type: Option<i16>,
+ pub default_listing_type: Option<i16>,
+ pub interface_language: Option<String>,
+ pub show_avatars: Option<bool>,
+ pub send_notifications_to_email: Option<bool>,
+ pub show_bot_accounts: Option<bool>,
+ pub show_scores: Option<bool>,
+ pub show_read_posts: Option<bool>,
+ pub show_new_post_notifs: Option<bool>,
+ pub email_verified: Option<bool>,
+ pub accepted_application: Option<bool>,
+}
+
+#[derive(Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
+#[cfg_attr(feature = "full", derive(AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = local_user))]
+pub struct LocalUserUpdateForm {
+ pub password_encrypted: Option<String>,
+ pub email: Option<Option<String>>,
+ pub show_nsfw: Option<bool>,
+ pub theme: Option<String>,
+ pub default_sort_type: Option<i16>,
+ pub default_listing_type: Option<i16>,
+ pub interface_language: Option<String>,
+ pub show_avatars: Option<bool>,
+ pub send_notifications_to_email: Option<bool>,
+ pub show_bot_accounts: Option<bool>,
+ pub show_scores: Option<bool>,
+ pub show_read_posts: Option<bool>,
+ pub show_new_post_notifs: Option<bool>,
+ pub email_verified: Option<bool>,
+ pub accepted_application: Option<bool>,
+}
pub mod community;
pub mod community_block;
pub mod email_verification;
+pub mod federation_allowlist;
+pub mod federation_blocklist;
+pub mod instance;
pub mod language;
+pub mod local_site;
+pub mod local_site_rate_limit;
pub mod local_user;
pub mod moderator;
pub mod password_reset_request;
-use crate::newtypes::{DbUrl, PersonId};
+use crate::newtypes::{DbUrl, InstanceId, PersonId};
use serde::{Deserialize, Serialize};
+use typed_builder::TypedBuilder;
#[cfg(feature = "full")]
use crate::schema::person;
pub admin: bool,
pub bot_account: bool,
pub ban_expires: Option<chrono::NaiveDateTime>,
+ pub instance_id: InstanceId,
}
/// A safe representation of person, without the sensitive info
pub admin: bool,
pub bot_account: bool,
pub ban_expires: Option<chrono::NaiveDateTime>,
+ pub instance_id: InstanceId,
}
-#[derive(Clone, Default)]
+#[derive(Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
#[cfg_attr(feature = "full", diesel(table_name = person))]
-pub struct PersonForm {
+pub struct PersonInsertForm {
+ #[builder(!default)]
pub name: String,
- pub display_name: Option<Option<String>>,
- pub avatar: Option<Option<DbUrl>>,
+ #[builder(!default)]
+ pub public_key: String,
+ #[builder(!default)]
+ pub instance_id: InstanceId,
+ pub display_name: Option<String>,
+ pub avatar: Option<DbUrl>,
pub banned: Option<bool>,
pub published: Option<chrono::NaiveDateTime>,
pub updated: Option<chrono::NaiveDateTime>,
pub actor_id: Option<DbUrl>,
+ pub bio: Option<String>,
+ pub local: Option<bool>,
+ pub private_key: Option<String>,
+ pub last_refreshed_at: Option<chrono::NaiveDateTime>,
+ pub banner: Option<DbUrl>,
+ pub deleted: Option<bool>,
+ pub inbox_url: Option<DbUrl>,
+ pub shared_inbox_url: Option<DbUrl>,
+ pub matrix_user_id: Option<String>,
+ pub admin: Option<bool>,
+ pub bot_account: Option<bool>,
+ pub ban_expires: Option<chrono::NaiveDateTime>,
+}
+
+#[derive(Clone, TypedBuilder)]
+#[cfg_attr(feature = "full", derive(AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = person))]
+#[builder(field_defaults(default))]
+pub struct PersonUpdateForm {
+ pub display_name: Option<Option<String>>,
+ pub avatar: Option<Option<DbUrl>>,
+ pub banned: Option<bool>,
+ pub updated: Option<Option<chrono::NaiveDateTime>>,
+ pub actor_id: Option<DbUrl>,
pub bio: Option<Option<String>>,
pub local: Option<bool>,
- pub private_key: Option<Option<String>>,
pub public_key: Option<String>,
+ pub private_key: Option<Option<String>>,
pub last_refreshed_at: Option<chrono::NaiveDateTime>,
pub banner: Option<Option<DbUrl>>,
pub deleted: Option<bool>,
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
#[cfg_attr(feature = "full", diesel(table_name = person_mention))]
-pub struct PersonMentionForm {
+pub struct PersonMentionInsertForm {
pub recipient_id: PersonId,
pub comment_id: CommentId,
pub read: Option<bool>,
}
+
+#[cfg_attr(feature = "full", derive(AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = person_mention))]
+pub struct PersonMentionUpdateForm {
+ pub read: Option<bool>,
+}
use crate::newtypes::{CommunityId, DbUrl, LanguageId, PersonId, PostId};
use serde::{Deserialize, Serialize};
+use typed_builder::TypedBuilder;
#[cfg(feature = "full")]
use crate::schema::{post, post_like, post_read, post_saved};
pub language_id: LanguageId,
}
-#[derive(Default)]
+#[derive(Debug, Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
#[cfg_attr(feature = "full", diesel(table_name = post))]
-pub struct PostForm {
+pub struct PostInsertForm {
+ #[builder(!default)]
pub name: String,
+ #[builder(!default)]
pub creator_id: PersonId,
+ #[builder(!default)]
pub community_id: CommunityId,
pub nsfw: Option<bool>,
+ pub url: Option<DbUrl>,
+ pub body: Option<String>,
+ pub removed: Option<bool>,
+ pub locked: Option<bool>,
+ pub updated: Option<chrono::NaiveDateTime>,
+ pub published: Option<chrono::NaiveDateTime>,
+ pub deleted: Option<bool>,
+ pub stickied: Option<bool>,
+ pub embed_title: Option<String>,
+ pub embed_description: Option<String>,
+ pub embed_video_url: Option<DbUrl>,
+ pub thumbnail_url: Option<DbUrl>,
+ pub ap_id: Option<DbUrl>,
+ pub local: Option<bool>,
+ pub language_id: Option<LanguageId>,
+}
+
+#[derive(Debug, Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
+#[cfg_attr(feature = "full", derive(AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = post))]
+pub struct PostUpdateForm {
+ pub name: Option<String>,
+ pub nsfw: Option<bool>,
pub url: Option<Option<DbUrl>>,
pub body: Option<Option<String>>,
pub removed: Option<bool>,
pub locked: Option<bool>,
pub published: Option<chrono::NaiveDateTime>,
- pub updated: Option<chrono::NaiveDateTime>,
+ pub updated: Option<Option<chrono::NaiveDateTime>>,
pub deleted: Option<bool>,
pub stickied: Option<bool>,
pub embed_title: Option<Option<String>>,
use crate::newtypes::{DbUrl, PersonId, PrivateMessageId};
use serde::{Deserialize, Serialize};
+use typed_builder::TypedBuilder;
#[cfg(feature = "full")]
use crate::schema::private_message;
pub local: bool,
}
-#[derive(Default)]
+#[derive(Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
#[cfg_attr(feature = "full", diesel(table_name = private_message))]
-pub struct PrivateMessageForm {
+pub struct PrivateMessageInsertForm {
+ #[builder(!default)]
pub creator_id: PersonId,
+ #[builder(!default)]
pub recipient_id: PersonId,
+ #[builder(!default)]
pub content: String,
pub deleted: Option<bool>,
pub read: Option<bool>,
pub ap_id: Option<DbUrl>,
pub local: Option<bool>,
}
+
+#[derive(Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
+#[cfg_attr(feature = "full", derive(AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = private_message))]
+pub struct PrivateMessageUpdateForm {
+ pub content: Option<String>,
+ pub deleted: Option<bool>,
+ pub read: Option<bool>,
+ pub published: Option<chrono::NaiveDateTime>,
+ pub updated: Option<Option<chrono::NaiveDateTime>>,
+ pub ap_id: Option<DbUrl>,
+ pub local: Option<bool>,
+}
pub published: chrono::NaiveDateTime,
}
-#[derive(Default)]
-#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", derive(Insertable))]
#[cfg_attr(feature = "full", diesel(table_name = registration_application))]
-pub struct RegistrationApplicationForm {
- pub local_user_id: Option<LocalUserId>,
- pub answer: Option<String>,
- pub admin_id: Option<PersonId>,
+pub struct RegistrationApplicationInsertForm {
+ pub local_user_id: LocalUserId,
+ pub answer: String,
+}
+
+#[cfg_attr(feature = "full", derive(AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = registration_application))]
+pub struct RegistrationApplicationUpdateForm {
+ pub admin_id: Option<Option<PersonId>>,
pub deny_reason: Option<Option<String>>,
}
-use crate::newtypes::{DbUrl, SiteId};
+use crate::newtypes::{DbUrl, InstanceId, SiteId};
use serde::{Deserialize, Serialize};
+use typed_builder::TypedBuilder;
#[cfg(feature = "full")]
use crate::schema::site;
pub sidebar: Option<String>,
pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime>,
- pub enable_downvotes: bool,
- pub open_registration: bool,
- pub enable_nsfw: bool,
pub icon: Option<DbUrl>,
pub banner: Option<DbUrl>,
pub description: Option<String>,
- pub community_creation_admin_only: bool,
- pub require_email_verification: bool,
- pub require_application: bool,
- pub application_question: Option<String>,
- pub private_instance: bool,
pub actor_id: DbUrl,
pub last_refreshed_at: chrono::NaiveDateTime,
pub inbox_url: DbUrl,
pub private_key: Option<String>,
pub public_key: String,
- pub default_theme: String,
- pub default_post_listing_type: String,
- pub legal_information: Option<String>,
- pub application_email_admins: bool,
- pub hide_modlog_mod_names: bool,
+ pub instance_id: InstanceId,
}
-#[derive(Default)]
+#[derive(Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
#[cfg_attr(feature = "full", diesel(table_name = site))]
-pub struct SiteForm {
+pub struct SiteInsertForm {
+ #[builder(!default)]
pub name: String,
- pub sidebar: Option<Option<String>>,
+ pub sidebar: Option<String>,
pub updated: Option<chrono::NaiveDateTime>,
- pub enable_downvotes: Option<bool>,
- pub open_registration: Option<bool>,
- pub enable_nsfw: Option<bool>,
+ pub icon: Option<DbUrl>,
+ pub banner: Option<DbUrl>,
+ pub description: Option<String>,
+ pub actor_id: Option<DbUrl>,
+ pub last_refreshed_at: Option<chrono::NaiveDateTime>,
+ pub inbox_url: Option<DbUrl>,
+ pub private_key: Option<String>,
+ pub public_key: Option<String>,
+ #[builder(!default)]
+ pub instance_id: InstanceId,
+}
+
+#[derive(Clone, TypedBuilder)]
+#[builder(field_defaults(default))]
+#[cfg_attr(feature = "full", derive(AsChangeset))]
+#[cfg_attr(feature = "full", diesel(table_name = site))]
+pub struct SiteUpdateForm {
+ pub name: Option<String>,
+ pub sidebar: Option<Option<String>>,
+ pub updated: Option<Option<chrono::NaiveDateTime>>,
// 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<DbUrl>>,
pub banner: Option<Option<DbUrl>>,
pub description: Option<Option<String>>,
- pub community_creation_admin_only: Option<bool>,
- pub require_email_verification: Option<bool>,
- pub require_application: Option<bool>,
- pub application_question: Option<Option<String>>,
- pub private_instance: Option<bool>,
pub actor_id: Option<DbUrl>,
pub last_refreshed_at: Option<chrono::NaiveDateTime>,
pub inbox_url: Option<DbUrl>,
pub private_key: Option<Option<String>>,
pub public_key: Option<String>,
- pub default_theme: Option<String>,
- pub default_post_listing_type: Option<String>,
- pub legal_information: Option<Option<String>>,
- pub application_email_admins: Option<bool>,
- pub hide_modlog_mod_names: Option<bool>,
}
use diesel::{result::Error, PgConnection};
pub trait Crud {
- type Form;
+ type InsertForm;
+ type UpdateForm;
type IdType;
- fn create(conn: &mut PgConnection, form: &Self::Form) -> Result<Self, Error>
+ fn create(conn: &mut PgConnection, form: &Self::InsertForm) -> Result<Self, Error>
where
Self: Sized;
fn read(conn: &mut PgConnection, id: Self::IdType) -> Result<Self, Error>
where
Self: Sized;
- fn update(conn: &mut PgConnection, id: Self::IdType, form: &Self::Form) -> Result<Self, Error>
+ /// 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.
+ fn update(
+ conn: &mut PgConnection,
+ id: Self::IdType,
+ form: &Self::UpdateForm,
+ ) -> Result<Self, Error>
where
Self: Sized;
fn delete(_conn: &mut PgConnection, _id: Self::IdType) -> Result<usize, Error>
}
}
+pub fn diesel_option_overwrite_to_url_create(
+ opt: &Option<String>,
+) -> Result<Option<DbUrl>, LemmyError> {
+ match opt.as_ref().map(|s| s.as_str()) {
+ // An empty string is nothing
+ Some("") => Ok(None),
+ Some(str_url) => match Url::parse(str_url) {
+ Ok(url) => Ok(Some(url.into())),
+ Err(e) => Err(LemmyError::from_error_message(e, "invalid_url")),
+ },
+ None => Ok(None),
+ }
+}
+
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!();
pub fn establish_unpooled_connection() -> PgConnection {
tracing = { version = "0.1.36", optional = true }
diesel_ltree = "0.3.0"
typed-builder = "0.10.0"
+url = { version = "2.3.1", features = ["serde"] }
[dev-dependencies]
serial_test = "0.9.0"
use crate::comment_report_view::{CommentReportQuery, CommentReportView};
use lemmy_db_schema::{
aggregates::structs::CommentAggregates,
- source::{comment::*, comment_report::*, community::*, person::*, post::*},
+ source::{comment::*, comment_report::*, community::*, instance::Instance, person::*, post::*},
traits::{Crud, Joinable, Reportable},
utils::establish_unpooled_connection,
};
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "timmy_crv".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("timmy_crv".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_timmy = Person::create(conn, &new_person).unwrap();
- let new_person_2 = PersonForm {
- name: "sara_crv".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let new_person_2 = PersonInsertForm::builder()
+ .name("sara_crv".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_sara = Person::create(conn, &new_person_2).unwrap();
// Add a third person, since new ppl can only report something once.
- let new_person_3 = PersonForm {
- name: "jessica_crv".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let new_person_3 = PersonInsertForm::builder()
+ .name("jessica_crv".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_jessica = Person::create(conn, &new_person_3).unwrap();
- let new_community = CommunityForm {
- name: "test community crv".to_string(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("test community crv".to_string())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
let _inserted_moderator = CommunityModerator::join(conn, &timmy_moderator_form).unwrap();
- let new_post = PostForm {
- name: "A test post crv".into(),
- creator_id: inserted_timmy.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("A test post crv".into())
+ .creator_id(inserted_timmy.id)
+ .community_id(inserted_community.id)
+ .build();
let inserted_post = Post::create(conn, &new_post).unwrap();
- let comment_form = CommentForm {
- content: "A test comment 32".into(),
- creator_id: inserted_timmy.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form = CommentInsertForm::builder()
+ .content("A test comment 32".into())
+ .creator_id(inserted_timmy.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_comment = Comment::create(conn, &comment_form, None).unwrap();
hidden: false,
posting_restricted_to_mods: false,
published: inserted_community.published,
+ instance_id: inserted_instance.id,
},
creator: PersonSafe {
id: inserted_jessica.id,
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
+ instance_id: inserted_instance.id,
},
comment_creator: PersonSafe {
id: inserted_timmy.id,
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
+ instance_id: inserted_instance.id,
},
creator_banned_from_community: false,
counts: CommentAggregates {
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
+ instance_id: inserted_instance.id,
};
// Do a batch read of timmys reports
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
+ instance_id: inserted_instance.id,
});
assert_eq!(
Person::delete(conn, inserted_sara.id).unwrap();
Person::delete(conn, inserted_jessica.id).unwrap();
Community::delete(conn, inserted_community.id).unwrap();
+ Instance::delete(conn, inserted_instance.id).unwrap();
}
}
actor_language::LocalUserLanguage,
comment::*,
community::*,
+ instance::Instance,
language::Language,
- local_user::LocalUserForm,
+ local_user::LocalUserInsertForm,
person::*,
person_block::PersonBlockForm,
post::*,
use serial_test::serial;
struct Data {
+ inserted_instance: Instance,
inserted_comment_0: Comment,
inserted_comment_1: Comment,
inserted_comment_2: Comment,
}
fn init_data(conn: &mut PgConnection) -> Data {
- let new_person = PersonForm {
- name: "timmy".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("timmy".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let local_user_form = LocalUserForm {
- person_id: Some(inserted_person.id),
- password_encrypted: Some("".to_string()),
- ..Default::default()
- };
+ let local_user_form = LocalUserInsertForm::builder()
+ .person_id(inserted_person.id)
+ .password_encrypted("".to_string())
+ .build();
let inserted_local_user = LocalUser::create(conn, &local_user_form).unwrap();
- let new_person_2 = PersonForm {
- name: "sara".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let new_person_2 = PersonInsertForm::builder()
+ .name("sara".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person_2 = Person::create(conn, &new_person_2).unwrap();
- let new_community = CommunityForm {
- name: "test community 5".to_string(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("test community 5".to_string())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
- let new_post = PostForm {
- name: "A test post 2".into(),
- creator_id: inserted_person.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("A test post 2".into())
+ .creator_id(inserted_person.id)
+ .community_id(inserted_community.id)
+ .build();
let inserted_post = Post::create(conn, &new_post).unwrap();
// 3 4
// \
// 5
- let comment_form_0 = CommentForm {
- content: "Comment 0".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form_0 = CommentInsertForm::builder()
+ .content("Comment 0".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_comment_0 = Comment::create(conn, &comment_form_0, None).unwrap();
- let comment_form_1 = CommentForm {
- content: "Comment 1, A test blocked comment".into(),
- creator_id: inserted_person_2.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form_1 = CommentInsertForm::builder()
+ .content("Comment 1, A test blocked comment".into())
+ .creator_id(inserted_person_2.id)
+ .post_id(inserted_post.id)
+ .build();
let inserted_comment_1 =
Comment::create(conn, &comment_form_1, Some(&inserted_comment_0.path)).unwrap();
let finnish_id = Language::read_id_from_code(conn, "fi").unwrap();
- let comment_form_2 = CommentForm {
- content: "Comment 2".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- language_id: Some(finnish_id),
- ..CommentForm::default()
- };
+ let comment_form_2 = CommentInsertForm::builder()
+ .content("Comment 2".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .language_id(Some(finnish_id))
+ .build();
let inserted_comment_2 =
Comment::create(conn, &comment_form_2, Some(&inserted_comment_0.path)).unwrap();
- let comment_form_3 = CommentForm {
- content: "Comment 3".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form_3 = CommentInsertForm::builder()
+ .content("Comment 3".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let _inserted_comment_3 =
Comment::create(conn, &comment_form_3, Some(&inserted_comment_1.path)).unwrap();
let polish_id = Language::read_id_from_code(conn, "pl").unwrap();
- let comment_form_4 = CommentForm {
- content: "Comment 4".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- language_id: Some(polish_id),
- ..CommentForm::default()
- };
+ let comment_form_4 = CommentInsertForm::builder()
+ .content("Comment 4".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .language_id(Some(polish_id))
+ .build();
let inserted_comment_4 =
Comment::create(conn, &comment_form_4, Some(&inserted_comment_1.path)).unwrap();
- let comment_form_5 = CommentForm {
- content: "Comment 5".into(),
- creator_id: inserted_person.id,
- post_id: inserted_post.id,
- ..CommentForm::default()
- };
+ let comment_form_5 = CommentInsertForm::builder()
+ .content("Comment 5".into())
+ .creator_id(inserted_person.id)
+ .post_id(inserted_post.id)
+ .build();
let _inserted_comment_5 =
Comment::create(conn, &comment_form_5, Some(&inserted_comment_4.path)).unwrap();
let _inserted_comment_like = CommentLike::like(conn, &comment_like_form).unwrap();
Data {
+ inserted_instance,
inserted_comment_0,
inserted_comment_1,
inserted_comment_2,
Community::delete(conn, data.inserted_community.id).unwrap();
Person::delete(conn, data.inserted_person.id).unwrap();
Person::delete(conn, data.inserted_person_2.id).unwrap();
+ Instance::delete(conn, data.inserted_instance.id).unwrap();
}
fn expected_comment_view(data: &Data, conn: &mut PgConnection) -> CommentView {
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
+ instance_id: data.inserted_instance.id,
},
post: Post {
id: data.inserted_post.id,
hidden: false,
posting_restricted_to_mods: false,
published: data.inserted_community.published,
+ instance_id: data.inserted_instance.id,
},
counts: CommentAggregates {
id: agg.id,
aggregates::structs::PostAggregates,
source::{
community::*,
+ instance::Instance,
person::*,
post::*,
post_report::{PostReport, PostReportForm},
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person = PersonForm {
- name: "timmy_prv".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person = PersonInsertForm::builder()
+ .name("timmy_prv".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_timmy = Person::create(conn, &new_person).unwrap();
- let new_person_2 = PersonForm {
- name: "sara_prv".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let new_person_2 = PersonInsertForm::builder()
+ .name("sara_prv".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_sara = Person::create(conn, &new_person_2).unwrap();
// Add a third person, since new ppl can only report something once.
- let new_person_3 = PersonForm {
- name: "jessica_prv".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let new_person_3 = PersonInsertForm::builder()
+ .name("jessica_prv".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_jessica = Person::create(conn, &new_person_3).unwrap();
- let new_community = CommunityForm {
- name: "test community prv".to_string(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("test community prv".to_string())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
let _inserted_moderator = CommunityModerator::join(conn, &timmy_moderator_form).unwrap();
- let new_post = PostForm {
- name: "A test post crv".into(),
- creator_id: inserted_timmy.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("A test post crv".into())
+ .creator_id(inserted_timmy.id)
+ .community_id(inserted_community.id)
+ .build();
let inserted_post = Post::create(conn, &new_post).unwrap();
hidden: false,
posting_restricted_to_mods: false,
published: inserted_community.published,
+ instance_id: inserted_instance.id,
},
creator: PersonSafe {
id: inserted_jessica.id,
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
+ instance_id: inserted_instance.id,
},
post_creator: PersonSafe {
id: inserted_timmy.id,
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
+ instance_id: inserted_instance.id,
},
creator_banned_from_community: false,
my_vote: None,
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
+ instance_id: inserted_instance.id,
};
// Do a batch read of timmys reports
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
+ instance_id: inserted_instance.id,
});
assert_eq!(
Person::delete(conn, inserted_sara.id).unwrap();
Person::delete(conn, inserted_jessica.id).unwrap();
Community::delete(conn, inserted_community.id).unwrap();
+ Instance::delete(conn, inserted_instance.id).unwrap();
}
}
actor_language::LocalUserLanguage,
community::*,
community_block::{CommunityBlock, CommunityBlockForm},
+ instance::Instance,
language::Language,
- local_user::{LocalUser, LocalUserForm},
+ local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
person::*,
person_block::{PersonBlock, PersonBlockForm},
post::*,
use serial_test::serial;
struct Data {
+ inserted_instance: Instance,
inserted_person: Person,
inserted_local_user: LocalUser,
inserted_blocked_person: Person,
}
fn init_data(conn: &mut PgConnection) -> Data {
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
let person_name = "tegan".to_string();
- let new_person = PersonForm {
- name: person_name.to_owned(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let new_person = PersonInsertForm::builder()
+ .name(person_name.to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_person = Person::create(conn, &new_person).unwrap();
- let local_user_form = LocalUserForm {
- person_id: Some(inserted_person.id),
- password_encrypted: Some("".to_string()),
- ..Default::default()
- };
+ let local_user_form = LocalUserInsertForm::builder()
+ .person_id(inserted_person.id)
+ .password_encrypted("".to_string())
+ .build();
let inserted_local_user = LocalUser::create(conn, &local_user_form).unwrap();
- let new_bot = PersonForm {
- name: "mybot".to_string(),
- bot_account: Some(true),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let new_bot = PersonInsertForm::builder()
+ .name("mybot".to_string())
+ .bot_account(Some(true))
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_bot = Person::create(conn, &new_bot).unwrap();
- let new_community = CommunityForm {
- name: "test_community_3".to_string(),
- title: "nada".to_owned(),
- public_key: Some("pubkey".to_string()),
- ..CommunityForm::default()
- };
+ let new_community = CommunityInsertForm::builder()
+ .name("test_community_3".to_string())
+ .title("nada".to_owned())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_community = Community::create(conn, &new_community).unwrap();
// Test a person block, make sure the post query doesn't include their post
- let blocked_person = PersonForm {
- name: person_name,
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let blocked_person = PersonInsertForm::builder()
+ .name(person_name)
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_blocked_person = Person::create(conn, &blocked_person).unwrap();
- let post_from_blocked_person = PostForm {
- name: "blocked_person_post".to_string(),
- creator_id: inserted_blocked_person.id,
- community_id: inserted_community.id,
- language_id: Some(LanguageId(1)),
- ..PostForm::default()
- };
+ let post_from_blocked_person = PostInsertForm::builder()
+ .name("blocked_person_post".to_string())
+ .creator_id(inserted_blocked_person.id)
+ .community_id(inserted_community.id)
+ .language_id(Some(LanguageId(1)))
+ .build();
Post::create(conn, &post_from_blocked_person).unwrap();
PersonBlock::block(conn, &person_block).unwrap();
// A sample post
- let new_post = PostForm {
- name: "test post 3".to_string(),
- creator_id: inserted_person.id,
- community_id: inserted_community.id,
- language_id: Some(LanguageId(47)),
- ..PostForm::default()
- };
+ let new_post = PostInsertForm::builder()
+ .name("test post 3".to_string())
+ .creator_id(inserted_person.id)
+ .community_id(inserted_community.id)
+ .language_id(Some(LanguageId(47)))
+ .build();
let inserted_post = Post::create(conn, &new_post).unwrap();
- let new_bot_post = PostForm {
- name: "test bot post".to_string(),
- creator_id: inserted_bot.id,
- community_id: inserted_community.id,
- ..PostForm::default()
- };
+ let new_bot_post = PostInsertForm::builder()
+ .name("test bot post".to_string())
+ .creator_id(inserted_bot.id)
+ .community_id(inserted_community.id)
+ .build();
let _inserted_bot_post = Post::create(conn, &new_bot_post).unwrap();
Data {
+ inserted_instance,
inserted_person,
inserted_local_user,
inserted_blocked_person,
let conn = &mut establish_unpooled_connection();
let data = init_data(conn);
- let local_user_form = LocalUserForm {
- show_bot_accounts: Some(false),
- ..Default::default()
- };
+ let local_user_form = LocalUserUpdateForm::builder()
+ .show_bot_accounts(Some(false))
+ .build();
let inserted_local_user =
LocalUser::update(conn, data.inserted_local_user.id, &local_user_form).unwrap();
post_listing_single_with_person
);
- let local_user_form = LocalUserForm {
- show_bot_accounts: Some(true),
- ..Default::default()
- };
+ let local_user_form = LocalUserUpdateForm::builder()
+ .show_bot_accounts(Some(true))
+ .build();
let inserted_local_user =
LocalUser::update(conn, data.inserted_local_user.id, &local_user_form).unwrap();
let data = init_data(conn);
let spanish_id = Language::read_id_from_code(conn, "es").unwrap();
- let post_spanish = PostForm {
- name: "asffgdsc".to_string(),
- creator_id: data.inserted_person.id,
- community_id: data.inserted_community.id,
- language_id: Some(spanish_id),
- ..PostForm::default()
- };
+ let post_spanish = PostInsertForm::builder()
+ .name("asffgdsc".to_string())
+ .creator_id(data.inserted_person.id)
+ .community_id(data.inserted_community.id)
+ .language_id(Some(spanish_id))
+ .build();
Post::create(conn, &post_spanish).unwrap();
Person::delete(conn, data.inserted_person.id).unwrap();
Person::delete(conn, data.inserted_bot.id).unwrap();
Person::delete(conn, data.inserted_blocked_person.id).unwrap();
+ Instance::delete(conn, data.inserted_instance.id).unwrap();
assert_eq!(1, num_deleted);
}
shared_inbox_url: None,
matrix_user_id: None,
ban_expires: None,
+ instance_id: data.inserted_instance.id,
},
creator_banned_from_community: false,
community: CommunitySafe {
hidden: false,
posting_restricted_to_mods: false,
published: inserted_community.published,
+ instance_id: data.inserted_instance.id,
},
counts: PostAggregates {
id: agg.id,
use crate::private_message_report_view::PrivateMessageReportQuery;
use lemmy_db_schema::{
source::{
- person::{Person, PersonForm},
- private_message::{PrivateMessage, PrivateMessageForm},
+ instance::Instance,
+ person::{Person, PersonInsertForm},
+ private_message::{PrivateMessage, PrivateMessageInsertForm},
private_message_report::{PrivateMessageReport, PrivateMessageReportForm},
},
traits::{Crud, Reportable},
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let new_person_1 = PersonForm {
- name: "timmy_mrv".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let new_person_1 = PersonInsertForm::builder()
+ .name("timmy_mrv".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_timmy = Person::create(conn, &new_person_1).unwrap();
- let new_person_2 = PersonForm {
- name: "jessica_mrv".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let new_person_2 = PersonInsertForm::builder()
+ .name("jessica_mrv".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_jessica = Person::create(conn, &new_person_2).unwrap();
// timmy sends private message to jessica
- let pm_form = PrivateMessageForm {
- creator_id: inserted_timmy.id,
- recipient_id: inserted_jessica.id,
- content: "something offensive".to_string(),
- ..Default::default()
- };
+ let pm_form = PrivateMessageInsertForm::builder()
+ .creator_id(inserted_timmy.id)
+ .recipient_id(inserted_jessica.id)
+ .content("something offensive".to_string())
+ .build();
let pm = PrivateMessage::create(conn, &pm_form).unwrap();
// jessica reports private message
assert_eq!(pm_report.reason, reports[0].private_message_report.reason);
assert_eq!(pm.content, reports[0].private_message.content);
- let new_person_3 = PersonForm {
- name: "admin_mrv".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let new_person_3 = PersonInsertForm::builder()
+ .name("admin_mrv".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_admin = Person::create(conn, &new_person_3).unwrap();
// admin resolves the report (after taking appropriate action)
inserted_admin.name,
reports[0].resolver.as_ref().unwrap().name
);
+
+ Instance::delete(conn, inserted_instance.id).unwrap();
}
}
};
use lemmy_db_schema::{
source::{
- local_user::{LocalUser, LocalUserForm, LocalUserSettings},
+ instance::Instance,
+ local_user::{LocalUser, LocalUserInsertForm, LocalUserSettings, LocalUserUpdateForm},
person::*,
- registration_application::{RegistrationApplication, RegistrationApplicationForm},
+ registration_application::{
+ RegistrationApplication,
+ RegistrationApplicationInsertForm,
+ RegistrationApplicationUpdateForm,
+ },
},
traits::Crud,
utils::establish_unpooled_connection,
fn test_crud() {
let conn = &mut establish_unpooled_connection();
- let timmy_person_form = PersonForm {
- name: "timmy_rav".into(),
- admin: Some(true),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
+
+ let timmy_person_form = PersonInsertForm::builder()
+ .name("timmy_rav".into())
+ .admin(Some(true))
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_timmy_person = Person::create(conn, &timmy_person_form).unwrap();
- let timmy_local_user_form = LocalUserForm {
- person_id: Some(inserted_timmy_person.id),
- password_encrypted: Some("nada".to_string()),
- ..LocalUserForm::default()
- };
+ let timmy_local_user_form = LocalUserInsertForm::builder()
+ .person_id(inserted_timmy_person.id)
+ .password_encrypted("nada".to_string())
+ .build();
let _inserted_timmy_local_user = LocalUser::create(conn, &timmy_local_user_form).unwrap();
- let sara_person_form = PersonForm {
- name: "sara_rav".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let sara_person_form = PersonInsertForm::builder()
+ .name("sara_rav".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_sara_person = Person::create(conn, &sara_person_form).unwrap();
- let sara_local_user_form = LocalUserForm {
- person_id: Some(inserted_sara_person.id),
- password_encrypted: Some("nada".to_string()),
- ..LocalUserForm::default()
- };
+ let sara_local_user_form = LocalUserInsertForm::builder()
+ .person_id(inserted_sara_person.id)
+ .password_encrypted("nada".to_string())
+ .build();
let inserted_sara_local_user = LocalUser::create(conn, &sara_local_user_form).unwrap();
// Sara creates an application
- let sara_app_form = RegistrationApplicationForm {
- local_user_id: Some(inserted_sara_local_user.id),
- answer: Some("LET ME IIIIINN".to_string()),
- ..RegistrationApplicationForm::default()
+ let sara_app_form = RegistrationApplicationInsertForm {
+ local_user_id: inserted_sara_local_user.id,
+ answer: "LET ME IIIIINN".to_string(),
};
let sara_app = RegistrationApplication::create(conn, &sara_app_form).unwrap();
let read_sara_app_view = RegistrationApplicationView::read(conn, sara_app.id).unwrap();
- let jess_person_form = PersonForm {
- name: "jess_rav".into(),
- public_key: Some("pubkey".to_string()),
- ..PersonForm::default()
- };
+ let jess_person_form = PersonInsertForm::builder()
+ .name("jess_rav".into())
+ .public_key("pubkey".to_string())
+ .instance_id(inserted_instance.id)
+ .build();
let inserted_jess_person = Person::create(conn, &jess_person_form).unwrap();
- let jess_local_user_form = LocalUserForm {
- person_id: Some(inserted_jess_person.id),
- password_encrypted: Some("nada".to_string()),
- ..LocalUserForm::default()
- };
+ let jess_local_user_form = LocalUserInsertForm::builder()
+ .person_id(inserted_jess_person.id)
+ .password_encrypted("nada".to_string())
+ .build();
let inserted_jess_local_user = LocalUser::create(conn, &jess_local_user_form).unwrap();
// Sara creates an application
- let jess_app_form = RegistrationApplicationForm {
- local_user_id: Some(inserted_jess_local_user.id),
- answer: Some("LET ME IIIIINN".to_string()),
- ..RegistrationApplicationForm::default()
+ let jess_app_form = RegistrationApplicationInsertForm {
+ local_user_id: inserted_jess_local_user.id,
+ answer: "LET ME IIIIINN".to_string(),
};
let jess_app = RegistrationApplication::create(conn, &jess_app_form).unwrap();
inbox_url: inserted_sara_person.inbox_url.to_owned(),
shared_inbox_url: None,
matrix_user_id: None,
+ instance_id: inserted_instance.id,
},
admin: None,
};
assert_eq!(unread_count, 2);
// Approve the application
- let approve_form = RegistrationApplicationForm {
- admin_id: Some(inserted_timmy_person.id),
+ let approve_form = RegistrationApplicationUpdateForm {
+ admin_id: Some(Some(inserted_timmy_person.id)),
deny_reason: None,
- ..RegistrationApplicationForm::default()
};
RegistrationApplication::update(conn, sara_app.id, &approve_form).unwrap();
// Update the local_user row
- let approve_local_user_form = LocalUserForm {
- accepted_application: Some(true),
- ..LocalUserForm::default()
- };
+ let approve_local_user_form = LocalUserUpdateForm::builder()
+ .accepted_application(Some(true))
+ .build();
LocalUser::update(conn, inserted_sara_local_user.id, &approve_local_user_form).unwrap();
inbox_url: inserted_timmy_person.inbox_url.to_owned(),
shared_inbox_url: None,
matrix_user_id: None,
+ instance_id: inserted_instance.id,
});
assert_eq!(read_sara_app_view_after_approve, expected_sara_app_view);
Person::delete(conn, inserted_timmy_person.id).unwrap();
Person::delete(conn, inserted_sara_person.id).unwrap();
Person::delete(conn, inserted_jess_person.id).unwrap();
+ Instance::delete(conn, inserted_instance.id).unwrap();
}
}
use diesel::{result::Error, *};
use lemmy_db_schema::{
aggregates::structs::SiteAggregates,
- schema::{site, site_aggregates},
- source::site::Site,
+ schema::{local_site, local_site_rate_limit, site, site_aggregates},
+ source::{local_site::LocalSite, local_site_rate_limit::LocalSiteRateLimit, site::Site},
};
impl SiteView {
pub fn read_local(conn: &mut PgConnection) -> Result<Self, Error> {
- let (mut site, counts) = site::table
+ let (mut site, local_site, local_site_rate_limit, counts) = site::table
+ .inner_join(local_site::table)
+ .inner_join(
+ local_site_rate_limit::table.on(local_site::id.eq(local_site_rate_limit::local_site_id)),
+ )
.inner_join(site_aggregates::table)
- .select((site::all_columns, site_aggregates::all_columns))
- .order_by(site::id)
- .first::<(Site, SiteAggregates)>(conn)?;
+ .select((
+ site::all_columns,
+ local_site::all_columns,
+ local_site_rate_limit::all_columns,
+ site_aggregates::all_columns,
+ ))
+ .first::<(Site, LocalSite, LocalSiteRateLimit, SiteAggregates)>(conn)?;
site.private_key = None;
- Ok(SiteView { site, counts })
+ Ok(SiteView {
+ site,
+ local_site,
+ local_site_rate_limit,
+ counts,
+ })
}
}
comment_report::CommentReport,
community::CommunitySafe,
language::Language,
+ local_site::LocalSite,
+ local_site_rate_limit::LocalSiteRateLimit,
local_user::{LocalUser, LocalUserSettings},
person::{Person, PersonSafe},
post::Post,
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SiteView {
pub site: Site,
+ pub local_site: LocalSite,
+ pub local_site_rate_limit: LocalSiteRateLimit,
pub counts: SiteAggregates,
}
.await?
.map_err(|_| ErrorBadRequest(LemmyError::from(anyhow!("not_found"))))?;
- let protocols = if context.settings().federation.enabled {
+ let protocols = if site_view.local_site.federation_enabled {
vec!["activitypub".to_string()]
} else {
vec![]
local_posts: site_view.counts.posts,
local_comments: site_view.counts.comments,
},
- open_registrations: site_view.site.open_registration,
+ open_registrations: site_view.local_site.open_registration,
};
Ok(HttpResponse::Ok().json(json))
source::{community::Community, person::Person},
traits::ApubActor,
};
-use lemmy_utils::{error::LemmyError, location_info, settings::structs::Settings};
+use lemmy_utils::{error::LemmyError, location_info};
use lemmy_websocket::LemmyContext;
use serde::Deserialize;
use url::Url;
resource: String,
}
-pub fn config(cfg: &mut web::ServiceConfig, settings: &Settings) {
- if settings.federation.enabled {
- cfg.route(
- ".well-known/webfinger",
- web::get().to(get_webfinger_response),
- );
- }
+pub fn config(cfg: &mut web::ServiceConfig) {
+ cfg.route(
+ ".well-known/webfinger",
+ web::get().to(get_webfinger_response),
+ );
}
/// Responds to webfinger requests of the following format. There isn't any real documentation for
html2text = "0.4.2"
rosetta-i18n = "0.1.2"
parking_lot = "0.12.1"
+typed-builder = "0.10.0"
[build-dependencies]
rosetta-build = "0.1.2"
-use crate::{settings::structs::RateLimitConfig, utils::get_ip, IpAddr};
+use crate::{utils::get_ip, IpAddr};
use actix_web::{
dev::{Service, ServiceRequest, ServiceResponse, Transform},
HttpResponse,
};
use futures::future::{ok, Ready};
use rate_limiter::{RateLimitType, RateLimiter};
+use serde::{Deserialize, Serialize};
use std::{
future::Future,
pin::Pin,
sync::{Arc, Mutex},
task::{Context, Poll},
};
+use typed_builder::TypedBuilder;
pub mod rate_limiter;
+#[derive(Debug, Deserialize, Serialize, Clone, TypedBuilder)]
+pub struct RateLimitConfig {
+ #[builder(default = 180)]
+ /// Maximum number of messages created in interval
+ pub message: i32,
+ #[builder(default = 60)]
+ /// Interval length for message limit, in seconds
+ pub message_per_second: i32,
+ #[builder(default = 6)]
+ /// Maximum number of posts created in interval
+ pub post: i32,
+ #[builder(default = 300)]
+ /// Interval length for post limit, in seconds
+ pub post_per_second: i32,
+ #[builder(default = 3)]
+ /// Maximum number of registrations in interval
+ pub register: i32,
+ #[builder(default = 3600)]
+ /// Interval length for registration limit, in seconds
+ pub register_per_second: i32,
+ #[builder(default = 6)]
+ /// Maximum number of image uploads in interval
+ pub image: i32,
+ #[builder(default = 3600)]
+ /// Interval length for image uploads, in seconds
+ pub image_per_second: i32,
+ #[builder(default = 6)]
+ /// Maximum number of comments created in interval
+ pub comment: i32,
+ #[builder(default = 600)]
+ /// Interval length for comment limit, in seconds
+ pub comment_per_second: i32,
+ #[builder(default = 60)]
+ /// Maximum number of searches created in interval
+ pub search: i32,
+ #[builder(default = 600)]
+ /// Interval length for search limit, in seconds
+ pub search_per_second: i32,
+}
+
#[derive(Debug, Clone)]
pub struct RateLimit {
// it might be reasonable to use a std::sync::Mutex here, since we don't need to lock this
use anyhow::{anyhow, Context};
use deser_hjson::from_str;
use once_cell::sync::Lazy;
-use regex::{Regex, RegexBuilder};
+use regex::Regex;
use std::{env, fs, io::Error};
pub mod structs;
WEBFINGER_REGEX.to_owned()
}
- pub fn slur_regex(&self) -> Option<Regex> {
- self.slur_filter.as_ref().map(|slurs| {
- RegexBuilder::new(slurs)
- .case_insensitive(true)
- .build()
- .expect("compile regex")
- })
- }
-
pub fn pictrs_config(&self) -> Result<PictrsConfig, LemmyError> {
self
.pictrs
/// settings related to the postgresql database
#[default(Default::default())]
pub database: DatabaseConfig,
- /// rate limits for various user actions, by user ip
- #[default(Some(Default::default()))]
- pub rate_limit: Option<RateLimitConfig>,
/// Settings related to activitypub federation
- #[default(Default::default())]
- pub federation: FederationConfig,
/// Pictrs image server configuration.
#[default(Some(Default::default()))]
pub(crate) pictrs: Option<PictrsConfig>,
- #[default(Default::default())]
- pub captcha: CaptchaConfig,
/// Email sending configuration. All options except login/password are mandatory
#[default(None)]
#[doku(example = "Some(Default::default())")]
/// Whether the site is available over TLS. Needs to be true for federation to work.
#[default(true)]
pub tls_enabled: bool,
- #[default(None)]
- #[doku(example = "(\\bThis\\b)|(\\bis\\b)|(\\bsample\\b)")]
- /// A regex list of slurs to block / hide
- pub slur_filter: Option<String>,
- /// Maximum length of local community and user names
- #[default(20)]
- pub actor_name_max_length: usize,
-
/// Set the URL for opentelemetry exports. If you do not have an opentelemetry collector, do not set this option
#[default(None)]
#[doku(skip)]
pub api_key: Option<String>,
}
-#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
-#[serde(default)]
-pub struct CaptchaConfig {
- /// Whether captcha is required for signup
- #[default(false)]
- pub enabled: bool,
- /// Can be easy, medium, or hard
- #[default("medium")]
- pub difficulty: String,
-}
-
#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
#[serde(default)]
pub struct DatabaseConfig {
pub tls_type: String,
}
-#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
-#[serde(default)]
-pub struct FederationConfig {
- /// Whether to enable activitypub federation.
- #[default(false)]
- pub enabled: bool,
- /// Allows and blocks are described here:
- /// https://join-lemmy.org/docs/en/administration/federation_getting_started.html
- ///
- /// list of instances with which federation is allowed
- #[default(None)]
- #[doku(example = "instance1.tld")]
- #[doku(example = "instance2.tld")]
- pub allowed_instances: Option<Vec<String>>,
- /// Instances which we never federate anything with (but previously federated objects are unaffected)
- #[default(None)]
- pub blocked_instances: Option<Vec<String>>,
- /// If true, only federate with instances on the allowlist and block everything else. If false,
- /// use allowlist only for remote communities, and posts/comments in local communities
- /// (meaning remote communities will show content from arbitrary instances).
- #[default(true)]
- pub strict_allowlist: bool,
- /// Maximum number of HTTP requests allowed to handle a single incoming activity (or a single object fetch through the search).
- #[default(25)]
- pub http_fetch_retry_limit: i32,
- /// Number of workers for sending outgoing activities. Search logs for "Activity queue stats" to
- /// see information. If "running" number is consistently close to the worker_count, you should
- /// increase it.
- #[default(64)]
- pub worker_count: u64,
- /// Use federation debug mode. Allows connecting to http and localhost urls. Also sends outgoing
- /// activities synchronously for easier testing. Do not use in production.
- #[default(false)]
- pub debug: bool,
-}
-
-#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
-#[serde(default)]
-pub struct RateLimitConfig {
- /// Maximum number of messages created in interval
- #[default(180)]
- pub message: i32,
- /// Interval length for message limit, in seconds
- #[default(60)]
- pub message_per_second: i32,
- /// Maximum number of posts created in interval
- #[default(6)]
- pub post: i32,
- /// Interval length for post limit, in seconds
- #[default(600)]
- pub post_per_second: i32,
- /// Maximum number of registrations in interval
- #[default(3)]
- pub register: i32,
- /// Interval length for registration limit, in seconds
- #[default(3600)]
- pub register_per_second: i32,
- /// Maximum number of image uploads in interval
- #[default(6)]
- pub image: i32,
- /// Interval length for image uploads, in seconds
- #[default(3600)]
- pub image_per_second: i32,
- /// Maximum number of comments created in interval
- #[default(6)]
- pub comment: i32,
- /// Interval length for comment limit, in seconds
- #[default(600)]
- pub comment_per_second: i32,
- #[default(60)]
- pub search: i32,
- /// Interval length for search limit, in seconds
- #[default(600)]
- pub search_per_second: i32,
-}
-
#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
pub struct SetupConfig {
/// Username for the admin user
-use crate::{
- settings::SETTINGS,
- utils::{
- is_valid_actor_name,
- is_valid_display_name,
- is_valid_matrix_id,
- is_valid_post_title,
- remove_slurs,
- scrape_text_for_mentions,
- slur_check,
- slurs_vec_to_str,
- },
+use regex::RegexBuilder;
+
+use crate::utils::{
+ is_valid_actor_name,
+ is_valid_display_name,
+ is_valid_matrix_id,
+ is_valid_post_title,
+ remove_slurs,
+ scrape_text_for_mentions,
+ slur_check,
+ slurs_vec_to_str,
};
#[test]
#[test]
fn test_valid_actor_name() {
- let actor_name_max_length = SETTINGS.actor_name_max_length;
+ let actor_name_max_length = 20;
assert!(is_valid_actor_name("Hello_98", actor_name_max_length));
assert!(is_valid_actor_name("ten", actor_name_max_length));
assert!(!is_valid_actor_name("Hello-98", actor_name_max_length));
#[test]
fn test_valid_display_name() {
- let actor_name_max_length = SETTINGS.actor_name_max_length;
+ let actor_name_max_length = 20;
assert!(is_valid_display_name("hello @there", actor_name_max_length));
assert!(!is_valid_display_name(
"@hello there",
#[test]
fn test_slur_filter() {
- let slur_regex = SETTINGS.slur_regex();
+ let slur_regex = Some(RegexBuilder::new(r"(fag(g|got|tard)?\b|cock\s?sucker(s|ing)?|ni((g{2,}|q)+|[gq]{2,})[e3r]+(s|z)?|mudslime?s?|kikes?|\bspi(c|k)s?\b|\bchinks?|gooks?|bitch(es|ing|y)?|whor(es?|ing)|\btr(a|@)nn?(y|ies?)|\b(b|re|r)tard(ed)?s?)").case_insensitive(true).build().unwrap());
let test =
"faggot test kike tranny cocksucker retardeds. Capitalized Niggerz. This is a bunch of other safe text.";
let slur_free = "No slurs here";
-use crate::{error::LemmyError, IpAddr};
+use crate::{error::LemmyError, location_info, IpAddr};
use actix_web::dev::ConnectionInfo;
+use anyhow::Context;
use chrono::{DateTime, FixedOffset, NaiveDateTime};
use itertools::Itertools;
use once_cell::sync::Lazy;
use rand::{distributions::Alphanumeric, thread_rng, Rng};
-use regex::Regex;
+use regex::{Regex, RegexBuilder};
use url::Url;
static MENTIONS_REGEX: Lazy<Regex> = Lazy::new(|| {
}
}
+pub fn build_slur_regex(regex_str: Option<&str>) -> Option<Regex> {
+ regex_str.map(|slurs| {
+ RegexBuilder::new(slurs)
+ .case_insensitive(true)
+ .build()
+ .expect("compile regex")
+ })
+}
+
pub fn check_slurs(text: &str, slur_regex: &Option<Regex>) -> Result<(), LemmyError> {
if let Err(slurs) = slur_check(text, slur_regex) {
Err(LemmyError::from_error_message(
[start, combined].concat()
}
+/// Make sure if applications are required, that there is an application questionnaire
+pub fn check_application_question(
+ application_question: &Option<Option<String>>,
+ require_application: &Option<bool>,
+) -> Result<(), LemmyError> {
+ if require_application.unwrap_or(false)
+ && application_question.as_ref().unwrap_or(&None).is_none()
+ {
+ Err(LemmyError::from_message("application_question_required"))
+ } else {
+ Ok(())
+ }
+}
+
pub fn generate_random_string() -> String {
thread_rng()
.sample_iter(&Alphanumeric)
url_out
}
+pub fn generate_domain_url(actor_id: &Url) -> Result<String, LemmyError> {
+ Ok(actor_id.host_str().context(location_info!())?.to_string())
+}
+
#[cfg(test)]
mod tests {
use crate::utils::{clean_url_params, is_valid_post_title};
-Subproject commit f5d6f0eabafd559417bf8f203fd655f7858bffcf
+Subproject commit 454debaede4cc932ac15fea9bf620cf1daf1ae4c
newtypes::{CommentId, CommunityId, LocalUserId, PersonId, PostId, PrivateMessageId},
source::{
comment::Comment,
- comment_reply::{CommentReply, CommentReplyForm},
+ comment_reply::{CommentReply, CommentReplyInsertForm},
person::Person,
- person_mention::{PersonMention, PersonMentionForm},
+ person_mention::{PersonMention, PersonMentionInsertForm},
post::Post,
},
traits::{Crud, DeleteableOrRemoveable},
// This can cause two notifications, one for reply and the other for mention
recipient_ids.push(mention_user_view.local_user.id);
- let user_mention_form = PersonMentionForm {
+ let user_mention_form = PersonMentionInsertForm {
recipient_id: mention_user_view.person.id,
comment_id: comment.id,
read: None,
if let Ok(parent_user_view) = user_view {
recipient_ids.push(parent_user_view.local_user.id);
- let comment_reply_form = CommentReplyForm {
+ let comment_reply_form = CommentReplyInsertForm {
recipient_id: parent_user_view.person.id,
comment_id: comment.id,
read: None,
if let Ok(parent_user_view) = parent_user {
recipient_ids.push(parent_user_view.local_user.id);
- let comment_reply_form = CommentReplyForm {
+ let comment_reply_form = CommentReplyInsertForm {
recipient_id: parent_user_view.person.id,
comment_id: comment.id,
read: None,
admin_username: lemmy_alpha
admin_password: lemmylemmy
site_name: lemmy-alpha
- sidebar: alphas sidebar
}
database: {
database: lemmy
port: 5432
pool_size: 5
}
- federation: {
- enabled: true
- allowed_instances: ["lemmy-beta","lemmy-gamma","lemmy-delta","lemmy-epsilon"]
- debug: true
- }
- captcha: {
- enabled: false
- difficulty: medium
- }
- rate_limit: {
- message: 180
- message_per_second: 60
- post: 99999
- post_per_second: 600
- register: 99999
- register_per_second: 3600
- image: 6
- image_per_second: 3600
- comment: 99999
- comment_per_second: 600
- }
}
port: 5432
pool_size: 5
}
- federation: {
- enabled: true
- allowed_instances: ["lemmy-alpha","lemmy-gamma","lemmy-delta","lemmy-epsilon"]
- debug: true
- }
- captcha: {
- enabled: false
- difficulty: medium
- }
- rate_limit: {
- message: 180
- message_per_second: 60
- post: 99999
- post_per_second: 600
- register: 99999
- register_per_second: 3600
- image: 6
- image_per_second: 3600
- comment: 99999
- comment_per_second: 600
- }
}
port: 5432
pool_size: 5
}
- federation: {
- enabled: true
- allowed_instances: ["lemmy-beta"]
- debug: true
- }
- captcha: {
- enabled: false
- difficulty: medium
- }
- rate_limit: {
- message: 180
- message_per_second: 60
- post: 99999
- post_per_second: 600
- register: 99999
- register_per_second: 3600
- image: 6
- image_per_second: 3600
- comment: 99999
- comment_per_second: 600
- }
}
port: 5432
pool_size: 5
}
- federation: {
- enabled: true
- blocked_instances: ["lemmy-alpha"]
- debug: true
- }
- captcha: {
- enabled: false
- difficulty: medium
- }
- rate_limit: {
- message: 180
- message_per_second: 60
- post: 99999
- post_per_second: 600
- register: 99999
- register_per_second: 3600
- image: 6
- image_per_second: 3600
- comment: 99999
- comment_per_second: 600
- }
}
port: 5432
pool_size: 5
}
- federation: {
- enabled: true
- allowed_instances: ["lemmy-alpha","lemmy-beta","lemmy-delta","lemmy-epsilon"]
- debug: true
- }
- captcha: {
- enabled: false
- difficulty: medium
- }
- rate_limit: {
- message: 180
- message_per_second: 60
- post: 99999
- post_per_second: 600
- register: 99999
- register_per_second: 3600
- image: 6
- image_per_second: 3600
- comment: 99999
- comment_per_second: 600
- }
}
--- /dev/null
+-- Add back site columns
+alter table site
+ add column enable_downvotes boolean default true not null,
+ add column open_registration boolean default true not null,
+ add column enable_nsfw boolean default true not null,
+ add column community_creation_admin_only boolean default false not null,
+ add column require_email_verification boolean default false not null,
+ add column require_application boolean default true not null,
+ add column application_question text default 'to verify that you are human, please explain why you want to create an account on this site'::text,
+ add column private_instance boolean default false not null,
+ add column default_theme text default 'browser'::text not null,
+ add column default_post_listing_type text default 'Local'::text not null,
+ add column legal_information text,
+ add column hide_modlog_mod_names boolean default true not null,
+ add column application_email_admins boolean default false not null;
+
+-- Insert the data back from local_site
+update site set
+ enable_downvotes = ls.enable_downvotes,
+ open_registration = ls.open_registration,
+ enable_nsfw = ls.enable_nsfw,
+ community_creation_admin_only = ls.community_creation_admin_only,
+ require_email_verification = ls.require_email_verification,
+ require_application = ls.require_application,
+ application_question = ls.application_question,
+ private_instance = ls.private_instance,
+ default_theme = ls.default_theme,
+ default_post_listing_type = ls.default_post_listing_type,
+ legal_information = ls.legal_information,
+ hide_modlog_mod_names = ls.hide_modlog_mod_names,
+ application_email_admins = ls.application_email_admins,
+ published = ls.published,
+ updated = ls.updated
+from (select
+ site_id,
+ enable_downvotes,
+ open_registration,
+ enable_nsfw,
+ community_creation_admin_only,
+ require_email_verification,
+ require_application,
+ application_question,
+ private_instance,
+ default_theme,
+ default_post_listing_type,
+ legal_information,
+ hide_modlog_mod_names,
+ application_email_admins,
+ published,
+ updated
+from local_site) as ls
+where site.id = ls.site_id;
+
+-- drop instance columns
+alter table site drop column instance_id;
+alter table person drop column instance_id;
+alter table community drop column instance_id;
+
+drop table local_site_rate_limit;
+drop table local_site;
+drop table federation_allowlist;
+drop table federation_blocklist;
+drop table instance;
--- /dev/null
+-- Create an instance table
+-- Holds any connected or unconnected domain
+create table instance (
+ id serial primary key,
+ domain varchar(255) not null unique,
+ published timestamp not null default now(),
+ updated timestamp null
+);
+
+-- Insert all the domains to the instance table
+insert into instance (domain)
+select distinct substring(p.actor_id from '(?:.*://)?(?:www\.)?([^/?]*)') from (
+ select actor_id from site
+ union
+ select actor_id from person
+ union
+ select actor_id from community
+) as p;
+
+-- Alter site, person, and community tables to reference the instance table.
+alter table site add column
+instance_id int references instance on update cascade on delete cascade;
+
+alter table person add column
+instance_id int references instance on update cascade on delete cascade;
+
+alter table community add column
+instance_id int references instance on update cascade on delete cascade;
+
+-- Add those columns
+update site set instance_id = i.id
+from instance i
+where substring(actor_id from '(?:.*://)?(?:www\.)?([^/?]*)') = i.domain;
+
+update person set instance_id = i.id
+from instance i
+where substring(actor_id from '(?:.*://)?(?:www\.)?([^/?]*)') = i.domain;
+
+update community set instance_id = i.id
+from instance i
+where substring(actor_id from '(?:.*://)?(?:www\.)?([^/?]*)') = i.domain;
+
+-- Make those columns unique not null now
+alter table site alter column instance_id set not null;
+alter table site add constraint idx_site_instance_unique unique (instance_id);
+
+alter table person alter column instance_id set not null;
+alter table community alter column instance_id set not null;
+
+-- Create allowlist and blocklist tables
+create table federation_allowlist (
+ id serial primary key,
+ instance_id int references instance on update cascade on delete cascade not null unique,
+ published timestamp not null default now(),
+ updated timestamp null
+);
+
+create table federation_blocklist (
+ id serial primary key,
+ instance_id int references instance on update cascade on delete cascade not null unique,
+ published timestamp not null default now(),
+ updated timestamp null
+);
+
+-- Move all the extra site settings-type columns to a local_site table
+-- Add a lot of other fields currently in the lemmy.hjson
+create table local_site (
+ id serial primary key,
+ site_id int references site on update cascade on delete cascade not null unique,
+
+ -- Site table fields
+ site_setup boolean default false not null,
+ enable_downvotes boolean default true not null,
+ open_registration boolean default true not null,
+ enable_nsfw boolean default true not null,
+ community_creation_admin_only boolean default false not null,
+ require_email_verification boolean default false not null,
+ require_application boolean default true not null,
+ application_question text default 'to verify that you are human, please explain why you want to create an account on this site'::text,
+ private_instance boolean default false not null,
+ default_theme text default 'browser'::text not null,
+ default_post_listing_type text default 'Local'::text not null,
+ legal_information text,
+ hide_modlog_mod_names boolean default true not null,
+ application_email_admins boolean default false not null,
+
+ -- Fields from lemmy.hjson
+ slur_filter_regex text,
+ actor_name_max_length int default 20 not null,
+ federation_enabled boolean default true not null,
+ federation_debug boolean default false not null,
+ federation_strict_allowlist boolean default true not null,
+ federation_http_fetch_retry_limit int default 25 not null,
+ federation_worker_count int default 64 not null,
+ captcha_enabled boolean default false not null,
+ captcha_difficulty varchar(255) default 'medium' not null,
+
+ -- Time fields
+ published timestamp without time zone default now() not null,
+ updated timestamp without time zone
+);
+
+-- local_site_rate_limit is its own table, so as to not go over 32 columns, and force diesel to use the 64-column-tables feature
+create table local_site_rate_limit (
+ id serial primary key,
+ local_site_id int references local_site on update cascade on delete cascade not null unique,
+ message int default 180 not null,
+ message_per_second int default 60 not null,
+ post int default 6 not null,
+ post_per_second int default 600 not null,
+ register int default 3 not null,
+ register_per_second int default 3600 not null,
+ image int default 6 not null,
+ image_per_second int default 3600 not null,
+ comment int default 6 not null,
+ comment_per_second int default 600 not null,
+ search int default 60 not null,
+ search_per_second int default 600 not null,
+ published timestamp without time zone default now() not null,
+ updated timestamp without time zone
+);
+
+-- Insert the data into local_site
+insert into local_site (
+ site_id,
+ site_setup,
+ enable_downvotes,
+ open_registration,
+ enable_nsfw,
+ community_creation_admin_only,
+ require_email_verification,
+ require_application,
+ application_question,
+ private_instance,
+ default_theme,
+ default_post_listing_type,
+ legal_information,
+ hide_modlog_mod_names,
+ application_email_admins,
+ published,
+ updated
+)
+select
+ id,
+ true, -- Assume site if setup if there's already a site row
+ enable_downvotes,
+ open_registration,
+ enable_nsfw,
+ community_creation_admin_only,
+ require_email_verification,
+ require_application,
+ application_question,
+ private_instance,
+ default_theme,
+ default_post_listing_type,
+ legal_information,
+ hide_modlog_mod_names,
+ application_email_admins,
+ published,
+ updated
+from site
+order by id limit 1;
+
+-- Default here
+insert into local_site_rate_limit (
+ local_site_id
+)
+select id from local_site
+order by id limit 1;
+
+-- Drop all those columns from site
+alter table site
+ drop column enable_downvotes,
+ drop column open_registration,
+ drop column enable_nsfw,
+ drop column community_creation_admin_only,
+ drop column require_email_verification,
+ drop column require_application,
+ drop column application_question,
+ drop column private_instance,
+ drop column default_theme,
+ drop column default_post_listing_type,
+ drop column legal_information,
+ drop column hide_modlog_mod_names,
+ drop column application_email_admins;
+
sql_types::{Nullable, Text},
*,
};
+use lemmy_api_common::lemmy_db_views::structs::SiteView;
use lemmy_apub::{
generate_followers_url,
generate_inbox_url,
};
use lemmy_db_schema::{
source::{
- comment::Comment,
- community::{Community, CommunityForm},
- person::{Person, PersonForm},
- post::Post,
- private_message::PrivateMessage,
- site::{Site, SiteForm},
+ comment::{Comment, CommentUpdateForm},
+ community::{Community, CommunityUpdateForm},
+ instance::Instance,
+ local_site::{LocalSite, LocalSiteInsertForm},
+ local_site_rate_limit::{LocalSiteRateLimit, LocalSiteRateLimitInsertForm},
+ local_user::{LocalUser, LocalUserInsertForm},
+ person::{Person, PersonInsertForm, PersonUpdateForm},
+ post::{Post, PostUpdateForm},
+ private_message::{PrivateMessage, PrivateMessageUpdateForm},
+ site::{Site, SiteInsertForm, SiteUpdateForm},
},
traits::Crud,
utils::naive_now,
};
-use lemmy_utils::error::LemmyError;
-use std::default::Default;
+use lemmy_utils::{error::LemmyError, settings::structs::Settings};
use tracing::info;
use url::Url;
pub fn run_advanced_migrations(
conn: &mut PgConnection,
- protocol_and_hostname: &str,
+ settings: &Settings,
) -> Result<(), LemmyError> {
+ let protocol_and_hostname = &settings.get_protocol_and_hostname();
user_updates_2020_04_02(conn, protocol_and_hostname)?;
community_updates_2020_04_02(conn, protocol_and_hostname)?;
post_updates_2020_04_03(conn, protocol_and_hostname)?;
apub_columns_2021_02_02(conn)?;
instance_actor_2022_01_28(conn, protocol_and_hostname)?;
regenerate_public_keys_2022_07_05(conn)?;
+ initialize_local_site_2022_10_10(conn, settings)?;
Ok(())
}
for cperson in &incorrect_persons {
let keypair = generate_actor_keypair()?;
- let form = PersonForm {
- name: cperson.name.to_owned(),
- actor_id: Some(generate_local_apub_endpoint(
+ let form = PersonUpdateForm::builder()
+ .actor_id(Some(generate_local_apub_endpoint(
EndpointType::Person,
&cperson.name,
protocol_and_hostname,
- )?),
- private_key: Some(Some(keypair.private_key)),
- public_key: Some(keypair.public_key),
- last_refreshed_at: Some(naive_now()),
- ..PersonForm::default()
- };
+ )?))
+ .private_key(Some(Some(keypair.private_key)))
+ .public_key(Some(keypair.public_key))
+ .last_refreshed_at(Some(naive_now()))
+ .build();
Person::update(conn, cperson.id, &form)?;
}
protocol_and_hostname,
)?;
- let form = CommunityForm {
- name: ccommunity.name.to_owned(),
- title: ccommunity.title.to_owned(),
- description: Some(ccommunity.description.to_owned()),
- hidden: Some(false),
- actor_id: Some(community_actor_id.to_owned()),
- local: Some(ccommunity.local),
- private_key: Some(Some(keypair.private_key)),
- public_key: Some(keypair.public_key),
- last_refreshed_at: Some(naive_now()),
- icon: Some(ccommunity.icon.to_owned()),
- banner: Some(ccommunity.banner.to_owned()),
- ..Default::default()
- };
+ let form = CommunityUpdateForm::builder()
+ .actor_id(Some(community_actor_id.to_owned()))
+ .private_key(Some(Some(keypair.private_key)))
+ .public_key(Some(keypair.public_key))
+ .last_refreshed_at(Some(naive_now()))
+ .build();
Community::update(conn, ccommunity.id, &form)?;
}
&cpost.id.to_string(),
protocol_and_hostname,
)?;
- Post::update_ap_id(conn, cpost.id, apub_id)?;
+ Post::update(
+ conn,
+ cpost.id,
+ &PostUpdateForm::builder().ap_id(Some(apub_id)).build(),
+ )?;
}
info!("{} post rows updated.", incorrect_posts.len());
&ccomment.id.to_string(),
protocol_and_hostname,
)?;
- Comment::update_ap_id(conn, ccomment.id, apub_id)?;
+ Comment::update(
+ conn,
+ ccomment.id,
+ &CommentUpdateForm::builder().ap_id(Some(apub_id)).build(),
+ )?;
}
info!("{} comment rows updated.", incorrect_comments.len());
&cpm.id.to_string(),
protocol_and_hostname,
)?;
- PrivateMessage::update_ap_id(conn, cpm.id, apub_id)?;
+ PrivateMessage::update(
+ conn,
+ cpm.id,
+ &PrivateMessageUpdateForm::builder()
+ .ap_id(Some(apub_id))
+ .build(),
+ )?;
}
info!("{} private message rows updated.", incorrect_pms.len());
protocol_and_hostname: &str,
) -> Result<(), LemmyError> {
info!("Running instance_actor_2021_09_29");
- if let Ok(site) = Site::read_local(conn) {
+ if let Ok(site_view) = SiteView::read_local(conn) {
+ let site = site_view.site;
// if site already has public key, we dont need to do anything here
if !site.public_key.is_empty() {
return Ok(());
}
let key_pair = generate_actor_keypair()?;
let actor_id = Url::parse(protocol_and_hostname)?;
- let site_form = SiteForm {
- name: site.name,
- actor_id: Some(actor_id.clone().into()),
- last_refreshed_at: Some(naive_now()),
- inbox_url: Some(generate_site_inbox_url(&actor_id.into())?),
- private_key: Some(Some(key_pair.private_key)),
- public_key: Some(key_pair.public_key),
- ..Default::default()
- };
+ let site_form = SiteUpdateForm::builder()
+ .actor_id(Some(actor_id.clone().into()))
+ .last_refreshed_at(Some(naive_now()))
+ .inbox_url(Some(generate_site_inbox_url(&actor_id.into())?))
+ .private_key(Some(Some(key_pair.private_key)))
+ .public_key(Some(key_pair.public_key))
+ .build();
Site::update(conn, site.id, &site_form)?;
}
Ok(())
community_.name
);
let key_pair = generate_actor_keypair()?;
- let form = CommunityForm {
- name: community_.name,
- title: community_.title,
- public_key: Some(key_pair.public_key),
- private_key: Some(Some(key_pair.private_key)),
- ..Default::default()
- };
+ let form = CommunityUpdateForm::builder()
+ .public_key(Some(key_pair.public_key))
+ .private_key(Some(Some(key_pair.private_key)))
+ .build();
Community::update(conn, community_.id, &form)?;
}
}
person_.name
);
let key_pair = generate_actor_keypair()?;
- let form = PersonForm {
- name: person_.name,
- public_key: Some(key_pair.public_key),
- private_key: Some(Some(key_pair.private_key)),
- ..Default::default()
- };
+ let form = PersonUpdateForm::builder()
+ .public_key(Some(key_pair.public_key))
+ .private_key(Some(Some(key_pair.private_key)))
+ .build();
Person::update(conn, person_.id, &form)?;
}
}
Ok(())
}
+
+/// This ensures that your local site is initialized and exists.
+///
+/// If a site already exists, the DB migration should generate a local_site row.
+/// This will only be run for brand new sites.
+fn initialize_local_site_2022_10_10(
+ conn: &mut PgConnection,
+ settings: &Settings,
+) -> Result<(), LemmyError> {
+ info!("Running initialize_local_site_2022_10_10");
+
+ // Check to see if local_site exists
+ if LocalSite::read(conn).is_ok() {
+ return Ok(());
+ }
+ info!("No Local Site found, creating it.");
+
+ let domain = settings
+ .get_hostname_without_port()
+ .expect("must have domain");
+
+ // Upsert this to the instance table
+ let instance = Instance::create(conn, &domain)?;
+
+ if let Some(setup) = &settings.setup {
+ let person_keypair = generate_actor_keypair()?;
+ let person_actor_id = generate_local_apub_endpoint(
+ EndpointType::Person,
+ &setup.admin_username,
+ &settings.get_protocol_and_hostname(),
+ )?;
+
+ // Register the user if there's a site setup
+ let person_form = PersonInsertForm::builder()
+ .name(setup.admin_username.to_owned())
+ .admin(Some(true))
+ .instance_id(instance.id)
+ .actor_id(Some(person_actor_id.clone()))
+ .private_key(Some(person_keypair.private_key))
+ .public_key(person_keypair.public_key)
+ .inbox_url(Some(generate_inbox_url(&person_actor_id)?))
+ .shared_inbox_url(Some(generate_shared_inbox_url(&person_actor_id)?))
+ .build();
+ let person_inserted = Person::create(conn, &person_form)?;
+
+ let local_user_form = LocalUserInsertForm::builder()
+ .person_id(person_inserted.id)
+ .password_encrypted(setup.admin_password.to_owned())
+ .email(setup.admin_email.to_owned())
+ .build();
+ LocalUser::create(conn, &local_user_form)?;
+ };
+
+ // Add an entry for the site table
+ let site_key_pair = generate_actor_keypair()?;
+ let site_actor_id = Url::parse(&settings.get_protocol_and_hostname())?;
+
+ let site_form = SiteInsertForm::builder()
+ .name(
+ settings
+ .setup
+ .to_owned()
+ .map(|s| s.site_name)
+ .unwrap_or_else(|| "New Site".to_string()),
+ )
+ .instance_id(instance.id)
+ .actor_id(Some(site_actor_id.clone().into()))
+ .last_refreshed_at(Some(naive_now()))
+ .inbox_url(Some(generate_site_inbox_url(&site_actor_id.into())?))
+ .private_key(Some(site_key_pair.private_key))
+ .public_key(Some(site_key_pair.public_key))
+ .build();
+ let site = Site::create(conn, &site_form)?;
+
+ // Finally create the local_site row
+ let local_site_form = LocalSiteInsertForm::builder()
+ .site_id(site.id)
+ .site_setup(Some(settings.setup.is_some()))
+ .build();
+ let local_site = LocalSite::create(conn, &local_site_form)?;
+
+ // Create the rate limit table
+ let local_site_rate_limit_form = LocalSiteRateLimitInsertForm::builder()
+ // TODO these have to be set, because the database defaults are too low for the federation
+ // tests to pass, and there's no way to live update the rate limits without restarting the
+ // server.
+ // This can be removed once live rate limits are enabled.
+ .message(Some(999))
+ .post(Some(999))
+ .register(Some(999))
+ .image(Some(999))
+ .comment(Some(999))
+ .search(Some(999))
+ .local_site_id(local_site.id)
+ .build();
+ LocalSiteRateLimit::create(conn, &local_site_rate_limit_form)?;
+
+ Ok(())
+}
-#![recursion_limit = "512"]
pub mod api_routes;
pub mod code_migrations;
pub mod root_span_builder;
use doku::json::{AutoComments, Formatting};
use lemmy_api::match_websocket_operation;
use lemmy_api_common::{
+ lemmy_db_views::structs::SiteView,
request::build_user_agent,
- utils::{blocking, check_private_instance_and_federation_enabled},
+ utils::{
+ blocking,
+ check_private_instance_and_federation_enabled,
+ local_site_rate_limit_to_rate_limit_config,
+ },
};
use lemmy_api_crud::match_websocket_operation_crud;
use lemmy_db_schema::{source::secret::Secret, utils::get_database_url_from_env};
.unwrap_or_else(|_| panic!("Error connecting to {}", db_url));
// Run the migrations from code
- let protocol_and_hostname = settings.get_protocol_and_hostname();
+ let settings_cloned = settings.to_owned();
blocking(&pool, move |conn| {
let _ = conn
.run_pending_migrations(MIGRATIONS)
.map_err(|_| LemmyError::from_message("Couldn't run migrations"))?;
- run_advanced_migrations(conn, &protocol_and_hostname)?;
+ run_advanced_migrations(conn, &settings_cloned)?;
Ok(()) as Result<(), LemmyError>
})
.await??;
scheduled_tasks::setup(pool2).expect("Couldn't set up scheduled_tasks");
});
+ // Initialize the secrets
+ let conn = &mut pool.get()?;
+ let secret = Secret::init(conn).expect("Couldn't initialize secrets.");
+
+ // Make sure the local site is set up.
+ let site_view = SiteView::read_local(conn).expect("local site not set up");
+ let local_site = site_view.local_site;
+ let federation_enabled = local_site.federation_enabled;
+
+ if federation_enabled {
+ println!("federation enabled, host is {}", &settings.hostname);
+ }
+
+ check_private_instance_and_federation_enabled(&local_site)?;
+
// Set up the rate limiter
+ let rate_limit_config =
+ local_site_rate_limit_to_rate_limit_config(&site_view.local_site_rate_limit);
+
+ // TODO this isn't live-updating
+ // https://github.com/LemmyNet/lemmy/issues/2508
let rate_limiter = RateLimit {
rate_limiter: Arc::new(Mutex::new(RateLimiter::default())),
- rate_limit_config: settings.rate_limit.to_owned().unwrap_or_default(),
+ rate_limit_config,
};
- // Initialize the secrets
- let conn = &mut pool.get()?;
- let secret = Secret::init(conn).expect("Couldn't initialize secrets.");
-
println!(
"Starting http server at {}:{}",
settings.bind, settings.port
.with(TracingMiddleware::default())
.build();
- check_private_instance_and_federation_enabled(&pool, &settings).await?;
-
let chat_server = ChatServer::startup(
pool.clone(),
rate_limiter.clone(),
.app_data(Data::new(rate_limiter.clone()))
// The routes
.configure(|cfg| api_routes::config(cfg, &rate_limiter))
- .configure(|cfg| lemmy_apub::http::routes::config(cfg, &settings))
+ .configure(|cfg| {
+ if federation_enabled {
+ lemmy_apub::http::routes::config(cfg);
+ webfinger::config(cfg);
+ }
+ })
.configure(feeds::config)
.configure(|cfg| images::config(cfg, pictrs_client.clone(), &rate_limiter))
.configure(nodeinfo::config)
- .configure(|cfg| webfinger::config(cfg, &settings))
})
.bind((settings_bind.bind, settings_bind.port))?
.run()