mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-04 02:09:37 +02:00
Merge branch 'develop' into pr/1285
This commit is contained in:
commit
b718fd2237
387 changed files with 18290 additions and 10001 deletions
|
@ -14,6 +14,8 @@ import { AccountModel } from '../../models/account/account'
|
|||
import { VideoModel } from '../../models/video/video'
|
||||
import { buildNSFWFilter, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
|
||||
import { VideoChannelModel } from '../../models/video/video-channel'
|
||||
import { JobQueue } from '../../lib/job-queue'
|
||||
import { logger } from '../../helpers/logger'
|
||||
|
||||
const accountsRouter = express.Router()
|
||||
|
||||
|
@ -57,6 +59,11 @@ export {
|
|||
function getAccount (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const account: AccountModel = res.locals.account
|
||||
|
||||
if (account.isOutdated()) {
|
||||
JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } })
|
||||
.catch(err => logger.error('Cannot create AP refresher job for actor %s.', account.Actor.url, { err }))
|
||||
}
|
||||
|
||||
return res.json(account.toFormattedJSON())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as express from 'express'
|
||||
import { omit, snakeCase } from 'lodash'
|
||||
import { snakeCase } from 'lodash'
|
||||
import { ServerConfig, UserRight } from '../../../shared'
|
||||
import { About } from '../../../shared/models/server/about.model'
|
||||
import { CustomConfig } from '../../../shared/models/server/custom-config.model'
|
||||
|
@ -78,6 +78,9 @@ async function getConfig (req: express.Request, res: express.Response) {
|
|||
requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION
|
||||
},
|
||||
transcoding: {
|
||||
hls: {
|
||||
enabled: CONFIG.TRANSCODING.HLS.ENABLED
|
||||
},
|
||||
enabledResolutions
|
||||
},
|
||||
import: {
|
||||
|
@ -120,6 +123,11 @@ async function getConfig (req: express.Request, res: express.Response) {
|
|||
user: {
|
||||
videoQuota: CONFIG.USER.VIDEO_QUOTA,
|
||||
videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY
|
||||
},
|
||||
trending: {
|
||||
videos: {
|
||||
intervalDays: CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,6 +249,9 @@ function customConfig (): CustomConfig {
|
|||
'480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ],
|
||||
'720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ],
|
||||
'1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ]
|
||||
},
|
||||
hls: {
|
||||
enabled: CONFIG.TRANSCODING.HLS.ENABLED
|
||||
}
|
||||
},
|
||||
import: {
|
||||
|
|
|
@ -8,6 +8,7 @@ import { VideoCommentModel } from '../../../models/video/video-comment'
|
|||
import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy'
|
||||
import { CONFIG, ROUTE_CACHE_LIFETIME } from '../../../initializers/constants'
|
||||
import { cacheRoute } from '../../../middlewares/cache'
|
||||
import { VideoFileModel } from '../../../models/video/video-file'
|
||||
|
||||
const statsRouter = express.Router()
|
||||
|
||||
|
@ -16,11 +17,12 @@ statsRouter.get('/stats',
|
|||
asyncMiddleware(getStats)
|
||||
)
|
||||
|
||||
async function getStats (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function getStats (req: express.Request, res: express.Response) {
|
||||
const { totalLocalVideos, totalLocalVideoViews, totalVideos } = await VideoModel.getStats()
|
||||
const { totalLocalVideoComments, totalVideoComments } = await VideoCommentModel.getStats()
|
||||
const { totalUsers } = await UserModel.getStats()
|
||||
const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats()
|
||||
const { totalLocalVideoFilesSize } = await VideoFileModel.getStats()
|
||||
|
||||
const videosRedundancyStats = await Promise.all(
|
||||
CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.map(r => {
|
||||
|
@ -32,8 +34,9 @@ async function getStats (req: express.Request, res: express.Response, next: expr
|
|||
const data: ServerStats = {
|
||||
totalLocalVideos,
|
||||
totalLocalVideoViews,
|
||||
totalVideos,
|
||||
totalLocalVideoFilesSize,
|
||||
totalLocalVideoComments,
|
||||
totalVideos,
|
||||
totalVideoComments,
|
||||
totalUsers,
|
||||
totalInstanceFollowers,
|
||||
|
|
|
@ -41,6 +41,7 @@ import { myBlocklistRouter } from './my-blocklist'
|
|||
import { myVideosHistoryRouter } from './my-history'
|
||||
import { myNotificationsRouter } from './my-notifications'
|
||||
import { Notifier } from '../../../lib/notifier'
|
||||
import { mySubscriptionsRouter } from './my-subscriptions'
|
||||
|
||||
const auditLogger = auditLoggerFactory('users')
|
||||
|
||||
|
@ -58,6 +59,7 @@ const askSendEmailLimiter = new RateLimit({
|
|||
|
||||
const usersRouter = express.Router()
|
||||
usersRouter.use('/', myNotificationsRouter)
|
||||
usersRouter.use('/', mySubscriptionsRouter)
|
||||
usersRouter.use('/', myBlocklistRouter)
|
||||
usersRouter.use('/', myVideosHistoryRouter)
|
||||
usersRouter.use('/', meRouter)
|
||||
|
@ -227,7 +229,7 @@ async function unblockUser (req: express.Request, res: express.Response, next: e
|
|||
return res.status(204).end()
|
||||
}
|
||||
|
||||
async function blockUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function blockUser (req: express.Request, res: express.Response) {
|
||||
const user: UserModel = res.locals.user
|
||||
const reason = req.body.reason
|
||||
|
||||
|
@ -236,23 +238,23 @@ async function blockUser (req: express.Request, res: express.Response, next: exp
|
|||
return res.status(204).end()
|
||||
}
|
||||
|
||||
function getUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
function getUser (req: express.Request, res: express.Response) {
|
||||
return res.json((res.locals.user as UserModel).toFormattedJSON())
|
||||
}
|
||||
|
||||
async function autocompleteUsers (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function autocompleteUsers (req: express.Request, res: express.Response) {
|
||||
const resultList = await UserModel.autoComplete(req.query.search as string)
|
||||
|
||||
return res.json(resultList)
|
||||
}
|
||||
|
||||
async function listUsers (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function listUsers (req: express.Request, res: express.Response) {
|
||||
const resultList = await UserModel.listForApi(req.query.start, req.query.count, req.query.sort, req.query.search)
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
async function removeUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function removeUser (req: express.Request, res: express.Response) {
|
||||
const user: UserModel = res.locals.user
|
||||
|
||||
await user.destroy()
|
||||
|
@ -262,12 +264,13 @@ async function removeUser (req: express.Request, res: express.Response, next: ex
|
|||
return res.sendStatus(204)
|
||||
}
|
||||
|
||||
async function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function updateUser (req: express.Request, res: express.Response) {
|
||||
const body: UserUpdate = req.body
|
||||
const userToUpdate = res.locals.user as UserModel
|
||||
const oldUserAuditView = new UserAuditView(userToUpdate.toFormattedJSON())
|
||||
const roleChanged = body.role !== undefined && body.role !== userToUpdate.role
|
||||
|
||||
if (body.password !== undefined) userToUpdate.password = body.password
|
||||
if (body.email !== undefined) userToUpdate.email = body.email
|
||||
if (body.emailVerified !== undefined) userToUpdate.emailVerified = body.emailVerified
|
||||
if (body.videoQuota !== undefined) userToUpdate.videoQuota = body.videoQuota
|
||||
|
@ -277,11 +280,11 @@ async function updateUser (req: express.Request, res: express.Response, next: ex
|
|||
const user = await userToUpdate.save()
|
||||
|
||||
// Destroy user token to refresh rights
|
||||
if (roleChanged) await deleteUserToken(userToUpdate.id)
|
||||
if (roleChanged || body.password !== undefined) await deleteUserToken(userToUpdate.id)
|
||||
|
||||
auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView)
|
||||
|
||||
// Don't need to send this update to followers, these attributes are not propagated
|
||||
// Don't need to send this update to followers, these attributes are not federated
|
||||
|
||||
return res.sendStatus(204)
|
||||
}
|
||||
|
@ -291,7 +294,7 @@ async function askResetUserPassword (req: express.Request, res: express.Response
|
|||
|
||||
const verificationString = await Redis.Instance.setResetPasswordVerificationString(user.id)
|
||||
const url = CONFIG.WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString
|
||||
await Emailer.Instance.addForgetPasswordEmailJob(user.email, url)
|
||||
await Emailer.Instance.addPasswordResetEmailJob(user.email, url)
|
||||
|
||||
return res.status(204).end()
|
||||
}
|
||||
|
|
|
@ -8,36 +8,23 @@ import {
|
|||
asyncMiddleware,
|
||||
asyncRetryTransactionMiddleware,
|
||||
authenticate,
|
||||
commonVideosFiltersValidator,
|
||||
paginationValidator,
|
||||
setDefaultPagination,
|
||||
setDefaultSort,
|
||||
userSubscriptionAddValidator,
|
||||
userSubscriptionGetValidator,
|
||||
usersUpdateMeValidator,
|
||||
usersVideoRatingValidator
|
||||
} from '../../../middlewares'
|
||||
import {
|
||||
areSubscriptionsExistValidator,
|
||||
deleteMeValidator,
|
||||
userSubscriptionsSortValidator,
|
||||
videoImportsSortValidator,
|
||||
videosSortValidator
|
||||
} from '../../../middlewares/validators'
|
||||
import { deleteMeValidator, videoImportsSortValidator, videosSortValidator } from '../../../middlewares/validators'
|
||||
import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
|
||||
import { UserModel } from '../../../models/account/user'
|
||||
import { VideoModel } from '../../../models/video/video'
|
||||
import { VideoSortField } from '../../../../client/src/app/shared/video/sort-field.type'
|
||||
import { buildNSFWFilter, createReqFiles } from '../../../helpers/express-utils'
|
||||
import { createReqFiles } from '../../../helpers/express-utils'
|
||||
import { UserVideoQuota } from '../../../../shared/models/users/user-video-quota.model'
|
||||
import { updateAvatarValidator } from '../../../middlewares/validators/avatar'
|
||||
import { updateActorAvatarFile } from '../../../lib/avatar'
|
||||
import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger'
|
||||
import { VideoImportModel } from '../../../models/video/video-import'
|
||||
import { VideoFilter } from '../../../../shared/models/videos/video-query.type'
|
||||
import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
|
||||
import { JobQueue } from '../../../lib/job-queue'
|
||||
import { logger } from '../../../helpers/logger'
|
||||
import { AccountModel } from '../../../models/account/account'
|
||||
|
||||
const auditLogger = auditLoggerFactory('users-me')
|
||||
|
@ -98,51 +85,6 @@ meRouter.post('/me/avatar/pick',
|
|||
asyncRetryTransactionMiddleware(updateMyAvatar)
|
||||
)
|
||||
|
||||
// ##### Subscriptions part #####
|
||||
|
||||
meRouter.get('/me/subscriptions/videos',
|
||||
authenticate,
|
||||
paginationValidator,
|
||||
videosSortValidator,
|
||||
setDefaultSort,
|
||||
setDefaultPagination,
|
||||
commonVideosFiltersValidator,
|
||||
asyncMiddleware(getUserSubscriptionVideos)
|
||||
)
|
||||
|
||||
meRouter.get('/me/subscriptions/exist',
|
||||
authenticate,
|
||||
areSubscriptionsExistValidator,
|
||||
asyncMiddleware(areSubscriptionsExist)
|
||||
)
|
||||
|
||||
meRouter.get('/me/subscriptions',
|
||||
authenticate,
|
||||
paginationValidator,
|
||||
userSubscriptionsSortValidator,
|
||||
setDefaultSort,
|
||||
setDefaultPagination,
|
||||
asyncMiddleware(getUserSubscriptions)
|
||||
)
|
||||
|
||||
meRouter.post('/me/subscriptions',
|
||||
authenticate,
|
||||
userSubscriptionAddValidator,
|
||||
asyncMiddleware(addUserSubscription)
|
||||
)
|
||||
|
||||
meRouter.get('/me/subscriptions/:uri',
|
||||
authenticate,
|
||||
userSubscriptionGetValidator,
|
||||
getUserSubscription
|
||||
)
|
||||
|
||||
meRouter.delete('/me/subscriptions/:uri',
|
||||
authenticate,
|
||||
userSubscriptionGetValidator,
|
||||
asyncRetryTransactionMiddleware(deleteUserSubscription)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
|
@ -151,100 +93,6 @@ export {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function areSubscriptionsExist (req: express.Request, res: express.Response) {
|
||||
const uris = req.query.uris as string[]
|
||||
const user = res.locals.oauth.token.User as UserModel
|
||||
|
||||
const handles = uris.map(u => {
|
||||
let [ name, host ] = u.split('@')
|
||||
if (host === CONFIG.WEBSERVER.HOST) host = null
|
||||
|
||||
return { name, host, uri: u }
|
||||
})
|
||||
|
||||
const results = await ActorFollowModel.listSubscribedIn(user.Account.Actor.id, handles)
|
||||
|
||||
const existObject: { [id: string ]: boolean } = {}
|
||||
for (const handle of handles) {
|
||||
const obj = results.find(r => {
|
||||
const server = r.ActorFollowing.Server
|
||||
|
||||
return r.ActorFollowing.preferredUsername === handle.name &&
|
||||
(
|
||||
(!server && !handle.host) ||
|
||||
(server.host === handle.host)
|
||||
)
|
||||
})
|
||||
|
||||
existObject[handle.uri] = obj !== undefined
|
||||
}
|
||||
|
||||
return res.json(existObject)
|
||||
}
|
||||
|
||||
async function addUserSubscription (req: express.Request, res: express.Response) {
|
||||
const user = res.locals.oauth.token.User as UserModel
|
||||
const [ name, host ] = req.body.uri.split('@')
|
||||
|
||||
const payload = {
|
||||
name,
|
||||
host,
|
||||
followerActorId: user.Account.Actor.id
|
||||
}
|
||||
|
||||
JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
|
||||
.catch(err => logger.error('Cannot create follow job for subscription %s.', req.body.uri, err))
|
||||
|
||||
return res.status(204).end()
|
||||
}
|
||||
|
||||
function getUserSubscription (req: express.Request, res: express.Response) {
|
||||
const subscription: ActorFollowModel = res.locals.subscription
|
||||
|
||||
return res.json(subscription.ActorFollowing.VideoChannel.toFormattedJSON())
|
||||
}
|
||||
|
||||
async function deleteUserSubscription (req: express.Request, res: express.Response) {
|
||||
const subscription: ActorFollowModel = res.locals.subscription
|
||||
|
||||
await sequelizeTypescript.transaction(async t => {
|
||||
return subscription.destroy({ transaction: t })
|
||||
})
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
async function getUserSubscriptions (req: express.Request, res: express.Response) {
|
||||
const user = res.locals.oauth.token.User as UserModel
|
||||
const actorId = user.Account.Actor.id
|
||||
|
||||
const resultList = await ActorFollowModel.listSubscriptionsForApi(actorId, req.query.start, req.query.count, req.query.sort)
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
async function getUserSubscriptionVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const user = res.locals.oauth.token.User as UserModel
|
||||
const resultList = await VideoModel.listForApi({
|
||||
start: req.query.start,
|
||||
count: req.query.count,
|
||||
sort: req.query.sort,
|
||||
includeLocalVideos: false,
|
||||
categoryOneOf: req.query.categoryOneOf,
|
||||
licenceOneOf: req.query.licenceOneOf,
|
||||
languageOneOf: req.query.languageOneOf,
|
||||
tagsOneOf: req.query.tagsOneOf,
|
||||
tagsAllOf: req.query.tagsAllOf,
|
||||
nsfw: buildNSFWFilter(res, req.query.nsfw),
|
||||
filter: req.query.filter as VideoFilter,
|
||||
withFiles: false,
|
||||
followerActorId: user.Account.Actor.id,
|
||||
user
|
||||
})
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
async function getUserVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const user = res.locals.oauth.token.User as UserModel
|
||||
const resultList = await VideoModel.listUserVideosForApi(
|
||||
|
@ -319,7 +167,7 @@ async function deleteMe (req: express.Request, res: express.Response) {
|
|||
return res.sendStatus(204)
|
||||
}
|
||||
|
||||
async function updateMe (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function updateMe (req: express.Request, res: express.Response) {
|
||||
const body: UserUpdateMe = req.body
|
||||
|
||||
const user: UserModel = res.locals.oauth.token.user
|
||||
|
|
170
server/controllers/api/users/my-subscriptions.ts
Normal file
170
server/controllers/api/users/my-subscriptions.ts
Normal file
|
@ -0,0 +1,170 @@
|
|||
import * as express from 'express'
|
||||
import 'multer'
|
||||
import { getFormattedObjects } from '../../../helpers/utils'
|
||||
import { CONFIG, sequelizeTypescript } from '../../../initializers'
|
||||
import {
|
||||
asyncMiddleware,
|
||||
asyncRetryTransactionMiddleware,
|
||||
authenticate,
|
||||
commonVideosFiltersValidator,
|
||||
paginationValidator,
|
||||
setDefaultPagination,
|
||||
setDefaultSort,
|
||||
userSubscriptionAddValidator,
|
||||
userSubscriptionGetValidator
|
||||
} from '../../../middlewares'
|
||||
import { areSubscriptionsExistValidator, userSubscriptionsSortValidator, videosSortValidator } from '../../../middlewares/validators'
|
||||
import { UserModel } from '../../../models/account/user'
|
||||
import { VideoModel } from '../../../models/video/video'
|
||||
import { buildNSFWFilter } from '../../../helpers/express-utils'
|
||||
import { VideoFilter } from '../../../../shared/models/videos/video-query.type'
|
||||
import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
|
||||
import { JobQueue } from '../../../lib/job-queue'
|
||||
import { logger } from '../../../helpers/logger'
|
||||
|
||||
const mySubscriptionsRouter = express.Router()
|
||||
|
||||
mySubscriptionsRouter.get('/me/subscriptions/videos',
|
||||
authenticate,
|
||||
paginationValidator,
|
||||
videosSortValidator,
|
||||
setDefaultSort,
|
||||
setDefaultPagination,
|
||||
commonVideosFiltersValidator,
|
||||
asyncMiddleware(getUserSubscriptionVideos)
|
||||
)
|
||||
|
||||
mySubscriptionsRouter.get('/me/subscriptions/exist',
|
||||
authenticate,
|
||||
areSubscriptionsExistValidator,
|
||||
asyncMiddleware(areSubscriptionsExist)
|
||||
)
|
||||
|
||||
mySubscriptionsRouter.get('/me/subscriptions',
|
||||
authenticate,
|
||||
paginationValidator,
|
||||
userSubscriptionsSortValidator,
|
||||
setDefaultSort,
|
||||
setDefaultPagination,
|
||||
asyncMiddleware(getUserSubscriptions)
|
||||
)
|
||||
|
||||
mySubscriptionsRouter.post('/me/subscriptions',
|
||||
authenticate,
|
||||
userSubscriptionAddValidator,
|
||||
asyncMiddleware(addUserSubscription)
|
||||
)
|
||||
|
||||
mySubscriptionsRouter.get('/me/subscriptions/:uri',
|
||||
authenticate,
|
||||
userSubscriptionGetValidator,
|
||||
getUserSubscription
|
||||
)
|
||||
|
||||
mySubscriptionsRouter.delete('/me/subscriptions/:uri',
|
||||
authenticate,
|
||||
userSubscriptionGetValidator,
|
||||
asyncRetryTransactionMiddleware(deleteUserSubscription)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
mySubscriptionsRouter
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function areSubscriptionsExist (req: express.Request, res: express.Response) {
|
||||
const uris = req.query.uris as string[]
|
||||
const user = res.locals.oauth.token.User as UserModel
|
||||
|
||||
const handles = uris.map(u => {
|
||||
let [ name, host ] = u.split('@')
|
||||
if (host === CONFIG.WEBSERVER.HOST) host = null
|
||||
|
||||
return { name, host, uri: u }
|
||||
})
|
||||
|
||||
const results = await ActorFollowModel.listSubscribedIn(user.Account.Actor.id, handles)
|
||||
|
||||
const existObject: { [id: string ]: boolean } = {}
|
||||
for (const handle of handles) {
|
||||
const obj = results.find(r => {
|
||||
const server = r.ActorFollowing.Server
|
||||
|
||||
return r.ActorFollowing.preferredUsername === handle.name &&
|
||||
(
|
||||
(!server && !handle.host) ||
|
||||
(server.host === handle.host)
|
||||
)
|
||||
})
|
||||
|
||||
existObject[handle.uri] = obj !== undefined
|
||||
}
|
||||
|
||||
return res.json(existObject)
|
||||
}
|
||||
|
||||
async function addUserSubscription (req: express.Request, res: express.Response) {
|
||||
const user = res.locals.oauth.token.User as UserModel
|
||||
const [ name, host ] = req.body.uri.split('@')
|
||||
|
||||
const payload = {
|
||||
name,
|
||||
host,
|
||||
followerActorId: user.Account.Actor.id
|
||||
}
|
||||
|
||||
JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
|
||||
.catch(err => logger.error('Cannot create follow job for subscription %s.', req.body.uri, err))
|
||||
|
||||
return res.status(204).end()
|
||||
}
|
||||
|
||||
function getUserSubscription (req: express.Request, res: express.Response) {
|
||||
const subscription: ActorFollowModel = res.locals.subscription
|
||||
|
||||
return res.json(subscription.ActorFollowing.VideoChannel.toFormattedJSON())
|
||||
}
|
||||
|
||||
async function deleteUserSubscription (req: express.Request, res: express.Response) {
|
||||
const subscription: ActorFollowModel = res.locals.subscription
|
||||
|
||||
await sequelizeTypescript.transaction(async t => {
|
||||
return subscription.destroy({ transaction: t })
|
||||
})
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
async function getUserSubscriptions (req: express.Request, res: express.Response) {
|
||||
const user = res.locals.oauth.token.User as UserModel
|
||||
const actorId = user.Account.Actor.id
|
||||
|
||||
const resultList = await ActorFollowModel.listSubscriptionsForApi(actorId, req.query.start, req.query.count, req.query.sort)
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
async function getUserSubscriptionVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const user = res.locals.oauth.token.User as UserModel
|
||||
const resultList = await VideoModel.listForApi({
|
||||
start: req.query.start,
|
||||
count: req.query.count,
|
||||
sort: req.query.sort,
|
||||
includeLocalVideos: false,
|
||||
categoryOneOf: req.query.categoryOneOf,
|
||||
licenceOneOf: req.query.licenceOneOf,
|
||||
languageOneOf: req.query.languageOneOf,
|
||||
tagsOneOf: req.query.tagsOneOf,
|
||||
tagsAllOf: req.query.tagsAllOf,
|
||||
nsfw: buildNSFWFilter(res, req.query.nsfw),
|
||||
filter: req.query.filter as VideoFilter,
|
||||
withFiles: false,
|
||||
followerActorId: user.Account.Actor.id,
|
||||
user
|
||||
})
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
|
@ -30,6 +30,7 @@ import { updateActorAvatarFile } from '../../lib/avatar'
|
|||
import { auditLoggerFactory, getAuditIdFromRes, VideoChannelAuditView } from '../../helpers/audit-logger'
|
||||
import { resetSequelizeInstance } from '../../helpers/database-utils'
|
||||
import { UserModel } from '../../models/account/user'
|
||||
import { JobQueue } from '../../lib/job-queue'
|
||||
|
||||
const auditLogger = auditLoggerFactory('channels')
|
||||
const reqAvatarFile = createReqFiles([ 'avatarfile' ], MIMETYPES.IMAGE.MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.TMP_DIR })
|
||||
|
@ -197,6 +198,11 @@ async function removeVideoChannel (req: express.Request, res: express.Response)
|
|||
async function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const videoChannelWithVideos = await VideoChannelModel.loadAndPopulateAccountAndVideos(res.locals.videoChannel.id)
|
||||
|
||||
if (videoChannelWithVideos.isOutdated()) {
|
||||
JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannelWithVideos.Actor.url } })
|
||||
.catch(err => logger.error('Cannot create AP refresher job for actor %s.', videoChannelWithVideos.Actor.url, { err }))
|
||||
}
|
||||
|
||||
return res.json(videoChannelWithVideos.toFormattedJSON())
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ import { UserRight, VideoAbuseCreate, VideoAbuseState } from '../../../../shared
|
|||
import { logger } from '../../../helpers/logger'
|
||||
import { getFormattedObjects } from '../../../helpers/utils'
|
||||
import { sequelizeTypescript } from '../../../initializers'
|
||||
import { sendVideoAbuse } from '../../../lib/activitypub/send'
|
||||
import {
|
||||
asyncMiddleware,
|
||||
asyncRetryTransactionMiddleware,
|
||||
|
@ -23,6 +22,7 @@ import { VideoAbuseModel } from '../../../models/video/video-abuse'
|
|||
import { auditLoggerFactory, VideoAbuseAuditView } from '../../../helpers/audit-logger'
|
||||
import { UserModel } from '../../../models/account/user'
|
||||
import { Notifier } from '../../../lib/notifier'
|
||||
import { sendVideoAbuse } from '../../../lib/activitypub/send/send-flag'
|
||||
|
||||
const auditLogger = auditLoggerFactory('abuse')
|
||||
const abuseVideoRouter = express.Router()
|
||||
|
|
|
@ -18,6 +18,8 @@ import { VideoBlacklistModel } from '../../../models/video/video-blacklist'
|
|||
import { sequelizeTypescript } from '../../../initializers'
|
||||
import { Notifier } from '../../../lib/notifier'
|
||||
import { VideoModel } from '../../../models/video/video'
|
||||
import { sendCreateVideo, sendDeleteVideo, sendUpdateVideo } from '../../../lib/activitypub/send'
|
||||
import { federateVideoIfNeeded } from '../../../lib/activitypub'
|
||||
|
||||
const blacklistRouter = express.Router()
|
||||
|
||||
|
@ -66,12 +68,17 @@ async function addVideoToBlacklist (req: express.Request, res: express.Response)
|
|||
|
||||
const toCreate = {
|
||||
videoId: videoInstance.id,
|
||||
unfederated: body.unfederate === true,
|
||||
reason: body.reason
|
||||
}
|
||||
|
||||
const blacklist = await VideoBlacklistModel.create(toCreate)
|
||||
blacklist.Video = videoInstance
|
||||
|
||||
if (body.unfederate === true) {
|
||||
await sendDeleteVideo(videoInstance, undefined)
|
||||
}
|
||||
|
||||
Notifier.Instance.notifyOnVideoBlacklist(blacklist)
|
||||
|
||||
logger.info('Video %s blacklisted.', res.locals.video.uuid)
|
||||
|
@ -101,8 +108,14 @@ async function removeVideoFromBlacklistController (req: express.Request, res: ex
|
|||
const videoBlacklist = res.locals.videoBlacklist as VideoBlacklistModel
|
||||
const video: VideoModel = res.locals.video
|
||||
|
||||
await sequelizeTypescript.transaction(t => {
|
||||
return videoBlacklist.destroy({ transaction: t })
|
||||
await sequelizeTypescript.transaction(async t => {
|
||||
const unfederated = videoBlacklist.unfederated
|
||||
await videoBlacklist.destroy({ transaction: t })
|
||||
|
||||
// Re federate the video
|
||||
if (unfederated === true) {
|
||||
await federateVideoIfNeeded(video, true, t)
|
||||
}
|
||||
})
|
||||
|
||||
Notifier.Instance.notifyOnVideoUnblacklist(video)
|
||||
|
|
|
@ -164,6 +164,7 @@ function buildVideo (channelId: number, body: VideoImportCreate, importData: You
|
|||
licence: body.licence || importData.licence,
|
||||
language: body.language || undefined,
|
||||
commentsEnabled: body.commentsEnabled || true,
|
||||
downloadEnabled: body.downloadEnabled || true,
|
||||
waitTranscoding: body.waitTranscoding || false,
|
||||
state: VideoState.TO_IMPORT,
|
||||
nsfw: body.nsfw || importData.nsfw || false,
|
||||
|
|
|
@ -23,7 +23,6 @@ import {
|
|||
fetchRemoteVideoDescription,
|
||||
getVideoActivityPubUrl
|
||||
} from '../../../lib/activitypub'
|
||||
import { sendCreateView } from '../../../lib/activitypub/send'
|
||||
import { JobQueue } from '../../../lib/job-queue'
|
||||
import { Redis } from '../../../lib/redis'
|
||||
import {
|
||||
|
@ -37,6 +36,7 @@ import {
|
|||
setDefaultPagination,
|
||||
setDefaultSort,
|
||||
videosAddValidator,
|
||||
videosCustomGetValidator,
|
||||
videosGetValidator,
|
||||
videosRemoveValidator,
|
||||
videosSortValidator,
|
||||
|
@ -59,6 +59,7 @@ import { resetSequelizeInstance } from '../../../helpers/database-utils'
|
|||
import { move } from 'fs-extra'
|
||||
import { watchingRouter } from './watching'
|
||||
import { Notifier } from '../../../lib/notifier'
|
||||
import { sendView } from '../../../lib/activitypub/send/send-view'
|
||||
|
||||
const auditLogger = auditLoggerFactory('videos')
|
||||
const videosRouter = express.Router()
|
||||
|
@ -123,9 +124,9 @@ videosRouter.get('/:id/description',
|
|||
)
|
||||
videosRouter.get('/:id',
|
||||
optionalAuthenticate,
|
||||
asyncMiddleware(videosGetValidator),
|
||||
asyncMiddleware(videosCustomGetValidator('only-video-with-rights')),
|
||||
asyncMiddleware(checkVideoFollowConstraints),
|
||||
getVideo
|
||||
asyncMiddleware(getVideo)
|
||||
)
|
||||
videosRouter.post('/:id/views',
|
||||
asyncMiddleware(videosGetValidator),
|
||||
|
@ -181,6 +182,7 @@ async function addVideo (req: express.Request, res: express.Response) {
|
|||
licence: videoInfo.licence,
|
||||
language: videoInfo.language,
|
||||
commentsEnabled: videoInfo.commentsEnabled || false,
|
||||
downloadEnabled: videoInfo.downloadEnabled || true,
|
||||
waitTranscoding: videoInfo.waitTranscoding || false,
|
||||
state: CONFIG.TRANSCODING.ENABLED ? VideoState.TO_TRANSCODE : VideoState.PUBLISHED,
|
||||
nsfw: videoInfo.nsfw || false,
|
||||
|
@ -326,8 +328,9 @@ async function updateVideo (req: express.Request, res: express.Response) {
|
|||
if (videoInfoToUpdate.support !== undefined) videoInstance.set('support', videoInfoToUpdate.support)
|
||||
if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description)
|
||||
if (videoInfoToUpdate.commentsEnabled !== undefined) videoInstance.set('commentsEnabled', videoInfoToUpdate.commentsEnabled)
|
||||
if (videoInfoToUpdate.originallyPublishedAt !== undefined &&
|
||||
videoInfoToUpdate.originallyPublishedAt !== null) {
|
||||
if (videoInfoToUpdate.downloadEnabled !== undefined) videoInstance.set('downloadEnabled', videoInfoToUpdate.downloadEnabled)
|
||||
|
||||
if (videoInfoToUpdate.originallyPublishedAt !== undefined && videoInfoToUpdate.originallyPublishedAt !== null) {
|
||||
videoInstance.set('originallyPublishedAt', videoInfoToUpdate.originallyPublishedAt)
|
||||
}
|
||||
|
||||
|
@ -370,7 +373,11 @@ async function updateVideo (req: express.Request, res: express.Response) {
|
|||
}
|
||||
|
||||
const isNewVideo = wasPrivateVideo && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE
|
||||
await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t)
|
||||
|
||||
// Don't send update if the video was unfederated
|
||||
if (!videoInstanceUpdated.VideoBlacklist || videoInstanceUpdated.VideoBlacklist.unfederated === false) {
|
||||
await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t)
|
||||
}
|
||||
|
||||
auditLogger.update(
|
||||
getAuditIdFromRes(res),
|
||||
|
@ -397,15 +404,17 @@ async function updateVideo (req: express.Request, res: express.Response) {
|
|||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function getVideo (req: express.Request, res: express.Response) {
|
||||
const videoInstance = res.locals.video
|
||||
async function getVideo (req: express.Request, res: express.Response) {
|
||||
// We need more attributes
|
||||
const userId: number = res.locals.oauth ? res.locals.oauth.token.User.id : null
|
||||
const video: VideoModel = await VideoModel.loadForGetAPI(res.locals.video.id, undefined, userId)
|
||||
|
||||
if (videoInstance.isOutdated()) {
|
||||
JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', videoUrl: videoInstance.url } })
|
||||
.catch(err => logger.error('Cannot create AP refresher job for video %s.', videoInstance.url, { err }))
|
||||
if (video.isOutdated()) {
|
||||
JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } })
|
||||
.catch(err => logger.error('Cannot create AP refresher job for video %s.', video.url, { err }))
|
||||
}
|
||||
|
||||
return res.json(videoInstance.toFormattedDetailsJSON())
|
||||
return res.json(video.toFormattedDetailsJSON())
|
||||
}
|
||||
|
||||
async function viewVideo (req: express.Request, res: express.Response) {
|
||||
|
@ -424,7 +433,7 @@ async function viewVideo (req: express.Request, res: express.Response) {
|
|||
])
|
||||
|
||||
const serverActor = await getServerActor()
|
||||
await sendCreateView(serverActor, videoInstance, undefined)
|
||||
await sendView(serverActor, videoInstance, undefined)
|
||||
|
||||
return res.status(204).end()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue