[mastodon-client] GET /v1/announcements, POST /v1/announcements/:id/dismiss

This commit is contained in:
Laura Hausmann 2023-10-05 00:44:33 +02:00
parent 059a20f4b1
commit 44b72a2ecc
No known key found for this signature in database
GPG Key ID: D044E84C5BE01605
3 changed files with 108 additions and 23 deletions

View File

@ -0,0 +1,27 @@
import { Announcement } from "@/models/entities/announcement.js";
import { ILocalUser } from "@/models/entities/user.js";
import { awaitAll } from "@/prelude/await-all";
import { AnnouncementReads } from "@/models/index.js";
import { MfmHelpers } from "@/server/api/mastodon/helpers/mfm.js";
import mfm from "mfm-js";
export class AnnouncementConverter {
public static encode(announcement: Announcement, isRead: boolean): MastodonEntity.Announcement {
return {
id: announcement.id,
content: `<h1>${MfmHelpers.toHtml(mfm.parse(announcement.title), []) ?? 'Announcement'}</h1>${MfmHelpers.toHtml(mfm.parse(announcement.text), []) ?? ''}`,
starts_at: null,
ends_at: null,
published: true,
all_day: false,
published_at: announcement.createdAt.toISOString(),
updated_at: announcement.updatedAt?.toISOString() ?? announcement.createdAt.toISOString(),
read: isRead,
mentions: [], //FIXME
statuses: [],
tags: [],
emojis: [], //FIXME
reactions: [],
};
}
}

View File

@ -1,8 +1,11 @@
import Router from "@koa/router";
import { getClient } from "@/server/api/mastodon/index.js";
import { convertId, IdType } from "@/misc/convert-id.js";
import { convertAnnouncementId } from "@/server/api/mastodon/converters.js";
import { MiscHelpers } from "@/server/api/mastodon/helpers/misc.js";
import authenticate from "@/server/api/authenticate.js";
import { argsToBools } from "@/server/api/mastodon/endpoints/timeline.js";
import { Announcements } from "@/models/index.js";
import { convertAnnouncementId } from "@/server/api/mastodon/converters.js";
import { convertId, IdType } from "@/misc/convert-id.js";
export function setupEndpointsMisc(router: Router): void {
router.get("/v1/custom_emojis", async (ctx) => {
@ -30,36 +33,49 @@ export function setupEndpointsMisc(router: Router): void {
});
router.get("/v1/announcements", async (ctx) => {
const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`;
const accessTokens = ctx.request.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.getInstanceAnnouncements();
ctx.body = data.data.map((announcement) =>
convertAnnouncementId(announcement),
);
const auth = await authenticate(ctx.headers.authorization, null);
const user = auth[0] ?? null;
if (!user) {
ctx.status = 401;
return;
}
const args = argsToBools(ctx.query, ['with_dismissed']);
ctx.body = await MiscHelpers.getAnnouncements(user, args['with_dismissed'])
.then(p => p.map(x => convertAnnouncementId(x)));
} catch (e: any) {
console.error(e);
ctx.status = 401;
ctx.body = e.response.data;
ctx.status = 500;
ctx.body = { error: e.message };
}
});
router.post<{ Params: { id: string } }>(
"/v1/announcements/:id/dismiss",
async (ctx) => {
const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`;
const accessTokens = ctx.request.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.dismissInstanceAnnouncement(
convertId(ctx.params.id, IdType.IceshrimpId),
);
ctx.body = data.data;
const auth = await authenticate(ctx.headers.authorization, null);
const user = auth[0] ?? null;
if (!user) {
ctx.status = 401;
return;
}
const id = convertId(ctx.params.id, IdType.IceshrimpId);
const announcement = await Announcements.findOneBy({id: id});
if (!announcement) {
ctx.status = 404;
return;
}
await MiscHelpers.dismissAnnouncement(announcement, user);
ctx.body = {};
} catch (e: any) {
console.error(e);
ctx.status = 401;
ctx.body = e.response.data;
ctx.status = 500;
ctx.body = { error: e.message };
}
},
);

View File

@ -1,11 +1,15 @@
import config from "@/config/index.js";
import { FILE_TYPE_BROWSERSAFE, MAX_NOTE_TEXT_LENGTH } from "@/const.js";
import { fetchMeta } from "@/misc/fetch-meta.js";
import { Instances, Notes, Users } from "@/models/index.js";
import { AnnouncementReads, Announcements, Instances, Notes, Users } from "@/models/index.js";
import { IsNull } from "typeorm";
import { awaitAll } from "@/prelude/await-all.js";
import { UserConverter } from "@/server/api/mastodon/converters/user.js";
import { convertAccountId } from "@/server/api/mastodon/converters.js";
import { Announcement } from "@/models/entities/announcement.js";
import { ILocalUser } from "@/models/entities/user.js";
import { AnnouncementConverter } from "@/server/api/mastodon/converters/announcement.js";
import { genId } from "@/misc/gen-id.js";
export class MiscHelpers {
public static async getInstance(): Promise<MastodonEntity.Instance> {
@ -81,4 +85,42 @@ export class MiscHelpers {
return awaitAll(res);
}
public static async getAnnouncements(user: ILocalUser, includeRead: boolean = false): Promise<MastodonEntity.Announcement[]> {
if (includeRead) {
const [announcements, reads] = await Promise.all([
Announcements.createQueryBuilder("announcement")
.orderBy({"announcement.id": "DESC"})
.getMany(),
AnnouncementReads.findBy({userId: user.id})
.then(p => p.map(x => x.announcementId))
]);
return announcements.map(p => AnnouncementConverter.encode(p, reads.includes(p.id)));
}
const sq = AnnouncementReads.createQueryBuilder("reads")
.select("reads.announcementId")
.where("reads.userId = :userId");
const query = Announcements.createQueryBuilder("announcement")
.where(`announcement.id NOT IN (${sq.getQuery()})`)
.orderBy({"announcement.id": "DESC"})
.setParameter("userId", user.id);
return query.getMany()
.then(p => p.map(x => AnnouncementConverter.encode(x, false)));
}
public static async dismissAnnouncement(announcement: Announcement, user: ILocalUser): Promise<void> {
const exists = await AnnouncementReads.exist({where: {userId: user.id, announcementId: announcement.id}});
if (!exists) {
await AnnouncementReads.insert({
id: genId(),
createdAt: new Date(),
userId: user.id,
announcementId: announcement.id
});
}
}
}