diff --git a/client/src/app/videos/+video-edit/video-add.component.ts b/client/src/app/videos/+video-edit/video-add.component.ts
index 066f945fc..a86d9d3c2 100644
--- a/client/src/app/videos/+video-edit/video-add.component.ts
+++ b/client/src/app/videos/+video-edit/video-add.component.ts
@@ -2,7 +2,9 @@ import { HttpEventType, HttpResponse } from '@angular/common/http'
import { Component, OnInit, ViewChild } from '@angular/core'
import { FormBuilder, FormGroup } from '@angular/forms'
import { Router } from '@angular/router'
+import { UserService } from '@app/shared'
import { NotificationsService } from 'angular2-notifications'
+import { BytesPipe } from 'ngx-pipes'
import { VideoPrivacy } from '../../../../../shared/models/videos'
import { AuthService, ServerService } from '../../core'
import { FormReactive } from '../../shared'
@@ -31,12 +33,12 @@ export class VideoAddComponent extends FormReactive implements OnInit {
uuid: ''
}
- error: string = null
form: FormGroup
formErrors: { [ id: string ]: string } = {}
validationMessages: ValidatorMessage = {}
userVideoChannels = []
+ userVideoQuotaUsed = 0
videoPrivacies = []
firstStepPrivacyId = 0
firstStepChannelId = 0
@@ -46,6 +48,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
private router: Router,
private notificationsService: NotificationsService,
private authService: AuthService,
+ private userService: UserService,
private serverService: ServerService,
private videoService: VideoService
) {
@@ -67,6 +70,9 @@ export class VideoAddComponent extends FormReactive implements OnInit {
populateAsyncUserVideoChannels(this.authService, this.userVideoChannels)
.then(() => this.firstStepChannelId = this.userVideoChannels[0].id)
+ this.userService.getMyVideoQuotaUsed()
+ .subscribe(data => this.userVideoQuotaUsed = data.videoQuotaUsed)
+
this.serverService.videoPrivaciesLoaded
.subscribe(
() => {
@@ -89,6 +95,18 @@ export class VideoAddComponent extends FormReactive implements OnInit {
uploadFirstStep () {
const videofile = this.videofileInput.nativeElement.files[0]
+ const videoQuota = this.authService.getUser().videoQuota
+ if ((this.userVideoQuotaUsed + videofile.size) > videoQuota) {
+ const bytePipes = new BytesPipe()
+
+ const msg = 'Your video quota is exceeded with this video ' +
+ `(video size: ${bytePipes.transform(videofile.size, 0)}, ` +
+ `used: ${bytePipes.transform(this.userVideoQuotaUsed, 0)}, ` +
+ `quota: ${bytePipes.transform(videoQuota, 0)})`
+ this.notificationsService.error('Error', msg)
+ return
+ }
+
const name = videofile.name.replace(/\.[^/.]+$/, '')
const privacy = this.firstStepPrivacyId.toString()
const nsfw = false
@@ -127,8 +145,9 @@ export class VideoAddComponent extends FormReactive implements OnInit {
err => {
// Reset progress
+ this.isUploadingVideo = false
this.videoUploadPercents = 0
- this.error = err.message
+ this.notificationsService.error('Error', err.message)
}
)
}
@@ -152,7 +171,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
},
err => {
- this.error = 'Cannot update the video.'
+ this.notificationsService.error('Error', err.message)
console.error(err)
}
)
diff --git a/client/src/app/videos/+video-edit/video-update.component.ts b/client/src/app/videos/+video-edit/video-update.component.ts
index 941ef2478..7f41b56d8 100644
--- a/client/src/app/videos/+video-edit/video-update.component.ts
+++ b/client/src/app/videos/+video-edit/video-update.component.ts
@@ -21,7 +21,6 @@ import { VideoService } from '../../shared/video/video.service'
export class VideoUpdateComponent extends FormReactive implements OnInit {
video: VideoEdit
- error: string = null
form: FormGroup
formErrors: { [ id: string ]: string } = {}
validationMessages: ValidatorMessage = {}
@@ -82,7 +81,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
err => {
console.error(err)
- this.error = 'Cannot fetch video.'
+ this.notificationsService.error('Error', err.message)
}
)
}
@@ -108,7 +107,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
},
err => {
- this.error = 'Cannot update the video.'
+ this.notificationsService.error('Error', err.message)
console.error(err)
}
)
diff --git a/server/controllers/api/users.ts b/server/controllers/api/users.ts
index 2d77a5249..5374c4b6a 100644
--- a/server/controllers/api/users.ts
+++ b/server/controllers/api/users.ts
@@ -30,6 +30,11 @@ usersRouter.get('/me',
asyncMiddleware(getUserInformation)
)
+usersRouter.get('/me/video-quota-used',
+ authenticate,
+ asyncMiddleware(getUserVideoQuotaUsed)
+)
+
usersRouter.get('/me/videos',
authenticate,
paginationValidator,
@@ -183,8 +188,18 @@ async function getUserInformation (req: express.Request, res: express.Response,
return res.json(user.toFormattedJSON())
}
+async function getUserVideoQuotaUsed (req: express.Request, res: express.Response, next: express.NextFunction) {
+ // We did not load channels in res.locals.user
+ const user = await UserModel.loadByUsernameAndPopulateChannels(res.locals.oauth.token.user.username)
+ const videoQuotaUsed = await UserModel.getOriginalVideoFileTotalFromUser(user)
+
+ return res.json({
+ videoQuotaUsed
+ })
+}
+
function getUser (req: express.Request, res: express.Response, next: express.NextFunction) {
- return res.json(res.locals.user.toFormattedJSON())
+ return res.json((res.locals.user as UserModel).toFormattedJSON())
}
async function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) {
diff --git a/server/models/account/user.ts b/server/models/account/user.ts
index 4226bcb35..e37fd4d3b 100644
--- a/server/models/account/user.ts
+++ b/server/models/account/user.ts
@@ -181,7 +181,7 @@ export class UserModel extends Model
{
return UserModel.findOne(query)
}
- private static getOriginalVideoFileTotalFromUser (user: UserModel) {
+ static getOriginalVideoFileTotalFromUser (user: UserModel) {
// Don't use sequelize because we need to use a sub query
const query = 'SELECT SUM("size") AS "total" FROM ' +
'(SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' +
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts
index f7e5972d3..b788637e7 100644
--- a/server/tests/api/users/users.ts
+++ b/server/tests/api/users/users.ts
@@ -4,7 +4,8 @@ import * as chai from 'chai'
import 'mocha'
import { UserRole } from '../../../../shared/index'
import {
- createUser, flushTests, getBlacklistedVideosList, getMyUserInformation, getMyUserVideoRating, getUserInformation, getUsersList,
+ createUser, flushTests, getBlacklistedVideosList, getMyUserInformation, getMyUserVideoQuotaUsed, getMyUserVideoRating, getUserInformation,
+ getUsersList,
getUsersListPaginationAndSort, getVideosList, killallServers, login, makePutBodyRequest, rateVideo, registerUser, removeUser, removeVideo,
runServer, ServerInfo, serverLogin, testVideoImage, updateMyAvatar, updateMyUser, updateUser, uploadVideo
} from '../../utils/index'
@@ -179,11 +180,19 @@ describe('Test users', function () {
this.timeout(5000)
const videoAttributes = {
- name: 'super user video'
+ name: 'super user video',
+ fixture: 'video_short.webm'
}
await uploadVideo(server.url, accessTokenUser, videoAttributes)
})
+ it('Should have video quota updated', async function () {
+ const res = await getMyUserVideoQuotaUsed(server.url, accessTokenUser)
+ const data = res.body
+
+ expect(data.videoQuotaUsed).to.equal(218910)
+ })
+
it('Should be able to list my videos', async function () {
const res = await getMyVideos(server.url, accessTokenUser, 0, 5)
expect(res.body.total).to.equal(1)
diff --git a/server/tests/utils/users/users.ts b/server/tests/utils/users/users.ts
index 90b1ca0a6..12945a805 100644
--- a/server/tests/utils/users/users.ts
+++ b/server/tests/utils/users/users.ts
@@ -56,6 +56,17 @@ function getMyUserInformation (url: string, accessToken: string, specialStatus =
.expect('Content-Type', /json/)
}
+function getMyUserVideoQuotaUsed (url: string, accessToken: string, specialStatus = 200) {
+ const path = '/api/v1/users/me/video-quota-used'
+
+ return request(url)
+ .get(path)
+ .set('Accept', 'application/json')
+ .set('Authorization', 'Bearer ' + accessToken)
+ .expect(specialStatus)
+ .expect('Content-Type', /json/)
+}
+
function getUserInformation (url: string, accessToken: string, userId: number) {
const path = '/api/v1/users/' + userId
@@ -192,6 +203,7 @@ export {
registerUser,
getMyUserInformation,
getMyUserVideoRating,
+ getMyUserVideoQuotaUsed,
getUsersList,
getUsersListPaginationAndSort,
removeUser,