mirror of
https://github.com/roleypoly/roleypoly.git
synced 2025-06-17 01:59:08 +00:00
update web, fix integration issues
This commit is contained in:
parent
2fb721078e
commit
e162096c03
30 changed files with 476 additions and 2574 deletions
|
@ -46,7 +46,7 @@ describe('getGuild', () => {
|
|||
roles: [],
|
||||
};
|
||||
|
||||
await config.kv.guilds.put('guilds/123', guild, config.retention.guild);
|
||||
await config.kv.guilds.put('123', guild, config.retention.guild);
|
||||
mockDiscordFetch.mockReturnValue({ ...guild, name: 'test2' });
|
||||
|
||||
const result = await getGuild(config, '123');
|
||||
|
@ -220,7 +220,7 @@ describe('getGuildMember', () => {
|
|||
nick: 'test2',
|
||||
};
|
||||
|
||||
await config.kv.guilds.put('guilds/123/members/123', member, config.retention.guild);
|
||||
await config.kv.guilds.put('123:members:123', member, config.retention.guild);
|
||||
mockDiscordFetch.mockReturnValue({ ...member, nick: 'test' });
|
||||
|
||||
const result = await getGuildMember(config, '123', '123');
|
||||
|
|
|
@ -25,7 +25,7 @@ export const getGuild = async (
|
|||
forceMiss?: boolean
|
||||
): Promise<(Guild & OwnRoleInfo) | null> =>
|
||||
config.kv.guilds.cacheThrough(
|
||||
`guilds/${id}`,
|
||||
`guild/${id}`,
|
||||
async () => {
|
||||
const guildRaw = await discordFetch<APIGuild>(
|
||||
`/guilds/${id}`,
|
||||
|
@ -54,7 +54,7 @@ export const getGuild = async (
|
|||
managed: role.managed,
|
||||
position: role.position,
|
||||
permissions: role.permissions,
|
||||
safety: RoleSafety.Safe, // TODO: calculate this
|
||||
safety: calculateRoleSafety(role, highestRolePosition),
|
||||
}));
|
||||
|
||||
const guild: Guild & OwnRoleInfo = {
|
||||
|
@ -133,7 +133,7 @@ export const getGuildMember = async (
|
|||
overrideRetention?: number // allows for own-member to be cached as long as it's used.
|
||||
): Promise<Member | null> =>
|
||||
config.kv.guilds.cacheThrough(
|
||||
`guilds/${serverID}/members/${userID}`,
|
||||
`members/${serverID}/${userID}`,
|
||||
async () => {
|
||||
const discordMember = await discordFetch<APIMember>(
|
||||
`/guilds/${serverID}/members/${userID}`,
|
||||
|
@ -156,6 +156,23 @@ export const getGuildMember = async (
|
|||
forceMiss
|
||||
);
|
||||
|
||||
export const updateGuildMember = async (
|
||||
config: Config,
|
||||
serverID: string,
|
||||
member: APIMember
|
||||
): Promise<void> => {
|
||||
config.kv.guilds.put(
|
||||
`members/${serverID}/${member.user.id}`,
|
||||
{
|
||||
guildid: serverID,
|
||||
roles: member.roles,
|
||||
pending: member.pending,
|
||||
nick: member.nick,
|
||||
},
|
||||
config.retention.member
|
||||
);
|
||||
};
|
||||
|
||||
const calculateRoleSafety = (role: Role | APIRole, highestBotRolePosition: number) => {
|
||||
let safety = RoleSafety.Safe;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import { Router } from 'itty-router';
|
|||
import { authBounce } from './routes/auth/bounce';
|
||||
import { Environment, parseEnvironment } from './utils/config';
|
||||
import { Context, RoleypolyHandler } from './utils/context';
|
||||
import { json, notFound, serverError } from './utils/response';
|
||||
import { corsHeaders, json, notFound, serverError } from './utils/response';
|
||||
|
||||
const router = Router();
|
||||
|
||||
|
@ -42,8 +42,7 @@ router.delete(
|
|||
);
|
||||
router.put('/guilds/:guildId/roles', ...guildsCommon, guildsRolesPut);
|
||||
|
||||
// Slug is unauthenticated...
|
||||
router.get('/guilds/slug/:guildId', injectParams, guildsSlug);
|
||||
router.get('/guilds/:guildId/slug', injectParams, withSession, guildsSlug);
|
||||
|
||||
router.post('/interactions', handleInteraction);
|
||||
|
||||
|
@ -60,7 +59,23 @@ router.get('/', ((request: Request, { config }: Context) =>
|
|||
meta: config.uiPublicURI,
|
||||
})) as RoleypolyHandler);
|
||||
|
||||
router.any('*', () => notFound());
|
||||
router.options('*', (request: Request) => {
|
||||
return new Response(null, {
|
||||
headers: {
|
||||
...corsHeaders,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
router.all('/*', notFound);
|
||||
|
||||
const scrubURL = (urlStr: string) => {
|
||||
const url = new URL(urlStr);
|
||||
url.searchParams.delete('code');
|
||||
url.searchParams.delete('state');
|
||||
|
||||
return url.toString();
|
||||
};
|
||||
|
||||
export default {
|
||||
async fetch(request: Request, env: Environment, event: Context['fetchContext']) {
|
||||
|
@ -68,13 +83,14 @@ export default {
|
|||
const context: Context = {
|
||||
config,
|
||||
fetchContext: {
|
||||
waitUntil: event.waitUntil,
|
||||
waitUntil: event.waitUntil.bind(event),
|
||||
},
|
||||
authMode: {
|
||||
type: 'anonymous',
|
||||
},
|
||||
params: {},
|
||||
};
|
||||
console.log(`${request.method} ${scrubURL(request.url)}`);
|
||||
return router
|
||||
.handle(request, context)
|
||||
.catch((e: Error) => (!e ? notFound() : serverError(e)));
|
||||
|
|
|
@ -2,7 +2,7 @@ import { isAllowedCallbackHost } from '@roleypoly/api/src/routes/auth/bounce';
|
|||
import { createSession } from '@roleypoly/api/src/sessions/create';
|
||||
import { getStateSession } from '@roleypoly/api/src/sessions/state';
|
||||
import { Context, RoleypolyHandler } from '@roleypoly/api/src/utils/context';
|
||||
import { AuthType, discordAPIBase, discordFetch } from '@roleypoly/api/src/utils/discord';
|
||||
import { AuthType, discordFetch } from '@roleypoly/api/src/utils/discord';
|
||||
import { dateFromID } from '@roleypoly/api/src/utils/id';
|
||||
import { formDataRequest, getQuery } from '@roleypoly/api/src/utils/request';
|
||||
import { seeOther } from '@roleypoly/api/src/utils/response';
|
||||
|
@ -51,7 +51,7 @@ export const authCallback: RoleypolyHandler = async (
|
|||
}
|
||||
|
||||
const response = await discordFetch<AuthTokenResponse>(
|
||||
`${discordAPIBase}/oauth2/token`,
|
||||
`/oauth2/token`,
|
||||
'',
|
||||
AuthType.None,
|
||||
formDataRequest({
|
||||
|
|
|
@ -2,9 +2,10 @@ import {
|
|||
getGuild,
|
||||
getGuildData,
|
||||
getGuildMember,
|
||||
updateGuildMember,
|
||||
} from '@roleypoly/api/src/guilds/getters';
|
||||
import { Context, RoleypolyHandler } from '@roleypoly/api/src/utils/context';
|
||||
import { AuthType, discordFetch } from '@roleypoly/api/src/utils/discord';
|
||||
import { APIMember, AuthType, discordFetch } from '@roleypoly/api/src/utils/discord';
|
||||
import {
|
||||
engineeringProblem,
|
||||
invalid,
|
||||
|
@ -66,11 +67,14 @@ export const guildsRolesPut: RoleypolyHandler = async (
|
|||
updateRequest,
|
||||
});
|
||||
|
||||
if (isIdenticalArray(member.roles, newRoles)) {
|
||||
if (
|
||||
isIdenticalArray(member.roles, newRoles) ||
|
||||
isIdenticalArray(updateRequest.knownState, newRoles)
|
||||
) {
|
||||
return invalid();
|
||||
}
|
||||
|
||||
const patchMemberRoles = await discordFetch<Member>(
|
||||
const patchMemberRoles = await discordFetch<APIMember>(
|
||||
`/guilds/${guildID}/members/${userID}`,
|
||||
context.config.botToken,
|
||||
AuthType.Bot,
|
||||
|
@ -90,7 +94,9 @@ export const guildsRolesPut: RoleypolyHandler = async (
|
|||
return serverError(new Error('discord rejected the request'));
|
||||
}
|
||||
|
||||
context.fetchContext.waitUntil(getGuildMember(context.config, guildID, userID, true));
|
||||
context.fetchContext.waitUntil(
|
||||
updateGuildMember(context.config, guildID, patchMemberRoles)
|
||||
);
|
||||
|
||||
const updatedMember: Member = {
|
||||
roles: patchMemberRoles.roles,
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
getGuildMember,
|
||||
} from '@roleypoly/api/src/guilds/getters';
|
||||
import { Context, RoleypolyHandler } from '@roleypoly/api/src/utils/context';
|
||||
import { getQuery } from '@roleypoly/api/src/utils/request';
|
||||
import { json, notFound } from '@roleypoly/api/src/utils/response';
|
||||
import { PresentableGuild } from '@roleypoly/types';
|
||||
|
||||
|
@ -11,7 +12,8 @@ export const guildsGuild: RoleypolyHandler = async (
|
|||
request: Request,
|
||||
context: Context
|
||||
) => {
|
||||
const guild = await getGuild(context.config, context.params!.guildId!);
|
||||
const { noCache } = getQuery(request);
|
||||
const guild = await getGuild(context.config, context.params!.guildId!, !!noCache);
|
||||
|
||||
if (!guild) {
|
||||
return notFound();
|
||||
|
@ -20,7 +22,8 @@ export const guildsGuild: RoleypolyHandler = async (
|
|||
const member = await getGuildMember(
|
||||
context.config,
|
||||
context.params!.guildId!,
|
||||
context.session!.user.id
|
||||
context.session!.user.id,
|
||||
!!noCache
|
||||
);
|
||||
|
||||
if (!member) {
|
||||
|
|
|
@ -8,6 +8,13 @@ export const guildsSlug: RoleypolyHandler = async (
|
|||
context: Context
|
||||
) => {
|
||||
const id = context.params.guildId!;
|
||||
|
||||
const guildInSession = context.session?.guilds.find((guild) => guild.id === id);
|
||||
|
||||
if (guildInSession) {
|
||||
return json<GuildSlug>(guildInSession);
|
||||
}
|
||||
|
||||
const guild = await getGuild(context.config, id);
|
||||
if (!guild) {
|
||||
return notFound();
|
||||
|
@ -19,5 +26,6 @@ export const guildsSlug: RoleypolyHandler = async (
|
|||
icon: guild.icon,
|
||||
permissionLevel: UserGuildPermissions.User,
|
||||
};
|
||||
return json(slug);
|
||||
|
||||
return json<GuildSlug>(slug);
|
||||
};
|
||||
|
|
|
@ -125,6 +125,9 @@ export type APIMember = {
|
|||
roles: string[];
|
||||
pending: boolean;
|
||||
nick: string;
|
||||
user: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
export const parsePermissions = (
|
||||
|
|
|
@ -22,7 +22,7 @@ export const fetchLegacyServer = async (
|
|||
config: Config,
|
||||
id: string
|
||||
): Promise<LegacyGuildData | null> => {
|
||||
if (!config.interactionsSharedKey) {
|
||||
if (!config.importSharedKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
export const json = (obj: any, init?: ResponseInit): Response => {
|
||||
export const json = <T>(obj: T, init?: ResponseInit): Response => {
|
||||
const body = JSON.stringify(obj);
|
||||
return new Response(body, {
|
||||
...init,
|
||||
headers: {
|
||||
...init?.headers,
|
||||
'content-type': 'application/json; charset=utf-8',
|
||||
...corsHeaders,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const corsHeaders = {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS, PATCH',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
'Access-Control-Max-Age': '86400',
|
||||
};
|
||||
|
||||
export const noContent = () => new Response(null, { status: 204 });
|
||||
export const seeOther = (url: string) =>
|
||||
new Response(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue