X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fmodels%2Faccount%2Fuser-notification.ts;h=25c5232032132ea977217697b4553456b0c49d3a;hb=32a18cbf33a7cdbbe3d4885d32e4b67e19cdc1cf;hp=2945bf70953656d3926caac95d45d91fb3c73812;hpb=17aa80ed016bafa3ccb071af3f86054033823284;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/models/account/user-notification.ts b/server/models/account/user-notification.ts index 2945bf709..25c523203 100644 --- a/server/models/account/user-notification.ts +++ b/server/models/account/user-notification.ts @@ -9,7 +9,9 @@ import { VideoAbuseModel } from '../abuse/video-abuse' import { VideoCommentAbuseModel } from '../abuse/video-comment-abuse' import { ActorModel } from '../activitypub/actor' import { ActorFollowModel } from '../activitypub/actor-follow' +import { ApplicationModel } from '../application/application' import { AvatarModel } from '../avatar/avatar' +import { PluginModel } from '../server/plugin' import { ServerModel } from '../server/server' import { getSort, throwIfNotValid } from '../utils' import { VideoModel } from '../video/video' @@ -88,7 +90,7 @@ function buildAccountInclude (required: boolean, withActor = false) { }, { - attributes: [ 'id' ], + attributes: [ 'id', 'state' ], model: AbuseModel.unscoped(), required: false, include: [ @@ -96,7 +98,7 @@ function buildAccountInclude (required: boolean, withActor = false) { attributes: [ 'id' ], model: VideoAbuseModel.unscoped(), required: false, - include: [ buildVideoInclude(true) ] + include: [ buildVideoInclude(false) ] }, { attributes: [ 'id' ], @@ -105,13 +107,13 @@ function buildAccountInclude (required: boolean, withActor = false) { include: [ { attributes: [ 'id', 'originCommentId' ], - model: VideoCommentModel, - required: true, + model: VideoCommentModel.unscoped(), + required: false, include: [ { attributes: [ 'id', 'name', 'uuid' ], model: VideoModel.unscoped(), - required: true + required: false } ] } @@ -120,7 +122,7 @@ function buildAccountInclude (required: boolean, withActor = false) { { model: AccountModel, as: 'FlaggedAccount', - required: true, + required: false, include: [ buildActorWithAvatarInclude() ] } ] @@ -140,6 +142,18 @@ function buildAccountInclude (required: boolean, withActor = false) { include: [ buildVideoInclude(false) ] }, + { + attributes: [ 'id', 'name', 'type', 'latestVersion' ], + model: PluginModel.unscoped(), + required: false + }, + + { + attributes: [ 'id', 'latestPeerTubeVersion' ], + model: ApplicationModel.unscoped(), + required: false + }, + { attributes: [ 'id', 'state' ], model: ActorFollowModel.unscoped(), @@ -251,10 +265,26 @@ function buildAccountInclude (required: boolean, withActor = false) { [Op.ne]: null } } + }, + { + fields: [ 'pluginId' ], + where: { + pluginId: { + [Op.ne]: null + } + } + }, + { + fields: [ 'applicationId' ], + where: { + applicationId: { + [Op.ne]: null + } + } } ] as (ModelIndexesOptions & { where?: WhereOptions })[] }) -export class UserNotificationModel extends Model { +export class UserNotificationModel extends Model { @AllowNull(false) @Default(null) @@ -370,6 +400,30 @@ export class UserNotificationModel extends Model { }) ActorFollow: ActorFollowModel + @ForeignKey(() => PluginModel) + @Column + pluginId: number + + @BelongsTo(() => PluginModel, { + foreignKey: { + allowNull: true + }, + onDelete: 'cascade' + }) + Plugin: PluginModel + + @ForeignKey(() => ApplicationModel) + @Column + applicationId: number + + @BelongsTo(() => ApplicationModel, { + foreignKey: { + allowNull: true + }, + onDelete: 'cascade' + }) + Application: ApplicationModel + static listForApi (userId: number, start: number, count: number, sort: string, unread?: boolean) { const where = { userId } @@ -411,32 +465,91 @@ export class UserNotificationModel extends Model { return UserNotificationModel.update({ read: true }, query) } + static removeNotificationsOf (options: { id: number, type: 'account' | 'server', forUserId?: number }) { + const id = parseInt(options.id + '', 10) + + function buildAccountWhereQuery (base: string) { + const whereSuffix = options.forUserId + ? ` AND "userNotification"."userId" = ${options.forUserId}` + : '' + + if (options.type === 'account') { + return base + + ` WHERE "account"."id" = ${id} ${whereSuffix}` + } + + return base + + ` WHERE "actor"."serverId" = ${id} ${whereSuffix}` + } + + const queries = [ + buildAccountWhereQuery( + `SELECT "userNotification"."id" FROM "userNotification" ` + + `INNER JOIN "account" ON "userNotification"."accountId" = "account"."id" ` + + `INNER JOIN actor ON "actor"."id" = "account"."actorId" ` + ), + + // Remove notifications from muted accounts that followed ours + buildAccountWhereQuery( + `SELECT "userNotification"."id" FROM "userNotification" ` + + `INNER JOIN "actorFollow" ON "actorFollow".id = "userNotification"."actorFollowId" ` + + `INNER JOIN actor ON actor.id = "actorFollow"."actorId" ` + + `INNER JOIN account ON account."actorId" = actor.id ` + ), + + // Remove notifications from muted accounts that commented something + buildAccountWhereQuery( + `SELECT "userNotification"."id" FROM "userNotification" ` + + `INNER JOIN "actorFollow" ON "actorFollow".id = "userNotification"."actorFollowId" ` + + `INNER JOIN actor ON actor.id = "actorFollow"."actorId" ` + + `INNER JOIN account ON account."actorId" = actor.id ` + ), + + buildAccountWhereQuery( + `SELECT "userNotification"."id" FROM "userNotification" ` + + `INNER JOIN "videoComment" ON "videoComment".id = "userNotification"."commentId" ` + + `INNER JOIN account ON account.id = "videoComment"."accountId" ` + + `INNER JOIN actor ON "actor"."id" = "account"."actorId" ` + ) + ] + + const query = `DELETE FROM "userNotification" WHERE id IN (${queries.join(' UNION ')})` + + return UserNotificationModel.sequelize.query(query) + } + toFormattedJSON (this: UserNotificationModelForApi): UserNotification { const video = this.Video ? Object.assign(this.formatVideo(this.Video), { channel: this.formatActor(this.Video.VideoChannel) }) : undefined - const videoImport = this.VideoImport ? { - id: this.VideoImport.id, - video: this.VideoImport.Video ? this.formatVideo(this.VideoImport.Video) : undefined, - torrentName: this.VideoImport.torrentName, - magnetUri: this.VideoImport.magnetUri, - targetUrl: this.VideoImport.targetUrl - } : undefined - - const comment = this.Comment ? { - id: this.Comment.id, - threadId: this.Comment.getThreadId(), - account: this.formatActor(this.Comment.Account), - video: this.formatVideo(this.Comment.Video) - } : undefined + const videoImport = this.VideoImport + ? { + id: this.VideoImport.id, + video: this.VideoImport.Video ? this.formatVideo(this.VideoImport.Video) : undefined, + torrentName: this.VideoImport.torrentName, + magnetUri: this.VideoImport.magnetUri, + targetUrl: this.VideoImport.targetUrl + } + : undefined + + const comment = this.Comment + ? { + id: this.Comment.id, + threadId: this.Comment.getThreadId(), + account: this.formatActor(this.Comment.Account), + video: this.formatVideo(this.Comment.Video) + } + : undefined const abuse = this.Abuse ? this.formatAbuse(this.Abuse) : undefined - const videoBlacklist = this.VideoBlacklist ? { - id: this.VideoBlacklist.id, - video: this.formatVideo(this.VideoBlacklist.Video) - } : undefined + const videoBlacklist = this.VideoBlacklist + ? { + id: this.VideoBlacklist.id, + video: this.formatVideo(this.VideoBlacklist.Video) + } + : undefined const account = this.Account ? this.formatActor(this.Account) : undefined @@ -445,23 +558,37 @@ export class UserNotificationModel extends Model { Group: 'channel' as 'channel', Person: 'account' as 'account' } - const actorFollow = this.ActorFollow ? { - id: this.ActorFollow.id, - state: this.ActorFollow.state, - follower: { - id: this.ActorFollow.ActorFollower.Account.id, - displayName: this.ActorFollow.ActorFollower.Account.getDisplayName(), - name: this.ActorFollow.ActorFollower.preferredUsername, - avatar: this.ActorFollow.ActorFollower.Avatar ? { path: this.ActorFollow.ActorFollower.Avatar.getStaticPath() } : undefined, - host: this.ActorFollow.ActorFollower.getHost() - }, - following: { - type: actorFollowingType[this.ActorFollow.ActorFollowing.type], - displayName: (this.ActorFollow.ActorFollowing.VideoChannel || this.ActorFollow.ActorFollowing.Account).getDisplayName(), - name: this.ActorFollow.ActorFollowing.preferredUsername, - host: this.ActorFollow.ActorFollowing.getHost() + const actorFollow = this.ActorFollow + ? { + id: this.ActorFollow.id, + state: this.ActorFollow.state, + follower: { + id: this.ActorFollow.ActorFollower.Account.id, + displayName: this.ActorFollow.ActorFollower.Account.getDisplayName(), + name: this.ActorFollow.ActorFollower.preferredUsername, + avatar: this.ActorFollow.ActorFollower.Avatar ? { path: this.ActorFollow.ActorFollower.Avatar.getStaticPath() } : undefined, + host: this.ActorFollow.ActorFollower.getHost() + }, + following: { + type: actorFollowingType[this.ActorFollow.ActorFollowing.type], + displayName: (this.ActorFollow.ActorFollowing.VideoChannel || this.ActorFollow.ActorFollowing.Account).getDisplayName(), + name: this.ActorFollow.ActorFollowing.preferredUsername, + host: this.ActorFollow.ActorFollowing.getHost() + } } - } : undefined + : undefined + + const plugin = this.Plugin + ? { + name: this.Plugin.name, + type: this.Plugin.type, + latestVersion: this.Plugin.latestVersion + } + : undefined + + const peertube = this.Application + ? { latestVersion: this.Application.latestPeerTubeVersion } + : undefined return { id: this.id, @@ -474,6 +601,8 @@ export class UserNotificationModel extends Model { videoBlacklist, account, actorFollow, + plugin, + peertube, createdAt: this.createdAt.toISOString(), updatedAt: this.updatedAt.toISOString() } @@ -488,22 +617,27 @@ export class UserNotificationModel extends Model { } formatAbuse (this: UserNotificationModelForApi, abuse: UserNotificationIncludes.AbuseInclude) { - const commentAbuse = abuse.VideoCommentAbuse?.VideoComment ? { - threadId: abuse.VideoCommentAbuse.VideoComment.getThreadId(), - - video: { - id: abuse.VideoCommentAbuse.VideoComment.Video.id, - name: abuse.VideoCommentAbuse.VideoComment.Video.name, - uuid: abuse.VideoCommentAbuse.VideoComment.Video.uuid + const commentAbuse = abuse.VideoCommentAbuse?.VideoComment + ? { + threadId: abuse.VideoCommentAbuse.VideoComment.getThreadId(), + + video: abuse.VideoCommentAbuse.VideoComment.Video + ? { + id: abuse.VideoCommentAbuse.VideoComment.Video.id, + name: abuse.VideoCommentAbuse.VideoComment.Video.name, + uuid: abuse.VideoCommentAbuse.VideoComment.Video.uuid + } + : undefined } - } : undefined + : undefined const videoAbuse = abuse.VideoAbuse?.Video ? this.formatVideo(abuse.VideoAbuse.Video) : undefined - const accountAbuse = (!commentAbuse && !videoAbuse) ? this.formatActor(abuse.FlaggedAccount) : undefined + const accountAbuse = (!commentAbuse && !videoAbuse && abuse.FlaggedAccount) ? this.formatActor(abuse.FlaggedAccount) : undefined return { id: abuse.id, + state: abuse.state, video: videoAbuse, comment: commentAbuse, account: accountAbuse