From 7e9334c34db23e5ad1e118151b24c720dd985984 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 20 Nov 2017 11:19:23 +0100 Subject: [PATCH] Add ability to unfollow a server --- .../followers-list.component.html | 4 +-- .../following-list.component.html | 9 +++++-- .../following-list.component.ts | 19 ++++++++++++++ .../+admin/follows/shared/follow.service.ts | 8 +++++- .../users/user-list/user-list.component.ts | 8 ++---- server/initializers/constants.ts | 2 +- .../lib/activitypub/process/process-undo.ts | 2 +- server/middlewares/validators/follows.ts | 6 ++--- .../account/account-follow-interface.ts | 11 +++++--- server/models/account/account-follow.ts | 26 ++++++++++++++++--- shared/models/accounts/follow.model.ts | 10 ++++--- support/nginx/peertube | 3 +++ support/nginx/peertube-https | 3 +++ 13 files changed, 85 insertions(+), 26 deletions(-) diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.html b/client/src/app/+admin/follows/followers-list/followers-list.component.html index 24d75d2b3..549aacdf0 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.html +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.html @@ -7,9 +7,9 @@ sortField="createdAt" (onLazyLoad)="loadLazy($event)" > - + - + diff --git a/client/src/app/+admin/follows/following-list/following-list.component.html b/client/src/app/+admin/follows/following-list/following-list.component.html index fbcebfaa7..dcc03f4a5 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.html +++ b/client/src/app/+admin/follows/following-list/following-list.component.html @@ -7,10 +7,15 @@ sortField="createdAt" (onLazyLoad)="loadLazy($event)" > - + - + + + + + + diff --git a/client/src/app/+admin/follows/following-list/following-list.component.ts b/client/src/app/+admin/follows/following-list/following-list.component.ts index a1dff1db3..411b8f640 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.ts +++ b/client/src/app/+admin/follows/following-list/following-list.component.ts @@ -2,6 +2,7 @@ import { Component } from '@angular/core' import { NotificationsService } from 'angular2-notifications' import { SortMeta } from 'primeng/primeng' import { AccountFollow } from '../../../../../../shared/models/accounts/follow.model' +import { ConfirmService } from '../../../core/confirm/confirm.service' import { RestPagination, RestTable } from '../../../shared' import { FollowService } from '../shared' @@ -18,11 +19,29 @@ export class FollowingListComponent extends RestTable { constructor ( private notificationsService: NotificationsService, + private confirmService: ConfirmService, private followService: FollowService ) { super() } + removeFollowing (follow: AccountFollow) { + this.confirmService.confirm(`Do you really want to unfollow ${follow.following.host}?`, 'Unfollow').subscribe( + res => { + if (res === false) return + + this.followService.unfollow(follow).subscribe( + () => { + this.notificationsService.success('Success', `You are not following ${follow.following.host} anymore.`) + this.loadData() + }, + + err => this.notificationsService.error('Error', err.message) + ) + } + ) + } + protected loadData () { this.followService.getFollowing(this.pagination, this.sort) .subscribe( diff --git a/client/src/app/+admin/follows/shared/follow.service.ts b/client/src/app/+admin/follows/shared/follow.service.ts index f66ed477d..0bfbe8eb6 100644 --- a/client/src/app/+admin/follows/shared/follow.service.ts +++ b/client/src/app/+admin/follows/shared/follow.service.ts @@ -37,7 +37,7 @@ export class FollowService { .catch(res => this.restExtractor.handleError(res)) } - follow (notEmptyHosts: String[]) { + follow (notEmptyHosts: string[]) { const body = { hosts: notEmptyHosts } @@ -46,4 +46,10 @@ export class FollowService { .map(this.restExtractor.extractDataBool) .catch(res => this.restExtractor.handleError(res)) } + + unfollow (follow: AccountFollow) { + return this.authHttp.delete(FollowService.BASE_APPLICATION_URL + '/following/' + follow.following.id) + .map(this.restExtractor.extractDataBool) + .catch(res => this.restExtractor.handleError(res)) + } } diff --git a/client/src/app/+admin/users/user-list/user-list.component.ts b/client/src/app/+admin/users/user-list/user-list.component.ts index 6debf89be..1e8e1af49 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.ts +++ b/client/src/app/+admin/users/user-list/user-list.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core' +import { Component } from '@angular/core' import { SortMeta } from 'primeng/components/common/sortmeta' import { NotificationsService } from 'angular2-notifications' @@ -12,7 +12,7 @@ import { UserService } from '../shared' templateUrl: './user-list.component.html', styleUrls: [ './user-list.component.scss' ] }) -export class UserListComponent extends RestTable implements OnInit { +export class UserListComponent extends RestTable { users: User[] = [] totalRecords = 0 rowsPerPage = 10 @@ -27,10 +27,6 @@ export class UserListComponent extends RestTable implements OnInit { super() } - ngOnInit () { - this.loadData() - } - removeUser (user: User) { if (user.username === 'root') { this.notificationsService.error('Error', 'You cannot delete root.') diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 9c7c31a61..c46043931 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts @@ -134,7 +134,7 @@ const CONSTRAINTS_FIELDS = { VIEWS: { min: 0 }, LIKES: { min: 0 }, DISLIKES: { min: 0 }, - FILE_SIZE: { min: 10, max: 1024 * 1024 * 1024 * 3 /* 3Go */ }, + FILE_SIZE: { min: 10, max: 1024 * 1024 * 1024 * 10 /* 10Go */ }, URL: { min: 3, max: 2000 } // Length }, ACCOUNTS: { diff --git a/server/lib/activitypub/process/process-undo.ts b/server/lib/activitypub/process/process-undo.ts index 5d09423e1..610b800fb 100644 --- a/server/lib/activitypub/process/process-undo.ts +++ b/server/lib/activitypub/process/process-undo.ts @@ -10,7 +10,7 @@ async function processUndoActivity (activity: ActivityUndo) { const following = await db.Account.loadByUrl(activityToUndo.object) const accountFollow = await db.AccountFollow.loadByAccountAndTarget(follower.id, following.id) - if (!accountFollow) throw new Error(`'Unknown account follow (${follower.id} -> ${following.id}.`) + if (!accountFollow) throw new Error(`'Unknown account follow ${follower.id} -> ${following.id}.`) await accountFollow.destroy() diff --git a/server/middlewares/validators/follows.ts b/server/middlewares/validators/follows.ts index e22349726..dfd6e7f03 100644 --- a/server/middlewares/validators/follows.ts +++ b/server/middlewares/validators/follows.ts @@ -1,12 +1,12 @@ import * as express from 'express' -import { body } from 'express-validator/check' +import { body, param } from 'express-validator/check' import { isTestInstance } from '../../helpers/core-utils' -import { isAccountIdValid } from '../../helpers/custom-validators/activitypub/account' import { isEachUniqueHostValid } from '../../helpers/custom-validators/servers' import { logger } from '../../helpers/logger' import { CONFIG, database as db } from '../../initializers' import { checkErrors } from './utils' import { getServerAccount } from '../../helpers/utils' +import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' const followValidator = [ body('hosts').custom(isEachUniqueHostValid).withMessage('Should have an array of unique hosts'), @@ -28,7 +28,7 @@ const followValidator = [ ] const removeFollowingValidator = [ - body('accountId').custom(isAccountIdValid).withMessage('Should have a valid account id'), + param('accountId').custom(isIdOrUUIDValid).withMessage('Should have a valid account id'), (req: express.Request, res: express.Response, next: express.NextFunction) => { logger.debug('Checking follow parameters', { parameters: req.body }) diff --git a/server/models/account/account-follow-interface.ts b/server/models/account/account-follow-interface.ts index 21fda98ce..6f228c790 100644 --- a/server/models/account/account-follow-interface.ts +++ b/server/models/account/account-follow-interface.ts @@ -1,18 +1,19 @@ -import * as Sequelize from 'sequelize' import * as Bluebird from 'bluebird' -import { FollowState } from '../../../shared/models/accounts/follow.model' +import * as Sequelize from 'sequelize' +import { AccountFollow, FollowState } from '../../../shared/models/accounts/follow.model' import { ResultList } from '../../../shared/models/result-list.model' import { AccountInstance } from './account-interface' export namespace AccountFollowMethods { export type LoadByAccountAndTarget = (accountId: number, targetAccountId: number) => Bluebird - export type ListFollowingForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList > - export type ListFollowersForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList > + export type ListFollowingForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList> + export type ListFollowersForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList> export type ListAcceptedFollowerUrlsForApi = (accountId: number[], start?: number, count?: number) => Promise< ResultList > export type ListAcceptedFollowingUrlsForApi = (accountId: number[], start?: number, count?: number) => Promise< ResultList > export type ListAcceptedFollowerSharedInboxUrls = (accountId: number[]) => Promise< ResultList > + export type ToFormattedJSON = (this: AccountFollowInstance) => AccountFollow } export interface AccountFollowClass { @@ -38,6 +39,8 @@ export interface AccountFollowInstance extends AccountFollowClass, AccountFollow AccountFollower?: AccountInstance AccountFollowing?: AccountInstance + + toFormattedJSON: AccountFollowMethods.ToFormattedJSON } export interface AccountFollowModel extends AccountFollowClass, Sequelize.Model {} diff --git a/server/models/account/account-follow.ts b/server/models/account/account-follow.ts index f00c7dcd9..34ba3f8db 100644 --- a/server/models/account/account-follow.ts +++ b/server/models/account/account-follow.ts @@ -12,6 +12,7 @@ let listFollowersForApi: AccountFollowMethods.ListFollowersForApi let listAcceptedFollowerUrlsForApi: AccountFollowMethods.ListAcceptedFollowerUrlsForApi let listAcceptedFollowingUrlsForApi: AccountFollowMethods.ListAcceptedFollowingUrlsForApi let listAcceptedFollowerSharedInboxUrls: AccountFollowMethods.ListAcceptedFollowerSharedInboxUrls +let toFormattedJSON: AccountFollowMethods.ToFormattedJSON export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { AccountFollow = sequelize.define('AccountFollow', @@ -46,7 +47,10 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da listAcceptedFollowingUrlsForApi, listAcceptedFollowerSharedInboxUrls ] - addMethodsToModel(AccountFollow, classMethods) + const instanceMethods = [ + toFormattedJSON + ] + addMethodsToModel(AccountFollow, classMethods, instanceMethods) return AccountFollow } @@ -73,6 +77,22 @@ function associate (models) { }) } +toFormattedJSON = function (this: AccountFollowInstance) { + const follower = this.AccountFollower.toFormattedJSON() + const following = this.AccountFollowing.toFormattedJSON() + + const json = { + id: this.id, + follower, + following, + state: this.state, + createdAt: this.createdAt, + updatedAt: this.updatedAt + } + + return json +} + loadByAccountAndTarget = function (accountId: number, targetAccountId: number) { const query = { where: { @@ -122,7 +142,7 @@ listFollowingForApi = function (id: number, start: number, count: number, sort: return AccountFollow.findAndCountAll(query).then(({ rows, count }) => { return { - data: rows.map(r => r.AccountFollowing), + data: rows, total: count } }) @@ -154,7 +174,7 @@ listFollowersForApi = function (id: number, start: number, count: number, sort: return AccountFollow.findAndCountAll(query).then(({ rows, count }) => { return { - data: rows.map(r => r.AccountFollower), + data: rows, total: count } }) diff --git a/shared/models/accounts/follow.model.ts b/shared/models/accounts/follow.model.ts index 8094634c1..cdc3da560 100644 --- a/shared/models/accounts/follow.model.ts +++ b/shared/models/accounts/follow.model.ts @@ -1,8 +1,12 @@ +import { Account } from './account.model' + export type FollowState = 'pending' | 'accepted' export interface AccountFollow { id: number - name: string - score?: number // Used for followers - host: string + follower: Account + following: Account + state: FollowState + createdAt: Date + updatedAt: Date } diff --git a/support/nginx/peertube b/support/nginx/peertube index f7db3eea3..8120738f6 100644 --- a/support/nginx/peertube +++ b/support/nginx/peertube @@ -10,6 +10,9 @@ server { # For the video upload client_max_body_size 2G; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; } # Bypass PeerTube webseed route for better performances diff --git a/support/nginx/peertube-https b/support/nginx/peertube-https index 1b9c40e7f..f46442835 100644 --- a/support/nginx/peertube-https +++ b/support/nginx/peertube-https @@ -23,6 +23,9 @@ server { # For the video upload client_max_body_size 2G; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; } # Bypass PeerTube webseed route for better performances