diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2017-11-15 10:10:41 +0100 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2017-11-27 19:40:51 +0100 |
commit | 51548b31815c6f96f314ae96588a9adca150519d (patch) | |
tree | b3298447b7ac128823016fdec92d083e07d9432e | |
parent | 350e31d6b64e4973dfa5e9f7b46841cb09aeb1ad (diff) | |
download | PeerTube-51548b31815c6f96f314ae96588a9adca150519d.tar.gz PeerTube-51548b31815c6f96f314ae96588a9adca150519d.tar.zst PeerTube-51548b31815c6f96f314ae96588a9adca150519d.zip |
Add follow tabs
Following
Follow
Followers
44 files changed, 495 insertions, 397 deletions
diff --git a/client/src/app/+admin/admin-routing.module.ts b/client/src/app/+admin/admin-routing.module.ts index 88f44a811..cd8b9bdef 100644 --- a/client/src/app/+admin/admin-routing.module.ts +++ b/client/src/app/+admin/admin-routing.module.ts | |||
@@ -4,7 +4,7 @@ import { RouterModule, Routes } from '@angular/router' | |||
4 | import { MetaGuard } from '@ngx-meta/core' | 4 | import { MetaGuard } from '@ngx-meta/core' |
5 | 5 | ||
6 | import { AdminComponent } from './admin.component' | 6 | import { AdminComponent } from './admin.component' |
7 | import { FriendsRoutes } from './friends' | 7 | import { FollowsRoutes } from './follows' |
8 | import { UsersRoutes } from './users' | 8 | import { UsersRoutes } from './users' |
9 | import { VideoAbusesRoutes } from './video-abuses' | 9 | import { VideoAbusesRoutes } from './video-abuses' |
10 | import { VideoBlacklistRoutes } from './video-blacklist' | 10 | import { VideoBlacklistRoutes } from './video-blacklist' |
@@ -21,7 +21,7 @@ const adminRoutes: Routes = [ | |||
21 | redirectTo: 'users', | 21 | redirectTo: 'users', |
22 | pathMatch: 'full' | 22 | pathMatch: 'full' |
23 | }, | 23 | }, |
24 | ...FriendsRoutes, | 24 | ...FollowsRoutes, |
25 | ...UsersRoutes, | 25 | ...UsersRoutes, |
26 | ...VideoAbusesRoutes, | 26 | ...VideoAbusesRoutes, |
27 | ...VideoBlacklistRoutes | 27 | ...VideoBlacklistRoutes |
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index 32f6c42a6..3c6b7a793 100644 --- a/client/src/app/+admin/admin.module.ts +++ b/client/src/app/+admin/admin.module.ts | |||
@@ -1,25 +1,28 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | 2 | import { TabsModule } from 'ngx-bootstrap/tabs' | |
3 | import { AdminComponent } from './admin.component' | 3 | import { SharedModule } from '../shared' |
4 | import { AdminRoutingModule } from './admin-routing.module' | 4 | import { AdminRoutingModule } from './admin-routing.module' |
5 | import { FriendsComponent, FriendAddComponent, FriendListComponent, FriendService } from './friends' | 5 | import { AdminComponent } from './admin.component' |
6 | import { UsersComponent, UserAddComponent, UserUpdateComponent, UserListComponent, UserService } from './users' | 6 | import { FollowersListComponent, FollowingAddComponent, FollowsComponent, FollowService } from './follows' |
7 | import { VideoAbusesComponent, VideoAbuseListComponent } from './video-abuses' | 7 | import { FollowingListComponent } from './follows/following-list/following-list.component' |
8 | import { UserAddComponent, UserListComponent, UsersComponent, UserService, UserUpdateComponent } from './users' | ||
9 | import { VideoAbuseListComponent, VideoAbusesComponent } from './video-abuses' | ||
8 | import { VideoBlacklistComponent, VideoBlacklistListComponent } from './video-blacklist' | 10 | import { VideoBlacklistComponent, VideoBlacklistListComponent } from './video-blacklist' |
9 | import { SharedModule } from '../shared' | ||
10 | 11 | ||
11 | @NgModule({ | 12 | @NgModule({ |
12 | imports: [ | 13 | imports: [ |
13 | AdminRoutingModule, | 14 | AdminRoutingModule, |
15 | TabsModule.forRoot(), | ||
14 | SharedModule | 16 | SharedModule |
15 | ], | 17 | ], |
16 | 18 | ||
17 | declarations: [ | 19 | declarations: [ |
18 | AdminComponent, | 20 | AdminComponent, |
19 | 21 | ||
20 | FriendsComponent, | 22 | FollowsComponent, |
21 | FriendAddComponent, | 23 | FollowingAddComponent, |
22 | FriendListComponent, | 24 | FollowersListComponent, |
25 | FollowingListComponent, | ||
23 | 26 | ||
24 | UsersComponent, | 27 | UsersComponent, |
25 | UserAddComponent, | 28 | UserAddComponent, |
@@ -38,7 +41,7 @@ import { SharedModule } from '../shared' | |||
38 | ], | 41 | ], |
39 | 42 | ||
40 | providers: [ | 43 | providers: [ |
41 | FriendService, | 44 | FollowService, |
42 | UserService | 45 | UserService |
43 | ] | 46 | ] |
44 | }) | 47 | }) |
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 new file mode 100644 index 000000000..24d75d2b3 --- /dev/null +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.html | |||
@@ -0,0 +1,16 @@ | |||
1 | <div class="row"> | ||
2 | <div class="content-padding"> | ||
3 | <h3>Followers list</h3> | ||
4 | |||
5 | <p-dataTable | ||
6 | [value]="followers" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" | ||
7 | sortField="createdAt" (onLazyLoad)="loadLazy($event)" | ||
8 | > | ||
9 | <p-column field="id" header="ID"></p-column> | ||
10 | <p-column field="host" header="Host"></p-column> | ||
11 | <p-column field="email" header="Email"></p-column> | ||
12 | <p-column field="score" header="Score"></p-column> | ||
13 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> | ||
14 | </p-dataTable> | ||
15 | </div> | ||
16 | </div> | ||
diff --git a/client/src/app/+admin/friends/friend-list/friend-list.component.scss b/client/src/app/+admin/follows/followers-list/followers-list.component.scss index 0a0f621c6..0a0f621c6 100644 --- a/client/src/app/+admin/friends/friend-list/friend-list.component.scss +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.scss | |||
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.ts b/client/src/app/+admin/follows/followers-list/followers-list.component.ts new file mode 100644 index 000000000..208a0c648 --- /dev/null +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.ts | |||
@@ -0,0 +1,41 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | |||
3 | import { NotificationsService } from 'angular2-notifications' | ||
4 | import { SortMeta } from 'primeng/primeng' | ||
5 | |||
6 | import { ConfirmService } from '../../../core' | ||
7 | import { RestTable, RestPagination } from '../../../shared' | ||
8 | import { Pod } from '../../../../../../shared' | ||
9 | import { FollowService } from '../shared' | ||
10 | |||
11 | @Component({ | ||
12 | selector: 'my-followers-list', | ||
13 | templateUrl: './followers-list.component.html', | ||
14 | styleUrls: [ './followers-list.component.scss' ] | ||
15 | }) | ||
16 | export class FollowersListComponent extends RestTable { | ||
17 | followers: Pod[] = [] | ||
18 | totalRecords = 0 | ||
19 | rowsPerPage = 10 | ||
20 | sort: SortMeta = { field: 'createdAt', order: 1 } | ||
21 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
22 | |||
23 | constructor ( | ||
24 | private notificationsService: NotificationsService, | ||
25 | private followService: FollowService | ||
26 | ) { | ||
27 | super() | ||
28 | } | ||
29 | |||
30 | protected loadData () { | ||
31 | this.followService.getFollowers(this.pagination, this.sort) | ||
32 | .subscribe( | ||
33 | resultList => { | ||
34 | this.followers = resultList.data | ||
35 | this.totalRecords = resultList.total | ||
36 | }, | ||
37 | |||
38 | err => this.notificationsService.error('Error', err.message) | ||
39 | ) | ||
40 | } | ||
41 | } | ||
diff --git a/client/src/app/+admin/follows/followers-list/index.ts b/client/src/app/+admin/follows/followers-list/index.ts new file mode 100644 index 000000000..15390cfbe --- /dev/null +++ b/client/src/app/+admin/follows/followers-list/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './followers-list.component' | |||
diff --git a/client/src/app/+admin/friends/friend-add/friend-add.component.html b/client/src/app/+admin/follows/following-add/following-add.component.html index 81d8291cd..111f6a8de 100644 --- a/client/src/app/+admin/friends/friend-add/friend-add.component.html +++ b/client/src/app/+admin/follows/following-add/following-add.component.html | |||
@@ -1,11 +1,11 @@ | |||
1 | <div class="row"> | 1 | <div class="row"> |
2 | <div class="content-padding"> | 2 | <div class="content-padding"> |
3 | 3 | ||
4 | <h3>Make friends</h3> | 4 | <h3>Add following</h3> |
5 | 5 | ||
6 | <div *ngIf="error" class="alert alert-danger">{{ error }}</div> | 6 | <div *ngIf="error" class="alert alert-danger">{{ error }}</div> |
7 | 7 | ||
8 | <form (ngSubmit)="makeFriends()" [formGroup]="form"> | 8 | <form (ngSubmit)="addFollowing()" [formGroup]="form"> |
9 | <div class="form-group" *ngFor="let host of hosts; let id = index; trackBy:customTrackBy"> | 9 | <div class="form-group" *ngFor="let host of hosts; let id = index; trackBy:customTrackBy"> |
10 | <label [for]="'host-' + id">Host (so without "http://")</label> | 10 | <label [for]="'host-' + id">Host (so without "http://")</label> |
11 | 11 | ||
@@ -26,10 +26,10 @@ | |||
26 | </div> | 26 | </div> |
27 | 27 | ||
28 | <div *ngIf="canMakeFriends() === false" class="alert alert-warning"> | 28 | <div *ngIf="canMakeFriends() === false" class="alert alert-warning"> |
29 | It seems that you are not on a HTTPS pod. Your webserver need to have TLS activated in order to make friends. | 29 | It seems that you are not on a HTTPS pod. Your webserver need to have TLS activated in order to follow servers. |
30 | </div> | 30 | </div> |
31 | 31 | ||
32 | <input type="submit" value="Make friends" class="btn btn-default" [disabled]="!isFormValid()"> | 32 | <input type="submit" value="Add following" class="btn btn-default" [disabled]="!isFormValid()"> |
33 | </form> | 33 | </form> |
34 | </div> | 34 | </div> |
35 | </div> | 35 | </div> |
diff --git a/client/src/app/+admin/friends/friend-add/friend-add.component.scss b/client/src/app/+admin/follows/following-add/following-add.component.scss index 5fde51636..5fde51636 100644 --- a/client/src/app/+admin/friends/friend-add/friend-add.component.scss +++ b/client/src/app/+admin/follows/following-add/following-add.component.scss | |||
diff --git a/client/src/app/+admin/friends/friend-add/friend-add.component.ts b/client/src/app/+admin/follows/following-add/following-add.component.ts index 29ed23e0c..d95d6afa9 100644 --- a/client/src/app/+admin/friends/friend-add/friend-add.component.ts +++ b/client/src/app/+admin/follows/following-add/following-add.component.ts | |||
@@ -6,14 +6,14 @@ import { NotificationsService } from 'angular2-notifications' | |||
6 | 6 | ||
7 | import { ConfirmService } from '../../../core' | 7 | import { ConfirmService } from '../../../core' |
8 | import { validateHost } from '../../../shared' | 8 | import { validateHost } from '../../../shared' |
9 | import { FriendService } from '../shared' | 9 | import { FollowService } from '../shared' |
10 | 10 | ||
11 | @Component({ | 11 | @Component({ |
12 | selector: 'my-friend-add', | 12 | selector: 'my-following-add', |
13 | templateUrl: './friend-add.component.html', | 13 | templateUrl: './following-add.component.html', |
14 | styleUrls: [ './friend-add.component.scss' ] | 14 | styleUrls: [ './following-add.component.scss' ] |
15 | }) | 15 | }) |
16 | export class FriendAddComponent implements OnInit { | 16 | export class FollowingAddComponent implements OnInit { |
17 | form: FormGroup | 17 | form: FormGroup |
18 | hosts: string[] = [ ] | 18 | hosts: string[] = [ ] |
19 | error: string = null | 19 | error: string = null |
@@ -22,7 +22,7 @@ export class FriendAddComponent implements OnInit { | |||
22 | private router: Router, | 22 | private router: Router, |
23 | private notificationsService: NotificationsService, | 23 | private notificationsService: NotificationsService, |
24 | private confirmService: ConfirmService, | 24 | private confirmService: ConfirmService, |
25 | private friendService: FriendService | 25 | private followService: FollowService |
26 | ) {} | 26 | ) {} |
27 | 27 | ||
28 | ngOnInit () { | 28 | ngOnInit () { |
@@ -72,7 +72,7 @@ export class FriendAddComponent implements OnInit { | |||
72 | this.hosts.splice(index, 1) | 72 | this.hosts.splice(index, 1) |
73 | } | 73 | } |
74 | 74 | ||
75 | makeFriends () { | 75 | addFollowing () { |
76 | this.error = '' | 76 | this.error = '' |
77 | 77 | ||
78 | const notEmptyHosts = this.getNotEmptyHosts() | 78 | const notEmptyHosts = this.getNotEmptyHosts() |
@@ -87,13 +87,13 @@ export class FriendAddComponent implements OnInit { | |||
87 | } | 87 | } |
88 | 88 | ||
89 | const confirmMessage = 'Are you sure to make friends with:<br /> - ' + notEmptyHosts.join('<br /> - ') | 89 | const confirmMessage = 'Are you sure to make friends with:<br /> - ' + notEmptyHosts.join('<br /> - ') |
90 | this.confirmService.confirm(confirmMessage, 'Make friends').subscribe( | 90 | this.confirmService.confirm(confirmMessage, 'Follow new server(s)').subscribe( |
91 | res => { | 91 | res => { |
92 | if (res === false) return | 92 | if (res === false) return |
93 | 93 | ||
94 | this.friendService.follow(notEmptyHosts).subscribe( | 94 | this.followService.follow(notEmptyHosts).subscribe( |
95 | status => { | 95 | status => { |
96 | this.notificationsService.success('Success', 'Make friends request sent!') | 96 | this.notificationsService.success('Success', 'Follow request(s) sent!') |
97 | // Wait requests between pods | 97 | // Wait requests between pods |
98 | setTimeout(() => this.router.navigate([ '/admin/friends/list' ]), 1000) | 98 | setTimeout(() => this.router.navigate([ '/admin/friends/list' ]), 1000) |
99 | }, | 99 | }, |
diff --git a/client/src/app/+admin/follows/following-add/index.ts b/client/src/app/+admin/follows/following-add/index.ts new file mode 100644 index 000000000..1b1897ffa --- /dev/null +++ b/client/src/app/+admin/follows/following-add/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './following-add.component' | |||
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 new file mode 100644 index 000000000..fbcebfaa7 --- /dev/null +++ b/client/src/app/+admin/follows/following-list/following-list.component.html | |||
@@ -0,0 +1,16 @@ | |||
1 | <div class="row"> | ||
2 | <div class="content-padding"> | ||
3 | <h3>Following list</h3> | ||
4 | |||
5 | <p-dataTable | ||
6 | [value]="following" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" | ||
7 | sortField="createdAt" (onLazyLoad)="loadLazy($event)" | ||
8 | > | ||
9 | <p-column field="id" header="ID"></p-column> | ||
10 | <p-column field="host" header="Host"></p-column> | ||
11 | <p-column field="email" header="Email"></p-column> | ||
12 | <p-column field="score" header="Score"></p-column> | ||
13 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> | ||
14 | </p-dataTable> | ||
15 | </div> | ||
16 | </div> | ||
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 new file mode 100644 index 000000000..7d2c5084b --- /dev/null +++ b/client/src/app/+admin/follows/following-list/following-list.component.ts | |||
@@ -0,0 +1,40 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | |||
3 | import { NotificationsService } from 'angular2-notifications' | ||
4 | import { SortMeta } from 'primeng/primeng' | ||
5 | |||
6 | import { ConfirmService } from '../../../core' | ||
7 | import { RestTable, RestPagination } from '../../../shared' | ||
8 | import { Pod } from '../../../../../../shared' | ||
9 | import { FollowService } from '../shared' | ||
10 | |||
11 | @Component({ | ||
12 | selector: 'my-followers-list', | ||
13 | templateUrl: './following-list.component.html' | ||
14 | }) | ||
15 | export class FollowingListComponent extends RestTable { | ||
16 | following: Pod[] = [] | ||
17 | totalRecords = 0 | ||
18 | rowsPerPage = 10 | ||
19 | sort: SortMeta = { field: 'createdAt', order: 1 } | ||
20 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
21 | |||
22 | constructor ( | ||
23 | private notificationsService: NotificationsService, | ||
24 | private followService: FollowService | ||
25 | ) { | ||
26 | super() | ||
27 | } | ||
28 | |||
29 | protected loadData () { | ||
30 | this.followService.getFollowing(this.pagination, this.sort) | ||
31 | .subscribe( | ||
32 | resultList => { | ||
33 | this.following = resultList.data | ||
34 | this.totalRecords = resultList.total | ||
35 | }, | ||
36 | |||
37 | err => this.notificationsService.error('Error', err.message) | ||
38 | ) | ||
39 | } | ||
40 | } | ||
diff --git a/client/src/app/+admin/follows/following-list/index.ts b/client/src/app/+admin/follows/following-list/index.ts new file mode 100644 index 000000000..a70d46a7e --- /dev/null +++ b/client/src/app/+admin/follows/following-list/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './following-list.component' | |||
diff --git a/client/src/app/+admin/follows/follows.component.html b/client/src/app/+admin/follows/follows.component.html new file mode 100644 index 000000000..b67bc9736 --- /dev/null +++ b/client/src/app/+admin/follows/follows.component.html | |||
@@ -0,0 +1,11 @@ | |||
1 | <div class="follows-menu"> | ||
2 | <tabset #followsMenuTabs> | ||
3 | <tab *ngFor="let link of links"> | ||
4 | <ng-template tabHeading> | ||
5 | <a class="tab-link" [routerLink]="link.path">{{ link.title }}</a> | ||
6 | </ng-template> | ||
7 | </tab> | ||
8 | </tabset> | ||
9 | </div> | ||
10 | |||
11 | <router-outlet></router-outlet> | ||
diff --git a/client/src/app/+admin/follows/follows.component.scss b/client/src/app/+admin/follows/follows.component.scss new file mode 100644 index 000000000..d8ab41975 --- /dev/null +++ b/client/src/app/+admin/follows/follows.component.scss | |||
@@ -0,0 +1,21 @@ | |||
1 | .follows-menu { | ||
2 | margin-top: 20px; | ||
3 | } | ||
4 | |||
5 | tabset /deep/ { | ||
6 | .nav-link { | ||
7 | padding: 0; | ||
8 | } | ||
9 | |||
10 | .tab-link { | ||
11 | display: block; | ||
12 | text-align: center; | ||
13 | height: 40px; | ||
14 | width: 120px; | ||
15 | line-height: 40px; | ||
16 | |||
17 | &:hover, &:active, &:focus { | ||
18 | text-decoration: none !important; | ||
19 | } | ||
20 | } | ||
21 | } | ||
diff --git a/client/src/app/+admin/follows/follows.component.ts b/client/src/app/+admin/follows/follows.component.ts new file mode 100644 index 000000000..97422a41b --- /dev/null +++ b/client/src/app/+admin/follows/follows.component.ts | |||
@@ -0,0 +1,43 @@ | |||
1 | import { AfterViewInit, Component, ViewChild } from '@angular/core' | ||
2 | import { TabsetComponent } from 'ngx-bootstrap/tabs' | ||
3 | |||
4 | @Component({ | ||
5 | templateUrl: './follows.component.html', | ||
6 | styleUrls: [ './follows.component.scss' ] | ||
7 | }) | ||
8 | export class FollowsComponent implements AfterViewInit { | ||
9 | @ViewChild('followsMenuTabs') followsMenuTabs: TabsetComponent | ||
10 | |||
11 | links = [ | ||
12 | { | ||
13 | path: 'following-list', | ||
14 | title: 'Following' | ||
15 | }, | ||
16 | { | ||
17 | path: 'following-add', | ||
18 | title: 'Follow' | ||
19 | }, | ||
20 | { | ||
21 | path: 'followers-list', | ||
22 | title: 'Followers' | ||
23 | } | ||
24 | ] | ||
25 | |||
26 | ngAfterViewInit () { | ||
27 | // Avoid issue with change detector | ||
28 | setTimeout(() => this.updateActiveTab()) | ||
29 | } | ||
30 | |||
31 | private updateActiveTab () { | ||
32 | const url = window.location.pathname | ||
33 | |||
34 | for (let i = 0; i < this.links.length; i++) { | ||
35 | const path = this.links[i].path | ||
36 | |||
37 | if (url.endsWith(path) === true) { | ||
38 | this.followsMenuTabs.tabs[i].active = true | ||
39 | return | ||
40 | } | ||
41 | } | ||
42 | } | ||
43 | } | ||
diff --git a/client/src/app/+admin/follows/follows.routes.ts b/client/src/app/+admin/follows/follows.routes.ts new file mode 100644 index 000000000..b7d44f75b --- /dev/null +++ b/client/src/app/+admin/follows/follows.routes.ts | |||
@@ -0,0 +1,53 @@ | |||
1 | import { Routes } from '@angular/router' | ||
2 | |||
3 | import { UserRightGuard } from '../../core' | ||
4 | import { FollowsComponent } from './follows.component' | ||
5 | import { FollowingAddComponent } from './following-add' | ||
6 | import { FollowersListComponent } from './followers-list' | ||
7 | import { UserRight } from '../../../../../shared' | ||
8 | import { FollowingListComponent } from './following-list/following-list.component' | ||
9 | |||
10 | export const FollowsRoutes: Routes = [ | ||
11 | { | ||
12 | path: 'follows', | ||
13 | component: FollowsComponent, | ||
14 | canActivate: [ UserRightGuard ], | ||
15 | data: { | ||
16 | userRight: UserRight.MANAGE_APPLICATION_FOLLOW | ||
17 | }, | ||
18 | children: [ | ||
19 | { | ||
20 | path: '', | ||
21 | redirectTo: 'following-list', | ||
22 | pathMatch: 'full' | ||
23 | }, | ||
24 | { | ||
25 | path: 'following-list', | ||
26 | component: FollowingListComponent, | ||
27 | data: { | ||
28 | meta: { | ||
29 | title: 'Following list' | ||
30 | } | ||
31 | } | ||
32 | }, | ||
33 | { | ||
34 | path: 'followers-list', | ||
35 | component: FollowersListComponent, | ||
36 | data: { | ||
37 | meta: { | ||
38 | title: 'Followers list' | ||
39 | } | ||
40 | } | ||
41 | }, | ||
42 | { | ||
43 | path: 'following-add', | ||
44 | component: FollowingAddComponent, | ||
45 | data: { | ||
46 | meta: { | ||
47 | title: 'Add follow' | ||
48 | } | ||
49 | } | ||
50 | } | ||
51 | ] | ||
52 | } | ||
53 | ] | ||
diff --git a/client/src/app/+admin/follows/index.ts b/client/src/app/+admin/follows/index.ts new file mode 100644 index 000000000..7849a06e7 --- /dev/null +++ b/client/src/app/+admin/follows/index.ts | |||
@@ -0,0 +1,6 @@ | |||
1 | export * from './following-add' | ||
2 | export * from './followers-list' | ||
3 | export * from './following-list' | ||
4 | export * from './shared' | ||
5 | export * from './follows.component' | ||
6 | export * from './follows.routes' | ||
diff --git a/client/src/app/+admin/friends/shared/friend.service.ts b/client/src/app/+admin/follows/shared/follow.service.ts index 867656a53..622c33cea 100644 --- a/client/src/app/+admin/friends/shared/friend.service.ts +++ b/client/src/app/+admin/follows/shared/follow.service.ts | |||
@@ -10,8 +10,8 @@ import { RestExtractor, RestPagination, RestService } from '../../../shared' | |||
10 | import { Pod, ResultList } from '../../../../../../shared' | 10 | import { Pod, ResultList } from '../../../../../../shared' |
11 | 11 | ||
12 | @Injectable() | 12 | @Injectable() |
13 | export class FriendService { | 13 | export class FollowService { |
14 | private static BASE_FRIEND_URL = API_URL + '/api/v1/pods/' | 14 | private static BASE_APPLICATION_URL = API_URL + '/api/v1/application' |
15 | 15 | ||
16 | constructor ( | 16 | constructor ( |
17 | private authHttp: HttpClient, | 17 | private authHttp: HttpClient, |
@@ -23,29 +23,26 @@ export class FriendService { | |||
23 | let params = new HttpParams() | 23 | let params = new HttpParams() |
24 | params = this.restService.addRestGetParams(params, pagination, sort) | 24 | params = this.restService.addRestGetParams(params, pagination, sort) |
25 | 25 | ||
26 | return this.authHttp.get<ResultList<Account>>(API_URL + '/api/v1/pods/followers', { params }) | 26 | return this.authHttp.get<ResultList<Account>>(FollowService.BASE_APPLICATION_URL + '/following', { params }) |
27 | .map(res => this.restExtractor.convertResultListDateToHuman(res)) | 27 | .map(res => this.restExtractor.convertResultListDateToHuman(res)) |
28 | .catch(res => this.restExtractor.handleError(res)) | 28 | .catch(res => this.restExtractor.handleError(res)) |
29 | } | 29 | } |
30 | 30 | ||
31 | getFollowers (pagination: RestPagination, sort: SortMeta): Observable<ResultList<Pod>> { | ||
32 | let params = new HttpParams() | ||
33 | params = this.restService.addRestGetParams(params, pagination, sort) | ||
34 | |||
35 | return this.authHttp.get<ResultList<Account>>(FollowService.BASE_APPLICATION_URL + '/followers', { params }) | ||
36 | .map(res => this.restExtractor.convertResultListDateToHuman(res)) | ||
37 | .catch(res => this.restExtractor.handleError(res)) | ||
38 | } | ||
39 | |||
31 | follow (notEmptyHosts: String[]) { | 40 | follow (notEmptyHosts: String[]) { |
32 | const body = { | 41 | const body = { |
33 | hosts: notEmptyHosts | 42 | hosts: notEmptyHosts |
34 | } | 43 | } |
35 | 44 | ||
36 | return this.authHttp.post(API_URL + '/api/v1/pods/follow', body) | 45 | return this.authHttp.post(FollowService.BASE_APPLICATION_URL + '/follow', body) |
37 | .map(this.restExtractor.extractDataBool) | ||
38 | .catch(res => this.restExtractor.handleError(res)) | ||
39 | } | ||
40 | |||
41 | quitFriends () { | ||
42 | return this.authHttp.get(FriendService.BASE_FRIEND_URL + 'quit-friends') | ||
43 | .map(this.restExtractor.extractDataBool) | ||
44 | .catch(res => this.restExtractor.handleError(res)) | ||
45 | } | ||
46 | |||
47 | removeFriend (friend: Pod) { | ||
48 | return this.authHttp.delete(FriendService.BASE_FRIEND_URL + friend.id) | ||
49 | .map(this.restExtractor.extractDataBool) | 46 | .map(this.restExtractor.extractDataBool) |
50 | .catch(res => this.restExtractor.handleError(res)) | 47 | .catch(res => this.restExtractor.handleError(res)) |
51 | } | 48 | } |
diff --git a/client/src/app/+admin/follows/shared/index.ts b/client/src/app/+admin/follows/shared/index.ts new file mode 100644 index 000000000..78d456def --- /dev/null +++ b/client/src/app/+admin/follows/shared/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './follow.service' | |||
diff --git a/client/src/app/+admin/friends/friend-add/index.ts b/client/src/app/+admin/friends/friend-add/index.ts deleted file mode 100644 index 978ab3d46..000000000 --- a/client/src/app/+admin/friends/friend-add/index.ts +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | export * from './friend-add.component' | ||
diff --git a/client/src/app/+admin/friends/friend-list/friend-list.component.html b/client/src/app/+admin/friends/friend-list/friend-list.component.html deleted file mode 100644 index df5a570fd..000000000 --- a/client/src/app/+admin/friends/friend-list/friend-list.component.html +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | <div class="row"> | ||
2 | <div class="content-padding"> | ||
3 | <h3>Friends list</h3> | ||
4 | |||
5 | <p-dataTable | ||
6 | [value]="friends" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" | ||
7 | sortField="createdAt" (onLazyLoad)="loadLazy($event)" | ||
8 | > | ||
9 | <p-column field="id" header="ID"></p-column> | ||
10 | <p-column field="host" header="Host"></p-column> | ||
11 | <p-column field="email" header="Email"></p-column> | ||
12 | <p-column field="score" header="Score"></p-column> | ||
13 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> | ||
14 | <p-column header="Delete" styleClass="action-cell"> | ||
15 | <ng-template pTemplate="body" let-pod="rowData"> | ||
16 | <span (click)="removeFriend(pod)" class="glyphicon glyphicon-remove glyphicon-black" title="Remove this pod"></span> | ||
17 | </ng-template> | ||
18 | </p-column> | ||
19 | </p-dataTable> | ||
20 | |||
21 | <a *ngIf="hasFriends()" class="btn btn-danger pull-left" (click)="quitFriends()"> | ||
22 | Quit friends | ||
23 | </a> | ||
24 | |||
25 | <a *ngIf="!hasFriends()" class="btn btn-success pull-right" [routerLink]="[ '/admin/friends/add' ]"> | ||
26 | Make friends | ||
27 | </a> | ||
28 | </div> | ||
29 | </div> | ||
diff --git a/client/src/app/+admin/friends/friend-list/friend-list.component.ts b/client/src/app/+admin/friends/friend-list/friend-list.component.ts deleted file mode 100644 index 3fa8ef19f..000000000 --- a/client/src/app/+admin/friends/friend-list/friend-list.component.ts +++ /dev/null | |||
@@ -1,87 +0,0 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | |||
3 | import { NotificationsService } from 'angular2-notifications' | ||
4 | import { SortMeta } from 'primeng/primeng' | ||
5 | |||
6 | import { ConfirmService } from '../../../core' | ||
7 | import { RestTable, RestPagination } from '../../../shared' | ||
8 | import { Pod } from '../../../../../../shared' | ||
9 | import { FriendService } from '../shared' | ||
10 | |||
11 | @Component({ | ||
12 | selector: 'my-friend-list', | ||
13 | templateUrl: './friend-list.component.html', | ||
14 | styleUrls: ['./friend-list.component.scss'] | ||
15 | }) | ||
16 | export class FriendListComponent extends RestTable implements OnInit { | ||
17 | friends: Pod[] = [] | ||
18 | totalRecords = 0 | ||
19 | rowsPerPage = 10 | ||
20 | sort: SortMeta = { field: 'createdAt', order: 1 } | ||
21 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
22 | |||
23 | constructor ( | ||
24 | private notificationsService: NotificationsService, | ||
25 | private confirmService: ConfirmService, | ||
26 | private friendService: FriendService | ||
27 | ) { | ||
28 | super() | ||
29 | } | ||
30 | |||
31 | ngOnInit () { | ||
32 | this.loadData() | ||
33 | } | ||
34 | |||
35 | hasFriends () { | ||
36 | return this.friends.length !== 0 | ||
37 | } | ||
38 | |||
39 | quitFriends () { | ||
40 | const confirmMessage = 'Do you really want to quit your friends? All their videos will be deleted.' | ||
41 | this.confirmService.confirm(confirmMessage, 'Quit friends').subscribe( | ||
42 | res => { | ||
43 | if (res === false) return | ||
44 | |||
45 | this.friendService.quitFriends().subscribe( | ||
46 | status => { | ||
47 | this.notificationsService.success('Success', 'Friends left!') | ||
48 | this.loadData() | ||
49 | }, | ||
50 | |||
51 | err => this.notificationsService.error('Error', err.message) | ||
52 | ) | ||
53 | } | ||
54 | ) | ||
55 | } | ||
56 | |||
57 | removeFriend (friend: Pod) { | ||
58 | const confirmMessage = 'Do you really want to remove this friend ? All its videos will be deleted.' | ||
59 | |||
60 | this.confirmService.confirm(confirmMessage, 'Remove').subscribe( | ||
61 | res => { | ||
62 | if (res === false) return | ||
63 | |||
64 | this.friendService.removeFriend(friend).subscribe( | ||
65 | status => { | ||
66 | this.notificationsService.success('Success', 'Friend removed') | ||
67 | this.loadData() | ||
68 | }, | ||
69 | |||
70 | err => this.notificationsService.error('Error', err.message) | ||
71 | ) | ||
72 | } | ||
73 | ) | ||
74 | } | ||
75 | |||
76 | protected loadData () { | ||
77 | this.friendService.getFollowing(this.pagination, this.sort) | ||
78 | .subscribe( | ||
79 | resultList => { | ||
80 | this.friends = resultList.data | ||
81 | this.totalRecords = resultList.total | ||
82 | }, | ||
83 | |||
84 | err => this.notificationsService.error('Error', err.message) | ||
85 | ) | ||
86 | } | ||
87 | } | ||
diff --git a/client/src/app/+admin/friends/friend-list/index.ts b/client/src/app/+admin/friends/friend-list/index.ts deleted file mode 100644 index c9cbd2800..000000000 --- a/client/src/app/+admin/friends/friend-list/index.ts +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | export * from './friend-list.component' | ||
diff --git a/client/src/app/+admin/friends/friends.component.ts b/client/src/app/+admin/friends/friends.component.ts deleted file mode 100644 index 5ef0aaa03..000000000 --- a/client/src/app/+admin/friends/friends.component.ts +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | import { Component } from '@angular/core' | ||
2 | |||
3 | @Component({ | ||
4 | template: '<router-outlet></router-outlet>' | ||
5 | }) | ||
6 | export class FriendsComponent { | ||
7 | } | ||
diff --git a/client/src/app/+admin/friends/friends.routes.ts b/client/src/app/+admin/friends/friends.routes.ts deleted file mode 100644 index e2cb953b3..000000000 --- a/client/src/app/+admin/friends/friends.routes.ts +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | import { Routes } from '@angular/router' | ||
2 | |||
3 | import { UserRightGuard } from '../../core' | ||
4 | import { FriendsComponent } from './friends.component' | ||
5 | import { FriendAddComponent } from './friend-add' | ||
6 | import { FriendListComponent } from './friend-list' | ||
7 | import { UserRight } from '../../../../../shared' | ||
8 | |||
9 | export const FriendsRoutes: Routes = [ | ||
10 | { | ||
11 | path: 'friends', | ||
12 | component: FriendsComponent, | ||
13 | canActivate: [ UserRightGuard ], | ||
14 | data: { | ||
15 | userRight: UserRight.MANAGE_PEERTUBE_FOLLOW | ||
16 | }, | ||
17 | children: [ | ||
18 | { | ||
19 | path: '', | ||
20 | redirectTo: 'list', | ||
21 | pathMatch: 'full' | ||
22 | }, | ||
23 | { | ||
24 | path: 'list', | ||
25 | component: FriendListComponent, | ||
26 | data: { | ||
27 | meta: { | ||
28 | title: 'Friends list' | ||
29 | } | ||
30 | } | ||
31 | }, | ||
32 | { | ||
33 | path: 'add', | ||
34 | component: FriendAddComponent, | ||
35 | data: { | ||
36 | meta: { | ||
37 | title: 'Add friends' | ||
38 | } | ||
39 | } | ||
40 | } | ||
41 | ] | ||
42 | } | ||
43 | ] | ||
diff --git a/client/src/app/+admin/friends/index.ts b/client/src/app/+admin/friends/index.ts deleted file mode 100644 index 356dee8e9..000000000 --- a/client/src/app/+admin/friends/index.ts +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | export * from './friend-add' | ||
2 | export * from './friend-list' | ||
3 | export * from './shared' | ||
4 | export * from './friends.component' | ||
5 | export * from './friends.routes' | ||
diff --git a/client/src/app/+admin/friends/shared/index.ts b/client/src/app/+admin/friends/shared/index.ts deleted file mode 100644 index 65ab9fb46..000000000 --- a/client/src/app/+admin/friends/shared/index.ts +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | export * from './friend.service' | ||
diff --git a/client/src/app/core/menu/menu-admin.component.html b/client/src/app/core/menu/menu-admin.component.html index 1966a944c..99ee287c5 100644 --- a/client/src/app/core/menu/menu-admin.component.html +++ b/client/src/app/core/menu/menu-admin.component.html | |||
@@ -5,9 +5,9 @@ | |||
5 | List users | 5 | List users |
6 | </a> | 6 | </a> |
7 | 7 | ||
8 | <a *ngIf="hasFriendsRight()" routerLink="/admin/friends" routerLinkActive="active"> | 8 | <a *ngIf="hasApplicationFollowRight()" routerLink="/admin/follows" routerLinkActive="active"> |
9 | <span class="hidden-xs glyphicon glyphicon-cloud"></span> | 9 | <span class="hidden-xs glyphicon glyphicon-cloud"></span> |
10 | List friends | 10 | Manage follows |
11 | </a> | 11 | </a> |
12 | 12 | ||
13 | <a *ngIf="hasVideoAbusesRight()" routerLink="/admin/video-abuses" routerLinkActive="active"> | 13 | <a *ngIf="hasVideoAbusesRight()" routerLink="/admin/video-abuses" routerLinkActive="active"> |
diff --git a/client/src/app/core/menu/menu-admin.component.ts b/client/src/app/core/menu/menu-admin.component.ts index 92aab9a05..88a654d1f 100644 --- a/client/src/app/core/menu/menu-admin.component.ts +++ b/client/src/app/core/menu/menu-admin.component.ts | |||
@@ -15,8 +15,8 @@ export class MenuAdminComponent { | |||
15 | return this.auth.getUser().hasRight(UserRight.MANAGE_USERS) | 15 | return this.auth.getUser().hasRight(UserRight.MANAGE_USERS) |
16 | } | 16 | } |
17 | 17 | ||
18 | hasFriendsRight () { | 18 | hasApplicationFollowRight () { |
19 | return this.auth.getUser().hasRight(UserRight.MANAGE_PEERTUBE_FOLLOW) | 19 | return this.auth.getUser().hasRight(UserRight.MANAGE_APPLICATION_FOLLOW) |
20 | } | 20 | } |
21 | 21 | ||
22 | hasVideoAbusesRight () { | 22 | hasVideoAbusesRight () { |
diff --git a/client/src/app/core/menu/menu.component.ts b/client/src/app/core/menu/menu.component.ts index 71295be86..872d29819 100644 --- a/client/src/app/core/menu/menu.component.ts +++ b/client/src/app/core/menu/menu.component.ts | |||
@@ -16,7 +16,7 @@ export class MenuComponent implements OnInit { | |||
16 | 16 | ||
17 | private routesPerRight = { | 17 | private routesPerRight = { |
18 | [UserRight.MANAGE_USERS]: '/admin/users', | 18 | [UserRight.MANAGE_USERS]: '/admin/users', |
19 | [UserRight.MANAGE_PEERTUBE_FOLLOW]: '/admin/friends', | 19 | [UserRight.MANAGE_APPLICATION_FOLLOW]: '/admin/friends', |
20 | [UserRight.MANAGE_VIDEO_ABUSES]: '/admin/video-abuses', | 20 | [UserRight.MANAGE_VIDEO_ABUSES]: '/admin/video-abuses', |
21 | [UserRight.MANAGE_VIDEO_BLACKLIST]: '/admin/video-blacklist' | 21 | [UserRight.MANAGE_VIDEO_BLACKLIST]: '/admin/video-blacklist' |
22 | } | 22 | } |
@@ -58,7 +58,7 @@ export class MenuComponent implements OnInit { | |||
58 | 58 | ||
59 | const adminRights = [ | 59 | const adminRights = [ |
60 | UserRight.MANAGE_USERS, | 60 | UserRight.MANAGE_USERS, |
61 | UserRight.MANAGE_PEERTUBE_FOLLOW, | 61 | UserRight.MANAGE_APPLICATION_FOLLOW, |
62 | UserRight.MANAGE_VIDEO_ABUSES, | 62 | UserRight.MANAGE_VIDEO_ABUSES, |
63 | UserRight.MANAGE_VIDEO_BLACKLIST | 63 | UserRight.MANAGE_VIDEO_BLACKLIST |
64 | ] | 64 | ] |
diff --git a/scripts/update-host.ts b/scripts/update-host.ts index 7c46dc52b..05f0ef96d 100755 --- a/scripts/update-host.ts +++ b/scripts/update-host.ts | |||
@@ -3,7 +3,7 @@ import { database as db } from '../server/initializers/database' | |||
3 | 3 | ||
4 | db.init(true) | 4 | db.init(true) |
5 | .then(() => { | 5 | .then(() => { |
6 | // FIXME: check if has followers | 6 | // FIXME: check if has following |
7 | // return hasFriends() | 7 | // return hasFriends() |
8 | return true | 8 | return true |
9 | }) | 9 | }) |
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts index 56a4054fa..49dd24e79 100644 --- a/server/controllers/activitypub/client.ts +++ b/server/controllers/activitypub/client.ts | |||
@@ -46,7 +46,7 @@ async function accountFollowersController (req: express.Request, res: express.Re | |||
46 | const page = req.params.page || 1 | 46 | const page = req.params.page || 1 |
47 | const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE) | 47 | const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE) |
48 | 48 | ||
49 | const result = await db.Account.listAcceptedFollowerUrlsForApi(account.id, start, count) | 49 | const result = await db.AccountFollow.listAcceptedFollowerUrlsForApi(account.id, start, count) |
50 | const activityPubResult = activityPubCollectionPagination(req.url, page, result) | 50 | const activityPubResult = activityPubCollectionPagination(req.url, page, result) |
51 | 51 | ||
52 | return res.json(activityPubResult) | 52 | return res.json(activityPubResult) |
@@ -58,7 +58,7 @@ async function accountFollowingController (req: express.Request, res: express.Re | |||
58 | const page = req.params.page || 1 | 58 | const page = req.params.page || 1 |
59 | const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE) | 59 | const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE) |
60 | 60 | ||
61 | const result = await db.Account.listAcceptedFollowingUrlsForApi(account.id, start, count) | 61 | const result = await db.AccountFollow.listAcceptedFollowingUrlsForApi(account.id, start, count) |
62 | const activityPubResult = activityPubCollectionPagination(req.url, page, result) | 62 | const activityPubResult = activityPubCollectionPagination(req.url, page, result) |
63 | 63 | ||
64 | return res.json(activityPubResult) | 64 | return res.json(activityPubResult) |
diff --git a/server/controllers/activitypub/index.ts b/server/controllers/activitypub/index.ts index 0c8574ef7..c5bec6448 100644 --- a/server/controllers/activitypub/index.ts +++ b/server/controllers/activitypub/index.ts | |||
@@ -1,14 +1,11 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | |||
3 | import { badRequest } from '../../helpers' | ||
4 | import { inboxRouter } from './inbox' | ||
5 | import { activityPubClientRouter } from './client' | 2 | import { activityPubClientRouter } from './client' |
3 | import { inboxRouter } from './inbox' | ||
6 | 4 | ||
7 | const activityPubRouter = express.Router() | 5 | const activityPubRouter = express.Router() |
8 | 6 | ||
9 | activityPubRouter.use('/', inboxRouter) | 7 | activityPubRouter.use('/', inboxRouter) |
10 | activityPubRouter.use('/', activityPubClientRouter) | 8 | activityPubRouter.use('/', activityPubClientRouter) |
11 | activityPubRouter.use('/*', badRequest) | ||
12 | 9 | ||
13 | // --------------------------------------------------------------------------- | 10 | // --------------------------------------------------------------------------- |
14 | 11 | ||
diff --git a/server/controllers/api/pods.ts b/server/controllers/api/application/follows.ts index 0bd6971bb..000bbd23e 100644 --- a/server/controllers/api/pods.ts +++ b/server/controllers/api/application/follows.ts | |||
@@ -1,23 +1,23 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { UserRight } from '../../../shared/models/users/user-right.enum' | 2 | import { UserRight } from '../../../../shared/models/users/user-right.enum' |
3 | import { getFormattedObjects } from '../../helpers' | 3 | import { getFormattedObjects } from '../../../helpers' |
4 | import { logger } from '../../helpers/logger' | 4 | import { logger } from '../../../helpers/logger' |
5 | import { getApplicationAccount } from '../../helpers/utils' | 5 | import { getApplicationAccount } from '../../../helpers/utils' |
6 | import { getAccountFromWebfinger } from '../../helpers/webfinger' | 6 | import { getAccountFromWebfinger } from '../../../helpers/webfinger' |
7 | import { SERVER_ACCOUNT_NAME } from '../../initializers/constants' | 7 | import { SERVER_ACCOUNT_NAME } from '../../../initializers/constants' |
8 | import { database as db } from '../../initializers/database' | 8 | import { database as db } from '../../../initializers/database' |
9 | import { sendFollow } from '../../lib/activitypub/send-request' | 9 | import { sendFollow } from '../../../lib/activitypub/send-request' |
10 | import { asyncMiddleware, paginationValidator, setFollowersSort, setPagination } from '../../middlewares' | 10 | import { asyncMiddleware, paginationValidator, setFollowersSort, setPagination } from '../../../middlewares' |
11 | import { authenticate } from '../../middlewares/oauth' | 11 | import { authenticate } from '../../../middlewares/oauth' |
12 | import { setBodyHostsPort } from '../../middlewares/pods' | 12 | import { setBodyHostsPort } from '../../../middlewares/pods' |
13 | import { setFollowingSort } from '../../middlewares/sort' | 13 | import { setFollowingSort } from '../../../middlewares/sort' |
14 | import { ensureUserHasRight } from '../../middlewares/user-right' | 14 | import { ensureUserHasRight } from '../../../middlewares/user-right' |
15 | import { followValidator } from '../../middlewares/validators/pods' | 15 | import { followValidator } from '../../../middlewares/validators/pods' |
16 | import { followersSortValidator, followingSortValidator } from '../../middlewares/validators/sort' | 16 | import { followersSortValidator, followingSortValidator } from '../../../middlewares/validators/sort' |
17 | 17 | ||
18 | const podsRouter = express.Router() | 18 | const applicationFollowsRouter = express.Router() |
19 | 19 | ||
20 | podsRouter.get('/following', | 20 | applicationFollowsRouter.get('/following', |
21 | paginationValidator, | 21 | paginationValidator, |
22 | followingSortValidator, | 22 | followingSortValidator, |
23 | setFollowingSort, | 23 | setFollowingSort, |
@@ -25,15 +25,15 @@ podsRouter.get('/following', | |||
25 | asyncMiddleware(listFollowing) | 25 | asyncMiddleware(listFollowing) |
26 | ) | 26 | ) |
27 | 27 | ||
28 | podsRouter.post('/follow', | 28 | applicationFollowsRouter.post('/follow', |
29 | authenticate, | 29 | authenticate, |
30 | ensureUserHasRight(UserRight.MANAGE_PEERTUBE_FOLLOW), | 30 | ensureUserHasRight(UserRight.MANAGE_APPLICATION_FOLLOW), |
31 | followValidator, | 31 | followValidator, |
32 | setBodyHostsPort, | 32 | setBodyHostsPort, |
33 | asyncMiddleware(follow) | 33 | asyncMiddleware(follow) |
34 | ) | 34 | ) |
35 | 35 | ||
36 | podsRouter.get('/followers', | 36 | applicationFollowsRouter.get('/followers', |
37 | paginationValidator, | 37 | paginationValidator, |
38 | followersSortValidator, | 38 | followersSortValidator, |
39 | setFollowersSort, | 39 | setFollowersSort, |
@@ -44,21 +44,21 @@ podsRouter.get('/followers', | |||
44 | // --------------------------------------------------------------------------- | 44 | // --------------------------------------------------------------------------- |
45 | 45 | ||
46 | export { | 46 | export { |
47 | podsRouter | 47 | applicationFollowsRouter |
48 | } | 48 | } |
49 | 49 | ||
50 | // --------------------------------------------------------------------------- | 50 | // --------------------------------------------------------------------------- |
51 | 51 | ||
52 | async function listFollowing (req: express.Request, res: express.Response, next: express.NextFunction) { | 52 | async function listFollowing (req: express.Request, res: express.Response, next: express.NextFunction) { |
53 | const applicationAccount = await getApplicationAccount() | 53 | const applicationAccount = await getApplicationAccount() |
54 | const resultList = await db.Account.listFollowingForApi(applicationAccount.id, req.query.start, req.query.count, req.query.sort) | 54 | const resultList = await db.AccountFollow.listFollowingForApi(applicationAccount.id, req.query.start, req.query.count, req.query.sort) |
55 | 55 | ||
56 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | 56 | return res.json(getFormattedObjects(resultList.data, resultList.total)) |
57 | } | 57 | } |
58 | 58 | ||
59 | async function listFollowers (req: express.Request, res: express.Response, next: express.NextFunction) { | 59 | async function listFollowers (req: express.Request, res: express.Response, next: express.NextFunction) { |
60 | const applicationAccount = await getApplicationAccount() | 60 | const applicationAccount = await getApplicationAccount() |
61 | const resultList = await db.Account.listFollowersForApi(applicationAccount.id, req.query.start, req.query.count, req.query.sort) | 61 | const resultList = await db.AccountFollow.listFollowersForApi(applicationAccount.id, req.query.start, req.query.count, req.query.sort) |
62 | 62 | ||
63 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | 63 | return res.json(getFormattedObjects(resultList.data, resultList.total)) |
64 | } | 64 | } |
diff --git a/server/controllers/api/application/index.ts b/server/controllers/api/application/index.ts new file mode 100644 index 000000000..011b971ed --- /dev/null +++ b/server/controllers/api/application/index.ts | |||
@@ -0,0 +1,12 @@ | |||
1 | import * as express from 'express' | ||
2 | import { applicationFollowsRouter } from './follows' | ||
3 | |||
4 | const applicationRouter = express.Router() | ||
5 | |||
6 | applicationRouter.use('/', applicationFollowsRouter) | ||
7 | |||
8 | // --------------------------------------------------------------------------- | ||
9 | |||
10 | export { | ||
11 | applicationRouter | ||
12 | } | ||
diff --git a/server/controllers/api/index.ts b/server/controllers/api/index.ts index 2e949d531..a22c78cce 100644 --- a/server/controllers/api/index.ts +++ b/server/controllers/api/index.ts | |||
@@ -4,15 +4,15 @@ import { badRequest } from '../../helpers' | |||
4 | 4 | ||
5 | import { oauthClientsRouter } from './oauth-clients' | 5 | import { oauthClientsRouter } from './oauth-clients' |
6 | import { configRouter } from './config' | 6 | import { configRouter } from './config' |
7 | import { podsRouter } from './pods' | 7 | import { applicationRouter } from './application' |
8 | import { usersRouter } from './users' | 8 | import { usersRouter } from './users' |
9 | import { videosRouter } from './videos' | 9 | import { videosRouter } from './videos' |
10 | 10 | ||
11 | const apiRouter = express.Router() | 11 | const apiRouter = express.Router() |
12 | 12 | ||
13 | apiRouter.use('/application', applicationRouter) | ||
13 | apiRouter.use('/oauth-clients', oauthClientsRouter) | 14 | apiRouter.use('/oauth-clients', oauthClientsRouter) |
14 | apiRouter.use('/config', configRouter) | 15 | apiRouter.use('/config', configRouter) |
15 | apiRouter.use('/pods', podsRouter) | ||
16 | apiRouter.use('/users', usersRouter) | 16 | apiRouter.use('/users', usersRouter) |
17 | apiRouter.use('/videos', videosRouter) | 17 | apiRouter.use('/videos', videosRouter) |
18 | apiRouter.use('/ping', pong) | 18 | apiRouter.use('/ping', pong) |
diff --git a/server/controllers/webfinger.ts b/server/controllers/webfinger.ts index 1c726f0cb..102ac0937 100644 --- a/server/controllers/webfinger.ts +++ b/server/controllers/webfinger.ts | |||
@@ -8,7 +8,7 @@ import { AccountInstance } from '../models/account/account-interface' | |||
8 | 8 | ||
9 | const webfingerRouter = express.Router() | 9 | const webfingerRouter = express.Router() |
10 | 10 | ||
11 | webfingerRouter.use('/.well-known/webfinger', | 11 | webfingerRouter.get('/.well-known/webfinger', |
12 | webfingerValidator, | 12 | webfingerValidator, |
13 | webfingerController | 13 | webfingerController |
14 | ) | 14 | ) |
diff --git a/server/lib/activitypub/send-request.ts b/server/lib/activitypub/send-request.ts index d47040d6d..f942a2eba 100644 --- a/server/lib/activitypub/send-request.ts +++ b/server/lib/activitypub/send-request.ts | |||
@@ -85,7 +85,7 @@ export { | |||
85 | // --------------------------------------------------------------------------- | 85 | // --------------------------------------------------------------------------- |
86 | 86 | ||
87 | async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) { | 87 | async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) { |
88 | const result = await db.Account.listAcceptedFollowerUrlsForApi(fromAccount.id, 0) | 88 | const result = await db.AccountFollow.listAcceptedFollowerUrlsForApi(fromAccount.id, 0) |
89 | 89 | ||
90 | const jobPayload = { | 90 | const jobPayload = { |
91 | uris: result.data, | 91 | uris: result.data, |
diff --git a/server/models/account/account-follow-interface.ts b/server/models/account/account-follow-interface.ts index efdff915e..413dad190 100644 --- a/server/models/account/account-follow-interface.ts +++ b/server/models/account/account-follow-interface.ts | |||
@@ -1,13 +1,26 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | import * as Bluebird from 'bluebird' | 2 | import * as Bluebird from 'bluebird' |
3 | import { FollowState } from '../../../shared/models/accounts/follow.model' | 3 | import { FollowState } from '../../../shared/models/accounts/follow.model' |
4 | import { ResultList } from '../../../shared/models/result-list.model' | ||
5 | import { AccountInstance } from './account-interface' | ||
4 | 6 | ||
5 | export namespace AccountFollowMethods { | 7 | export namespace AccountFollowMethods { |
6 | export type LoadByAccountAndTarget = (accountId: number, targetAccountId: number) => Bluebird<AccountFollowInstance> | 8 | export type LoadByAccountAndTarget = (accountId: number, targetAccountId: number) => Bluebird<AccountFollowInstance> |
9 | |||
10 | export type ListFollowingForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> > | ||
11 | export type ListFollowersForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> > | ||
12 | |||
13 | export type ListAcceptedFollowerUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> > | ||
14 | export type ListAcceptedFollowingUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> > | ||
7 | } | 15 | } |
8 | 16 | ||
9 | export interface AccountFollowClass { | 17 | export interface AccountFollowClass { |
10 | loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget | 18 | loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget |
19 | listFollowersForApi: AccountFollowMethods.ListFollowersForApi | ||
20 | listFollowingForApi: AccountFollowMethods.ListFollowingForApi | ||
21 | |||
22 | listAcceptedFollowerUrlsForApi: AccountFollowMethods.ListAcceptedFollowerUrlsForApi | ||
23 | listAcceptedFollowingUrlsForApi: AccountFollowMethods.ListAcceptedFollowingUrlsForApi | ||
11 | } | 24 | } |
12 | 25 | ||
13 | export interface AccountFollowAttributes { | 26 | export interface AccountFollowAttributes { |
@@ -20,6 +33,9 @@ export interface AccountFollowInstance extends AccountFollowClass, AccountFollow | |||
20 | id: number | 33 | id: number |
21 | createdAt: Date | 34 | createdAt: Date |
22 | updatedAt: Date | 35 | updatedAt: Date |
36 | |||
37 | AccountFollower?: AccountInstance | ||
38 | AccountFollowing?: AccountInstance | ||
23 | } | 39 | } |
24 | 40 | ||
25 | export interface AccountFollowModel extends AccountFollowClass, Sequelize.Model<AccountFollowInstance, AccountFollowAttributes> {} | 41 | export interface AccountFollowModel extends AccountFollowClass, Sequelize.Model<AccountFollowInstance, AccountFollowAttributes> {} |
diff --git a/server/models/account/account-follow.ts b/server/models/account/account-follow.ts index 7c129ab9d..6d7592326 100644 --- a/server/models/account/account-follow.ts +++ b/server/models/account/account-follow.ts | |||
@@ -1,12 +1,16 @@ | |||
1 | import { values } from 'lodash' | 1 | import { values } from 'lodash' |
2 | import * as Sequelize from 'sequelize' | 2 | import * as Sequelize from 'sequelize' |
3 | 3 | ||
4 | import { addMethodsToModel } from '../utils' | 4 | import { addMethodsToModel, getSort } from '../utils' |
5 | import { AccountFollowAttributes, AccountFollowInstance, AccountFollowMethods } from './account-follow-interface' | 5 | import { AccountFollowAttributes, AccountFollowInstance, AccountFollowMethods } from './account-follow-interface' |
6 | import { FOLLOW_STATES } from '../../initializers/constants' | 6 | import { FOLLOW_STATES } from '../../initializers/constants' |
7 | 7 | ||
8 | let AccountFollow: Sequelize.Model<AccountFollowInstance, AccountFollowAttributes> | 8 | let AccountFollow: Sequelize.Model<AccountFollowInstance, AccountFollowAttributes> |
9 | let loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget | 9 | let loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget |
10 | let listFollowingForApi: AccountFollowMethods.ListFollowingForApi | ||
11 | let listFollowersForApi: AccountFollowMethods.ListFollowersForApi | ||
12 | let listAcceptedFollowerUrlsForApi: AccountFollowMethods.ListAcceptedFollowerUrlsForApi | ||
13 | let listAcceptedFollowingUrlsForApi: AccountFollowMethods.ListAcceptedFollowingUrlsForApi | ||
10 | 14 | ||
11 | export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { | 15 | export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { |
12 | AccountFollow = sequelize.define<AccountFollowInstance, AccountFollowAttributes>('AccountFollow', | 16 | AccountFollow = sequelize.define<AccountFollowInstance, AccountFollowAttributes>('AccountFollow', |
@@ -34,7 +38,11 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da | |||
34 | 38 | ||
35 | const classMethods = [ | 39 | const classMethods = [ |
36 | associate, | 40 | associate, |
37 | loadByAccountAndTarget | 41 | loadByAccountAndTarget, |
42 | listFollowingForApi, | ||
43 | listFollowersForApi, | ||
44 | listAcceptedFollowerUrlsForApi, | ||
45 | listAcceptedFollowingUrlsForApi | ||
38 | ] | 46 | ] |
39 | addMethodsToModel(AccountFollow, classMethods) | 47 | addMethodsToModel(AccountFollow, classMethods) |
40 | 48 | ||
@@ -49,7 +57,7 @@ function associate (models) { | |||
49 | name: 'accountId', | 57 | name: 'accountId', |
50 | allowNull: false | 58 | allowNull: false |
51 | }, | 59 | }, |
52 | as: 'accountFollowers', | 60 | as: 'AccountFollower', |
53 | onDelete: 'CASCADE' | 61 | onDelete: 'CASCADE' |
54 | }) | 62 | }) |
55 | 63 | ||
@@ -58,7 +66,7 @@ function associate (models) { | |||
58 | name: 'targetAccountId', | 66 | name: 'targetAccountId', |
59 | allowNull: false | 67 | allowNull: false |
60 | }, | 68 | }, |
61 | as: 'accountFollowing', | 69 | as: 'AccountFollowing', |
62 | onDelete: 'CASCADE' | 70 | onDelete: 'CASCADE' |
63 | }) | 71 | }) |
64 | } | 72 | } |
@@ -73,3 +81,117 @@ loadByAccountAndTarget = function (accountId: number, targetAccountId: number) { | |||
73 | 81 | ||
74 | return AccountFollow.findOne(query) | 82 | return AccountFollow.findOne(query) |
75 | } | 83 | } |
84 | |||
85 | listFollowingForApi = function (id: number, start: number, count: number, sort: string) { | ||
86 | const query = { | ||
87 | distinct: true, | ||
88 | offset: start, | ||
89 | limit: count, | ||
90 | order: [ getSort(sort) ], | ||
91 | include: [ | ||
92 | { | ||
93 | model: AccountFollow[ 'sequelize' ].models.Account, | ||
94 | required: true, | ||
95 | as: 'AccountFollower', | ||
96 | where: { | ||
97 | id | ||
98 | } | ||
99 | }, | ||
100 | { | ||
101 | model: AccountFollow['sequelize'].models.Account, | ||
102 | as: 'AccountFollowing', | ||
103 | required: true, | ||
104 | include: [ AccountFollow['sequelize'].models.Pod ] | ||
105 | } | ||
106 | ] | ||
107 | } | ||
108 | |||
109 | return AccountFollow.findAndCountAll(query).then(({ rows, count }) => { | ||
110 | return { | ||
111 | data: rows.map(r => r.AccountFollowing), | ||
112 | total: count | ||
113 | } | ||
114 | }) | ||
115 | } | ||
116 | |||
117 | listFollowersForApi = function (id: number, start: number, count: number, sort: string) { | ||
118 | const query = { | ||
119 | distinct: true, | ||
120 | offset: start, | ||
121 | limit: count, | ||
122 | order: [ getSort(sort) ], | ||
123 | include: [ | ||
124 | { | ||
125 | model: AccountFollow[ 'sequelize' ].models.Account, | ||
126 | required: true, | ||
127 | as: 'AccountFollower', | ||
128 | include: [ AccountFollow['sequelize'].models.Pod ] | ||
129 | }, | ||
130 | { | ||
131 | model: AccountFollow['sequelize'].models.Account, | ||
132 | as: 'AccountFollowing', | ||
133 | required: true, | ||
134 | where: { | ||
135 | id | ||
136 | } | ||
137 | } | ||
138 | ] | ||
139 | } | ||
140 | |||
141 | return AccountFollow.findAndCountAll(query).then(({ rows, count }) => { | ||
142 | return { | ||
143 | data: rows.map(r => r.AccountFollower), | ||
144 | total: count | ||
145 | } | ||
146 | }) | ||
147 | } | ||
148 | |||
149 | listAcceptedFollowerUrlsForApi = function (id: number, start: number, count?: number) { | ||
150 | return createListAcceptedFollowForApiQuery('followers', id, start, count) | ||
151 | } | ||
152 | |||
153 | listAcceptedFollowingUrlsForApi = function (id: number, start: number, count?: number) { | ||
154 | return createListAcceptedFollowForApiQuery('following', id, start, count) | ||
155 | } | ||
156 | |||
157 | // ------------------------------ UTILS ------------------------------ | ||
158 | |||
159 | async function createListAcceptedFollowForApiQuery (type: 'followers' | 'following', id: number, start: number, count?: number) { | ||
160 | let firstJoin: string | ||
161 | let secondJoin: string | ||
162 | |||
163 | if (type === 'followers') { | ||
164 | firstJoin = 'targetAccountId' | ||
165 | secondJoin = 'accountId' | ||
166 | } else { | ||
167 | firstJoin = 'accountId' | ||
168 | secondJoin = 'targetAccountId' | ||
169 | } | ||
170 | |||
171 | const selections = [ '"Followers"."url" AS "url"', 'COUNT(*) AS "total"' ] | ||
172 | const tasks: Promise<any>[] = [] | ||
173 | |||
174 | for (const selection of selections) { | ||
175 | let query = 'SELECT ' + selection + ' FROM "Account" ' + | ||
176 | 'INNER JOIN "AccountFollow" ON "AccountFollow"."' + firstJoin + '" = "Account"."id" ' + | ||
177 | 'INNER JOIN "Account" AS "Follows" ON "Followers"."id" = "Follows"."' + secondJoin + '" ' + | ||
178 | 'WHERE "Account"."id" = $id AND "AccountFollow"."state" = \'accepted\' ' + | ||
179 | 'LIMIT ' + start | ||
180 | |||
181 | if (count !== undefined) query += ', ' + count | ||
182 | |||
183 | const options = { | ||
184 | bind: { id }, | ||
185 | type: Sequelize.QueryTypes.SELECT | ||
186 | } | ||
187 | tasks.push(AccountFollow['sequelize'].query(query, options)) | ||
188 | } | ||
189 | |||
190 | const [ followers, [ { total } ]] = await Promise.all(tasks) | ||
191 | const urls: string[] = followers.map(f => f.url) | ||
192 | |||
193 | return { | ||
194 | data: urls, | ||
195 | total: parseInt(total, 10) | ||
196 | } | ||
197 | } | ||
diff --git a/server/models/account/account-interface.ts b/server/models/account/account-interface.ts index 6fc36ae9d..ce1afec02 100644 --- a/server/models/account/account-interface.ts +++ b/server/models/account/account-interface.ts | |||
@@ -15,10 +15,6 @@ export namespace AccountMethods { | |||
15 | export type LoadLocalByName = (name: string) => Bluebird<AccountInstance> | 15 | export type LoadLocalByName = (name: string) => Bluebird<AccountInstance> |
16 | export type LoadByNameAndHost = (name: string, host: string) => Bluebird<AccountInstance> | 16 | export type LoadByNameAndHost = (name: string, host: string) => Bluebird<AccountInstance> |
17 | export type ListOwned = () => Bluebird<AccountInstance[]> | 17 | export type ListOwned = () => Bluebird<AccountInstance[]> |
18 | export type ListAcceptedFollowerUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> > | ||
19 | export type ListAcceptedFollowingUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> > | ||
20 | export type ListFollowingForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> > | ||
21 | export type ListFollowersForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> > | ||
22 | 18 | ||
23 | export type ToActivityPubObject = (this: AccountInstance) => ActivityPubActor | 19 | export type ToActivityPubObject = (this: AccountInstance) => ActivityPubActor |
24 | export type ToFormattedJSON = (this: AccountInstance) => FormattedAccount | 20 | export type ToFormattedJSON = (this: AccountInstance) => FormattedAccount |
@@ -38,10 +34,6 @@ export interface AccountClass { | |||
38 | loadLocalByName: AccountMethods.LoadLocalByName | 34 | loadLocalByName: AccountMethods.LoadLocalByName |
39 | loadByNameAndHost: AccountMethods.LoadByNameAndHost | 35 | loadByNameAndHost: AccountMethods.LoadByNameAndHost |
40 | listOwned: AccountMethods.ListOwned | 36 | listOwned: AccountMethods.ListOwned |
41 | listAcceptedFollowerUrlsForApi: AccountMethods.ListAcceptedFollowerUrlsForApi | ||
42 | listAcceptedFollowingUrlsForApi: AccountMethods.ListAcceptedFollowingUrlsForApi | ||
43 | listFollowingForApi: AccountMethods.ListFollowingForApi | ||
44 | listFollowersForApi: AccountMethods.ListFollowersForApi | ||
45 | } | 37 | } |
46 | 38 | ||
47 | export interface AccountAttributes { | 39 | export interface AccountAttributes { |
diff --git a/server/models/account/account.ts b/server/models/account/account.ts index d2293a939..e90eaae5e 100644 --- a/server/models/account/account.ts +++ b/server/models/account/account.ts | |||
@@ -23,7 +23,7 @@ import { | |||
23 | AccountMethods | 23 | AccountMethods |
24 | } from './account-interface' | 24 | } from './account-interface' |
25 | import { sendDeleteAccount } from '../../lib/activitypub/send-request' | 25 | import { sendDeleteAccount } from '../../lib/activitypub/send-request' |
26 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | 26 | import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers/constants' |
27 | 27 | ||
28 | let Account: Sequelize.Model<AccountInstance, AccountAttributes> | 28 | let Account: Sequelize.Model<AccountInstance, AccountAttributes> |
29 | let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID | 29 | let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID |
@@ -34,10 +34,6 @@ let loadByUrl: AccountMethods.LoadByUrl | |||
34 | let loadLocalByName: AccountMethods.LoadLocalByName | 34 | let loadLocalByName: AccountMethods.LoadLocalByName |
35 | let loadByNameAndHost: AccountMethods.LoadByNameAndHost | 35 | let loadByNameAndHost: AccountMethods.LoadByNameAndHost |
36 | let listOwned: AccountMethods.ListOwned | 36 | let listOwned: AccountMethods.ListOwned |
37 | let listAcceptedFollowerUrlsForApi: AccountMethods.ListAcceptedFollowerUrlsForApi | ||
38 | let listAcceptedFollowingUrlsForApi: AccountMethods.ListAcceptedFollowingUrlsForApi | ||
39 | let listFollowingForApi: AccountMethods.ListFollowingForApi | ||
40 | let listFollowersForApi: AccountMethods.ListFollowersForApi | ||
41 | let isOwned: AccountMethods.IsOwned | 37 | let isOwned: AccountMethods.IsOwned |
42 | let toActivityPubObject: AccountMethods.ToActivityPubObject | 38 | let toActivityPubObject: AccountMethods.ToActivityPubObject |
43 | let toFormattedJSON: AccountMethods.ToFormattedJSON | 39 | let toFormattedJSON: AccountMethods.ToFormattedJSON |
@@ -185,7 +181,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes | |||
185 | unique: true | 181 | unique: true |
186 | }, | 182 | }, |
187 | { | 183 | { |
188 | fields: [ 'name', 'podId' ], | 184 | fields: [ 'name', 'podId', 'applicationId' ], |
189 | unique: true | 185 | unique: true |
190 | } | 186 | } |
191 | ], | 187 | ], |
@@ -202,11 +198,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes | |||
202 | loadByUrl, | 198 | loadByUrl, |
203 | loadLocalByName, | 199 | loadLocalByName, |
204 | loadByNameAndHost, | 200 | loadByNameAndHost, |
205 | listOwned, | 201 | listOwned |
206 | listAcceptedFollowerUrlsForApi, | ||
207 | listAcceptedFollowingUrlsForApi, | ||
208 | listFollowingForApi, | ||
209 | listFollowersForApi | ||
210 | ] | 202 | ] |
211 | const instanceMethods = [ | 203 | const instanceMethods = [ |
212 | isOwned, | 204 | isOwned, |
@@ -286,9 +278,11 @@ function afterDestroy (account: AccountInstance) { | |||
286 | } | 278 | } |
287 | 279 | ||
288 | toFormattedJSON = function (this: AccountInstance) { | 280 | toFormattedJSON = function (this: AccountInstance) { |
281 | let host = this.Pod ? this.Pod.host : CONFIG.WEBSERVER.HOST | ||
282 | |||
289 | const json = { | 283 | const json = { |
290 | id: this.id, | 284 | id: this.id, |
291 | host: this.Pod.host, | 285 | host, |
292 | name: this.name | 286 | name: this.name |
293 | } | 287 | } |
294 | 288 | ||
@@ -346,7 +340,7 @@ getFollowerSharedInboxUrls = function (this: AccountInstance) { | |||
346 | } | 340 | } |
347 | 341 | ||
348 | getFollowingUrl = function (this: AccountInstance) { | 342 | getFollowingUrl = function (this: AccountInstance) { |
349 | return this.url + '/followers' | 343 | return this.url + '/following' |
350 | } | 344 | } |
351 | 345 | ||
352 | getFollowersUrl = function (this: AccountInstance) { | 346 | getFollowersUrl = function (this: AccountInstance) { |
@@ -369,76 +363,6 @@ listOwned = function () { | |||
369 | return Account.findAll(query) | 363 | return Account.findAll(query) |
370 | } | 364 | } |
371 | 365 | ||
372 | listAcceptedFollowerUrlsForApi = function (id: number, start: number, count?: number) { | ||
373 | return createListAcceptedFollowForApiQuery('followers', id, start, count) | ||
374 | } | ||
375 | |||
376 | listAcceptedFollowingUrlsForApi = function (id: number, start: number, count?: number) { | ||
377 | return createListAcceptedFollowForApiQuery('following', id, start, count) | ||
378 | } | ||
379 | |||
380 | listFollowingForApi = function (id: number, start: number, count: number, sort: string) { | ||
381 | const query = { | ||
382 | distinct: true, | ||
383 | offset: start, | ||
384 | limit: count, | ||
385 | order: [ getSort(sort) ], | ||
386 | include: [ | ||
387 | { | ||
388 | model: Account['sequelize'].models.AccountFollow, | ||
389 | required: true, | ||
390 | as: 'following', | ||
391 | include: [ | ||
392 | { | ||
393 | model: Account['sequelize'].models.Account, | ||
394 | as: 'accountFollowing', | ||
395 | required: true, | ||
396 | include: [ Account['sequelize'].models.Pod ] | ||
397 | } | ||
398 | ] | ||
399 | } | ||
400 | ] | ||
401 | } | ||
402 | |||
403 | return Account.findAndCountAll(query).then(({ rows, count }) => { | ||
404 | return { | ||
405 | data: rows, | ||
406 | total: count | ||
407 | } | ||
408 | }) | ||
409 | } | ||
410 | |||
411 | listFollowersForApi = function (id: number, start: number, count: number, sort: string) { | ||
412 | const query = { | ||
413 | distinct: true, | ||
414 | offset: start, | ||
415 | limit: count, | ||
416 | order: [ getSort(sort) ], | ||
417 | include: [ | ||
418 | { | ||
419 | model: Account['sequelize'].models.AccountFollow, | ||
420 | required: true, | ||
421 | as: 'followers', | ||
422 | include: [ | ||
423 | { | ||
424 | model: Account['sequelize'].models.Account, | ||
425 | as: 'accountFollowers', | ||
426 | required: true, | ||
427 | include: [ Account['sequelize'].models.Pod ] | ||
428 | } | ||
429 | ] | ||
430 | } | ||
431 | ] | ||
432 | } | ||
433 | |||
434 | return Account.findAndCountAll(query).then(({ rows, count }) => { | ||
435 | return { | ||
436 | data: rows, | ||
437 | total: count | ||
438 | } | ||
439 | }) | ||
440 | } | ||
441 | |||
442 | loadApplication = function () { | 366 | loadApplication = function () { |
443 | return Account.findOne({ | 367 | return Account.findOne({ |
444 | include: [ | 368 | include: [ |
@@ -527,45 +451,3 @@ loadAccountByPodAndUUID = function (uuid: string, podId: number, transaction: Se | |||
527 | 451 | ||
528 | return Account.find(query) | 452 | return Account.find(query) |
529 | } | 453 | } |
530 | |||
531 | // ------------------------------ UTILS ------------------------------ | ||
532 | |||
533 | async function createListAcceptedFollowForApiQuery (type: 'followers' | 'following', id: number, start: number, count?: number) { | ||
534 | let firstJoin: string | ||
535 | let secondJoin: string | ||
536 | |||
537 | if (type === 'followers') { | ||
538 | firstJoin = 'targetAccountId' | ||
539 | secondJoin = 'accountId' | ||
540 | } else { | ||
541 | firstJoin = 'accountId' | ||
542 | secondJoin = 'targetAccountId' | ||
543 | } | ||
544 | |||
545 | const selections = [ '"Followers"."url" AS "url"', 'COUNT(*) AS "total"' ] | ||
546 | const tasks: Promise<any>[] = [] | ||
547 | |||
548 | for (const selection of selections) { | ||
549 | let query = 'SELECT ' + selection + ' FROM "Account" ' + | ||
550 | 'INNER JOIN "AccountFollow" ON "AccountFollow"."' + firstJoin + '" = "Account"."id" ' + | ||
551 | 'INNER JOIN "Account" AS "Follows" ON "Followers"."id" = "Follows"."' + secondJoin + '" ' + | ||
552 | 'WHERE "Account"."id" = $id AND "AccountFollow"."state" = \'accepted\' ' + | ||
553 | 'LIMIT ' + start | ||
554 | |||
555 | if (count !== undefined) query += ', ' + count | ||
556 | |||
557 | const options = { | ||
558 | bind: { id }, | ||
559 | type: Sequelize.QueryTypes.SELECT | ||
560 | } | ||
561 | tasks.push(Account['sequelize'].query(query, options)) | ||
562 | } | ||
563 | |||
564 | const [ followers, [ { total } ]] = await Promise.all(tasks) | ||
565 | const urls: string[] = followers.map(f => f.url) | ||
566 | |||
567 | return { | ||
568 | data: urls, | ||
569 | total: parseInt(total, 10) | ||
570 | } | ||
571 | } | ||
diff --git a/shared/models/users/user-right.enum.ts b/shared/models/users/user-right.enum.ts index 9d5ebbb16..ecad69d6f 100644 --- a/shared/models/users/user-right.enum.ts +++ b/shared/models/users/user-right.enum.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | export enum UserRight { | 1 | export enum UserRight { |
2 | ALL, | 2 | ALL, |
3 | MANAGE_USERS, | 3 | MANAGE_USERS, |
4 | MANAGE_PEERTUBE_FOLLOW, | 4 | MANAGE_APPLICATION_FOLLOW, |
5 | MANAGE_VIDEO_ABUSES, | 5 | MANAGE_VIDEO_ABUSES, |
6 | MANAGE_VIDEO_BLACKLIST, | 6 | MANAGE_VIDEO_BLACKLIST, |
7 | REMOVE_ANY_VIDEO, | 7 | REMOVE_ANY_VIDEO, |
8 | REMOVE_ANY_VIDEO_CHANNEL, | 8 | REMOVE_ANY_VIDEO_CHANNEL |
9 | } | 9 | } |