remove queries to scheduled_note table
This commit is contained in:
parent
16f26bc6d7
commit
2c54bc3364
4 changed files with 88 additions and 64 deletions
|
@ -3,7 +3,10 @@ use crate::{
|
|||
database::db_conn,
|
||||
misc::get_note_summary::{get_note_summary, PartialNoteToSummarize},
|
||||
model::entity::{access_token, app, sw_subscription},
|
||||
util::{http_client, id::{get_timestamp, InvalidIdError}},
|
||||
util::{
|
||||
http_client,
|
||||
id::{get_timestamp, InvalidIdError},
|
||||
},
|
||||
};
|
||||
use once_cell::sync::OnceCell;
|
||||
use sea_orm::prelude::*;
|
||||
|
@ -255,8 +258,8 @@ pub async fn send_push_notification(
|
|||
|
||||
// TODO: refactoring
|
||||
let mut payload = if use_mastodon_api {
|
||||
// Content generated per subscription
|
||||
"".to_string()
|
||||
// Content generated per subscription
|
||||
"".to_string()
|
||||
} else {
|
||||
// Format the `content` passed from the TypeScript backend
|
||||
// for Firefish push notifications
|
||||
|
|
|
@ -40,7 +40,6 @@ import type { NoteReaction } from "@/models/entities/note-reaction.js";
|
|||
import { Cache } from "@/misc/cache.js";
|
||||
import { isFiltered } from "@/misc/is-filtered.js";
|
||||
import { unfurl } from "unfurl.js";
|
||||
import type { ScheduledNote } from "@/models/entities/scheduled-note.js";
|
||||
|
||||
export class NoteConverter {
|
||||
private static noteContentHtmlCache = new Cache<string | null>(
|
||||
|
@ -162,9 +161,7 @@ export class NoteConverter {
|
|||
return renote.url ?? renote.uri ?? `${config.url}/notes/${renote.id}`;
|
||||
});
|
||||
|
||||
const identifier = `${note.id}:${(
|
||||
note.updatedAt ?? note.createdAt
|
||||
).getTime()}`;
|
||||
const identifier = `${note.id}:${(note.updatedAt ?? note.createdAt).getTime()}`;
|
||||
|
||||
const text = quoteUri.then((quoteUri) =>
|
||||
note.text !== null
|
||||
|
@ -579,13 +576,12 @@ export class NoteConverter {
|
|||
|
||||
/** Encode a schduled note. */
|
||||
public static async encodeScheduledNote(
|
||||
scheduledNote: ScheduledNote,
|
||||
ctx: MastoContext,
|
||||
note: Note,
|
||||
_: MastoContext,
|
||||
): Promise<MastodonEntity.ScheduledStatus> {
|
||||
const { note, user } = scheduledNote;
|
||||
|
||||
const renote =
|
||||
note.renote ?? (note.renoteId ? getNote(note.renoteId, user) : null);
|
||||
note.renote ??
|
||||
(note.renoteId ? getNote(note.renoteId, { id: note.userId }) : null);
|
||||
const quoteUri = Promise.resolve(renote).then((renote) => {
|
||||
if (!renote || !isQuote(note)) return null;
|
||||
return renote.url ?? renote.uri ?? `${config.url}/notes/${renote.id}`;
|
||||
|
@ -604,12 +600,12 @@ export class NoteConverter {
|
|||
const files = DriveFiles.packMany(note.fileIds);
|
||||
|
||||
const a = await awaitAll({
|
||||
id: scheduledNote.noteId,
|
||||
scheduled_at: scheduledNote.scheduledAt.toISOString(),
|
||||
id: note.id,
|
||||
scheduled_at: note.scheduledAt!.toISOString(),
|
||||
params: {
|
||||
text,
|
||||
poll: note.hasPoll
|
||||
? populatePoll(note, user?.id ?? null).then((p) =>
|
||||
? populatePoll(note, note.userId ?? null).then((p) =>
|
||||
PollConverter.encodeScheduledPoll(p),
|
||||
)
|
||||
: null,
|
||||
|
@ -622,7 +618,7 @@ export class NoteConverter {
|
|||
in_reply_to_id: note.replyId,
|
||||
language: note.lang,
|
||||
application_id: 0,
|
||||
idempotency: scheduledNote.id,
|
||||
idempotency: note.id,
|
||||
with_rate_limit: false,
|
||||
},
|
||||
media_attachments: files.then((files) =>
|
||||
|
@ -634,7 +630,7 @@ export class NoteConverter {
|
|||
|
||||
/** Encode an array of schduled notes. */
|
||||
public static async encodeManyScheduledNotes(
|
||||
scheduledNotes: ScheduledNote[],
|
||||
scheduledNotes: Note[],
|
||||
ctx: MastoContext,
|
||||
): Promise<MastodonEntity.ScheduledStatus[]> {
|
||||
const encoded = scheduledNotes.map((n) => this.encodeScheduledNote(n, ctx));
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
NoteFavorites,
|
||||
NoteReactions,
|
||||
Notes,
|
||||
ScheduledNotes,
|
||||
UserNotePinings,
|
||||
} from "@/models/index.js";
|
||||
import { generateVisibilityQuery } from "@/server/api/common/generate-visibility-query.js";
|
||||
|
@ -20,7 +19,7 @@ import deleteReaction from "@/services/note/reaction/delete.js";
|
|||
import createNote, { extractMentionedUsers } from "@/services/note/create.js";
|
||||
import editNote from "@/services/note/edit.js";
|
||||
import deleteNote from "@/services/note/delete.js";
|
||||
import { genId } from "backend-rs";
|
||||
import { fetchMeta, genIdAt } from "backend-rs";
|
||||
import { PaginationHelpers } from "@/server/api/mastodon/helpers/pagination.js";
|
||||
import { UserConverter } from "@/server/api/mastodon/converters/user.js";
|
||||
import { UserHelpers } from "@/server/api/mastodon/helpers/user.js";
|
||||
|
@ -36,15 +35,13 @@ import { MastoApiError } from "@/server/api/mastodon/middleware/catch-errors.js"
|
|||
import { Cache } from "@/misc/cache.js";
|
||||
import AsyncLock from "async-lock";
|
||||
import { IdentifiableError } from "@/misc/identifiable-error.js";
|
||||
import { IsNull } from "typeorm";
|
||||
import { In, IsNull } from "typeorm";
|
||||
import {
|
||||
getStubMastoContext,
|
||||
type MastoContext,
|
||||
} from "@/server/api/mastodon/index.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { translate } from "@/misc/translate.js";
|
||||
import { createScheduledNoteJob } from "@/queue/index.js";
|
||||
import type { ScheduledNote } from "@/models/entities/scheduled-note.js";
|
||||
|
||||
export class NoteHelpers {
|
||||
public static postIdempotencyCache = new Cache<{
|
||||
|
@ -134,9 +131,11 @@ export class NoteHelpers {
|
|||
});
|
||||
|
||||
if (!bookmarked) {
|
||||
const now = new Date();
|
||||
|
||||
await NoteFavorites.insert({
|
||||
id: genId(),
|
||||
createdAt: new Date(),
|
||||
id: genIdAt(now),
|
||||
createdAt: now,
|
||||
noteId: note.id,
|
||||
userId: user.id,
|
||||
});
|
||||
|
@ -385,7 +384,7 @@ export class NoteHelpers {
|
|||
const user = ctx.user as ILocalUser;
|
||||
const files =
|
||||
request.media_ids && request.media_ids.length > 0
|
||||
? DriveFiles.findByIds(request.media_ids)
|
||||
? DriveFiles.findBy({ id: In(request.media_ids) })
|
||||
: [];
|
||||
|
||||
const reply = request.in_reply_to_id
|
||||
|
@ -403,8 +402,10 @@ export class NoteHelpers {
|
|||
const visibility =
|
||||
request.visibility ?? UserHelpers.getDefaultNoteVisibility(ctx);
|
||||
|
||||
const data = {
|
||||
createdAt: new Date(),
|
||||
const now = new Date();
|
||||
|
||||
const data = await awaitAll({
|
||||
createdAt: now,
|
||||
files: files,
|
||||
poll: request.poll
|
||||
? {
|
||||
|
@ -432,39 +433,71 @@ export class NoteHelpers {
|
|||
? this.extractMentions(request.text ?? "", ctx)
|
||||
: undefined,
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
return createNote(
|
||||
user,
|
||||
await awaitAll(data),
|
||||
{
|
||||
createdAt: now,
|
||||
scheduledAt: delay != null ? new Date(data.scheduledAt!) : null,
|
||||
files: data.files,
|
||||
poll:
|
||||
data.poll != null
|
||||
? {
|
||||
choices: data.poll.choices,
|
||||
multiple: data.poll.multiple,
|
||||
expiresAt:
|
||||
data.poll.expiresAt != null
|
||||
? new Date(data.poll.expiresAt)
|
||||
: null,
|
||||
}
|
||||
: undefined,
|
||||
text: data.text || undefined,
|
||||
lang: data.lang,
|
||||
reply,
|
||||
renote,
|
||||
cw: data.cw,
|
||||
...(delay != null
|
||||
? {
|
||||
visibility: "specified",
|
||||
visibleUsers: [],
|
||||
}
|
||||
: {
|
||||
visibility: data.visibility,
|
||||
visibleUsers: data.visibleUsers,
|
||||
}),
|
||||
},
|
||||
false,
|
||||
!delay
|
||||
? undefined
|
||||
: async (note) => {
|
||||
await ScheduledNotes.insert({
|
||||
id: genId(),
|
||||
noteId: note.id,
|
||||
userId: user.id,
|
||||
scheduledAt: request.scheduled_at,
|
||||
});
|
||||
|
||||
delay
|
||||
? async (note) => {
|
||||
createScheduledNoteJob(
|
||||
{
|
||||
user: { id: user.id },
|
||||
noteId: note.id,
|
||||
option: {
|
||||
poll: data.poll,
|
||||
visibility: await visibility,
|
||||
poll: data.poll
|
||||
? {
|
||||
choices: data.poll.choices,
|
||||
multiple: data.poll.multiple,
|
||||
expiresAt: data.poll.expiresAt
|
||||
? new Date(data.poll.expiresAt)
|
||||
: null,
|
||||
}
|
||||
: undefined,
|
||||
visibility: data.visibility,
|
||||
visibleUserIds: await Promise.resolve(visibility)
|
||||
.then((v) =>
|
||||
v === "specified" ? data.visibleUsers : undefined,
|
||||
)
|
||||
.then((users) => users?.map((u) => u.id)),
|
||||
replyId: data.reply?.id ?? undefined,
|
||||
renoteId: data.renote?.id ?? undefined,
|
||||
},
|
||||
},
|
||||
delay,
|
||||
);
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -476,7 +509,7 @@ export class NoteHelpers {
|
|||
const user = ctx.user as ILocalUser;
|
||||
const files =
|
||||
request.media_ids && request.media_ids.length > 0
|
||||
? await DriveFiles.findByIds(request.media_ids)
|
||||
? await DriveFiles.findBy({ id: In(request.media_ids) })
|
||||
: [];
|
||||
|
||||
if (request.media_attributes && request.media_attributes.length > 0) {
|
||||
|
@ -750,17 +783,17 @@ export class NoteHelpers {
|
|||
minId: string | undefined,
|
||||
limit = 20,
|
||||
ctx: MastoContext,
|
||||
): Promise<ScheduledNote[]> {
|
||||
): Promise<Note[]> {
|
||||
if (limit > 40) limit = 40;
|
||||
|
||||
const query = PaginationHelpers.makePaginationQuery(
|
||||
ScheduledNotes.createQueryBuilder("scheduledNote"),
|
||||
Notes.createQueryBuilder("note"),
|
||||
sinceId,
|
||||
maxId,
|
||||
minId,
|
||||
)
|
||||
.leftJoinAndSelect("scheduledNote.note", "note")
|
||||
.leftJoinAndSelect("scheduledNote.user", "user");
|
||||
.andWhere("note.scheduledAt IS NOT NULL")
|
||||
.leftJoinAndSelect("note.user", "user");
|
||||
|
||||
return PaginationHelpers.execQueryLinkPagination(
|
||||
query,
|
||||
|
@ -773,13 +806,13 @@ export class NoteHelpers {
|
|||
public static async getScheduledNoteOr404(
|
||||
id: string,
|
||||
ctx: MastoContext,
|
||||
): Promise<ScheduledNote> {
|
||||
): Promise<Note> {
|
||||
const user = ctx.user as ILocalUser | null;
|
||||
const query = ScheduledNotes.createQueryBuilder("scheduledNote")
|
||||
.where("scheduledNote.noteId = :id", { id })
|
||||
.andWhere("scheduledNote.userId = :userId", { userId: user?.id })
|
||||
.leftJoinAndSelect("scheduledNote.note", "note")
|
||||
.leftJoinAndSelect("scheduledNote.user", "user");
|
||||
const query = Notes.createQueryBuilder("note")
|
||||
.where("note.id = :id", { id })
|
||||
.andWhere("note.userId = :userId", { userId: user?.id })
|
||||
.andWhere("note.scheduledAt IS NOT NULL")
|
||||
.leftJoinAndSelect("note.user", "user");
|
||||
return query.getOneOrFail().catch((_) => {
|
||||
throw new MastoApiError(404);
|
||||
});
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import type { Note } from "@/models/entities/note.js";
|
||||
import type { ILocalUser, User } from "@/models/entities/user.js";
|
||||
import {
|
||||
Followings,
|
||||
Notes,
|
||||
Notifications,
|
||||
RegistryItems,
|
||||
|
@ -14,7 +13,7 @@ import { generateVisibilityQuery } from "@/server/api/common/generate-visibility
|
|||
import { generateMutedUserQuery } from "@/server/api/common/generate-muted-user-query.js";
|
||||
import { generateBlockedUserQuery } from "@/server/api/common/generate-block-query.js";
|
||||
import { generateMutedUserRenotesQueryForNotes } from "@/server/api/common/generated-muted-renote-query.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { fetchMeta, genId } from "backend-rs";
|
||||
import { PaginationHelpers } from "@/server/api/mastodon/helpers/pagination.js";
|
||||
import type { UserList } from "@/models/entities/user-list.js";
|
||||
import { UserHelpers } from "@/server/api/mastodon/helpers/user.js";
|
||||
|
@ -27,7 +26,6 @@ import { generatePaginationData } from "@/server/api/mastodon/middleware/paginat
|
|||
import type { MastoContext } from "@/server/api/mastodon/index.js";
|
||||
import { generateListQuery } from "@/server/api/common/generate-list-query.js";
|
||||
import { generateFollowingQuery } from "@/server/api/common/generate-following-query.js";
|
||||
import { genId } from "backend-rs";
|
||||
|
||||
export class TimelineHelpers {
|
||||
public static async getHomeTimeline(
|
||||
|
@ -379,14 +377,8 @@ export class TimelineHelpers {
|
|||
return result;
|
||||
}
|
||||
|
||||
/** Exclude scheduled notes from Mastodon timeline (visibility === "specified" && visibleUserIds.length === 0) */
|
||||
/** Exclude scheduled notes from Mastodon timeline */
|
||||
public static generateNoScheduleNotesQuery(q: SelectQueryBuilder<Note>) {
|
||||
q.andWhere(
|
||||
new Brackets((qb) => {
|
||||
qb.where("note.visibility != 'specified'").orWhere(
|
||||
"array_length(note.visibleUserIds, 1) != 0",
|
||||
);
|
||||
}),
|
||||
);
|
||||
q.andWhere("note.scheduledAt IS NULL");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue