iceshrimp/packages/backend/src/server/api/mastodon/endpoints/account.ts

246 lines
11 KiB
TypeScript

import Router from "@koa/router";
import { argsToBools, convertPaginationArgsIds, limitToInt, normalizeUrlQuery } from "./timeline.js";
import { convertId, IdType } from "../../index.js";
import { convertAccountId, convertListId, convertRelationshipId, convertStatusIds, } from "../converters.js";
import { UserConverter } from "@/server/api/mastodon/converters/user.js";
import { NoteConverter } from "@/server/api/mastodon/converters/note.js";
import { UserHelpers } from "@/server/api/mastodon/helpers/user.js";
import { PaginationHelpers } from "@/server/api/mastodon/helpers/pagination.js";
import { ListHelpers } from "@/server/api/mastodon/helpers/list.js";
import { Files } from "formidable";
import { auth } from "@/server/api/mastodon/middleware/auth.js";
export function setupEndpointsAccount(router: Router): void {
router.get("/v1/accounts/verify_credentials",
auth(true, ['read:accounts']),
async (ctx) => {
const acct = await UserHelpers.verifyCredentials(ctx.user);
ctx.body = convertAccountId(acct);
}
);
router.patch("/v1/accounts/update_credentials",
auth(true, ['write:accounts']),
async (ctx) => {
const files = (ctx.request as any).files as Files | undefined;
const acct = await UserHelpers.updateCredentials(ctx.user, (ctx.request as any).body as any, files);
ctx.body = convertAccountId(acct)
}
);
router.get("/v1/accounts/lookup",
async (ctx) => {
const args = normalizeUrlQuery(ctx.query);
const user = await UserHelpers.getUserFromAcct(args.acct);
const account = await UserConverter.encode(user);
ctx.body = convertAccountId(account);
}
);
router.get("/v1/accounts/relationships",
auth(true, ['read:follows']),
async (ctx) => {
const ids = (normalizeUrlQuery(ctx.query, ['id[]'])['id[]'] ?? [])
.map((id: string) => convertId(id, IdType.IceshrimpId));
const result = await UserHelpers.getUserRelationhipToMany(ids, ctx.user.id);
ctx.body = result.map(rel => convertRelationshipId(rel));
}
);
router.get<{ Params: { id: string } }>("/v1/accounts/:id",
auth(false),
async (ctx) => {
const userId = convertId(ctx.params.id, IdType.IceshrimpId);
const account = await UserConverter.encode(await UserHelpers.getUserOr404(userId));
ctx.body = convertAccountId(account);
}
);
router.get<{ Params: { id: string } }>(
"/v1/accounts/:id/statuses",
auth(false, ["read:statuses"]),
async (ctx) => {
const userId = convertId(ctx.params.id, IdType.IceshrimpId);
const query = await UserHelpers.getUserCachedOr404(userId, ctx.cache);
const args = normalizeUrlQuery(convertPaginationArgsIds(argsToBools(limitToInt(ctx.query))));
const res = await UserHelpers.getUserStatuses(query, ctx.user, args.max_id, args.since_id, args.min_id, args.limit, args['only_media'], args['exclude_replies'], args['exclude_reblogs'], args.pinned, args.tagged);
const tl = await NoteConverter.encodeMany(res.data, ctx.user, ctx.cache);
ctx.body = tl.map(s => convertStatusIds(s));
ctx.pagination = res.pagination;
},
);
router.get<{ Params: { id: string } }>(
"/v1/accounts/:id/featured_tags",
async (ctx) => {
ctx.body = [];
},
);
router.get<{ Params: { id: string } }>(
"/v1/accounts/:id/followers",
auth(false),
async (ctx) => {
const userId = convertId(ctx.params.id, IdType.IceshrimpId);
const query = await UserHelpers.getUserCachedOr404(userId, ctx.cache);
const args = normalizeUrlQuery(convertPaginationArgsIds(limitToInt(ctx.query as any)));
const res = await UserHelpers.getUserFollowers(query, ctx.user, args.max_id, args.since_id, args.min_id, args.limit);
const followers = await UserConverter.encodeMany(res.data, ctx.cache);
ctx.body = followers.map((account) => convertAccountId(account));
ctx.pagination = res.pagination;
},
);
router.get<{ Params: { id: string } }>(
"/v1/accounts/:id/following",
auth(false),
async (ctx) => {
const userId = convertId(ctx.params.id, IdType.IceshrimpId);
const query = await UserHelpers.getUserCachedOr404(userId, ctx.cache);
const args = normalizeUrlQuery(convertPaginationArgsIds(limitToInt(ctx.query as any)));
const res = await UserHelpers.getUserFollowing(query, ctx.user, args.max_id, args.since_id, args.min_id, args.limit);
const following = await UserConverter.encodeMany(res.data, ctx.cache);
ctx.body = following.map((account) => convertAccountId(account));
ctx.pagination = res.pagination;
},
);
router.get<{ Params: { id: string } }>(
"/v1/accounts/:id/lists",
auth(true, ["read:lists"]),
async (ctx) => {
const member = await UserHelpers.getUserCachedOr404(convertId(ctx.params.id, IdType.IceshrimpId));
const results = await ListHelpers.getListsByMember(ctx.user, member);
ctx.body = results.map(p => convertListId(p));
},
);
router.post<{ Params: { id: string } }>(
"/v1/accounts/:id/follow",
auth(true, ["write:follows"]),
async (ctx) => {
const target = await UserHelpers.getUserCachedOr404(convertId(ctx.params.id, IdType.IceshrimpId));
//FIXME: Parse form data
const result = await UserHelpers.followUser(target, ctx.user, true, false);
ctx.body = convertRelationshipId(result);
},
);
router.post<{ Params: { id: string } }>(
"/v1/accounts/:id/unfollow",
auth(true, ["write:follows"]),
async (ctx) => {
const target = await UserHelpers.getUserCachedOr404(convertId(ctx.params.id, IdType.IceshrimpId));
const result = await UserHelpers.unfollowUser(target, ctx.user);
ctx.body = convertRelationshipId(result);
},
);
router.post<{ Params: { id: string } }>(
"/v1/accounts/:id/block",
auth(true, ["write:blocks"]),
async (ctx) => {
const target = await UserHelpers.getUserCachedOr404(convertId(ctx.params.id, IdType.IceshrimpId));
const result = await UserHelpers.blockUser(target, ctx.user);
ctx.body = convertRelationshipId(result);
},
);
router.post<{ Params: { id: string } }>(
"/v1/accounts/:id/unblock",
auth(true, ["write:blocks"]),
async (ctx) => {
const target = await UserHelpers.getUserCachedOr404(convertId(ctx.params.id, IdType.IceshrimpId));
const result = await UserHelpers.unblockUser(target, ctx.user);
ctx.body = convertRelationshipId(result)
},
);
router.post<{ Params: { id: string } }>(
"/v1/accounts/:id/mute",
auth(true, ["write:mutes"]),
async (ctx) => {
//FIXME: parse form data
const args = normalizeUrlQuery(argsToBools(limitToInt(ctx.query, ['duration']), ['notifications']));
const target = await UserHelpers.getUserCachedOr404(convertId(ctx.params.id, IdType.IceshrimpId));
const result = await UserHelpers.muteUser(target, ctx.user, args.notifications, args.duration);
ctx.body = convertRelationshipId(result)
},
);
router.post<{ Params: { id: string } }>(
"/v1/accounts/:id/unmute",
auth(true, ["write:mutes"]),
async (ctx) => {
const target = await UserHelpers.getUserCachedOr404(convertId(ctx.params.id, IdType.IceshrimpId));
const result = await UserHelpers.unmuteUser(target, ctx.user);
ctx.body = convertRelationshipId(result)
},
);
router.get("/v1/featured_tags",
async (ctx) => {
ctx.body = [];
}
);
router.get("/v1/followed_tags",
async (ctx) => {
ctx.body = [];
}
);
router.get("/v1/bookmarks",
auth(true, ["read:bookmarks"]),
async (ctx) => {
const args = normalizeUrlQuery(convertPaginationArgsIds(limitToInt(ctx.query as any)));
const res = await UserHelpers.getUserBookmarks(ctx.user, args.max_id, args.since_id, args.min_id, args.limit);
const bookmarks = await NoteConverter.encodeMany(res.data, ctx.user, ctx.cache);
ctx.body = bookmarks.map(s => convertStatusIds(s));
ctx.pagination = res.pagination;
}
);
router.get("/v1/favourites",
auth(true, ["read:favourites"]),
async (ctx) => {
const args = normalizeUrlQuery(convertPaginationArgsIds(limitToInt(ctx.query as any)));
const res = await UserHelpers.getUserFavorites(ctx.user, args.max_id, args.since_id, args.min_id, args.limit);
const favorites = await NoteConverter.encodeMany(res.data, ctx.user, ctx.cache);
ctx.body = favorites.map(s => convertStatusIds(s));
ctx.pagination = res.pagination;
}
);
router.get("/v1/mutes",
auth(true, ["read:mutes"]),
async (ctx) => {
const args = normalizeUrlQuery(convertPaginationArgsIds(limitToInt(ctx.query as any)));
const res = await UserHelpers.getUserMutes(ctx.user, args.max_id, args.since_id, args.min_id, args.limit, ctx.cache);
ctx.body = res.data.map(m => convertAccountId(m));
ctx.pagination = res.pagination;
}
);
router.get("/v1/blocks",
auth(true, ["read:blocks"]),
async (ctx) => {
const args = normalizeUrlQuery(convertPaginationArgsIds(limitToInt(ctx.query as any)));
const res = await UserHelpers.getUserBlocks(ctx.user, args.max_id, args.since_id, args.min_id, args.limit);
const blocks = await UserConverter.encodeMany(res.data, ctx.cache);
ctx.body = blocks.map(b => convertAccountId(b));
ctx.pagination = res.pagination;
}
);
router.get("/v1/follow_requests",
auth(true, ["read:follows"]),
async (ctx) => {
const args = normalizeUrlQuery(convertPaginationArgsIds(limitToInt(ctx.query as any)));
const res = await UserHelpers.getUserFollowRequests(ctx.user, args.max_id, args.since_id, args.min_id, args.limit);
const requests = await UserConverter.encodeMany(res.data, ctx.cache);
ctx.body = requests.map(b => convertAccountId(b));
ctx.pagination = res.pagination;
}
);
router.post<{ Params: { id: string } }>(
"/v1/follow_requests/:id/authorize",
auth(true, ["write:follows"]),
async (ctx) => {
const target = await UserHelpers.getUserCachedOr404(convertId(ctx.params.id, IdType.IceshrimpId));
const result = await UserHelpers.acceptFollowRequest(target, ctx.user);
ctx.body = convertRelationshipId(result);
},
);
router.post<{ Params: { id: string } }>(
"/v1/follow_requests/:id/reject",
auth(true, ["write:follows"]),
async (ctx) => {
const target = await UserHelpers.getUserCachedOr404(convertId(ctx.params.id, IdType.IceshrimpId));
const result = await UserHelpers.rejectFollowRequest(target, ctx.user);
ctx.body = convertRelationshipId(result);
},
);
}