summaryrefslogtreecommitdiff
path: root/packages/backend/src/models
diff options
context:
space:
mode:
authorJulia <julia@insertdomain.name>2025-03-02 19:54:32 +0000
committerJulia <julia@insertdomain.name>2025-03-02 19:54:32 +0000
commit9e13c375c5ef4103ad5ee87fea583b154e9e16f3 (patch)
treefe9e7b1a474e22fb0c37bd68cfd260f7ba39be74 /packages/backend/src/models
parentmerge: pin corepack version (!885) (diff)
parentbump version (diff)
downloadsharkey-9e13c375c5ef4103ad5ee87fea583b154e9e16f3.tar.gz
sharkey-9e13c375c5ef4103ad5ee87fea583b154e9e16f3.tar.bz2
sharkey-9e13c375c5ef4103ad5ee87fea583b154e9e16f3.zip
merge: 2025.2.2 (!927)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/927 Approved-by: Marie <github@yuugi.dev> Approved-by: Julia <julia@insertdomain.name>
Diffstat (limited to 'packages/backend/src/models')
-rw-r--r--packages/backend/src/models/Instance.ts9
-rw-r--r--packages/backend/src/models/Meta.ts5
-rw-r--r--packages/backend/src/models/Note.ts12
-rw-r--r--packages/backend/src/models/Page.ts2
-rw-r--r--packages/backend/src/models/RepositoryModule.ts29
-rw-r--r--packages/backend/src/models/SkApContext.ts25
-rw-r--r--packages/backend/src/models/SkApFetchLog.ts89
-rw-r--r--packages/backend/src/models/SkApInboxLog.ts109
-rw-r--r--packages/backend/src/models/User.ts18
-rw-r--r--packages/backend/src/models/UserProfile.ts19
-rw-r--r--packages/backend/src/models/_.ts9
-rw-r--r--packages/backend/src/models/json-schema/emoji.ts83
-rw-r--r--packages/backend/src/models/json-schema/federation-instance.ts5
-rw-r--r--packages/backend/src/models/json-schema/meta.ts9
-rw-r--r--packages/backend/src/models/json-schema/note.ts13
-rw-r--r--packages/backend/src/models/json-schema/user.ts17
16 files changed, 449 insertions, 4 deletions
diff --git a/packages/backend/src/models/Instance.ts b/packages/backend/src/models/Instance.ts
index ba93190c57..c64ebb1b3b 100644
--- a/packages/backend/src/models/Instance.ts
+++ b/packages/backend/src/models/Instance.ts
@@ -164,6 +164,15 @@ export class MiInstance {
})
public rejectReports: boolean;
+ /**
+ * If true, quote posts from this instance will be downgraded to normal posts.
+ * The quote will be stripped and a process error will be generated.
+ */
+ @Column('boolean', {
+ default: false,
+ })
+ public rejectQuotes: boolean;
+
@Column('varchar', {
length: 16384, default: '',
})
diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts
index 3fc3f273dd..a224117676 100644
--- a/packages/backend/src/models/Meta.ts
+++ b/packages/backend/src/models/Meta.ts
@@ -599,6 +599,11 @@ export class MiMeta {
})
public enableAchievements: boolean;
+ @Column('varchar', {
+ length: 2048, nullable: true,
+ })
+ public robotsTxt: string | null;
+
@Column('jsonb', {
default: { },
})
diff --git a/packages/backend/src/models/Note.ts b/packages/backend/src/models/Note.ts
index 408e023ff7..2dabb75d83 100644
--- a/packages/backend/src/models/Note.ts
+++ b/packages/backend/src/models/Note.ts
@@ -143,6 +143,7 @@ export class MiNote {
})
public fileIds: MiDriveFile['id'][];
+ @Index('IDX_NOTE_ATTACHED_FILE_TYPES', { synchronize: false })
@Column('varchar', {
length: 256, array: true, default: '{}',
})
@@ -202,6 +203,17 @@ export class MiNote {
@JoinColumn()
public channel: MiChannel | null;
+ /**
+ * List of non-fatal errors encountered while processing (creating or updating) this note.
+ * Entries can be a translation key (which will be queried from the "_processErrors" section) or a raw string.
+ * Errors will be displayed to the user when viewing the note.
+ */
+ @Column('text', {
+ array: true,
+ nullable: true,
+ })
+ public processErrors: string[] | null;
+
//#region Denormalized fields
@Index()
@Column('varchar', {
diff --git a/packages/backend/src/models/Page.ts b/packages/backend/src/models/Page.ts
index 1695bf570e..0b59e7a92c 100644
--- a/packages/backend/src/models/Page.ts
+++ b/packages/backend/src/models/Page.ts
@@ -118,3 +118,5 @@ export class MiPage {
}
}
}
+
+export const pageNameSchema = { type: 'string', pattern: /^[^\s:\/?#\[\]@!$&'()*+,;=\\%\x00-\x20]{1,256}$/.source } as const;
diff --git a/packages/backend/src/models/RepositoryModule.ts b/packages/backend/src/models/RepositoryModule.ts
index 3a1158a42a..78510ba588 100644
--- a/packages/backend/src/models/RepositoryModule.ts
+++ b/packages/backend/src/models/RepositoryModule.ts
@@ -80,7 +80,10 @@ import {
MiUserPublickey,
MiUserSecurityKey,
MiWebhook,
- NoteEdit
+ NoteEdit,
+ SkApContext,
+ SkApFetchLog,
+ SkApInboxLog,
} from './_.js';
import type { DataSource } from 'typeorm';
@@ -126,6 +129,24 @@ const $latestNotesRepository: Provider = {
inject: [DI.db],
};
+const $apContextRepository: Provider = {
+ provide: DI.apContextsRepository,
+ useFactory: (db: DataSource) => db.getRepository(SkApContext).extend(miRepository as MiRepository<SkApContext>),
+ inject: [DI.db],
+};
+
+const $apFetchLogsRepository: Provider = {
+ provide: DI.apFetchLogsRepository,
+ useFactory: (db: DataSource) => db.getRepository(SkApFetchLog).extend(miRepository as MiRepository<SkApFetchLog>),
+ inject: [DI.db],
+};
+
+const $apInboxLogsRepository: Provider = {
+ provide: DI.apInboxLogsRepository,
+ useFactory: (db: DataSource) => db.getRepository(SkApInboxLog).extend(miRepository as MiRepository<SkApInboxLog>),
+ inject: [DI.db],
+};
+
const $noteFavoritesRepository: Provider = {
provide: DI.noteFavoritesRepository,
useFactory: (db: DataSource) => db.getRepository(MiNoteFavorite).extend(miRepository as MiRepository<MiNoteFavorite>),
@@ -526,6 +547,9 @@ const $noteScheduleRepository: Provider = {
$appsRepository,
$avatarDecorationsRepository,
$latestNotesRepository,
+ $apContextRepository,
+ $apFetchLogsRepository,
+ $apInboxLogsRepository,
$noteFavoritesRepository,
$noteThreadMutingsRepository,
$noteReactionsRepository,
@@ -600,6 +624,9 @@ const $noteScheduleRepository: Provider = {
$appsRepository,
$avatarDecorationsRepository,
$latestNotesRepository,
+ $apContextRepository,
+ $apFetchLogsRepository,
+ $apInboxLogsRepository,
$noteFavoritesRepository,
$noteThreadMutingsRepository,
$noteReactionsRepository,
diff --git a/packages/backend/src/models/SkApContext.ts b/packages/backend/src/models/SkApContext.ts
new file mode 100644
index 0000000000..ff4c6d6fbf
--- /dev/null
+++ b/packages/backend/src/models/SkApContext.ts
@@ -0,0 +1,25 @@
+/*
+ * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Column, PrimaryColumn, Entity } from 'typeorm';
+
+@Entity('ap_context')
+export class SkApContext {
+ @PrimaryColumn('text', {
+ primaryKeyConstraintName: 'PK_ap_context',
+ })
+ public md5: string;
+
+ @Column('jsonb')
+ // https://github.com/typeorm/typeorm/issues/8559
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ public json: any;
+
+ constructor(data?: Partial<SkApContext>) {
+ if (data) {
+ Object.assign(this, data);
+ }
+ }
+}
diff --git a/packages/backend/src/models/SkApFetchLog.ts b/packages/backend/src/models/SkApFetchLog.ts
new file mode 100644
index 0000000000..1e7d861b6c
--- /dev/null
+++ b/packages/backend/src/models/SkApFetchLog.ts
@@ -0,0 +1,89 @@
+/*
+ * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Column, Index, JoinColumn, ManyToOne, PrimaryColumn, Entity } from 'typeorm';
+import { SkApContext } from '@/models/SkApContext.js';
+import { id } from './util/id.js';
+
+/**
+ * Records objects fetched via AP
+ */
+@Entity('ap_fetch_log')
+export class SkApFetchLog {
+ @PrimaryColumn({
+ ...id(),
+ primaryKeyConstraintName: 'PK_ap_fetch_log',
+ })
+ public id: string;
+
+ @Index('IDX_ap_fetch_log_at')
+ @Column('timestamptz')
+ public at: Date;
+
+ /**
+ * Processing duration in milliseconds
+ */
+ @Column('double precision', { nullable: true })
+ public duration: number | null = null;
+
+ /**
+ * DB hostname extracted from responseUri, or requestUri if fetch is incomplete
+ */
+ @Index('IDX_ap_fetch_log_host')
+ @Column('text')
+ public host: string;
+
+ /**
+ * Original requested URI
+ */
+ @Column('text', {
+ name: 'request_uri',
+ })
+ public requestUri: string;
+
+ /**
+ * Canonical URI / object ID, taken from the final payload
+ */
+ @Column('text', {
+ name: 'object_uri',
+ nullable: true,
+ })
+ @Index('IDX_ap_fetch_log_object_uri')
+ public objectUri: string | null = null;
+
+ @Column('boolean', { nullable: true })
+ public accepted: boolean | null = null;
+
+ @Column('text', { nullable: true })
+ public result: string | null = null;
+
+ @Column('jsonb', { nullable: true })
+ // https://github.com/typeorm/typeorm/issues/8559
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ public object: any | null = null;
+
+ @Column({
+ type: 'text',
+ name: 'context_hash',
+ nullable: true,
+ })
+ public contextHash: string | null;
+
+ @ManyToOne(() => SkApContext, {
+ onDelete: 'CASCADE',
+ nullable: true,
+ })
+ @JoinColumn({
+ name: 'context_hash',
+ foreignKeyConstraintName: 'FK_ap_fetch_log_context_hash',
+ })
+ public context: SkApContext | null;
+
+ constructor(data?: Partial<SkApFetchLog>) {
+ if (data) {
+ Object.assign(this, data);
+ }
+ }
+}
diff --git a/packages/backend/src/models/SkApInboxLog.ts b/packages/backend/src/models/SkApInboxLog.ts
new file mode 100644
index 0000000000..867094405c
--- /dev/null
+++ b/packages/backend/src/models/SkApInboxLog.ts
@@ -0,0 +1,109 @@
+/*
+ * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
+import { SkApContext } from '@/models/SkApContext.js';
+import { MiUser } from '@/models/_.js';
+import { id } from './util/id.js';
+
+/**
+ * Records activities received in the inbox
+ */
+@Entity('ap_inbox_log')
+export class SkApInboxLog {
+ @PrimaryColumn({
+ ...id(),
+ primaryKeyConstraintName: 'PK_ap_inbox_log',
+ })
+ public id: string;
+
+ @Index('IDX_ap_inbox_log_at')
+ @Column('timestamptz')
+ public at: Date;
+
+ /**
+ * Processing duration in milliseconds
+ */
+ @Column('double precision', { nullable: true })
+ public duration: number | null = null;
+
+ /**
+ * Key ID that was used to sign this request.
+ * Untrusted unless verified is true.
+ */
+ @Column({
+ type: 'text',
+ name: 'key_id',
+ })
+ public keyId: string;
+
+ /**
+ * Instance that the activity was sent from.
+ * Untrusted unless verified is true.
+ */
+ @Index('IDX_ap_inbox_log_host')
+ @Column('text')
+ public host: string;
+
+ @Column('boolean')
+ public verified: boolean;
+
+ @Column('boolean')
+ public accepted: boolean;
+
+ @Column('text', { nullable: true })
+ public result: string | null = null;
+
+ @Column('jsonb')
+ // https://github.com/typeorm/typeorm/issues/8559
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ public activity: any;
+
+ @Column({
+ type: 'text',
+ name: 'context_hash',
+ nullable: true,
+ })
+ public contextHash: string | null;
+
+ @ManyToOne(() => SkApContext, {
+ onDelete: 'CASCADE',
+ nullable: true,
+ })
+ @JoinColumn({
+ name: 'context_hash',
+ foreignKeyConstraintName: 'FK_ap_inbox_log_context_hash',
+ })
+ public context: SkApContext | null;
+
+ /**
+ * ID of the user who signed this request.
+ */
+ @Column({
+ ...id(),
+ name: 'auth_user_id',
+ nullable: true,
+ })
+ public authUserId: string | null;
+
+ /**
+ * User who signed this request.
+ */
+ @ManyToOne(() => MiUser, {
+ onDelete: 'CASCADE',
+ nullable: true,
+ })
+ @JoinColumn({
+ name: 'auth_user_id',
+ foreignKeyConstraintName: 'FK_ap_inbox_log_auth_user_id',
+ })
+ public authUser: MiUser | null;
+
+ constructor(data?: Partial<SkApInboxLog>) {
+ if (data) {
+ Object.assign(this, data);
+ }
+ }
+}
diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts
index 3a825d36a7..5d87c7fa12 100644
--- a/packages/backend/src/models/User.ts
+++ b/packages/backend/src/models/User.ts
@@ -339,6 +339,24 @@ export class MiUser {
})
public enableRss: boolean;
+ /**
+ * Specifies a Content Warning that should be forcibly applied to all notes by this user.
+ * If null (default), then no Content Warning is applied.
+ */
+ @Column('text', {
+ nullable: true,
+ })
+ public mandatoryCW: string | null;
+
+ /**
+ * If true, quote posts from this user will be downgraded to normal posts.
+ * The quote will be stripped and a process error will be generated.
+ */
+ @Column('boolean', {
+ default: false,
+ })
+ public rejectQuotes: boolean;
+
constructor(data: Partial<MiUser>) {
if (data == null) return;
diff --git a/packages/backend/src/models/UserProfile.ts b/packages/backend/src/models/UserProfile.ts
index 751b1aff08..449c2f370b 100644
--- a/packages/backend/src/models/UserProfile.ts
+++ b/packages/backend/src/models/UserProfile.ts
@@ -4,7 +4,7 @@
*/
import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm';
-import { obsoleteNotificationTypes, followingVisibilities, followersVisibilities, notificationTypes } from '@/types.js';
+import { obsoleteNotificationTypes, followingVisibilities, followersVisibilities, notificationTypes, noteVisibilities, defaultCWPriorities } from '@/types.js';
import { id } from './util/id.js';
import { MiUser } from './User.js';
import { MiPage } from './Page.js';
@@ -36,10 +36,10 @@ export class MiUserProfile {
})
public birthday: string | null;
- @Column("varchar", {
+ @Column('varchar', {
length: 128,
nullable: true,
- comment: "The ListenBrainz username of the User.",
+ comment: 'The ListenBrainz username of the User.',
})
public listenbrainz: string | null;
@@ -290,6 +290,19 @@ export class MiUserProfile {
unlockedAt: number;
}[];
+ @Column('text', {
+ name: 'default_cw',
+ nullable: true,
+ })
+ public defaultCW: string | null;
+
+ @Column('enum', {
+ name: 'default_cw_priority',
+ enum: defaultCWPriorities,
+ default: 'parent',
+ })
+ public defaultCWPriority: typeof defaultCWPriorities[number];
+
//#region Denormalized fields
@Index()
@Column('varchar', {
diff --git a/packages/backend/src/models/_.ts b/packages/backend/src/models/_.ts
index 9a4ebfc90f..4bd6e78ef4 100644
--- a/packages/backend/src/models/_.ts
+++ b/packages/backend/src/models/_.ts
@@ -82,6 +82,9 @@ import { NoteEdit } from '@/models/NoteEdit.js';
import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
import { MiReversiGame } from '@/models/ReversiGame.js';
import { MiNoteSchedule } from '@/models/NoteSchedule.js';
+import { SkApInboxLog } from '@/models/SkApInboxLog.js';
+import { SkApFetchLog } from '@/models/SkApFetchLog.js';
+import { SkApContext } from '@/models/SkApContext.js';
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
export interface MiRepository<T extends ObjectLiteral> {
@@ -129,6 +132,9 @@ export const miRepository = {
export {
SkLatestNote,
+ SkApContext,
+ SkApFetchLog,
+ SkApInboxLog,
MiAbuseUserReport,
MiAbuseReportNotificationRecipient,
MiAccessToken,
@@ -229,6 +235,9 @@ export type HashtagsRepository = Repository<MiHashtag> & MiRepository<MiHashtag>
export type InstancesRepository = Repository<MiInstance> & MiRepository<MiInstance>;
export type MetasRepository = Repository<MiMeta> & MiRepository<MiMeta>;
export type LatestNotesRepository = Repository<SkLatestNote> & MiRepository<SkLatestNote>;
+export type ApContextsRepository = Repository<SkApContext> & MiRepository<SkApContext>;
+export type ApFetchLogsRepository = Repository<SkApFetchLog> & MiRepository<SkApFetchLog>;
+export type ApInboxLogsRepository = Repository<SkApInboxLog> & MiRepository<SkApInboxLog>;
export type ModerationLogsRepository = Repository<MiModerationLog> & MiRepository<MiModerationLog>;
export type MutingsRepository = Repository<MiMuting> & MiRepository<MiMuting>;
export type RenoteMutingsRepository = Repository<MiRenoteMuting> & MiRepository<MiRenoteMuting>;
diff --git a/packages/backend/src/models/json-schema/emoji.ts b/packages/backend/src/models/json-schema/emoji.ts
index 62686ad5ae..3cd263fa37 100644
--- a/packages/backend/src/models/json-schema/emoji.ts
+++ b/packages/backend/src/models/json-schema/emoji.ts
@@ -104,3 +104,86 @@ export const packedEmojiDetailedSchema = {
},
},
} as const;
+
+export const packedEmojiDetailedAdminSchema = {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ format: 'id',
+ optional: false, nullable: false,
+ },
+ updatedAt: {
+ type: 'string',
+ format: 'date-time',
+ optional: false, nullable: true,
+ },
+ name: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ host: {
+ type: 'string',
+ optional: false, nullable: true,
+ description: 'The local host is represented with `null`.',
+ },
+ publicUrl: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ originalUrl: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ uri: {
+ type: 'string',
+ optional: false, nullable: true,
+ },
+ type: {
+ type: 'string',
+ optional: false, nullable: true,
+ },
+ aliases: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'string',
+ format: 'id',
+ optional: false, nullable: false,
+ },
+ },
+ category: {
+ type: 'string',
+ optional: false, nullable: true,
+ },
+ license: {
+ type: 'string',
+ optional: false, nullable: true,
+ },
+ localOnly: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ isSensitive: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ roleIdsThatCanBeUsedThisEmojiAsReaction: {
+ type: 'array',
+ items: {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ format: 'misskey:id',
+ optional: false, nullable: false,
+ },
+ name: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ },
+ },
+ },
+ },
+} as const;
diff --git a/packages/backend/src/models/json-schema/federation-instance.ts b/packages/backend/src/models/json-schema/federation-instance.ts
index 7960e748e9..57d4466ffa 100644
--- a/packages/backend/src/models/json-schema/federation-instance.ts
+++ b/packages/backend/src/models/json-schema/federation-instance.ts
@@ -126,6 +126,11 @@ export const packedFederationInstanceSchema = {
optional: false,
nullable: false,
},
+ rejectQuotes: {
+ type: 'boolean',
+ optional: false,
+ nullable: false,
+ },
moderationNote: {
type: 'string',
optional: true, nullable: true,
diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts
index 5179e5d51c..bf68208c37 100644
--- a/packages/backend/src/models/json-schema/meta.ts
+++ b/packages/backend/src/models/json-schema/meta.ts
@@ -139,6 +139,10 @@ export const packedMetaLiteSchema = {
type: 'boolean',
optional: false, nullable: true,
},
+ robotsTxt: {
+ type: 'string',
+ optional: false, nullable: true,
+ },
enableTestcaptcha: {
type: 'boolean',
optional: false, nullable: false,
@@ -317,6 +321,11 @@ export const packedMetaLiteSchema = {
type: 'number',
optional: false, nullable: false,
},
+ federation: {
+ type: 'string',
+ enum: ['all', 'specified', 'none'],
+ optional: false, nullable: false,
+ },
},
} as const;
diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts
index 432c096e48..16e240ab11 100644
--- a/packages/backend/src/models/json-schema/note.ts
+++ b/packages/backend/src/models/json-schema/note.ts
@@ -17,6 +17,11 @@ export const packedNoteSchema = {
optional: false, nullable: false,
format: 'date-time',
},
+ updatedAt: {
+ type: 'string',
+ optional: true, nullable: false,
+ format: 'date-time',
+ },
deletedAt: {
type: 'string',
optional: true, nullable: true,
@@ -256,6 +261,14 @@ export const packedNoteSchema = {
type: 'number',
optional: true, nullable: false,
},
+ processErrors: {
+ type: 'array',
+ optional: true, nullable: true,
+ items: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ },
myReaction: {
type: 'string',
diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts
index f953008b3f..0f1601f138 100644
--- a/packages/backend/src/models/json-schema/user.ts
+++ b/packages/backend/src/models/json-schema/user.ts
@@ -134,6 +134,14 @@ export const packedUserLiteSchema = {
type: 'boolean',
nullable: false, optional: false,
},
+ mandatoryCW: {
+ type: 'string',
+ nullable: true, optional: false,
+ },
+ rejectQuotes: {
+ type: 'boolean',
+ nullable: false, optional: true,
+ },
isBot: {
type: 'boolean',
nullable: false, optional: true,
@@ -752,6 +760,15 @@ export const packedMeDetailedOnlySchema = {
},
},
//#endregion
+ defaultCW: {
+ type: 'string',
+ nullable: true, optional: false,
+ },
+ defaultCWPriority: {
+ type: 'string',
+ enum: ['default', 'parent', 'defaultParent', 'parentDefault'],
+ nullable: false, optional: false,
+ },
},
} as const;