mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-05 02:39:33 +02:00
server/server -> server/core
This commit is contained in:
parent
114327d4ce
commit
5a3d0650c9
838 changed files with 111 additions and 111 deletions
33
server/core/controllers/api/server/contact.ts
Normal file
33
server/core/controllers/api/server/contact.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import express from 'express'
|
||||
import { ContactForm, HttpStatusCode } from '@peertube/peertube-models'
|
||||
import { logger } from '@server/helpers/logger.js'
|
||||
import { Emailer } from '../../../lib/emailer.js'
|
||||
import { Redis } from '../../../lib/redis.js'
|
||||
import { asyncMiddleware, contactAdministratorValidator } from '../../../middlewares/index.js'
|
||||
|
||||
const contactRouter = express.Router()
|
||||
|
||||
contactRouter.post('/contact',
|
||||
asyncMiddleware(contactAdministratorValidator),
|
||||
asyncMiddleware(contactAdministrator)
|
||||
)
|
||||
|
||||
async function contactAdministrator (req: express.Request, res: express.Response) {
|
||||
const data = req.body as ContactForm
|
||||
|
||||
Emailer.Instance.addContactFormJob(data.fromEmail, data.fromName, data.subject, data.body)
|
||||
|
||||
try {
|
||||
await Redis.Instance.setContactFormIp(req.ip)
|
||||
} catch (err) {
|
||||
logger.error(err)
|
||||
}
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
contactRouter
|
||||
}
|
54
server/core/controllers/api/server/debug.ts
Normal file
54
server/core/controllers/api/server/debug.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
import express from 'express'
|
||||
import { Debug, HttpStatusCode, SendDebugCommand, UserRight } from '@peertube/peertube-models'
|
||||
import { InboxManager } from '@server/lib/activitypub/inbox-manager.js'
|
||||
import { RemoveDanglingResumableUploadsScheduler } from '@server/lib/schedulers/remove-dangling-resumable-uploads-scheduler.js'
|
||||
import { UpdateVideosScheduler } from '@server/lib/schedulers/update-videos-scheduler.js'
|
||||
import { VideoChannelSyncLatestScheduler } from '@server/lib/schedulers/video-channel-sync-latest-scheduler.js'
|
||||
import { VideoViewsBufferScheduler } from '@server/lib/schedulers/video-views-buffer-scheduler.js'
|
||||
import { VideoViewsManager } from '@server/lib/views/video-views-manager.js'
|
||||
import { authenticate, ensureUserHasRight } from '../../../middlewares/index.js'
|
||||
|
||||
const debugRouter = express.Router()
|
||||
|
||||
debugRouter.get('/debug',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_DEBUG),
|
||||
getDebug
|
||||
)
|
||||
|
||||
debugRouter.post('/debug/run-command',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_DEBUG),
|
||||
runCommand
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
debugRouter
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function getDebug (req: express.Request, res: express.Response) {
|
||||
return res.json({
|
||||
ip: req.ip,
|
||||
activityPubMessagesWaiting: InboxManager.Instance.getActivityPubMessagesWaiting()
|
||||
} as Debug)
|
||||
}
|
||||
|
||||
async function runCommand (req: express.Request, res: express.Response) {
|
||||
const body: SendDebugCommand = req.body
|
||||
|
||||
const processors: { [id in SendDebugCommand['command']]: () => Promise<any> } = {
|
||||
'remove-dandling-resumable-uploads': () => RemoveDanglingResumableUploadsScheduler.Instance.execute(),
|
||||
'process-video-views-buffer': () => VideoViewsBufferScheduler.Instance.execute(),
|
||||
'process-video-viewers': () => VideoViewsManager.Instance.processViewerStats(),
|
||||
'process-update-videos-scheduler': () => UpdateVideosScheduler.Instance.execute(),
|
||||
'process-video-channel-sync-latest': () => VideoChannelSyncLatestScheduler.Instance.execute()
|
||||
}
|
||||
|
||||
await processors[body.command]()
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
212
server/core/controllers/api/server/follows.ts
Normal file
212
server/core/controllers/api/server/follows.ts
Normal file
|
@ -0,0 +1,212 @@
|
|||
import express from 'express'
|
||||
import { HttpStatusCode, ServerFollowCreate, UserRight } from '@peertube/peertube-models'
|
||||
import { getServerActor } from '@server/models/application/application.js'
|
||||
import { logger } from '../../../helpers/logger.js'
|
||||
import { getFormattedObjects } from '../../../helpers/utils.js'
|
||||
import { SERVER_ACTOR_NAME } from '../../../initializers/constants.js'
|
||||
import { sequelizeTypescript } from '../../../initializers/database.js'
|
||||
import { autoFollowBackIfNeeded } from '../../../lib/activitypub/follow.js'
|
||||
import { sendAccept, sendReject, sendUndoFollow } from '../../../lib/activitypub/send/index.js'
|
||||
import { JobQueue } from '../../../lib/job-queue/index.js'
|
||||
import { removeRedundanciesOfServer } from '../../../lib/redundancy.js'
|
||||
import {
|
||||
asyncMiddleware,
|
||||
authenticate,
|
||||
ensureUserHasRight,
|
||||
paginationValidator,
|
||||
setBodyHostsPort,
|
||||
setDefaultPagination,
|
||||
setDefaultSort
|
||||
} from '../../../middlewares/index.js'
|
||||
import {
|
||||
acceptFollowerValidator,
|
||||
followValidator,
|
||||
getFollowerValidator,
|
||||
instanceFollowersSortValidator,
|
||||
instanceFollowingSortValidator,
|
||||
listFollowsValidator,
|
||||
rejectFollowerValidator,
|
||||
removeFollowingValidator
|
||||
} from '../../../middlewares/validators/index.js'
|
||||
import { ActorFollowModel } from '../../../models/actor/actor-follow.js'
|
||||
|
||||
const serverFollowsRouter = express.Router()
|
||||
serverFollowsRouter.get('/following',
|
||||
listFollowsValidator,
|
||||
paginationValidator,
|
||||
instanceFollowingSortValidator,
|
||||
setDefaultSort,
|
||||
setDefaultPagination,
|
||||
asyncMiddleware(listFollowing)
|
||||
)
|
||||
|
||||
serverFollowsRouter.post('/following',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
|
||||
followValidator,
|
||||
setBodyHostsPort,
|
||||
asyncMiddleware(addFollow)
|
||||
)
|
||||
|
||||
serverFollowsRouter.delete('/following/:hostOrHandle',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
|
||||
asyncMiddleware(removeFollowingValidator),
|
||||
asyncMiddleware(removeFollowing)
|
||||
)
|
||||
|
||||
serverFollowsRouter.get('/followers',
|
||||
listFollowsValidator,
|
||||
paginationValidator,
|
||||
instanceFollowersSortValidator,
|
||||
setDefaultSort,
|
||||
setDefaultPagination,
|
||||
asyncMiddleware(listFollowers)
|
||||
)
|
||||
|
||||
serverFollowsRouter.delete('/followers/:nameWithHost',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
|
||||
asyncMiddleware(getFollowerValidator),
|
||||
asyncMiddleware(removeFollower)
|
||||
)
|
||||
|
||||
serverFollowsRouter.post('/followers/:nameWithHost/reject',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
|
||||
asyncMiddleware(getFollowerValidator),
|
||||
rejectFollowerValidator,
|
||||
asyncMiddleware(rejectFollower)
|
||||
)
|
||||
|
||||
serverFollowsRouter.post('/followers/:nameWithHost/accept',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
|
||||
asyncMiddleware(getFollowerValidator),
|
||||
acceptFollowerValidator,
|
||||
asyncMiddleware(acceptFollower)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
serverFollowsRouter
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function listFollowing (req: express.Request, res: express.Response) {
|
||||
const serverActor = await getServerActor()
|
||||
const resultList = await ActorFollowModel.listInstanceFollowingForApi({
|
||||
followerId: serverActor.id,
|
||||
start: req.query.start,
|
||||
count: req.query.count,
|
||||
sort: req.query.sort,
|
||||
search: req.query.search,
|
||||
actorType: req.query.actorType,
|
||||
state: req.query.state
|
||||
})
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
async function listFollowers (req: express.Request, res: express.Response) {
|
||||
const serverActor = await getServerActor()
|
||||
const resultList = await ActorFollowModel.listFollowersForApi({
|
||||
actorIds: [ serverActor.id ],
|
||||
start: req.query.start,
|
||||
count: req.query.count,
|
||||
sort: req.query.sort,
|
||||
search: req.query.search,
|
||||
actorType: req.query.actorType,
|
||||
state: req.query.state
|
||||
})
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
async function addFollow (req: express.Request, res: express.Response) {
|
||||
const { hosts, handles } = req.body as ServerFollowCreate
|
||||
const follower = await getServerActor()
|
||||
|
||||
for (const host of hosts) {
|
||||
const payload = {
|
||||
host,
|
||||
name: SERVER_ACTOR_NAME,
|
||||
followerActorId: follower.id
|
||||
}
|
||||
|
||||
JobQueue.Instance.createJobAsync({ type: 'activitypub-follow', payload })
|
||||
}
|
||||
|
||||
for (const handle of handles) {
|
||||
const [ name, host ] = handle.split('@')
|
||||
|
||||
const payload = {
|
||||
host,
|
||||
name,
|
||||
followerActorId: follower.id
|
||||
}
|
||||
|
||||
JobQueue.Instance.createJobAsync({ type: 'activitypub-follow', payload })
|
||||
}
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
||||
|
||||
async function removeFollowing (req: express.Request, res: express.Response) {
|
||||
const follow = res.locals.follow
|
||||
|
||||
await sequelizeTypescript.transaction(async t => {
|
||||
if (follow.state === 'accepted') sendUndoFollow(follow, t)
|
||||
|
||||
// Disable redundancy on unfollowed instances
|
||||
const server = follow.ActorFollowing.Server
|
||||
server.redundancyAllowed = false
|
||||
await server.save({ transaction: t })
|
||||
|
||||
// Async, could be long
|
||||
removeRedundanciesOfServer(server.id)
|
||||
.catch(err => logger.error('Cannot remove redundancy of %s.', server.host, { err }))
|
||||
|
||||
await follow.destroy({ transaction: t })
|
||||
})
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
||||
|
||||
async function rejectFollower (req: express.Request, res: express.Response) {
|
||||
const follow = res.locals.follow
|
||||
|
||||
follow.state = 'rejected'
|
||||
await follow.save()
|
||||
|
||||
sendReject(follow.url, follow.ActorFollower, follow.ActorFollowing)
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
||||
|
||||
async function removeFollower (req: express.Request, res: express.Response) {
|
||||
const follow = res.locals.follow
|
||||
|
||||
if (follow.state === 'accepted' || follow.state === 'pending') {
|
||||
sendReject(follow.url, follow.ActorFollower, follow.ActorFollowing)
|
||||
}
|
||||
|
||||
await follow.destroy()
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
||||
|
||||
async function acceptFollower (req: express.Request, res: express.Response) {
|
||||
const follow = res.locals.follow
|
||||
|
||||
sendAccept(follow)
|
||||
|
||||
follow.state = 'accepted'
|
||||
await follow.save()
|
||||
|
||||
await autoFollowBackIfNeeded(follow)
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
27
server/core/controllers/api/server/index.ts
Normal file
27
server/core/controllers/api/server/index.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import express from 'express'
|
||||
import { apiRateLimiter } from '@server/middlewares/index.js'
|
||||
import { contactRouter } from './contact.js'
|
||||
import { debugRouter } from './debug.js'
|
||||
import { serverFollowsRouter } from './follows.js'
|
||||
import { logsRouter } from './logs.js'
|
||||
import { serverRedundancyRouter } from './redundancy.js'
|
||||
import { serverBlocklistRouter } from './server-blocklist.js'
|
||||
import { statsRouter } from './stats.js'
|
||||
|
||||
const serverRouter = express.Router()
|
||||
|
||||
serverRouter.use(apiRateLimiter)
|
||||
|
||||
serverRouter.use('/', serverFollowsRouter)
|
||||
serverRouter.use('/', serverRedundancyRouter)
|
||||
serverRouter.use('/', statsRouter)
|
||||
serverRouter.use('/', serverBlocklistRouter)
|
||||
serverRouter.use('/', contactRouter)
|
||||
serverRouter.use('/', logsRouter)
|
||||
serverRouter.use('/', debugRouter)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
serverRouter
|
||||
}
|
201
server/core/controllers/api/server/logs.ts
Normal file
201
server/core/controllers/api/server/logs.ts
Normal file
|
@ -0,0 +1,201 @@
|
|||
import express from 'express'
|
||||
import { readdir, readFile } from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
import { pick } from '@peertube/peertube-core-utils'
|
||||
import { ClientLogCreate, HttpStatusCode, ServerLogLevel, UserRight } from '@peertube/peertube-models'
|
||||
import { isArray } from '@server/helpers/custom-validators/misc.js'
|
||||
import { logger, mtimeSortFilesDesc } from '@server/helpers/logger.js'
|
||||
import { CONFIG } from '../../../initializers/config.js'
|
||||
import { AUDIT_LOG_FILENAME, LOG_FILENAME, MAX_LOGS_OUTPUT_CHARACTERS } from '../../../initializers/constants.js'
|
||||
import { asyncMiddleware, authenticate, buildRateLimiter, ensureUserHasRight, optionalAuthenticate } from '../../../middlewares/index.js'
|
||||
import { createClientLogValidator, getAuditLogsValidator, getLogsValidator } from '../../../middlewares/validators/logs.js'
|
||||
|
||||
const createClientLogRateLimiter = buildRateLimiter({
|
||||
windowMs: CONFIG.RATES_LIMIT.RECEIVE_CLIENT_LOG.WINDOW_MS,
|
||||
max: CONFIG.RATES_LIMIT.RECEIVE_CLIENT_LOG.MAX
|
||||
})
|
||||
|
||||
const logsRouter = express.Router()
|
||||
|
||||
logsRouter.post('/logs/client',
|
||||
createClientLogRateLimiter,
|
||||
optionalAuthenticate,
|
||||
createClientLogValidator,
|
||||
createClientLog
|
||||
)
|
||||
|
||||
logsRouter.get('/logs',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_LOGS),
|
||||
getLogsValidator,
|
||||
asyncMiddleware(getLogs)
|
||||
)
|
||||
|
||||
logsRouter.get('/audit-logs',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_LOGS),
|
||||
getAuditLogsValidator,
|
||||
asyncMiddleware(getAuditLogs)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
logsRouter
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function createClientLog (req: express.Request, res: express.Response) {
|
||||
const logInfo = req.body as ClientLogCreate
|
||||
|
||||
const meta = {
|
||||
tags: [ 'client' ],
|
||||
username: res.locals.oauth?.token?.User?.username,
|
||||
|
||||
...pick(logInfo, [ 'userAgent', 'stackTrace', 'meta', 'url' ])
|
||||
}
|
||||
|
||||
logger.log(logInfo.level, `Client log: ${logInfo.message}`, meta)
|
||||
|
||||
return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
|
||||
}
|
||||
|
||||
const auditLogNameFilter = generateLogNameFilter(AUDIT_LOG_FILENAME)
|
||||
async function getAuditLogs (req: express.Request, res: express.Response) {
|
||||
const output = await generateOutput({
|
||||
startDateQuery: req.query.startDate,
|
||||
endDateQuery: req.query.endDate,
|
||||
level: 'audit',
|
||||
nameFilter: auditLogNameFilter
|
||||
})
|
||||
|
||||
return res.json(output).end()
|
||||
}
|
||||
|
||||
const logNameFilter = generateLogNameFilter(LOG_FILENAME)
|
||||
async function getLogs (req: express.Request, res: express.Response) {
|
||||
const output = await generateOutput({
|
||||
startDateQuery: req.query.startDate,
|
||||
endDateQuery: req.query.endDate,
|
||||
level: req.query.level || 'info',
|
||||
tagsOneOf: req.query.tagsOneOf,
|
||||
nameFilter: logNameFilter
|
||||
})
|
||||
|
||||
return res.json(output)
|
||||
}
|
||||
|
||||
async function generateOutput (options: {
|
||||
startDateQuery: string
|
||||
endDateQuery?: string
|
||||
|
||||
level: ServerLogLevel
|
||||
nameFilter: RegExp
|
||||
tagsOneOf?: string[]
|
||||
}) {
|
||||
const { startDateQuery, level, nameFilter } = options
|
||||
|
||||
const tagsOneOf = Array.isArray(options.tagsOneOf) && options.tagsOneOf.length !== 0
|
||||
? new Set(options.tagsOneOf)
|
||||
: undefined
|
||||
|
||||
const logFiles = await readdir(CONFIG.STORAGE.LOG_DIR)
|
||||
const sortedLogFiles = await mtimeSortFilesDesc(logFiles, CONFIG.STORAGE.LOG_DIR)
|
||||
let currentSize = 0
|
||||
|
||||
const startDate = new Date(startDateQuery)
|
||||
const endDate = options.endDateQuery ? new Date(options.endDateQuery) : new Date()
|
||||
|
||||
let output: string[] = []
|
||||
|
||||
for (const meta of sortedLogFiles) {
|
||||
if (nameFilter.exec(meta.file) === null) continue
|
||||
|
||||
const path = join(CONFIG.STORAGE.LOG_DIR, meta.file)
|
||||
logger.debug('Opening %s to fetch logs.', path)
|
||||
|
||||
const result = await getOutputFromFile({ path, startDate, endDate, level, currentSize, tagsOneOf })
|
||||
if (!result.output) break
|
||||
|
||||
output = result.output.concat(output)
|
||||
currentSize = result.currentSize
|
||||
|
||||
if (currentSize > MAX_LOGS_OUTPUT_CHARACTERS || (result.logTime && result.logTime < startDate.getTime())) break
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
async function getOutputFromFile (options: {
|
||||
path: string
|
||||
startDate: Date
|
||||
endDate: Date
|
||||
level: ServerLogLevel
|
||||
currentSize: number
|
||||
tagsOneOf: Set<string>
|
||||
}) {
|
||||
const { path, startDate, endDate, level, tagsOneOf } = options
|
||||
|
||||
const startTime = startDate.getTime()
|
||||
const endTime = endDate.getTime()
|
||||
let currentSize = options.currentSize
|
||||
|
||||
let logTime: number
|
||||
|
||||
const logsLevel: { [ id in ServerLogLevel ]: number } = {
|
||||
audit: -1,
|
||||
debug: 0,
|
||||
info: 1,
|
||||
warn: 2,
|
||||
error: 3
|
||||
}
|
||||
|
||||
const content = await readFile(path)
|
||||
const lines = content.toString().split('\n')
|
||||
const output: any[] = []
|
||||
|
||||
for (let i = lines.length - 1; i >= 0; i--) {
|
||||
const line = lines[i]
|
||||
let log: any
|
||||
|
||||
try {
|
||||
log = JSON.parse(line)
|
||||
} catch {
|
||||
// Maybe there a multiple \n at the end of the file
|
||||
continue
|
||||
}
|
||||
|
||||
logTime = new Date(log.timestamp).getTime()
|
||||
if (
|
||||
logTime >= startTime &&
|
||||
logTime <= endTime &&
|
||||
logsLevel[log.level] >= logsLevel[level] &&
|
||||
(!tagsOneOf || lineHasTag(log, tagsOneOf))
|
||||
) {
|
||||
output.push(log)
|
||||
|
||||
currentSize += line.length
|
||||
|
||||
if (currentSize > MAX_LOGS_OUTPUT_CHARACTERS) break
|
||||
} else if (logTime < startTime) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return { currentSize, output: output.reverse(), logTime }
|
||||
}
|
||||
|
||||
function lineHasTag (line: { tags?: string }, tagsOneOf: Set<string>) {
|
||||
if (!isArray(line.tags)) return false
|
||||
|
||||
for (const lineTag of line.tags) {
|
||||
if (tagsOneOf.has(lineTag)) return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
function generateLogNameFilter (baseName: string) {
|
||||
return new RegExp('^' + baseName.replace(/\.log$/, '') + '\\d*.log$')
|
||||
}
|
115
server/core/controllers/api/server/redundancy.ts
Normal file
115
server/core/controllers/api/server/redundancy.ts
Normal file
|
@ -0,0 +1,115 @@
|
|||
import express from 'express'
|
||||
import { HttpStatusCode, UserRight } from '@peertube/peertube-models'
|
||||
import { JobQueue } from '@server/lib/job-queue/index.js'
|
||||
import { VideoRedundancyModel } from '@server/models/redundancy/video-redundancy.js'
|
||||
import { logger } from '../../../helpers/logger.js'
|
||||
import { removeRedundanciesOfServer, removeVideoRedundancy } from '../../../lib/redundancy.js'
|
||||
import {
|
||||
asyncMiddleware,
|
||||
authenticate,
|
||||
ensureUserHasRight,
|
||||
paginationValidator,
|
||||
setDefaultPagination,
|
||||
setDefaultVideoRedundanciesSort,
|
||||
videoRedundanciesSortValidator
|
||||
} from '../../../middlewares/index.js'
|
||||
import {
|
||||
addVideoRedundancyValidator,
|
||||
listVideoRedundanciesValidator,
|
||||
removeVideoRedundancyValidator,
|
||||
updateServerRedundancyValidator
|
||||
} from '../../../middlewares/validators/redundancy.js'
|
||||
|
||||
const serverRedundancyRouter = express.Router()
|
||||
|
||||
serverRedundancyRouter.put('/redundancy/:host',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
|
||||
asyncMiddleware(updateServerRedundancyValidator),
|
||||
asyncMiddleware(updateRedundancy)
|
||||
)
|
||||
|
||||
serverRedundancyRouter.get('/redundancy/videos',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_VIDEOS_REDUNDANCIES),
|
||||
listVideoRedundanciesValidator,
|
||||
paginationValidator,
|
||||
videoRedundanciesSortValidator,
|
||||
setDefaultVideoRedundanciesSort,
|
||||
setDefaultPagination,
|
||||
asyncMiddleware(listVideoRedundancies)
|
||||
)
|
||||
|
||||
serverRedundancyRouter.post('/redundancy/videos',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_VIDEOS_REDUNDANCIES),
|
||||
addVideoRedundancyValidator,
|
||||
asyncMiddleware(addVideoRedundancy)
|
||||
)
|
||||
|
||||
serverRedundancyRouter.delete('/redundancy/videos/:redundancyId',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_VIDEOS_REDUNDANCIES),
|
||||
removeVideoRedundancyValidator,
|
||||
asyncMiddleware(removeVideoRedundancyController)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
serverRedundancyRouter
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function listVideoRedundancies (req: express.Request, res: express.Response) {
|
||||
const resultList = await VideoRedundancyModel.listForApi({
|
||||
start: req.query.start,
|
||||
count: req.query.count,
|
||||
sort: req.query.sort,
|
||||
target: req.query.target,
|
||||
strategy: req.query.strategy
|
||||
})
|
||||
|
||||
const result = {
|
||||
total: resultList.total,
|
||||
data: resultList.data.map(r => VideoRedundancyModel.toFormattedJSONStatic(r))
|
||||
}
|
||||
|
||||
return res.json(result)
|
||||
}
|
||||
|
||||
async function addVideoRedundancy (req: express.Request, res: express.Response) {
|
||||
const payload = {
|
||||
videoId: res.locals.onlyVideo.id
|
||||
}
|
||||
|
||||
await JobQueue.Instance.createJob({
|
||||
type: 'video-redundancy',
|
||||
payload
|
||||
})
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
||||
|
||||
async function removeVideoRedundancyController (req: express.Request, res: express.Response) {
|
||||
await removeVideoRedundancy(res.locals.videoRedundancy)
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
||||
|
||||
async function updateRedundancy (req: express.Request, res: express.Response) {
|
||||
const server = res.locals.server
|
||||
|
||||
server.redundancyAllowed = req.body.redundancyAllowed
|
||||
|
||||
await server.save()
|
||||
|
||||
if (server.redundancyAllowed !== true) {
|
||||
// Async, could be long
|
||||
removeRedundanciesOfServer(server.id)
|
||||
.catch(err => logger.error('Cannot remove redundancy of %s.', server.host, { err }))
|
||||
}
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
162
server/core/controllers/api/server/server-blocklist.ts
Normal file
162
server/core/controllers/api/server/server-blocklist.ts
Normal file
|
@ -0,0 +1,162 @@
|
|||
import 'multer'
|
||||
import express from 'express'
|
||||
import { HttpStatusCode, UserRight } from '@peertube/peertube-models'
|
||||
import { logger } from '@server/helpers/logger.js'
|
||||
import { getServerActor } from '@server/models/application/application.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { getFormattedObjects } from '../../../helpers/utils.js'
|
||||
import {
|
||||
addAccountInBlocklist,
|
||||
addServerInBlocklist,
|
||||
removeAccountFromBlocklist,
|
||||
removeServerFromBlocklist
|
||||
} from '../../../lib/blocklist.js'
|
||||
import {
|
||||
asyncMiddleware,
|
||||
asyncRetryTransactionMiddleware,
|
||||
authenticate,
|
||||
ensureUserHasRight,
|
||||
paginationValidator,
|
||||
setDefaultPagination,
|
||||
setDefaultSort
|
||||
} from '../../../middlewares/index.js'
|
||||
import {
|
||||
accountsBlocklistSortValidator,
|
||||
blockAccountValidator,
|
||||
blockServerValidator,
|
||||
serversBlocklistSortValidator,
|
||||
unblockAccountByServerValidator,
|
||||
unblockServerByServerValidator
|
||||
} from '../../../middlewares/validators/index.js'
|
||||
import { AccountBlocklistModel } from '../../../models/account/account-blocklist.js'
|
||||
import { ServerBlocklistModel } from '../../../models/server/server-blocklist.js'
|
||||
|
||||
const serverBlocklistRouter = express.Router()
|
||||
|
||||
serverBlocklistRouter.get('/blocklist/accounts',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_ACCOUNTS_BLOCKLIST),
|
||||
paginationValidator,
|
||||
accountsBlocklistSortValidator,
|
||||
setDefaultSort,
|
||||
setDefaultPagination,
|
||||
asyncMiddleware(listBlockedAccounts)
|
||||
)
|
||||
|
||||
serverBlocklistRouter.post('/blocklist/accounts',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_ACCOUNTS_BLOCKLIST),
|
||||
asyncMiddleware(blockAccountValidator),
|
||||
asyncRetryTransactionMiddleware(blockAccount)
|
||||
)
|
||||
|
||||
serverBlocklistRouter.delete('/blocklist/accounts/:accountName',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_ACCOUNTS_BLOCKLIST),
|
||||
asyncMiddleware(unblockAccountByServerValidator),
|
||||
asyncRetryTransactionMiddleware(unblockAccount)
|
||||
)
|
||||
|
||||
serverBlocklistRouter.get('/blocklist/servers',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_SERVERS_BLOCKLIST),
|
||||
paginationValidator,
|
||||
serversBlocklistSortValidator,
|
||||
setDefaultSort,
|
||||
setDefaultPagination,
|
||||
asyncMiddleware(listBlockedServers)
|
||||
)
|
||||
|
||||
serverBlocklistRouter.post('/blocklist/servers',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_SERVERS_BLOCKLIST),
|
||||
asyncMiddleware(blockServerValidator),
|
||||
asyncRetryTransactionMiddleware(blockServer)
|
||||
)
|
||||
|
||||
serverBlocklistRouter.delete('/blocklist/servers/:host',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_SERVERS_BLOCKLIST),
|
||||
asyncMiddleware(unblockServerByServerValidator),
|
||||
asyncRetryTransactionMiddleware(unblockServer)
|
||||
)
|
||||
|
||||
export {
|
||||
serverBlocklistRouter
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function listBlockedAccounts (req: express.Request, res: express.Response) {
|
||||
const serverActor = await getServerActor()
|
||||
|
||||
const resultList = await AccountBlocklistModel.listForApi({
|
||||
start: req.query.start,
|
||||
count: req.query.count,
|
||||
sort: req.query.sort,
|
||||
search: req.query.search,
|
||||
accountId: serverActor.Account.id
|
||||
})
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
async function blockAccount (req: express.Request, res: express.Response) {
|
||||
const serverActor = await getServerActor()
|
||||
const accountToBlock = res.locals.account
|
||||
|
||||
await addAccountInBlocklist(serverActor.Account.id, accountToBlock.id)
|
||||
|
||||
UserNotificationModel.removeNotificationsOf({
|
||||
id: accountToBlock.id,
|
||||
type: 'account',
|
||||
forUserId: null // For all users
|
||||
}).catch(err => logger.error('Cannot remove notifications after an account mute.', { err }))
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
||||
|
||||
async function unblockAccount (req: express.Request, res: express.Response) {
|
||||
const accountBlock = res.locals.accountBlock
|
||||
|
||||
await removeAccountFromBlocklist(accountBlock)
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
||||
|
||||
async function listBlockedServers (req: express.Request, res: express.Response) {
|
||||
const serverActor = await getServerActor()
|
||||
|
||||
const resultList = await ServerBlocklistModel.listForApi({
|
||||
start: req.query.start,
|
||||
count: req.query.count,
|
||||
sort: req.query.sort,
|
||||
search: req.query.search,
|
||||
accountId: serverActor.Account.id
|
||||
})
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
async function blockServer (req: express.Request, res: express.Response) {
|
||||
const serverActor = await getServerActor()
|
||||
const serverToBlock = res.locals.server
|
||||
|
||||
await addServerInBlocklist(serverActor.Account.id, serverToBlock.id)
|
||||
|
||||
UserNotificationModel.removeNotificationsOf({
|
||||
id: serverToBlock.id,
|
||||
type: 'server',
|
||||
forUserId: null // For all users
|
||||
}).catch(err => logger.error('Cannot remove notifications after a server mute.', { err }))
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
||||
|
||||
async function unblockServer (req: express.Request, res: express.Response) {
|
||||
const serverBlock = res.locals.serverBlock
|
||||
|
||||
await removeServerFromBlocklist(serverBlock)
|
||||
|
||||
return res.status(HttpStatusCode.NO_CONTENT_204).end()
|
||||
}
|
26
server/core/controllers/api/server/stats.ts
Normal file
26
server/core/controllers/api/server/stats.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import express from 'express'
|
||||
import { StatsManager } from '@server/lib/stat-manager.js'
|
||||
import { ROUTE_CACHE_LIFETIME } from '../../../initializers/constants.js'
|
||||
import { asyncMiddleware } from '../../../middlewares/index.js'
|
||||
import { cacheRoute } from '../../../middlewares/cache/cache.js'
|
||||
import { Hooks } from '@server/lib/plugins/hooks.js'
|
||||
|
||||
const statsRouter = express.Router()
|
||||
|
||||
statsRouter.get('/stats',
|
||||
cacheRoute(ROUTE_CACHE_LIFETIME.STATS),
|
||||
asyncMiddleware(getStats)
|
||||
)
|
||||
|
||||
async function getStats (_req: express.Request, res: express.Response) {
|
||||
let data = await StatsManager.Instance.getStats()
|
||||
data = await Hooks.wrapObject(data, 'filter:api.server.stats.get.result')
|
||||
|
||||
return res.json(data)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
statsRouter
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue