mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-02-25 18:55:32 -06:00
Filter host for channels and playlists search
This commit is contained in:
@@ -52,6 +52,7 @@ export enum ScopeNames {
|
||||
export type SummaryOptions = {
|
||||
actorRequired?: boolean // Default: true
|
||||
whereActor?: WhereOptions
|
||||
whereServer?: WhereOptions
|
||||
withAccountBlockerIds?: number[]
|
||||
}
|
||||
|
||||
@@ -65,12 +66,11 @@ export type SummaryOptions = {
|
||||
}))
|
||||
@Scopes(() => ({
|
||||
[ScopeNames.SUMMARY]: (options: SummaryOptions = {}) => {
|
||||
const whereActor = options.whereActor || undefined
|
||||
|
||||
const serverInclude: IncludeOptions = {
|
||||
attributes: [ 'host' ],
|
||||
model: ServerModel.unscoped(),
|
||||
required: false
|
||||
required: !!options.whereServer,
|
||||
where: options.whereServer
|
||||
}
|
||||
|
||||
const queryInclude: Includeable[] = [
|
||||
@@ -78,7 +78,7 @@ export type SummaryOptions = {
|
||||
attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
|
||||
model: ActorModel.unscoped(),
|
||||
required: options.actorRequired ?? true,
|
||||
where: whereActor,
|
||||
where: options.whereActor,
|
||||
include: [
|
||||
serverInclude,
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript'
|
||||
import { isActivityPubUrlValid } from '@server/helpers/custom-validators/activitypub/misc'
|
||||
import { doesExist } from '@server/helpers/database-utils'
|
||||
import { getServerActor } from '@server/models/application/application'
|
||||
import {
|
||||
MActorFollowActorsDefault,
|
||||
@@ -36,6 +35,7 @@ import { logger } from '../../helpers/logger'
|
||||
import { ACTOR_FOLLOW_SCORE, CONSTRAINTS_FIELDS, FOLLOW_STATES, SERVER_ACTOR_NAME } from '../../initializers/constants'
|
||||
import { AccountModel } from '../account/account'
|
||||
import { ServerModel } from '../server/server'
|
||||
import { doesExist } from '../shared/query'
|
||||
import { createSafeIn, getFollowsSort, getSort, searchAttribute, throwIfNotValid } from '../utils'
|
||||
import { VideoChannelModel } from '../video/video-channel'
|
||||
import { ActorModel, unusedActorAttributesForAPI } from './actor'
|
||||
|
||||
2
server/models/shared/index.ts
Normal file
2
server/models/shared/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './query'
|
||||
export * from './update'
|
||||
17
server/models/shared/query.ts
Normal file
17
server/models/shared/query.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { BindOrReplacements, QueryTypes } from 'sequelize'
|
||||
import { sequelizeTypescript } from '@server/initializers/database'
|
||||
|
||||
function doesExist (query: string, bind?: BindOrReplacements) {
|
||||
const options = {
|
||||
type: QueryTypes.SELECT as QueryTypes.SELECT,
|
||||
bind,
|
||||
raw: true
|
||||
}
|
||||
|
||||
return sequelizeTypescript.query(query, options)
|
||||
.then(results => results.length === 1)
|
||||
}
|
||||
|
||||
export {
|
||||
doesExist
|
||||
}
|
||||
18
server/models/shared/update.ts
Normal file
18
server/models/shared/update.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { QueryTypes, Transaction } from 'sequelize'
|
||||
import { sequelizeTypescript } from '@server/initializers/database'
|
||||
|
||||
// Sequelize always skip the update if we only update updatedAt field
|
||||
function setAsUpdated (table: string, id: number, transaction?: Transaction) {
|
||||
return sequelizeTypescript.query(
|
||||
`UPDATE "${table}" SET "updatedAt" = :updatedAt WHERE id = :id`,
|
||||
{
|
||||
replacements: { table, id, updatedAt: new Date() },
|
||||
type: QueryTypes.UPDATE,
|
||||
transaction
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
setAsUpdated
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FindOptions, Includeable, literal, Op, QueryTypes, ScopeOptions, Transaction } from 'sequelize'
|
||||
import { FindOptions, Includeable, literal, Op, QueryTypes, ScopeOptions, Transaction, WhereOptions } from 'sequelize'
|
||||
import {
|
||||
AllowNull,
|
||||
BeforeDestroy,
|
||||
@@ -17,7 +17,6 @@ import {
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript'
|
||||
import { setAsUpdated } from '@server/helpers/database-utils'
|
||||
import { MAccountActor } from '@server/types/models'
|
||||
import { AttributesOnly } from '@shared/core-utils'
|
||||
import { ActivityPubActor } from '../../../shared/models/activitypub'
|
||||
@@ -41,6 +40,7 @@ import { ActorModel, unusedActorAttributesForAPI } from '../actor/actor'
|
||||
import { ActorFollowModel } from '../actor/actor-follow'
|
||||
import { ActorImageModel } from '../actor/actor-image'
|
||||
import { ServerModel } from '../server/server'
|
||||
import { setAsUpdated } from '../shared'
|
||||
import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttribute, getSort, throwIfNotValid } from '../utils'
|
||||
import { VideoModel } from './video'
|
||||
import { VideoPlaylistModel } from './video-playlist'
|
||||
@@ -58,6 +58,7 @@ export enum ScopeNames {
|
||||
type AvailableForListOptions = {
|
||||
actorId: number
|
||||
search?: string
|
||||
host?: string
|
||||
}
|
||||
|
||||
type AvailableWithStatsOptions = {
|
||||
@@ -83,6 +84,33 @@ export type SummaryOptions = {
|
||||
// Only list local channels OR channels that are on an instance followed by actorId
|
||||
const inQueryInstanceFollow = buildServerIdsFollowedBy(options.actorId)
|
||||
|
||||
const whereActor = {
|
||||
[Op.or]: [
|
||||
{
|
||||
serverId: null
|
||||
},
|
||||
{
|
||||
serverId: {
|
||||
[Op.in]: Sequelize.literal(inQueryInstanceFollow)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
let serverRequired = false
|
||||
let whereServer: WhereOptions
|
||||
|
||||
if (options.host && options.host !== WEBSERVER.HOST) {
|
||||
serverRequired = true
|
||||
whereServer = { host: options.host }
|
||||
}
|
||||
|
||||
if (options.host === WEBSERVER.HOST) {
|
||||
Object.assign(whereActor, {
|
||||
[Op.and]: [ { serverId: null } ]
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
include: [
|
||||
{
|
||||
@@ -90,19 +118,18 @@ export type SummaryOptions = {
|
||||
exclude: unusedActorAttributesForAPI
|
||||
},
|
||||
model: ActorModel,
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{
|
||||
serverId: null
|
||||
},
|
||||
{
|
||||
serverId: {
|
||||
[Op.in]: Sequelize.literal(inQueryInstanceFollow)
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
where: whereActor,
|
||||
include: [
|
||||
{
|
||||
model: ServerModel,
|
||||
required: serverRequired,
|
||||
where: whereServer
|
||||
},
|
||||
{
|
||||
model: ActorImageModel,
|
||||
as: 'Avatar',
|
||||
required: false
|
||||
},
|
||||
{
|
||||
model: ActorImageModel,
|
||||
as: 'Banner',
|
||||
@@ -431,6 +458,8 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
|
||||
start: number
|
||||
count: number
|
||||
sort: string
|
||||
|
||||
host?: string
|
||||
}) {
|
||||
const attributesInclude = []
|
||||
const escapedSearch = VideoChannelModel.sequelize.escape(options.search)
|
||||
@@ -458,7 +487,7 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
|
||||
|
||||
return VideoChannelModel
|
||||
.scope({
|
||||
method: [ ScopeNames.FOR_API, { actorId: options.actorId } as AvailableForListOptions ]
|
||||
method: [ ScopeNames.FOR_API, { actorId: options.actorId, host: options.host } as AvailableForListOptions ]
|
||||
})
|
||||
.findAndCountAll(query)
|
||||
.then(({ rows, count }) => {
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
import { Where } from 'sequelize/types/lib/utils'
|
||||
import validator from 'validator'
|
||||
import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub'
|
||||
import { doesExist } from '@server/helpers/database-utils'
|
||||
import { logger } from '@server/helpers/logger'
|
||||
import { extractVideo } from '@server/helpers/video'
|
||||
import { getTorrentFilePath } from '@server/lib/video-paths'
|
||||
@@ -45,6 +44,7 @@ import {
|
||||
} from '../../initializers/constants'
|
||||
import { MVideoFile, MVideoFileStreamingPlaylistVideo, MVideoFileVideo } from '../../types/models/video/video-file'
|
||||
import { VideoRedundancyModel } from '../redundancy/video-redundancy'
|
||||
import { doesExist } from '../shared'
|
||||
import { parseAggregateResult, throwIfNotValid } from '../utils'
|
||||
import { VideoModel } from './video'
|
||||
import { VideoStreamingPlaylistModel } from './video-streaming-playlist'
|
||||
|
||||
@@ -17,7 +17,6 @@ import {
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript'
|
||||
import { setAsUpdated } from '@server/helpers/database-utils'
|
||||
import { buildUUID, uuidToShort } from '@server/helpers/uuid'
|
||||
import { MAccountId, MChannelId } from '@server/types/models'
|
||||
import { AttributesOnly, buildPlaylistEmbedPath, buildPlaylistWatchPath } from '@shared/core-utils'
|
||||
@@ -53,6 +52,7 @@ import {
|
||||
} from '../../types/models/video/video-playlist'
|
||||
import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions } from '../account/account'
|
||||
import { ActorModel } from '../actor/actor'
|
||||
import { setAsUpdated } from '../shared'
|
||||
import {
|
||||
buildServerIdsFollowedBy,
|
||||
buildTrigramSearchIndex,
|
||||
@@ -82,6 +82,7 @@ type AvailableForListOptions = {
|
||||
videoChannelId?: number
|
||||
listMyPlaylists?: boolean
|
||||
search?: string
|
||||
host?: string
|
||||
withVideos?: boolean
|
||||
}
|
||||
|
||||
@@ -141,9 +142,19 @@ function getVideoLengthSelect () {
|
||||
]
|
||||
},
|
||||
[ScopeNames.AVAILABLE_FOR_LIST]: (options: AvailableForListOptions) => {
|
||||
const whereAnd: WhereOptions[] = []
|
||||
|
||||
const whereServer = options.host && options.host !== WEBSERVER.HOST
|
||||
? { host: options.host }
|
||||
: undefined
|
||||
|
||||
let whereActor: WhereOptions = {}
|
||||
|
||||
const whereAnd: WhereOptions[] = []
|
||||
if (options.host === WEBSERVER.HOST) {
|
||||
whereActor = {
|
||||
[Op.and]: [ { serverId: null } ]
|
||||
}
|
||||
}
|
||||
|
||||
if (options.listMyPlaylists !== true) {
|
||||
whereAnd.push({
|
||||
@@ -168,9 +179,7 @@ function getVideoLengthSelect () {
|
||||
})
|
||||
}
|
||||
|
||||
whereActor = {
|
||||
[Op.or]: whereActorOr
|
||||
}
|
||||
Object.assign(whereActor, { [Op.or]: whereActorOr })
|
||||
}
|
||||
|
||||
if (options.accountId) {
|
||||
@@ -228,7 +237,7 @@ function getVideoLengthSelect () {
|
||||
include: [
|
||||
{
|
||||
model: AccountModel.scope({
|
||||
method: [ AccountScopeNames.SUMMARY, { whereActor } as SummaryOptions ]
|
||||
method: [ AccountScopeNames.SUMMARY, { whereActor, whereServer } as SummaryOptions ]
|
||||
}),
|
||||
required: true
|
||||
},
|
||||
@@ -349,6 +358,7 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
|
||||
videoChannelId?: number
|
||||
listMyPlaylists?: boolean
|
||||
search?: string
|
||||
host?: string
|
||||
withVideos?: boolean // false by default
|
||||
}) {
|
||||
const query = {
|
||||
@@ -368,6 +378,7 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
|
||||
videoChannelId: options.videoChannelId,
|
||||
listMyPlaylists: options.listMyPlaylists,
|
||||
search: options.search,
|
||||
host: options.host,
|
||||
withVideos: options.withVideos || false
|
||||
} as AvailableForListOptions
|
||||
]
|
||||
@@ -390,6 +401,7 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
|
||||
count: number
|
||||
sort: string
|
||||
search?: string
|
||||
host?: string
|
||||
}) {
|
||||
return VideoPlaylistModel.listForApi({
|
||||
...options,
|
||||
|
||||
@@ -2,7 +2,6 @@ import * as memoizee from 'memoizee'
|
||||
import { join } from 'path'
|
||||
import { Op } from 'sequelize'
|
||||
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, HasMany, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
|
||||
import { doesExist } from '@server/helpers/database-utils'
|
||||
import { VideoFileModel } from '@server/models/video/video-file'
|
||||
import { MStreamingPlaylist, MVideo } from '@server/types/models'
|
||||
import { AttributesOnly } from '@shared/core-utils'
|
||||
@@ -20,6 +19,7 @@ import {
|
||||
WEBSERVER
|
||||
} from '../../initializers/constants'
|
||||
import { VideoRedundancyModel } from '../redundancy/video-redundancy'
|
||||
import { doesExist } from '../shared'
|
||||
import { throwIfNotValid } from '../utils'
|
||||
import { VideoModel } from './video'
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import {
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript'
|
||||
import { setAsUpdated } from '@server/helpers/database-utils'
|
||||
import { buildNSFWFilter } from '@server/helpers/express-utils'
|
||||
import { uuidToShort } from '@server/helpers/uuid'
|
||||
import { getPrivaciesForFederation, isPrivacyForFederation, isStateForFederation } from '@server/helpers/video'
|
||||
@@ -92,6 +91,7 @@ import { VideoRedundancyModel } from '../redundancy/video-redundancy'
|
||||
import { ServerModel } from '../server/server'
|
||||
import { TrackerModel } from '../server/tracker'
|
||||
import { VideoTrackerModel } from '../server/video-tracker'
|
||||
import { setAsUpdated } from '../shared'
|
||||
import { UserModel } from '../user/user'
|
||||
import { UserVideoHistoryModel } from '../user/user-video-history'
|
||||
import { buildTrigramSearchIndex, buildWhereIdOrUUID, getVideoSort, isOutdated, throwIfNotValid } from '../utils'
|
||||
|
||||
Reference in New Issue
Block a user