import { SharedModule } from '../shared'
import { AdminRoutingModule } from './admin-routing.module'
import { AdminComponent } from './admin.component'
-import { FollowersListComponent, FollowingAddComponent, FollowsComponent, VideoRedundanciesListComponent } from './follows'
+import { FollowersListComponent, FollowsComponent, VideoRedundanciesListComponent } from './follows'
import { FollowingListComponent } from './follows/following-list/following-list.component'
import { UserCreateComponent, UserListComponent, UserPasswordComponent, UsersComponent, UserUpdateComponent } from './users'
import {
import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service'
import { VideoRedundancyInformationComponent } from '@app/+admin/follows/video-redundancies-list/video-redundancy-information.component'
import { ChartModule } from 'primeng/chart'
+import { BatchDomainsModalComponent } from './config/shared/batch-domains-modal.component'
@NgModule({
imports: [
AdminComponent,
FollowsComponent,
- FollowingAddComponent,
FollowersListComponent,
FollowingListComponent,
RedundancyCheckboxComponent,
DebugComponent,
ConfigComponent,
- EditCustomConfigComponent
+ EditCustomConfigComponent,
+
+ BatchDomainsModalComponent
],
exports: [
--- /dev/null
+<ng-template #modal>
+ <div class="modal-header">
+ <h4 i18n class="modal-title">{{ action }}</h4>
+
+ <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
+ </div>
+
+ <div class="modal-body">
+ <form novalidate [formGroup]="form" (ngSubmit)="submit()">
+ <div class="form-group">
+ <label i18n for="hosts">1 host (without "http://") per line</label>
+
+ <textarea
+ [placeholder]="placeholder" formControlName="domains" type="text" id="hosts" name="hosts"
+ class="form-control" [ngClass]="{ 'input-error': formErrors['domains'] }" ngbAutofocus
+ ></textarea>
+
+ <div *ngIf="formErrors.domains" class="form-error">
+ {{ formErrors.domains }}
+
+ <div *ngIf="form.controls['domains'].errors.validDomains">
+ {{ form.controls['domains'].errors.validDomains.value }}
+ </div>
+ </div>
+ </div>
+
+ <ng-content select="warning"></ng-content>
+
+ <div class="form-group inputs">
+ <input
+ type="button" role="button" i18n-value value="Cancel" class="action-button action-button-cancel"
+ (click)="hide()" (key.enter)="hide()"
+ >
+
+ <input
+ type="submit" [value]="action" class="action-button-submit"
+ [disabled]="!form.valid"
+ >
+ </div>
+ </form>
+ </div>
+
+</ng-template>
--- /dev/null
+textarea {
+ height: 200px;
+}
--- /dev/null
+import { Component, OnInit, ViewChild, Input, Output, EventEmitter } from '@angular/core'
+import { I18n } from '@ngx-translate/i18n-polyfill'
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
+import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
+import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
+import { FormReactive } from '@app/shared/forms'
+import { BatchDomainsValidatorsService } from './batch-domains-validators.service'
+
+@Component({
+ selector: 'my-batch-domains-modal',
+ templateUrl: './batch-domains-modal.component.html',
+ styleUrls: [ './batch-domains-modal.component.scss' ]
+})
+export class BatchDomainsModalComponent extends FormReactive implements OnInit {
+ @ViewChild('modal', { static: true }) modal: NgbModal
+ @Input() placeholder = 'example.com'
+ @Input() action: string
+ @Output() domains = new EventEmitter<string[]>()
+
+ private openedModal: NgbModalRef
+
+ constructor (
+ protected formValidatorService: FormValidatorService,
+ private modalService: NgbModal,
+ private batchDomainsValidatorsService: BatchDomainsValidatorsService,
+ private i18n: I18n
+ ) {
+ super()
+ }
+
+ ngOnInit () {
+ if (!this.action) this.action = this.i18n('Process domains')
+
+ this.buildForm({
+ domains: this.batchDomainsValidatorsService.DOMAINS
+ })
+ }
+
+ openModal () {
+ this.openedModal = this.modalService.open(this.modal, { centered: true })
+ }
+
+ hide () {
+ this.openedModal.close()
+ }
+
+ submit () {
+ this.domains.emit(
+ this.batchDomainsValidatorsService.getNotEmptyHosts(this.form.controls['domains'].value)
+ )
+ this.form.reset()
+ this.hide()
+ }
+}
--- /dev/null
+import { I18n } from '@ngx-translate/i18n-polyfill'
+import { Validators, ValidatorFn } from '@angular/forms'
+import { Injectable } from '@angular/core'
+import { BuildFormValidator, validateHost } from '@app/shared'
+
+@Injectable()
+export class BatchDomainsValidatorsService {
+ readonly DOMAINS: BuildFormValidator
+
+ constructor (private i18n: I18n) {
+ this.DOMAINS = {
+ VALIDATORS: [ Validators.required, this.validDomains, this.isHostsUnique ],
+ MESSAGES: {
+ 'required': this.i18n('Domain is required.'),
+ 'validDomains': this.i18n('Domains entered are invalid.'),
+ 'uniqueDomains': this.i18n('Domains entered contain duplicates.')
+ }
+ }
+ }
+
+ getNotEmptyHosts (hosts: string) {
+ return hosts
+ .split('\n')
+ .filter((host: string) => host && host.length !== 0) // Eject empty hosts
+ }
+
+ private validDomains: ValidatorFn = (control) => {
+ if (!control.value) return null
+
+ const newHostsErrors = []
+ const hosts = this.getNotEmptyHosts(control.value)
+
+ for (const host of hosts) {
+ if (validateHost(host) === false) {
+ newHostsErrors.push(this.i18n('{{host}} is not valid', { host }))
+ }
+ }
+
+ /* Is not valid. */
+ if (newHostsErrors.length !== 0) {
+ return {
+ 'validDomains': {
+ reason: 'invalid',
+ value: newHostsErrors.join('. ') + '.'
+ }
+ }
+ }
+
+ /* Is valid. */
+ return null
+ }
+
+ private isHostsUnique: ValidatorFn = (control) => {
+ if (!control.value) return null
+
+ const hosts = this.getNotEmptyHosts(control.value)
+
+ if (hosts.every((host: string) => hosts.indexOf(host) === hosts.lastIndexOf(host))) {
+ return null
+ } else {
+ return {
+ 'uniqueDomains': {
+ reason: 'invalid'
+ }
+ }
+ }
+ }
+}
followers: ActorFollow[] = []
totalRecords = 0
rowsPerPage = 10
- sort: SortMeta = { field: 'createdAt', order: 1 }
+ sort: SortMeta = { field: 'createdAt', order: -1 }
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
constructor (
+++ /dev/null
-<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
-
-<form (ngSubmit)="addFollowing()">
- <div class="form-group">
- <label i18n for="hosts">1 host (without "http://") per line</label>
-
- <textarea
- type="text" class="form-control" placeholder="example.com" id="hosts" name="hosts"
- [(ngModel)]="hostsString" (ngModelChange)="onHostsChanged()" [ngClass]="{ 'input-error': hostsError }"
- ></textarea>
-
- <div *ngIf="hostsError" class="form-error">
- {{ hostsError }}
- </div>
- </div>
-
- <div i18n *ngIf="httpEnabled() === false" class="alert alert-warning">
- It seems that you are not on a HTTPS server. Your webserver needs to have TLS activated in order to follow servers.
- </div>
-
- <input type="submit" i18n-value value="Add following" [disabled]="hostsError || !hostsString" class="btn btn-secondary">
-</form>
+++ /dev/null
-@import '_variables';
-@import '_mixins';
-
-textarea {
- height: 250px;
-}
-
-input[type=submit] {
- @include peertube-button;
- @include orange-button;
-}
+++ /dev/null
-import { Component } from '@angular/core'
-import { Router } from '@angular/router'
-import { Notifier } from '@app/core'
-import { ConfirmService } from '../../../core'
-import { validateHost } from '../../../shared'
-import { FollowService } from '@app/shared/instance/follow.service'
-import { I18n } from '@ngx-translate/i18n-polyfill'
-
-@Component({
- selector: 'my-following-add',
- templateUrl: './following-add.component.html',
- styleUrls: [ './following-add.component.scss' ]
-})
-export class FollowingAddComponent {
- hostsString = ''
- hostsError: string = null
- error: string = null
-
- constructor (
- private router: Router,
- private notifier: Notifier,
- private confirmService: ConfirmService,
- private followService: FollowService,
- private i18n: I18n
- ) {}
-
- httpEnabled () {
- return window.location.protocol === 'https:'
- }
-
- onHostsChanged () {
- this.hostsError = null
-
- const newHostsErrors = []
- const hosts = this.getNotEmptyHosts()
-
- for (const host of hosts) {
- if (validateHost(host) === false) {
- newHostsErrors.push(this.i18n('{{host}} is not valid', { host }))
- }
- }
-
- if (newHostsErrors.length !== 0) {
- this.hostsError = newHostsErrors.join('. ')
- }
- }
-
- async addFollowing () {
- this.error = ''
-
- const hosts = this.getNotEmptyHosts()
- if (hosts.length === 0) {
- this.error = this.i18n('You need to specify hosts to follow.')
- }
-
- if (!this.isHostsUnique(hosts)) {
- this.error = this.i18n('Hosts need to be unique.')
- return
- }
-
- const confirmMessage = this.i18n('If you confirm, you will send a follow request to:<br /> - ') + hosts.join('<br /> - ')
- const res = await this.confirmService.confirm(confirmMessage, this.i18n('Follow new server(s)'))
- if (res === false) return
-
- this.followService.follow(hosts).subscribe(
- () => {
- this.notifier.success(this.i18n('Follow request(s) sent!'))
-
- setTimeout(() => this.router.navigate([ '/admin/follows/following-list' ]), 500)
- },
-
- err => this.notifier.error(err.message)
- )
- }
-
- private isHostsUnique (hosts: string[]) {
- return hosts.every(host => hosts.indexOf(host) === hosts.lastIndexOf(host))
- }
-
- private getNotEmptyHosts () {
- return this.hostsString
- .split('\n')
- .filter(host => host && host.length !== 0) // Eject empty hosts
- }
-}
+++ /dev/null
-export * from './following-add.component'
>
<ng-template pTemplate="caption">
<div class="caption">
- <div>
+ <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Â follow-button" (click)="addDomainsToFollow()" (key.enter)="addDomainsToFollow()">
+ <my-global-icon iconName="add"></my-global-icon>
+ <ng-container i18n>Follow domain</ng-container>
+ </a>
</div>
</ng-template>
</tr>
</ng-template>
</p-table>
+
+<my-batch-domains-modal #batchDomainsModal i18n-action action="Follow domains" (domains)="addFollowing($event)"></my-batch-domains-modal>
input {
@include peertube-input-text(250px);
}
-}
\ No newline at end of file
+}
+
+.follow-button {
+ @include create-button;
+}
-import { Component, OnInit } from '@angular/core'
+import { Component, OnInit, ViewChild } from '@angular/core'
import { Notifier } from '@app/core'
import { SortMeta } from 'primeng/api'
import { ActorFollow } from '../../../../../../shared/models/actors/follow.model'
import { RestPagination, RestTable } from '../../../shared'
import { FollowService } from '@app/shared/instance/follow.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
+import { BatchDomainsModalComponent } from '@app/+admin/config/shared/batch-domains-modal.component'
@Component({
selector: 'my-followers-list',
styleUrls: [ './following-list.component.scss' ]
})
export class FollowingListComponent extends RestTable implements OnInit {
+ @ViewChild('batchDomainsModal') batchDomainsModal: BatchDomainsModalComponent
+
following: ActorFollow[] = []
totalRecords = 0
rowsPerPage = 10
- sort: SortMeta = { field: 'createdAt', order: 1 }
+ sort: SortMeta = { field: 'createdAt', order: -1 }
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
constructor (
return 'FollowingListComponent'
}
+ addDomainsToFollow () {
+ this.batchDomainsModal.openModal()
+ }
+
+ async addFollowing (hosts: string[]) {
+ this.followService.follow(hosts).subscribe(
+ () => {
+ this.notifier.success(this.i18n('Follow request(s) sent!'))
+ this.loadData()
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+
async removeFollowing (follow: ActorFollow) {
const res = await this.confirmService.confirm(
this.i18n('Do you really want to unfollow {{host}}?', { host: follow.following.host }),
<div class="admin-sub-nav">
<a i18n routerLink="following-list" routerLinkActive="active">Following</a>
- <a i18n routerLink="following-add" routerLinkActive="active">Follow</a>
-
<a i18n routerLink="followers-list" routerLinkActive="active">Followers</a>
<a i18n routerLink="video-redundancies-list" routerLinkActive="active">Video redundancies</a>
import { UserRightGuard } from '../../core'
import { FollowsComponent } from './follows.component'
-import { FollowingAddComponent } from './following-add'
import { FollowersListComponent } from './followers-list'
import { UserRight } from '../../../../../shared'
import { FollowingListComponent } from './following-list/following-list.component'
},
{
path: 'following-add',
- component: FollowingAddComponent,
- data: {
- meta: {
- title: 'Add follow'
- }
- }
+ redirectTo: 'following-list'
},
{
path: 'video-redundancies-list',
-export * from './following-add'
export * from './followers-list'
export * from './following-list'
export * from './video-redundancies-list'
[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()">
+ <my-global-icon iconName="add"></my-global-icon>
+ <ng-container i18n>Mute domain</ng-container>
+ </a>
+ </div>
+ </ng-template>
<ng-template pTemplate="header">
<tr>
</tr>
</ng-template>
</p-table>
+
+<my-batch-domains-modal #batchDomainsModal i18n-action action="Mute domains" (domains)="onDomainsToBlock($event)">
+ <ng-container ngProjectAs="warning">
+ <div i18n *ngIf="httpEnabled() === false" class="alert alert-warning">
+ It seems that you are not on a HTTPS server. Your webserver needs to have TLS activated in order to follow servers.
+ </div>
+ </ng-container>
+</my-batch-domains-modal>
.unblock-button {
@include peertube-button;
@include grey-button;
-}
\ No newline at end of file
+}
+
+.block-button {
+ @include create-button;
+}
-import { Component, OnInit } from '@angular/core'
+import { Component, OnInit, ViewChild } from '@angular/core'
import { Notifier } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { RestPagination, RestTable } from '@app/shared'
import { SortMeta } from 'primeng/api'
import { BlocklistService } from '@app/shared/blocklist'
import { ServerBlock } from '../../../../../../shared'
+import { BatchDomainsModalComponent } from '@app/+admin/config/shared/batch-domains-modal.component'
@Component({
selector: 'my-instance-server-blocklist',
templateUrl: './instance-server-blocklist.component.html'
})
export class InstanceServerBlocklistComponent extends RestTable implements OnInit {
+ @ViewChild('batchDomainsModal') batchDomainsModal: BatchDomainsModalComponent
+
blockedServers: ServerBlock[] = []
totalRecords = 0
rowsPerPage = 10
)
}
+ httpEnabled () {
+ return window.location.protocol === 'https:'
+ }
+
+ addServersToBlock () {
+ this.batchDomainsModal.openModal()
+ }
+
+ onDomainsToBlock (domains: string[]) {
+ domains.forEach(domain => {
+ this.blocklistService.blockServerByInstance(domain)
+ .subscribe(
+ () => {
+ this.notifier.success(this.i18n('Instance {{domain}} muted by your instance.', { domain }))
+
+ this.loadData()
+ }
+ )
+ })
+ }
+
protected loadData () {
return this.blocklistService.getInstanceServerBlocklist(this.pagination, this.sort)
.subscribe(
</a>
</td>
- <td>
+ <td class="c-hand" [pRowToggler]="videoAbuse">
<span *ngIf="isVideoAbuseAccepted(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-ok"></span>
<span *ngIf="isVideoAbuseRejected(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-remove"></span>
</td>
<td class="action-cell">
- <my-action-dropdown placement="bottom-right" i18n-label label="Actions" [actions]="videoAbuseActions" [entry]="videoAbuse"></my-action-dropdown>
+ <my-action-dropdown placement="bottom-right auto" i18n-label label="Actions" [actions]="videoAbuseActions" [entry]="videoAbuse"></my-action-dropdown>
</td>
</tr>
</ng-template>
import { Component, OnInit, ViewChild } from '@angular/core'
-import { Account } from '../../../shared/account/account.model'
+import { Account } from '@app/shared/account/account.model'
import { Notifier } from '@app/core'
import { SortMeta } from 'primeng/api'
import { VideoAbuse, VideoAbuseState } from '../../../../../../shared'
-import { RestPagination, RestTable, VideoAbuseService } from '../../../shared'
+import { RestPagination, RestTable, VideoAbuseService, VideoBlacklistService } from '../../../shared'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { DropdownAction } from '../../../shared/buttons/action-dropdown.component'
import { ConfirmService } from '../../../core/index'
import { buildVideoLink, buildVideoEmbed } from 'src/assets/player/utils'
import { getAbsoluteAPIUrl } from '@app/shared/misc/utils'
import { DomSanitizer } from '@angular/platform-browser'
+import { BlocklistService } from '@app/shared/blocklist'
@Component({
selector: 'my-video-abuse-list',
sort: SortMeta = { field: 'createdAt', order: 1 }
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
- videoAbuseActions: DropdownAction<VideoAbuse>[] = []
+ videoAbuseActions: DropdownAction<VideoAbuse>[][] = []
constructor (
private notifier: Notifier,
private videoAbuseService: VideoAbuseService,
+ private blocklistService: BlocklistService,
+ private videoBlacklistService: VideoBlacklistService,
private confirmService: ConfirmService,
private i18n: I18n,
private markdownRenderer: MarkdownService,
super()
this.videoAbuseActions = [
- {
- label: this.i18n('Delete this report'),
- handler: videoAbuse => this.removeVideoAbuse(videoAbuse)
- },
- {
- label: this.i18n('Add note'),
- handler: videoAbuse => this.openModerationCommentModal(videoAbuse),
- isDisplayed: videoAbuse => !videoAbuse.moderationComment
- },
- {
- label: this.i18n('Update note'),
- handler: videoAbuse => this.openModerationCommentModal(videoAbuse),
- isDisplayed: videoAbuse => !!videoAbuse.moderationComment
- },
- {
- label: this.i18n('Mark as accepted'),
- handler: videoAbuse => this.updateVideoAbuseState(videoAbuse, VideoAbuseState.ACCEPTED),
- isDisplayed: videoAbuse => !this.isVideoAbuseAccepted(videoAbuse)
- },
- {
- label: this.i18n('Mark as rejected'),
- handler: videoAbuse => this.updateVideoAbuseState(videoAbuse, VideoAbuseState.REJECTED),
- isDisplayed: videoAbuse => !this.isVideoAbuseRejected(videoAbuse)
- }
+ [
+ {
+ label: this.i18n('Internal actions'),
+ isHeader: true
+ },
+ {
+ label: this.i18n('Delete report'),
+ handler: videoAbuse => this.removeVideoAbuse(videoAbuse)
+ },
+ {
+ label: this.i18n('Add note'),
+ handler: videoAbuse => this.openModerationCommentModal(videoAbuse),
+ isDisplayed: videoAbuse => !videoAbuse.moderationComment
+ },
+ {
+ label: this.i18n('Update note'),
+ handler: videoAbuse => this.openModerationCommentModal(videoAbuse),
+ isDisplayed: videoAbuse => !!videoAbuse.moderationComment
+ },
+ {
+ label: this.i18n('Mark as accepted'),
+ handler: videoAbuse => this.updateVideoAbuseState(videoAbuse, VideoAbuseState.ACCEPTED),
+ isDisplayed: videoAbuse => !this.isVideoAbuseAccepted(videoAbuse)
+ },
+ {
+ label: this.i18n('Mark as rejected'),
+ handler: videoAbuse => this.updateVideoAbuseState(videoAbuse, VideoAbuseState.REJECTED),
+ isDisplayed: videoAbuse => !this.isVideoAbuseRejected(videoAbuse)
+ }
+ ],
+ [
+ {
+ label: this.i18n('Actions for the video'),
+ isHeader: true
+ },
+ {
+ label: this.i18n('Blacklist video'),
+ handler: videoAbuse => {
+ this.videoBlacklistService.blacklistVideo(videoAbuse.video.id, undefined, true)
+ .subscribe(
+ () => {
+ this.notifier.success(this.i18n('Video blacklisted.'))
+
+ this.updateVideoAbuseState(videoAbuse, VideoAbuseState.ACCEPTED)
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+ }
+ ]
]
}
blacklist: (VideoBlacklist & { reasonHtml?: string })[] = []
totalRecords = 0
rowsPerPage = 10
- sort: SortMeta = { field: 'createdAt', order: 1 }
+ sort: SortMeta = { field: 'createdAt', order: -1 }
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
listBlacklistTypeFilter: VideoBlacklistType = undefined
</div>
</ng-template>
- <a *ngIf="action.linkBuilder" [ngClass]="{ 'with-icon': !!action.iconName }" class="dropdown-item" [routerLink]="action.linkBuilder(entry)" [title]="action.title || ''">
+ <a
+ *ngIf="action.linkBuilder && !action.isHeader" [ngClass]="{ 'with-icon': !!action.iconName }"
+ class="dropdown-item" [routerLink]="action.linkBuilder(entry)" [title]="action.title || ''"
+ >
<ng-container *ngTemplateOutlet="templateActionLabel; context:{ $implicit: action }"></ng-container>
</a>
<span
- *ngIf="!action.linkBuilder" [ngClass]="{ 'with-icon': !!action.iconName }" (click)="action.handler(entry)"
- class="custom-action dropdown-item" role="button" [title]="action.title || ''"
+ *ngIf="!action.linkBuilder && !action.isHeader" [ngClass]="{ 'with-icon': !!action.iconName }"
+ class="custom-action dropdown-item" role="button" [title]="action.title || ''" (click)="action.handler(entry)"
>
<ng-container *ngTemplateOutlet="templateActionLabel; context:{ $implicit: action }"></ng-container>
</span>
+ <h6
+ *ngIf="!action.linkBuilder && action.isHeader" [ngClass]="{ 'with-icon': !!action.iconName }"
+ class="dropdown-header" role="button" [title]="action.title || ''" (click)="action.handler(entry)"
+ >
+ <ng-container *ngTemplateOutlet="templateActionLabel; context:{ $implicit: action }"></ng-container>
+ </h6>
+
</ng-container>
</ng-container>
}
.dropdown-menu {
+ .dropdown-header {
+ padding: 0.2rem 1rem;
+ }
+
.dropdown-item {
display: flex;
cursor: pointer;
handler?: (a: T) => any
linkBuilder?: (a: T) => (string | number)[]
isDisplayed?: (a: T) => boolean
+ isHeader?: boolean
}
export type DropdownButtonSize = 'normal' | 'small'
import { MyAccountVideoSettingsComponent } from '@app/+my-account/my-account-settings/my-account-video-settings'
import { MyAccountInterfaceSettingsComponent } from '@app/+my-account/my-account-settings/my-account-interface'
import { ActorAvatarInfoComponent } from '@app/+my-account/shared/actor-avatar-info.component'
+import { BatchDomainsValidatorsService } from '@app/+admin/config/shared/batch-domains-validators.service'
@NgModule({
imports: [
LoginValidatorsService,
ResetPasswordValidatorsService,
UserValidatorsService,
+ BatchDomainsValidatorsService,
VideoPlaylistValidatorsService,
VideoAbuseValidatorsService,
VideoChannelValidatorsService,
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
import { VideoCommentValidatorsService } from '@app/shared/forms/form-validators/video-comment-validators.service'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
-import { AuthService } from '@app/core/auth'
@Component({
selector: 'my-video-comment-add',
private videoCommentValidatorsService: VideoCommentValidatorsService,
private notifier: Notifier,
private videoCommentService: VideoCommentService,
- private authService: AuthService,
private modalService: NgbModal,
private router: Router
) {
.end()
}
- const server = await ServerModel.loadByHost(host)
+ let server = await ServerModel.loadByHost(host)
if (!server) {
- return res.status(404)
- .send({ error: 'Server host not found.' })
- .end()
+ server = await ServerModel.create({ host })
}
res.locals.server = server
})
})
- it('Should fail with an unknown server', async function () {
+ it('Should succeed with an unknown server', async function () {
await makePostBodyRequest({
url: server.url,
token: server.accessToken,
path,
fields: { host: 'localhost:9003' },
- statusCodeExpected: 404
+ statusCodeExpected: 204
})
})
it('Should fail with an unknown server block', async function () {
await makeDeleteRequest({
url: server.url,
- path: path + '/localhost:9003',
+ path: path + '/localhost:9004',
token: server.accessToken,
statusCodeExpected: 404
})
})
})
- it('Should fail with an unknown server', async function () {
+ it('Should succeed with an unknown server', async function () {
await makePostBodyRequest({
url: server.url,
token: server.accessToken,
path,
fields: { host: 'localhost:9003' },
- statusCodeExpected: 404
+ statusCodeExpected: 204
})
})
it('Should fail with an unknown server block', async function () {
await makeDeleteRequest({
url: server.url,
- path: path + '/localhost:9003',
+ path: path + '/localhost:9004',
token: server.accessToken,
statusCodeExpected: 404
})