Handle announces in inbox
This commit is contained in:
parent
8e10cf1a5a
commit
d846501818
|
@ -5,6 +5,7 @@ import { isActivityValid } from '../../helpers/custom-validators/activitypub/act
|
|||
import { processCreateActivity, processFlagActivity, processUpdateActivity } from '../../lib'
|
||||
import { processAcceptActivity } from '../../lib/activitypub/process-accept'
|
||||
import { processAddActivity } from '../../lib/activitypub/process-add'
|
||||
import { processAnnounceActivity } from '../../lib/activitypub/process-announce'
|
||||
import { processDeleteActivity } from '../../lib/activitypub/process-delete'
|
||||
import { processFollowActivity } from '../../lib/activitypub/process-follow'
|
||||
import { asyncMiddleware, checkSignature, localAccountValidator, signatureValidator } from '../../middlewares'
|
||||
|
@ -18,7 +19,8 @@ const processActivity: { [ P in ActivityType ]: (activity: Activity, inboxAccoun
|
|||
Flag: processFlagActivity,
|
||||
Delete: processDeleteActivity,
|
||||
Follow: processFollowActivity,
|
||||
Accept: processAcceptActivity
|
||||
Accept: processAcceptActivity,
|
||||
Announce: processAnnounceActivity
|
||||
}
|
||||
|
||||
const inboxRouter = express.Router()
|
||||
|
|
|
@ -2,9 +2,12 @@ import * as validator from 'validator'
|
|||
import { isAccountAcceptActivityValid, isAccountDeleteActivityValid, isAccountFollowActivityValid } from './account'
|
||||
import { isActivityPubUrlValid } from './misc'
|
||||
import {
|
||||
isVideoAnnounceValid,
|
||||
isVideoChannelAnnounceValid,
|
||||
isVideoChannelCreateActivityValid,
|
||||
isVideoChannelDeleteActivityValid,
|
||||
isVideoChannelUpdateActivityValid,
|
||||
isVideoFlagValid,
|
||||
isVideoTorrentAddActivityValid,
|
||||
isVideoTorrentDeleteActivityValid,
|
||||
isVideoTorrentUpdateActivityValid
|
||||
|
@ -32,7 +35,10 @@ function isActivityValid (activity: any) {
|
|||
isVideoChannelDeleteActivityValid(activity) ||
|
||||
isAccountDeleteActivityValid(activity) ||
|
||||
isAccountFollowActivityValid(activity) ||
|
||||
isAccountAcceptActivityValid(activity)
|
||||
isAccountAcceptActivityValid(activity) ||
|
||||
isVideoFlagValid(activity) ||
|
||||
isVideoAnnounceValid(activity) ||
|
||||
isVideoChannelAnnounceValid(activity)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -3,6 +3,7 @@ import { ACTIVITY_PUB } from '../../../initializers'
|
|||
import { exists, isDateValid, isUUIDValid } from '../misc'
|
||||
import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels'
|
||||
import {
|
||||
isVideoAbuseReasonValid,
|
||||
isVideoDurationValid,
|
||||
isVideoNameValid,
|
||||
isVideoNSFWValid,
|
||||
|
@ -11,7 +12,7 @@ import {
|
|||
isVideoUrlValid,
|
||||
isVideoViewsValid
|
||||
} from '../videos'
|
||||
import { isBaseActivityValid } from './misc'
|
||||
import { isActivityPubUrlValid, isBaseActivityValid } from './misc'
|
||||
|
||||
function isVideoTorrentAddActivityValid (activity: any) {
|
||||
return isBaseActivityValid(activity, 'Add') &&
|
||||
|
@ -54,6 +55,22 @@ function isVideoTorrentObjectValid (video: any) {
|
|||
setValidRemoteVideoUrls(video.url)
|
||||
}
|
||||
|
||||
function isVideoFlagValid (activity: any) {
|
||||
return isBaseActivityValid(activity, 'Flag') &&
|
||||
isVideoAbuseReasonValid(activity.content) &&
|
||||
isActivityPubUrlValid(activity.object)
|
||||
}
|
||||
|
||||
function isVideoAnnounceValid (activity: any) {
|
||||
return isBaseActivityValid(activity, 'Announce') &&
|
||||
isVideoTorrentObjectValid(activity.object)
|
||||
}
|
||||
|
||||
function isVideoChannelAnnounceValid (activity: any) {
|
||||
return isBaseActivityValid(activity, 'Announce') &&
|
||||
isVideoChannelObjectValid(activity.object)
|
||||
}
|
||||
|
||||
function isVideoChannelCreateActivityValid (activity: any) {
|
||||
return isBaseActivityValid(activity, 'Create') &&
|
||||
isVideoChannelObjectValid(activity.object)
|
||||
|
@ -83,7 +100,10 @@ export {
|
|||
isVideoTorrentUpdateActivityValid,
|
||||
isVideoChannelUpdateActivityValid,
|
||||
isVideoChannelDeleteActivityValid,
|
||||
isVideoTorrentDeleteActivityValid
|
||||
isVideoTorrentDeleteActivityValid,
|
||||
isVideoFlagValid,
|
||||
isVideoAnnounceValid,
|
||||
isVideoChannelAnnounceValid
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -24,6 +24,8 @@ import { OAuthClientModel } from './../models/oauth/oauth-client-interface'
|
|||
import { JobModel } from './../models/job/job-interface'
|
||||
import { AccountModel } from './../models/account/account-interface'
|
||||
import { ApplicationModel } from './../models/application/application-interface'
|
||||
import { VideoChannelShareModel } from '../models/video/video-channel-share-interface'
|
||||
import { VideoShareModel } from '../models/video/video-share-interface'
|
||||
|
||||
const dbname = CONFIG.DATABASE.DBNAME
|
||||
const username = CONFIG.DATABASE.USERNAME
|
||||
|
@ -45,6 +47,8 @@ const database: {
|
|||
User?: UserModel,
|
||||
VideoAbuse?: VideoAbuseModel,
|
||||
VideoChannel?: VideoChannelModel,
|
||||
VideoChannelShare?: VideoChannelShareModel,
|
||||
VideoShare?: VideoShareModel,
|
||||
VideoFile?: VideoFileModel,
|
||||
BlacklistedVideo?: BlacklistedVideoModel,
|
||||
VideoTag?: VideoTagModel,
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
export * from './process-accept'
|
||||
export * from './process-add'
|
||||
export * from './process-announce'
|
||||
export * from './process-create'
|
||||
export * from './process-delete'
|
||||
export * from './process-flag'
|
||||
export * from './process-follow'
|
||||
export * from './process-update'
|
||||
export * from './send-request'
|
||||
|
|
|
@ -39,7 +39,7 @@ function processAddVideo (account: AccountInstance, videoChannelUrl: string, vid
|
|||
async function addRemoteVideo (account: AccountInstance, videoChannelUrl: string, videoToCreateData: VideoTorrentObject) {
|
||||
logger.debug('Adding remote video %s.', videoToCreateData.url)
|
||||
|
||||
await db.sequelize.transaction(async t => {
|
||||
return db.sequelize.transaction(async t => {
|
||||
const sequelizeOptions = {
|
||||
transaction: t
|
||||
}
|
||||
|
@ -66,7 +66,10 @@ async function addRemoteVideo (account: AccountInstance, videoChannelUrl: string
|
|||
const tags = videoToCreateData.tag.map(t => t.name)
|
||||
const tagInstances = await db.Tag.findOrCreateTags(tags, t)
|
||||
await videoCreated.setTags(tagInstances, sequelizeOptions)
|
||||
|
||||
logger.info('Remote video with uuid %s inserted.', videoToCreateData.uuid)
|
||||
|
||||
return videoCreated
|
||||
})
|
||||
|
||||
logger.info('Remote video with uuid %s inserted.', videoToCreateData.uuid)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
import { ActivityAnnounce } from '../../../shared/models/activitypub/activity'
|
||||
import { VideoChannelObject } from '../../../shared/models/activitypub/objects/video-channel-object'
|
||||
import { VideoTorrentObject } from '../../../shared/models/activitypub/objects/video-torrent-object'
|
||||
import { logger } from '../../helpers/logger'
|
||||
import { processAddActivity } from './process-add'
|
||||
import { processCreateActivity } from './process-create'
|
||||
import { database as db } from '../../initializers/index'
|
||||
import { getOrCreateAccount } from '../../helpers/activitypub'
|
||||
import { VideoChannelInstance } from '../../models/video/video-channel-interface'
|
||||
import { VideoInstance } from '../../models/index'
|
||||
|
||||
async function processAnnounceActivity (activity: ActivityAnnounce) {
|
||||
const activityType = activity.object.type
|
||||
const accountAnnouncer = await getOrCreateAccount(activity.actor)
|
||||
|
||||
if (activityType === 'VideoChannel') {
|
||||
const activityCreate = Object.assign(activity, {
|
||||
type: 'Create' as 'Create',
|
||||
actor: activity.object.actor,
|
||||
object: activity.object as VideoChannelObject
|
||||
})
|
||||
|
||||
// Add share entry
|
||||
const videoChannel: VideoChannelInstance = await processCreateActivity(activityCreate)
|
||||
await db.VideoChannelShare.create({
|
||||
accountId: accountAnnouncer.id,
|
||||
videoChannelId: videoChannel.id
|
||||
})
|
||||
} else if (activityType === 'Video') {
|
||||
const activityAdd = Object.assign(activity, {
|
||||
type: 'Add' as 'Add',
|
||||
actor: activity.object.actor,
|
||||
object: activity.object as VideoTorrentObject
|
||||
})
|
||||
|
||||
// Add share entry
|
||||
const video: VideoInstance = await processAddActivity(activityAdd)
|
||||
await db.VideoShare.create({
|
||||
accountId: accountAnnouncer.id,
|
||||
videoId: video.id
|
||||
})
|
||||
}
|
||||
|
||||
logger.warn('Unknown activity object type %s when announcing activity.', activityType, { activity: activity.id })
|
||||
return Promise.resolve(undefined)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
processAnnounceActivity
|
||||
}
|
|
@ -40,7 +40,7 @@ function processCreateVideoChannel (account: AccountInstance, videoChannelToCrea
|
|||
async function addRemoteVideoChannel (account: AccountInstance, videoChannelToCreateData: VideoChannelObject) {
|
||||
logger.debug('Adding remote video channel "%s".', videoChannelToCreateData.uuid)
|
||||
|
||||
await db.sequelize.transaction(async t => {
|
||||
return db.sequelize.transaction(async t => {
|
||||
let videoChannel = await db.VideoChannel.loadByUUIDOrUrl(videoChannelToCreateData.uuid, videoChannelToCreateData.id, t)
|
||||
if (videoChannel) throw new Error('Video channel with this URL/UUID already exists.')
|
||||
|
||||
|
@ -57,10 +57,11 @@ async function addRemoteVideoChannel (account: AccountInstance, videoChannelToCr
|
|||
videoChannel = db.VideoChannel.build(videoChannelData)
|
||||
videoChannel.url = getActivityPubUrl('videoChannel', videoChannel.uuid)
|
||||
|
||||
await videoChannel.save({ transaction: t })
|
||||
})
|
||||
videoChannel = await videoChannel.save({ transaction: t })
|
||||
logger.info('Remote video channel with uuid %s inserted.', videoChannelToCreateData.uuid)
|
||||
|
||||
logger.info('Remote video channel with uuid %s inserted.', videoChannelToCreateData.uuid)
|
||||
return videoChannel
|
||||
})
|
||||
}
|
||||
|
||||
function processCreateVideoAbuse (account: AccountInstance, videoAbuseToCreateData: VideoAbuseObject) {
|
||||
|
|
|
@ -5,3 +5,5 @@ export * from './video-channel-interface'
|
|||
export * from './video-tag-interface'
|
||||
export * from './video-file-interface'
|
||||
export * from './video-interface'
|
||||
export * from './video-share-interface'
|
||||
export * from './video-channel-share-interface'
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import * as Sequelize from 'sequelize'
|
||||
import { AccountInstance } from '../account/account-interface'
|
||||
import { VideoChannelInstance } from './video-channel-interface'
|
||||
|
||||
export namespace VideoChannelShareMethods {
|
||||
}
|
||||
|
||||
export interface VideoChannelShareClass {
|
||||
}
|
||||
|
||||
export interface VideoChannelShareAttributes {
|
||||
accountId: number
|
||||
videoChannelId: number
|
||||
}
|
||||
|
||||
export interface VideoChannelShareInstance
|
||||
extends VideoChannelShareClass, VideoChannelShareAttributes, Sequelize.Instance<VideoChannelShareAttributes> {
|
||||
id: number
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
|
||||
Account?: AccountInstance
|
||||
VideoChannel?: VideoChannelInstance
|
||||
}
|
||||
|
||||
export interface VideoChannelShareModel
|
||||
extends VideoChannelShareClass, Sequelize.Model<VideoChannelShareInstance, VideoChannelShareAttributes> {}
|
|
@ -0,0 +1,49 @@
|
|||
import * as Sequelize from 'sequelize'
|
||||
|
||||
import { addMethodsToModel } from '../utils'
|
||||
import { VideoChannelShareAttributes, VideoChannelShareInstance } from './video-channel-share-interface'
|
||||
|
||||
let VideoChannelShare: Sequelize.Model<VideoChannelShareInstance, VideoChannelShareAttributes>
|
||||
|
||||
export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
|
||||
VideoChannelShare = sequelize.define<VideoChannelShareInstance, VideoChannelShareAttributes>('VideoChannelShare',
|
||||
{ },
|
||||
{
|
||||
indexes: [
|
||||
{
|
||||
fields: [ 'accountId' ]
|
||||
},
|
||||
{
|
||||
fields: [ 'videoChannelId' ]
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
const classMethods = [
|
||||
associate
|
||||
]
|
||||
addMethodsToModel(VideoChannelShare, classMethods)
|
||||
|
||||
return VideoChannelShare
|
||||
}
|
||||
|
||||
// ------------------------------ METHODS ------------------------------
|
||||
|
||||
function associate (models) {
|
||||
VideoChannelShare.belongsTo(models.Account, {
|
||||
foreignKey: {
|
||||
name: 'accountId',
|
||||
allowNull: false
|
||||
},
|
||||
onDelete: 'cascade'
|
||||
})
|
||||
|
||||
VideoChannelShare.belongsTo(models.VideoChannel, {
|
||||
foreignKey: {
|
||||
name: 'videoChannelId',
|
||||
allowNull: true
|
||||
},
|
||||
onDelete: 'cascade'
|
||||
})
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import * as Sequelize from 'sequelize'
|
||||
import { AccountInstance } from '../account/account-interface'
|
||||
import { VideoInstance } from './video-interface'
|
||||
|
||||
export namespace VideoShareMethods {
|
||||
}
|
||||
|
||||
export interface VideoShareClass {
|
||||
}
|
||||
|
||||
export interface VideoShareAttributes {
|
||||
accountId: number
|
||||
videoId: number
|
||||
}
|
||||
|
||||
export interface VideoShareInstance extends VideoShareClass, VideoShareAttributes, Sequelize.Instance<VideoShareAttributes> {
|
||||
id: number
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
|
||||
Account?: AccountInstance
|
||||
Video?: VideoInstance
|
||||
}
|
||||
|
||||
export interface VideoShareModel extends VideoShareClass, Sequelize.Model<VideoShareInstance, VideoShareAttributes> {}
|
|
@ -0,0 +1,49 @@
|
|||
import * as Sequelize from 'sequelize'
|
||||
|
||||
import { addMethodsToModel } from '../utils'
|
||||
import { VideoShareAttributes, VideoShareInstance } from './video-share-interface'
|
||||
|
||||
let VideoShare: Sequelize.Model<VideoShareInstance, VideoShareAttributes>
|
||||
|
||||
export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
|
||||
VideoShare = sequelize.define<VideoShareInstance, VideoShareAttributes>('VideoShare',
|
||||
{ },
|
||||
{
|
||||
indexes: [
|
||||
{
|
||||
fields: [ 'accountId' ]
|
||||
},
|
||||
{
|
||||
fields: [ 'videoId' ]
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
const classMethods = [
|
||||
associate
|
||||
]
|
||||
addMethodsToModel(VideoShare, classMethods)
|
||||
|
||||
return VideoShare
|
||||
}
|
||||
|
||||
// ------------------------------ METHODS ------------------------------
|
||||
|
||||
function associate (models) {
|
||||
VideoShare.belongsTo(models.Account, {
|
||||
foreignKey: {
|
||||
name: 'accountId',
|
||||
allowNull: false
|
||||
},
|
||||
onDelete: 'cascade'
|
||||
})
|
||||
|
||||
VideoShare.belongsTo(models.Video, {
|
||||
foreignKey: {
|
||||
name: 'videoId',
|
||||
allowNull: true
|
||||
},
|
||||
onDelete: 'cascade'
|
||||
})
|
||||
}
|
|
@ -253,9 +253,6 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
|
|||
},
|
||||
{
|
||||
fields: [ 'channelId' ]
|
||||
},
|
||||
{
|
||||
fields: [ 'parentId' ]
|
||||
}
|
||||
],
|
||||
hooks: {
|
||||
|
@ -329,14 +326,6 @@ function associate (models) {
|
|||
onDelete: 'cascade'
|
||||
})
|
||||
|
||||
Video.belongsTo(models.Video, {
|
||||
foreignKey: {
|
||||
name: 'parentId',
|
||||
allowNull: true
|
||||
},
|
||||
onDelete: 'cascade'
|
||||
})
|
||||
|
||||
Video.belongsToMany(models.Tag, {
|
||||
foreignKey: 'videoId',
|
||||
through: models.VideoTag,
|
||||
|
|
|
@ -3,10 +3,10 @@ import { ActivityPubSignature } from './activitypub-signature'
|
|||
import { VideoAbuseObject } from './objects/video-abuse-object'
|
||||
|
||||
export type Activity = ActivityCreate | ActivityAdd | ActivityUpdate | ActivityFlag |
|
||||
ActivityDelete | ActivityFollow | ActivityAccept
|
||||
ActivityDelete | ActivityFollow | ActivityAccept | ActivityAnnounce
|
||||
|
||||
// Flag -> report abuse
|
||||
export type ActivityType = 'Create' | 'Add' | 'Update' | 'Flag' | 'Delete' | 'Follow' | 'Accept'
|
||||
export type ActivityType = 'Create' | 'Add' | 'Update' | 'Flag' | 'Delete' | 'Follow' | 'Accept' | 'Announce'
|
||||
|
||||
export interface BaseActivity {
|
||||
'@context'?: any[]
|
||||
|
@ -49,3 +49,8 @@ export interface ActivityFollow extends BaseActivity {
|
|||
export interface ActivityAccept extends BaseActivity {
|
||||
type: 'Accept'
|
||||
}
|
||||
|
||||
export interface ActivityAnnounce extends BaseActivity {
|
||||
type: 'Announce'
|
||||
object: VideoChannelObject | VideoTorrentObject
|
||||
}
|
||||
|
|
|
@ -6,4 +6,5 @@ export interface VideoChannelObject {
|
|||
uuid: string
|
||||
published: Date
|
||||
updated: Date
|
||||
actor?: string
|
||||
}
|
||||
|
|
|
@ -23,4 +23,5 @@ export interface VideoTorrentObject {
|
|||
content: string
|
||||
icon: ActivityIconObject
|
||||
url: ActivityUrlObject[]
|
||||
actor?: string
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue