Page MenuHomePhabricator

D7878.id.diff
No OneTemporary

D7878.id.diff

diff --git a/keyserver/src/creators/invite-link-creator.js b/keyserver/src/creators/invite-link-creator.js
new file mode 100644
--- /dev/null
+++ b/keyserver/src/creators/invite-link-creator.js
@@ -0,0 +1,121 @@
+// @flow
+
+import type {
+ CreateOrUpdatePublicLinkRequest,
+ InviteLink,
+} from 'lib/types/link-types.js';
+import { threadPermissions } from 'lib/types/thread-permission-types.js';
+import { ServerError } from 'lib/utils/errors.js';
+
+import createIDs from './id-creator.js';
+import { dbQuery, SQL } from '../database/database.js';
+import { fetchPrimaryInviteLinks } from '../fetchers/link-fetchers.js';
+import { fetchServerThreadInfos } from '../fetchers/thread-fetchers.js';
+import { checkThreadPermission } from '../fetchers/thread-permission-fetchers.js';
+import { Viewer } from '../session/viewer.js';
+
+const secretRegex = /^[a-zA-Z0-9]+$/;
+
+async function createOrUpdatePublicLink(
+ viewer: Viewer,
+ request: CreateOrUpdatePublicLinkRequest,
+): Promise<InviteLink> {
+ if (!secretRegex.test(request.name)) {
+ throw new ServerError('invalid_parameters');
+ }
+
+ const permissionPromise = checkThreadPermission(
+ viewer,
+ request.communityID,
+ threadPermissions.MANAGE_INVITE_LINKS,
+ );
+ const existingPrimaryLinksPromise = fetchPrimaryInviteLinks(viewer);
+ const fetchThreadInfoPromise = fetchServerThreadInfos(
+ SQL`t.id = ${request.communityID}`,
+ );
+ const [hasPermission, existingPrimaryLinks, { threadInfos }] =
+ await Promise.all([
+ permissionPromise,
+ existingPrimaryLinksPromise,
+ fetchThreadInfoPromise,
+ ]);
+ if (!hasPermission) {
+ throw new ServerError('invalid_credentials');
+ }
+ const threadInfo = threadInfos[request.communityID];
+ if (!threadInfo) {
+ throw new ServerError('invalid_parameters');
+ }
+ const defaultRoleID = Object.keys(threadInfo.roles).find(
+ roleID => threadInfo.roles[roleID].isDefault,
+ );
+ if (!defaultRoleID) {
+ throw new ServerError('invalid_parameters');
+ }
+
+ const existingPrimaryLink = existingPrimaryLinks.find(
+ link => link.communityID === request.communityID && link.primary,
+ );
+ if (existingPrimaryLink) {
+ const query = SQL`
+ UPDATE invite_links
+ SET name = ${request.name}
+ WHERE \`primary\` = 1 AND community = ${request.communityID}
+ `;
+ try {
+ await dbQuery(query);
+ } catch {
+ throw new ServerError('invalid_parameters');
+ }
+ return {
+ name: request.name,
+ primary: true,
+ role: defaultRoleID,
+ communityID: request.communityID,
+ expirationTime: null,
+ limitOfUses: null,
+ numberOfUses: 0,
+ };
+ }
+
+ const [id] = await createIDs('invite_links', 1);
+
+ const row = [id, request.name, true, request.communityID, defaultRoleID];
+
+ const createLinkQuery = SQL`
+ INSERT INTO invite_links(id, name, \`primary\`, community, role)
+ SELECT ${row}
+ WHERE NOT EXISTS (
+ SELECT i.id
+ FROM invite_links i
+ WHERE i.\`primary\` = 1 AND i.community = ${request.communityID}
+ )
+ `;
+ let result = null;
+ try {
+ result = (await dbQuery(createLinkQuery))[0];
+ } catch {
+ throw new ServerError('invalid_parameters');
+ }
+
+ if (result.affectedRows === 0) {
+ const deleteIDs = SQL`
+ DELETE FROM ids
+ WHERE id = ${id}
+ `;
+ await dbQuery(deleteIDs);
+ throw new ServerError('invalid_parameters');
+ }
+
+ return {
+ name: request.name,
+ primary: true,
+ role: defaultRoleID,
+ communityID: request.communityID,
+ expirationTime: null,
+ limitOfUses: null,
+ numberOfUses: 0,
+ };
+}
+
+export { createOrUpdatePublicLink };
diff --git a/keyserver/src/endpoints.js b/keyserver/src/endpoints.js
--- a/keyserver/src/endpoints.js
+++ b/keyserver/src/endpoints.js
@@ -20,6 +20,7 @@
import type { JSONResponder } from './responders/handlers.js';
import { getSessionPublicKeysResponder } from './responders/keys-responders.js';
import {
+ createOrUpdatePublicLinkResponder,
fetchPrimaryInviteLinksResponder,
inviteLinkVerificationResponder,
} from './responders/link-responders.js';
@@ -97,6 +98,10 @@
responder: multimediaMessageCreationResponder,
requiredPolicies: baseLegalPolicies,
},
+ create_or_update_public_link: {
+ responder: createOrUpdatePublicLinkResponder,
+ requiredPolicies: baseLegalPolicies,
+ },
create_reaction_message: {
responder: reactionMessageCreationResponder,
requiredPolicies: baseLegalPolicies,
diff --git a/keyserver/src/responders/link-responders.js b/keyserver/src/responders/link-responders.js
--- a/keyserver/src/responders/link-responders.js
+++ b/keyserver/src/responders/link-responders.js
@@ -6,10 +6,13 @@
type InviteLinkVerificationRequest,
type InviteLinkVerificationResponse,
type FetchInviteLinksResponse,
+ type InviteLink,
inviteLinkValidator,
+ type CreateOrUpdatePublicLinkRequest,
} from 'lib/types/link-types.js';
import { tShape, tID } from 'lib/utils/validation-utils.js';
+import { createOrUpdatePublicLink } from '../creators/invite-link-creator.js';
import {
fetchPrimaryInviteLinks,
verifyInviteLink,
@@ -71,4 +74,27 @@
);
}
-export { inviteLinkVerificationResponder, fetchPrimaryInviteLinksResponder };
+const createOrUpdatePublicLinkInputValidator: TInterface<CreateOrUpdatePublicLinkRequest> =
+ tShape({
+ name: t.String,
+ communityID: tID,
+ });
+
+async function createOrUpdatePublicLinkResponder(
+ viewer: Viewer,
+ input: mixed,
+): Promise<InviteLink> {
+ const request = await validateInput(
+ viewer,
+ createOrUpdatePublicLinkInputValidator,
+ input,
+ );
+ const response = await createOrUpdatePublicLink(viewer, request);
+ return validateOutput(viewer.platformDetails, inviteLinkValidator, response);
+}
+
+export {
+ inviteLinkVerificationResponder,
+ fetchPrimaryInviteLinksResponder,
+ createOrUpdatePublicLinkResponder,
+};
diff --git a/lib/types/endpoints.js b/lib/types/endpoints.js
--- a/lib/types/endpoints.js
+++ b/lib/types/endpoints.js
@@ -51,6 +51,7 @@
CREATE_ERROR_REPORT: 'create_error_report',
CREATE_MESSAGE_REPORT: 'create_message_report',
CREATE_MULTIMEDIA_MESSAGE: 'create_multimedia_message',
+ CREATE_OR_UPDATE_PUBLIC_LINK: 'create_or_update_public_link',
CREATE_REACTION_MESSAGE: 'create_reaction_message',
EDIT_MESSAGE: 'edit_message',
CREATE_TEXT_MESSAGE: 'create_text_message',
diff --git a/lib/types/link-types.js b/lib/types/link-types.js
--- a/lib/types/link-types.js
+++ b/lib/types/link-types.js
@@ -55,3 +55,8 @@
export type InviteLinksStore = {
+links: InviteLinks,
};
+
+export type CreateOrUpdatePublicLinkRequest = {
+ +name: string,
+ +communityID: string,
+};

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 26, 11:19 AM (7 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2584398
Default Alt Text
D7878.id.diff (6 KB)

Event Timeline