<p-table
- [value]="blockedAccounts" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
+ [value]="blockedAccounts" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions"
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)"
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} muted accounts"
>
+ <ng-template pTemplate="caption">
+ <div class="caption">
+ <div class="ml-auto">
+ <input
+ type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..."
+ (keyup)="onSearch($event)"
+ >
+ </div>
+ </div>
+ </ng-template>
<ng-template pTemplate="header">
<tr>
@Component({
selector: 'my-instance-account-blocklist',
- styleUrls: [ './instance-account-blocklist.component.scss' ],
+ styleUrls: [ '../moderation.component.scss', './instance-account-blocklist.component.scss' ],
templateUrl: './instance-account-blocklist.component.html'
})
export class InstanceAccountBlocklistComponent extends RestTable implements OnInit {
blockedAccounts: AccountBlock[] = []
totalRecords = 0
- rowsPerPage = 10
+ rowsPerPageOptions = [ 20, 50, 100 ]
+ rowsPerPage = this.rowsPerPageOptions[0]
sort: SortMeta = { field: 'createdAt', order: -1 }
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
}
protected loadData () {
- return this.blocklistService.getInstanceAccountBlocklist(this.pagination, this.sort)
+ return this.blocklistService.getInstanceAccountBlocklist({
+ pagination: this.pagination,
+ sort: this.sort,
+ search: this.search
+ })
.subscribe(
resultList => {
this.blockedAccounts = resultList.data
<p-table
- [value]="blockedServers" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
+ [value]="blockedServers" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions"
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)"
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} muted instances"
>
<ng-template pTemplate="caption">
<div class="caption">
- <a class="ml-auto block-button" (click)="addServersToBlock()" (key.enter)="addServersToBlock()">
+ <div class="ml-auto">
+ <input
+ type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..."
+ (keyup)="onSearch($event)"
+ >
+ </div>
+ <a class="ml-2 block-button" (click)="addServersToBlock()" (key.enter)="addServersToBlock()">
<my-global-icon iconName="add"></my-global-icon>
<ng-container i18n>Mute domain</ng-container>
</a>
@Component({
selector: 'my-instance-server-blocklist',
- styleUrls: [ './instance-server-blocklist.component.scss' ],
+ styleUrls: [ '../moderation.component.scss', './instance-server-blocklist.component.scss' ],
templateUrl: './instance-server-blocklist.component.html'
})
export class InstanceServerBlocklistComponent extends RestTable implements OnInit {
blockedServers: ServerBlock[] = []
totalRecords = 0
- rowsPerPage = 10
+ rowsPerPageOptions = [ 20, 50, 100 ]
+ rowsPerPage = this.rowsPerPageOptions[0]
sort: SortMeta = { field: 'createdAt', order: -1 }
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
}
protected loadData () {
- return this.blocklistService.getInstanceServerBlocklist(this.pagination, this.sort)
+ return this.blocklistService.getInstanceServerBlocklist({
+ pagination: this.pagination,
+ sort: this.sort,
+ search: this.search
+ })
.subscribe(
resultList => {
this.blockedServers = resultList.data
margin-right: 30px;
}
+.caption {
+ justify-content: flex-end;
+
+ input {
+ @include peertube-input-text(250px);
+ }
+}
+
.moderation-expanded {
font-size: 90%;
@import 'mixins';
@import 'miniature';
-.caption {
- justify-content: flex-end;
-
- input {
- @include peertube-input-text(250px);
- }
-}
-
.video-details-date-updated {
font-size: 90%;
margin-top: .1rem;
<p-table
- [value]="blacklist" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
+ [value]="blacklist" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions"
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id"
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} blacklisted videos"
>
+ <ng-template pTemplate="caption">
+ <div class="caption">
+ <div class="ml-auto">
+ <input
+ type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..."
+ (keyup)="onSearch($event)"
+ >
+ </div>
+ </div>
+ </ng-template>
+
<ng-template pTemplate="header">
<tr>
<th style="width: 40px"></th>
<div class="video-table-video-text">
<div>
{{ videoBlacklist.video.name }}
- <span class="glyphicon glyphicon-new-window"></span>
+ <span i18n-title title="Video was blacklisted" class="glyphicon glyphicon-ban-circle"></span>
</div>
<div class="text-muted">by {{ videoBlacklist.video.channel?.displayName }} on {{ videoBlacklist.video.channel?.host }} </div>
</div>
</ng-container>
<td class="action-cell">
- <my-action-dropdown i18n-label placement="bottom-right" label="Actions" [actions]="videoBlacklistActions" [entry]="videoBlacklist"></my-action-dropdown>
+ <my-action-dropdown
+ [ngClass]="{ 'show': expanded }" placement="bottom-right" container="body"
+ i18n-label label="Actions" [actions]="videoBlacklistActions" [entry]="videoBlacklist"
+ ></my-action-dropdown>
</td>
</tr>
</ng-template>
<ng-template pTemplate="rowexpansion" let-videoBlacklist>
<tr>
<td class="expand-cell" colspan="6">
- <span class="col-2 moderation-expanded-label" i18n>Blacklist reason:</span>
- <span class="col-9 moderation-expanded-text" [innerHTML]="videoBlacklist.reasonHtml"></span>
+ <div class="d-flex moderation-expanded">
+ <span class="col-2 moderation-expanded-label" i18n>Blacklist reason:</span>
+ <span class="col-9 moderation-expanded-text" [innerHTML]="videoBlacklist.reasonHtml"></span>
+ </div>
</td>
</tr>
</ng-template>
export class VideoBlacklistListComponent extends RestTable implements OnInit {
blacklist: (VideoBlacklist & { reasonHtml?: string })[] = []
totalRecords = 0
- rowsPerPage = 10
+ rowsPerPageOptions = [ 20, 50, 100 ]
+ rowsPerPage = this.rowsPerPageOptions[0]
sort: SortMeta = { field: 'createdAt', order: -1 }
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
listBlacklistTypeFilter: VideoBlacklistType = undefined
ngOnInit () {
this.serverService.getConfig()
.subscribe(config => {
- // don't filter if auto-blacklist not enabled as this will be the only list
+ // don't filter if auto-blacklist is not enabled as this will be the only list
if (config.autoBlacklist.videos.ofUsers.enabled) {
this.listBlacklistTypeFilter = VideoBlacklistType.MANUAL
}
}
protected loadData () {
- this.videoBlacklistService.listBlacklist(this.pagination, this.sort, this.listBlacklistTypeFilter)
+ this.videoBlacklistService.listBlacklist({
+ pagination: this.pagination,
+ sort: this.sort,
+ search: this.search,
+ type: this.listBlacklistTypeFilter
+ })
.subscribe(
async resultList => {
this.totalRecords = resultList.total
/*********************** Instance -> Account blocklist ***********************/
- getInstanceAccountBlocklist (pagination: RestPagination, sort: SortMeta) {
+ getInstanceAccountBlocklist (options: { pagination: RestPagination, sort: SortMeta, search: string }) {
+ const { pagination, sort, search } = options
+
let params = new HttpParams()
params = this.restService.addRestGetParams(params, pagination, sort)
+ if (search) params = params.append('search', search)
+
return this.authHttp.get<ResultList<AccountBlock>>(BlocklistService.BASE_SERVER_BLOCKLIST_URL + '/accounts', { params })
.pipe(
map(res => this.restExtractor.convertResultListDateToHuman(res)),
/*********************** Instance -> Server blocklist ***********************/
- getInstanceServerBlocklist (pagination: RestPagination, sort: SortMeta) {
+ getInstanceServerBlocklist (options: { pagination: RestPagination, sort: SortMeta, search: string }) {
+ const { pagination, sort, search } = options
+
let params = new HttpParams()
params = this.restService.addRestGetParams(params, pagination, sort)
+ if (search) params = params.append('search', search)
+
return this.authHttp.get<ResultList<ServerBlock>>(BlocklistService.BASE_SERVER_BLOCKLIST_URL + '/servers', { params })
.pipe(
map(res => this.restExtractor.convertResultListDateToHuman(res)),
private restExtractor: RestExtractor
) {}
- listBlacklist (pagination: RestPagination, sort: SortMeta, type?: VideoBlacklistType): Observable<ResultList<VideoBlacklist>> {
+ listBlacklist (options: {
+ pagination: RestPagination,
+ sort: SortMeta,
+ search?: string
+ type?: VideoBlacklistType
+ }): Observable<ResultList<VideoBlacklist>> {
+ const { pagination, sort, search, type } = options
+
let params = new HttpParams()
params = this.restService.addRestGetParams(params, pagination, sort)
- if (type) {
- params = params.set('type', type.toString())
- }
+ if (search) params = params.append('search', search)
+ if (type) params = params.append('type', type.toString())
return this.authHttp.get<ResultList<VideoBlacklist>>(VideoBlacklistService.BASE_VIDEOS_URL + 'blacklist', { params })
.pipe(
async function listBlockedAccounts (req: express.Request, res: express.Response) {
const serverActor = await getServerActor()
- const resultList = await AccountBlocklistModel.listForApi(serverActor.Account.id, req.query.start, req.query.count, req.query.sort)
+ 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 listBlockedServers (req: express.Request, res: express.Response) {
const serverActor = await getServerActor()
- const resultList = await ServerBlocklistModel.listForApi(serverActor.Account.id, req.query.start, req.query.count, req.query.sort)
+ 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 listBlockedAccounts (req: express.Request, res: express.Response) {
const user = res.locals.oauth.token.User
- const resultList = await AccountBlocklistModel.listForApi(user.Account.id, req.query.start, req.query.count, req.query.sort)
+ const resultList = await AccountBlocklistModel.listForApi({
+ start: req.query.start,
+ count: req.query.count,
+ sort: req.query.sort,
+ search: req.query.search,
+ accountId: user.Account.id
+ })
return res.json(getFormattedObjects(resultList.data, resultList.total))
}
async function listBlockedServers (req: express.Request, res: express.Response) {
const user = res.locals.oauth.token.User
- const resultList = await ServerBlocklistModel.listForApi(user.Account.id, req.query.start, req.query.count, req.query.sort)
+ const resultList = await ServerBlocklistModel.listForApi({
+ start: req.query.start,
+ count: req.query.count,
+ sort: req.query.sort,
+ search: req.query.search,
+ accountId: user.Account.id
+ })
return res.json(getFormattedObjects(resultList.data, resultList.total))
}
}
async function listBlacklist (req: express.Request, res: express.Response) {
- const resultList = await VideoBlacklistModel.listForApi(req.query.start, req.query.count, req.query.sort, req.query.type)
+ const resultList = await VideoBlacklistModel.listForApi({
+ start: req.query.start,
+ count: req.query.count,
+ sort: req.query.sort,
+ search: req.query.search,
+ type: req.query.type
+ })
return res.json(getFormattedObjects(resultList.data, resultList.total))
}
query('type')
.optional()
.custom(isVideoBlacklistTypeValid).withMessage('Should have a valid video blacklist type attribute'),
+ query('search')
+ .optional()
+ .not()
+ .isEmpty().withMessage('Should have a valid search'),
(req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videos blacklist filters query', { parameters: req.query })
import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
import { AccountModel } from './account'
-import { getSort } from '../utils'
+import { getSort, searchAttribute } from '../utils'
import { AccountBlock } from '../../../shared/models/blocklist'
import { Op } from 'sequelize'
import * as Bluebird from 'bluebird'
return AccountBlocklistModel.findOne(query)
}
- static listForApi (accountId: number, start: number, count: number, sort: string) {
+ static listForApi (parameters: {
+ start: number
+ count: number
+ sort: string
+ search?: string
+ accountId: number
+ }) {
+ const { start, count, sort, search, accountId } = parameters
+
const query = {
offset: start,
limit: count,
- order: getSort(sort),
- where: {
- accountId
- }
+ order: getSort(sort)
+ }
+
+ const where = {
+ accountId
}
+ if (search) {
+ Object.assign(where, {
+ [Op.or]: [
+ { ...searchAttribute(search, '$BlockedAccount.name$') },
+ { ...searchAttribute(search, '$BlockedAccount.Actor.url$') }
+ ]
+ })
+ }
+
+ Object.assign(query, { where })
+
return AccountBlocklistModel
.scope([ ScopeNames.WITH_ACCOUNTS ])
.findAndCountAll<MAccountBlocklistAccounts>(query)
import { AccountModel } from '../account/account'
import { ServerModel } from './server'
import { ServerBlock } from '../../../shared/models/blocklist'
-import { getSort } from '../utils'
+import { getSort, searchAttribute } from '../utils'
import * as Bluebird from 'bluebird'
import { MServerBlocklist, MServerBlocklistAccountServer, MServerBlocklistFormattable } from '@server/typings/models'
import { Op } from 'sequelize'
return ServerBlocklistModel.findOne(query)
}
- static listForApi (accountId: number, start: number, count: number, sort: string) {
+ static listForApi (parameters: {
+ start: number
+ count: number
+ sort: string
+ search?: string
+ accountId: number
+ }) {
+ const { start, count, sort, search, accountId } = parameters
+
const query = {
offset: start,
limit: count,
order: getSort(sort),
where: {
- accountId
+ accountId,
+ ...searchAttribute(search, '$BlockedServer.host$')
}
}
+ console.log(search)
+
return ServerBlocklistModel
.scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_SERVER ])
.findAndCountAll<MServerBlocklistAccountServer>(query)
import { Model, Sequelize } from 'sequelize-typescript'
import validator from 'validator'
import { Col } from 'sequelize/types/lib/utils'
-import { literal, OrderItem } from 'sequelize'
+import { literal, OrderItem, Op } from 'sequelize'
type Primitive = string | Function | number | boolean | Symbol | undefined | null
type DeepOmitHelper<T, K extends keyof T> = {
return { direction, field }
}
+function searchAttribute (sourceField, targetField) {
+ return sourceField
+ ? {
+ [targetField]: {
+ [Op.iLike]: `%${sourceField}%`
+ }
+ }
+ : {}
+}
+
// ---------------------------------------------------------------------------
export {
parseAggregateResult,
getFollowsSort,
buildDirectionAndField,
- createSafeIn
+ createSafeIn,
+ searchAttribute
}
// ---------------------------------------------------------------------------
isVideoAbuseStateValid
} from '../../helpers/custom-validators/video-abuses'
import { AccountModel } from '../account/account'
-import { buildBlockedAccountSQL, getSort, throwIfNotValid } from '../utils'
+import { buildBlockedAccountSQL, getSort, throwIfNotValid, searchAttribute } from '../utils'
import { VideoModel } from './video'
import { VideoAbuseState, VideoDetails } from '../../../shared'
import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants'
import * as Bluebird from 'bluebird'
import { literal, Op } from 'sequelize'
import { ThumbnailModel } from './thumbnail'
-import { VideoChannelModel } from './video-channel'
import { VideoBlacklistModel } from './video-blacklist'
+import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel'
export enum ScopeNames {
FOR_API = 'FOR_API'
serverAccountId: number
userAccountId: any
}) => {
- const search = (sourceField, targetField) => sourceField ? ({
- [targetField]: {
- [Op.iLike]: `%${sourceField}%`
- }
- }) : {}
-
let where = {
reporterAccountId: {
[Op.notIn]: literal('(' + buildBlockedAccountSQL(options.serverAccountId, options.userAccountId) + ')')
{
model: AccountModel,
required: true,
- where: { ...search(options.searchReporter, 'name') }
+ where: { ...searchAttribute(options.searchReporter, 'name') }
},
{
model: VideoModel,
required: false,
- where: { ...search(options.searchVideo, 'name') },
+ where: { ...searchAttribute(options.searchVideo, 'name') },
include: [
{
model: ThumbnailModel
},
{
- model: VideoChannelModel.scope([ 'WITH_ACTOR', 'WITH_ACCOUNT' ]),
- where: { ...search(options.searchVideoChannel, 'name') }
+ model: VideoChannelModel.scope({ method: [ VideoChannelScopeNames.SUMMARY, { withAccount: true } as SummaryOptions ] }),
+ where: { ...searchAttribute(options.searchVideoChannel, 'name') }
},
{
attributes: [ 'id', 'reason', 'unfederated' ],
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
-import { getBlacklistSort, SortType, throwIfNotValid } from '../utils'
+import { getBlacklistSort, SortType, throwIfNotValid, searchAttribute } from '../utils'
import { VideoModel } from './video'
import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel'
import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist'
})
Video: VideoModel
- static listForApi (start: number, count: number, sort: SortType, type?: VideoBlacklistType) {
+ static listForApi (parameters: {
+ start: number
+ count: number
+ sort: SortType
+ search?: string
+ type?: VideoBlacklistType
+ }) {
+ const { start, count, sort, search, type } = parameters
+
function buildBaseQuery (): FindOptions {
return {
offset: start,
{
model: VideoModel,
required: true,
+ where: { ...searchAttribute(search, 'name') },
include: [
{
model: VideoChannelModel.scope({ method: [ VideoChannelScopeNames.SUMMARY, { withAccount: true } as SummaryOptions ] }),