aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2017-12-29 19:10:13 +0100
committerChocobozzz <me@florianbigard.com>2017-12-29 19:10:13 +0100
commitc5911fd347c76e8bdc05ea9f3ee9efed4a58c236 (patch)
treeb8d287daca6c45305090cbec9da97d1155f275bd /client/src
parent8b0d42ee372de6589796be26b83e5bffb1b69cdf (diff)
downloadPeerTube-c5911fd347c76e8bdc05ea9f3ee9efed4a58c236.tar.gz
PeerTube-c5911fd347c76e8bdc05ea9f3ee9efed4a58c236.tar.zst
PeerTube-c5911fd347c76e8bdc05ea9f3ee9efed4a58c236.zip
Begin to add avatar to actors
Diffstat (limited to 'client/src')
-rw-r--r--client/src/app/account/account-settings/account-settings.component.html6
-rw-r--r--client/src/app/account/account-settings/account-settings.component.scss6
-rw-r--r--client/src/app/account/account-settings/account-settings.component.ts36
-rw-r--r--client/src/app/account/account-videos/account-videos.component.ts4
-rw-r--r--client/src/app/core/auth/auth.service.ts35
-rw-r--r--client/src/app/menu/menu.component.html2
-rw-r--r--client/src/app/menu/menu.component.ts4
-rw-r--r--client/src/app/shared/account/account.model.ts10
-rw-r--r--client/src/app/shared/misc/utils.ts14
-rw-r--r--client/src/app/shared/users/user.model.ts4
-rw-r--r--client/src/app/shared/users/user.service.ts16
-rw-r--r--client/src/app/shared/video/abstract-video-list.ts2
-rw-r--r--client/src/app/shared/video/video.model.ts7
-rw-r--r--client/src/app/videos/+video-edit/shared/video-edit.component.scss5
-rw-r--r--client/src/app/videos/+video-edit/video-add.component.scss25
-rw-r--r--client/src/app/videos/+video-watch/video-watch.component.ts8
-rw-r--r--client/src/sass/include/_mixins.scss26
17 files changed, 125 insertions, 85 deletions
diff --git a/client/src/app/account/account-settings/account-settings.component.html b/client/src/app/account/account-settings/account-settings.component.html
index f14eadd49..fe345207a 100644
--- a/client/src/app/account/account-settings/account-settings.component.html
+++ b/client/src/app/account/account-settings/account-settings.component.html
@@ -1,5 +1,5 @@
1<div class="user"> 1<div class="user">
2 <img [src]="getAvatarPath()" alt="Avatar" /> 2 <img [src]="getAvatarUrl()" alt="Avatar" />
3 3
4 <div class="user-info"> 4 <div class="user-info">
5 <div class="user-info-username">{{ user.username }}</div> 5 <div class="user-info-username">{{ user.username }}</div>
@@ -7,6 +7,10 @@
7 </div> 7 </div>
8</div> 8</div>
9 9
10<div class="button-file">
11 <span>Change your avatar</span>
12 <input #avatarfileInput type="file" name="avatarfile" id="avatarfile" (change)="changeAvatar()" />
13</div>
10 14
11<div class="account-title">Account settings</div> 15<div class="account-title">Account settings</div>
12<my-account-change-password></my-account-change-password> 16<my-account-change-password></my-account-change-password>
diff --git a/client/src/app/account/account-settings/account-settings.component.scss b/client/src/app/account/account-settings/account-settings.component.scss
index 7f1ade377..accd65214 100644
--- a/client/src/app/account/account-settings/account-settings.component.scss
+++ b/client/src/app/account/account-settings/account-settings.component.scss
@@ -21,6 +21,12 @@
21 } 21 }
22} 22}
23 23
24.button-file {
25 @include peertube-button-file(auto);
26
27 margin-top: 10px;
28}
29
24.account-title { 30.account-title {
25 text-transform: uppercase; 31 text-transform: uppercase;
26 color: $orange-color; 32 color: $orange-color;
diff --git a/client/src/app/account/account-settings/account-settings.component.ts b/client/src/app/account/account-settings/account-settings.component.ts
index cba251000..3e03085ce 100644
--- a/client/src/app/account/account-settings/account-settings.component.ts
+++ b/client/src/app/account/account-settings/account-settings.component.ts
@@ -1,6 +1,10 @@
1import { Component, OnInit } from '@angular/core' 1import { HttpEventType, HttpResponse } from '@angular/common/http'
2import { Component, OnInit, ViewChild } from '@angular/core'
3import { NotificationsService } from 'angular2-notifications'
4import { VideoPrivacy } from '../../../../../shared/models/videos'
2import { User } from '../../shared' 5import { User } from '../../shared'
3import { AuthService } from '../../core' 6import { AuthService } from '../../core'
7import { UserService } from '../../shared/users'
4 8
5@Component({ 9@Component({
6 selector: 'my-account-settings', 10 selector: 'my-account-settings',
@@ -8,15 +12,39 @@ import { AuthService } from '../../core'
8 styleUrls: [ './account-settings.component.scss' ] 12 styleUrls: [ './account-settings.component.scss' ]
9}) 13})
10export class AccountSettingsComponent implements OnInit { 14export class AccountSettingsComponent implements OnInit {
15 @ViewChild('avatarfileInput') avatarfileInput
16
11 user: User = null 17 user: User = null
12 18
13 constructor (private authService: AuthService) {} 19 constructor (
20 private userService: UserService,
21 private authService: AuthService,
22 private notificationsService: NotificationsService
23 ) {}
14 24
15 ngOnInit () { 25 ngOnInit () {
16 this.user = this.authService.getUser() 26 this.user = this.authService.getUser()
17 } 27 }
18 28
19 getAvatarPath () { 29 getAvatarUrl () {
20 return this.user.getAvatarPath() 30 return this.user.getAvatarUrl()
31 }
32
33 changeAvatar () {
34 const avatarfile = this.avatarfileInput.nativeElement.files[ 0 ]
35
36 const formData = new FormData()
37 formData.append('avatarfile', avatarfile)
38
39 this.userService.changeAvatar(formData)
40 .subscribe(
41 data => {
42 this.notificationsService.success('Success', 'Avatar changed.')
43
44 this.user.account.avatar = data.avatar
45 },
46
47 err => this.notificationsService.error('Error', err.message)
48 )
21 } 49 }
22} 50}
diff --git a/client/src/app/account/account-videos/account-videos.component.ts b/client/src/app/account/account-videos/account-videos.component.ts
index 22941619d..d51b70e06 100644
--- a/client/src/app/account/account-videos/account-videos.component.ts
+++ b/client/src/app/account/account-videos/account-videos.component.ts
@@ -68,7 +68,7 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
68 .subscribe( 68 .subscribe(
69 res => this.notificationsService.success('Success', `${toDeleteVideosIds.length} videos deleted.`), 69 res => this.notificationsService.success('Success', `${toDeleteVideosIds.length} videos deleted.`),
70 70
71 err => this.notificationsService.error('Error', err.text) 71 err => this.notificationsService.error('Error', err.message)
72 ) 72 )
73 } 73 }
74 ) 74 )
@@ -86,7 +86,7 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
86 this.spliceVideosById(video.id) 86 this.spliceVideosById(video.id)
87 }, 87 },
88 88
89 error => this.notificationsService.error('Error', error.text) 89 error => this.notificationsService.error('Error', error.message)
90 ) 90 )
91 } 91 }
92 ) 92 )
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts
index c914848ae..8a2ba77d6 100644
--- a/client/src/app/core/auth/auth.service.ts
+++ b/client/src/app/core/auth/auth.service.ts
@@ -9,8 +9,8 @@ import 'rxjs/add/operator/mergeMap'
9import { Observable } from 'rxjs/Observable' 9import { Observable } from 'rxjs/Observable'
10import { ReplaySubject } from 'rxjs/ReplaySubject' 10import { ReplaySubject } from 'rxjs/ReplaySubject'
11import { Subject } from 'rxjs/Subject' 11import { Subject } from 'rxjs/Subject'
12import { OAuthClientLocal, User as UserServerModel, UserRefreshToken, UserRole, VideoChannel } from '../../../../../shared' 12import { OAuthClientLocal, User as UserServerModel, UserRefreshToken } from '../../../../../shared'
13import { Account } from '../../../../../shared/models/actors' 13import { User } from '../../../../../shared/models/users'
14import { UserLogin } from '../../../../../shared/models/users/user-login.model' 14import { UserLogin } from '../../../../../shared/models/users/user-login.model'
15import { environment } from '../../../environments/environment' 15import { environment } from '../../../environments/environment'
16import { RestExtractor } from '../../shared/rest' 16import { RestExtractor } from '../../shared/rest'
@@ -25,20 +25,7 @@ interface UserLoginWithUsername extends UserLogin {
25 username: string 25 username: string
26} 26}
27 27
28interface UserLoginWithUserInformation extends UserLogin { 28type UserLoginWithUserInformation = UserLoginWithUsername & User
29 access_token: string
30 refresh_token: string
31 token_type: string
32 username: string
33 id: number
34 role: UserRole
35 displayNSFW: boolean
36 autoPlayVideo: boolean
37 email: string
38 videoQuota: number
39 account: Account
40 videoChannels: VideoChannel[]
41}
42 29
43@Injectable() 30@Injectable()
44export class AuthService { 31export class AuthService {
@@ -209,21 +196,7 @@ export class AuthService {
209 const headers = new HttpHeaders().set('Authorization', `${obj.token_type} ${obj.access_token}`) 196 const headers = new HttpHeaders().set('Authorization', `${obj.token_type} ${obj.access_token}`)
210 197
211 return this.http.get<UserServerModel>(AuthService.BASE_USER_INFORMATION_URL, { headers }) 198 return this.http.get<UserServerModel>(AuthService.BASE_USER_INFORMATION_URL, { headers })
212 .map(res => { 199 .map(res => Object.assign(obj, res))
213 const newProperties = {
214 id: res.id,
215 role: res.role,
216 displayNSFW: res.displayNSFW,
217 autoPlayVideo: res.autoPlayVideo,
218 email: res.email,
219 videoQuota: res.videoQuota,
220 account: res.account,
221 videoChannels: res.videoChannels
222 }
223
224 return Object.assign(obj, newProperties)
225 }
226 )
227 } 200 }
228 201
229 private handleLogin (obj: UserLoginWithUserInformation) { 202 private handleLogin (obj: UserLoginWithUserInformation) {
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html
index 6f52f4f45..5ea859fd2 100644
--- a/client/src/app/menu/menu.component.html
+++ b/client/src/app/menu/menu.component.html
@@ -1,6 +1,6 @@
1<menu> 1<menu>
2 <div *ngIf="isLoggedIn" class="logged-in-block"> 2 <div *ngIf="isLoggedIn" class="logged-in-block">
3 <img [src]="getUserAvatarPath()" alt="Avatar" /> 3 <img [src]="getUserAvatarUrl()" alt="Avatar" />
4 4
5 <div class="logged-in-info"> 5 <div class="logged-in-info">
6 <a routerLink="/account/settings" class="logged-in-username">{{ user.username }}</a> 6 <a routerLink="/account/settings" class="logged-in-username">{{ user.username }}</a>
diff --git a/client/src/app/menu/menu.component.ts b/client/src/app/menu/menu.component.ts
index 8b8b714a8..1f66e3754 100644
--- a/client/src/app/menu/menu.component.ts
+++ b/client/src/app/menu/menu.component.ts
@@ -51,8 +51,8 @@ export class MenuComponent implements OnInit {
51 ) 51 )
52 } 52 }
53 53
54 getUserAvatarPath () { 54 getUserAvatarUrl () {
55 return this.user.getAvatarPath() 55 return this.user.getAvatarUrl()
56 } 56 }
57 57
58 isRegistrationAllowed () { 58 isRegistrationAllowed () {
diff --git a/client/src/app/shared/account/account.model.ts b/client/src/app/shared/account/account.model.ts
index bacaa208a..cc46dad77 100644
--- a/client/src/app/shared/account/account.model.ts
+++ b/client/src/app/shared/account/account.model.ts
@@ -1,11 +1,13 @@
1import { Account as ServerAccount } from '../../../../../shared/models/actors/account.model' 1import { Account as ServerAccount } from '../../../../../shared/models/actors/account.model'
2import { Avatar } from '../../../../../shared/models/avatars/avatar.model' 2import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
3import { environment } from '../../../environments/environment' 3import { environment } from '../../../environments/environment'
4import { getAbsoluteAPIUrl } from '../misc/utils'
4 5
5export class Account implements ServerAccount { 6export class Account implements ServerAccount {
6 id: number 7 id: number
7 uuid: string 8 uuid: string
8 name: string 9 name: string
10 displayName: string
9 host: string 11 host: string
10 followingCount: number 12 followingCount: number
11 followersCount: number 13 followersCount: number
@@ -13,9 +15,11 @@ export class Account implements ServerAccount {
13 updatedAt: Date 15 updatedAt: Date
14 avatar: Avatar 16 avatar: Avatar
15 17
16 static GET_ACCOUNT_AVATAR_PATH (account: Account) { 18 static GET_ACCOUNT_AVATAR_URL (account: Account) {
17 if (account && account.avatar) return account.avatar.path 19 const absoluteAPIUrl = getAbsoluteAPIUrl()
18 20
19 return '/client/assets/images/default-avatar.png' 21 if (account && account.avatar) return absoluteAPIUrl + account.avatar.path
22
23 return window.location.origin + '/client/assets/images/default-avatar.png'
20 } 24 }
21} 25}
diff --git a/client/src/app/shared/misc/utils.ts b/client/src/app/shared/misc/utils.ts
index 5525e4efb..2739ff81a 100644
--- a/client/src/app/shared/misc/utils.ts
+++ b/client/src/app/shared/misc/utils.ts
@@ -1,5 +1,6 @@
1// Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript 1// Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
2 2
3import { environment } from '../../../environments/environment'
3import { AuthService } from '../../core/auth' 4import { AuthService } from '../../core/auth'
4 5
5function getParameterByName (name: string, url: string) { 6function getParameterByName (name: string, url: string) {
@@ -38,8 +39,19 @@ function populateAsyncUserVideoChannels (authService: AuthService, channel: any[
38 }) 39 })
39} 40}
40 41
42function getAbsoluteAPIUrl () {
43 let absoluteAPIUrl = environment.apiUrl
44 if (!absoluteAPIUrl) {
45 // The API is on the same domain
46 absoluteAPIUrl = window.location.origin
47 }
48
49 return absoluteAPIUrl
50}
51
41export { 52export {
42 viewportHeight, 53 viewportHeight,
43 getParameterByName, 54 getParameterByName,
44 populateAsyncUserVideoChannels 55 populateAsyncUserVideoChannels,
56 getAbsoluteAPIUrl
45} 57}
diff --git a/client/src/app/shared/users/user.model.ts b/client/src/app/shared/users/user.model.ts
index 7a962ae3e..83aae4463 100644
--- a/client/src/app/shared/users/user.model.ts
+++ b/client/src/app/shared/users/user.model.ts
@@ -57,7 +57,7 @@ export class User implements UserServerModel {
57 return hasUserRight(this.role, right) 57 return hasUserRight(this.role, right)
58 } 58 }
59 59
60 getAvatarPath () { 60 getAvatarUrl () {
61 return Account.GET_ACCOUNT_AVATAR_PATH(this.account) 61 return Account.GET_ACCOUNT_AVATAR_URL(this.account)
62 } 62 }
63} 63}
diff --git a/client/src/app/shared/users/user.service.ts b/client/src/app/shared/users/user.service.ts
index d97edbcbe..58ddaa5ee 100644
--- a/client/src/app/shared/users/user.service.ts
+++ b/client/src/app/shared/users/user.service.ts
@@ -5,6 +5,7 @@ import 'rxjs/add/operator/map'
5import { UserCreate, UserUpdateMe } from '../../../../../shared' 5import { UserCreate, UserUpdateMe } from '../../../../../shared'
6import { environment } from '../../../environments/environment' 6import { environment } from '../../../environments/environment'
7import { RestExtractor } from '../rest' 7import { RestExtractor } from '../rest'
8import { User } from './user.model'
8 9
9@Injectable() 10@Injectable()
10export class UserService { 11export class UserService {
@@ -34,9 +35,24 @@ export class UserService {
34 .catch(res => this.restExtractor.handleError(res)) 35 .catch(res => this.restExtractor.handleError(res))
35 } 36 }
36 37
38 changeAvatar (avatarForm: FormData) {
39 const url = UserService.BASE_USERS_URL + 'me/avatar/pick'
40
41 return this.authHttp.post(url, avatarForm)
42 .catch(this.restExtractor.handleError)
43 }
44
37 signup (userCreate: UserCreate) { 45 signup (userCreate: UserCreate) {
38 return this.authHttp.post(UserService.BASE_USERS_URL + 'register', userCreate) 46 return this.authHttp.post(UserService.BASE_USERS_URL + 'register', userCreate)
39 .map(this.restExtractor.extractDataBool) 47 .map(this.restExtractor.extractDataBool)
40 .catch(res => this.restExtractor.handleError(res)) 48 .catch(res => this.restExtractor.handleError(res))
41 } 49 }
50
51 getMyInformation () {
52 const url = UserService.BASE_USERS_URL + 'me'
53
54 return this.authHttp.get(url)
55 .map((userHash: any) => new User(userHash))
56 .catch(res => this.restExtractor.handleError(res))
57 }
42} 58}
diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts
index bfe46bcdd..354373776 100644
--- a/client/src/app/shared/video/abstract-video-list.ts
+++ b/client/src/app/shared/video/abstract-video-list.ts
@@ -83,7 +83,7 @@ export abstract class AbstractVideoList implements OnInit {
83 this.videos = this.videos.concat(videos) 83 this.videos = this.videos.concat(videos)
84 } 84 }
85 }, 85 },
86 error => this.notificationsService.error('Error', error.text) 86 error => this.notificationsService.error('Error', error.message)
87 ) 87 )
88 } 88 }
89 89
diff --git a/client/src/app/shared/video/video.model.ts b/client/src/app/shared/video/video.model.ts
index f159464c5..060bf933f 100644
--- a/client/src/app/shared/video/video.model.ts
+++ b/client/src/app/shared/video/video.model.ts
@@ -2,6 +2,7 @@ import { User } from '../'
2import { Video as VideoServerModel } from '../../../../../shared' 2import { Video as VideoServerModel } from '../../../../../shared'
3import { Account } from '../../../../../shared/models/actors' 3import { Account } from '../../../../../shared/models/actors'
4import { environment } from '../../../environments/environment' 4import { environment } from '../../../environments/environment'
5import { getAbsoluteAPIUrl } from '../misc/utils'
5 6
6export class Video implements VideoServerModel { 7export class Video implements VideoServerModel {
7 accountName: string 8 accountName: string
@@ -48,11 +49,7 @@ export class Video implements VideoServerModel {
48 } 49 }
49 50
50 constructor (hash: VideoServerModel) { 51 constructor (hash: VideoServerModel) {
51 let absoluteAPIUrl = environment.apiUrl 52 const absoluteAPIUrl = getAbsoluteAPIUrl()
52 if (!absoluteAPIUrl) {
53 // The API is on the same domain
54 absoluteAPIUrl = window.location.origin
55 }
56 53
57 this.accountName = hash.accountName 54 this.accountName = hash.accountName
58 this.createdAt = new Date(hash.createdAt.toString()) 55 this.createdAt = new Date(hash.createdAt.toString())
diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.scss b/client/src/app/videos/+video-edit/shared/video-edit.component.scss
index 81e3a0d19..0fefcee28 100644
--- a/client/src/app/videos/+video-edit/shared/video-edit.component.scss
+++ b/client/src/app/videos/+video-edit/shared/video-edit.component.scss
@@ -144,8 +144,3 @@
144 } 144 }
145 } 145 }
146} 146}
147
148.little-information {
149 font-size: 0.8em;
150 font-style: italic;
151}
diff --git a/client/src/app/videos/+video-edit/video-add.component.scss b/client/src/app/videos/+video-edit/video-add.component.scss
index 891f38819..4bb509009 100644
--- a/client/src/app/videos/+video-edit/video-add.component.scss
+++ b/client/src/app/videos/+video-edit/video-add.component.scss
@@ -34,30 +34,9 @@
34 } 34 }
35 35
36 .button-file { 36 .button-file {
37 position: relative; 37 @include peertube-button-file(190px);
38 overflow: hidden;
39 display: inline-block;
40 margin-bottom: 45px;
41 width: 190px;
42
43 @include peertube-button;
44 @include orange-button;
45 38
46 input[type=file] { 39 margin-bottom: 45px;
47 position: absolute;
48 top: 0;
49 right: 0;
50 min-width: 100%;
51 min-height: 100%;
52 font-size: 100px;
53 text-align: right;
54 filter: alpha(opacity=0);
55 opacity: 0;
56 outline: none;
57 background: white;
58 cursor: inherit;
59 display: block;
60 }
61 } 40 }
62 } 41 }
63} 42}
diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts
index 4afd6160c..0f44d3dd7 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/videos/+video-watch/video-watch.component.ts
@@ -148,7 +148,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
148 this.router.navigate(['/videos/list']) 148 this.router.navigate(['/videos/list'])
149 }, 149 },
150 150
151 error => this.notificationsService.error('Error', error.text) 151 error => this.notificationsService.error('Error', error.message)
152 ) 152 )
153 } 153 }
154 ) 154 )
@@ -185,7 +185,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
185 185
186 error => { 186 error => {
187 this.descriptionLoading = false 187 this.descriptionLoading = false
188 this.notificationsService.error('Error', error.text) 188 this.notificationsService.error('Error', error.message)
189 } 189 }
190 ) 190 )
191 } 191 }
@@ -217,7 +217,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
217 } 217 }
218 218
219 getAvatarPath () { 219 getAvatarPath () {
220 return Account.GET_ACCOUNT_AVATAR_PATH(this.video.account) 220 return Account.GET_ACCOUNT_AVATAR_URL(this.video.account)
221 } 221 }
222 222
223 getVideoTags () { 223 getVideoTags () {
@@ -247,7 +247,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
247 this.router.navigate([ '/videos/list' ]) 247 this.router.navigate([ '/videos/list' ])
248 }, 248 },
249 249
250 error => this.notificationsService.error('Error', error.text) 250 error => this.notificationsService.error('Error', error.message)
251 ) 251 )
252 } 252 }
253 ) 253 )
diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss
index 252cf2173..140de1b2c 100644
--- a/client/src/sass/include/_mixins.scss
+++ b/client/src/sass/include/_mixins.scss
@@ -84,6 +84,32 @@
84 @include peertube-button; 84 @include peertube-button;
85} 85}
86 86
87@mixin peertube-button-file ($width) {
88 position: relative;
89 overflow: hidden;
90 display: inline-block;
91 width: $width;
92
93 @include peertube-button;
94 @include orange-button;
95
96 input[type=file] {
97 position: absolute;
98 top: 0;
99 right: 0;
100 min-width: 100%;
101 min-height: 100%;
102 font-size: 100px;
103 text-align: right;
104 filter: alpha(opacity=0);
105 opacity: 0;
106 outline: none;
107 background: white;
108 cursor: inherit;
109 display: block;
110 }
111}
112
87@mixin avatar ($size) { 113@mixin avatar ($size) {
88 width: $size; 114 width: $size;
89 height: $size; 115 height: $size;