aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/account/user.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/account/user.ts')
-rw-r--r--server/models/account/user.ts159
1 files changed, 82 insertions, 77 deletions
diff --git a/server/models/account/user.ts b/server/models/account/user.ts
index 22e6715b4..e850d1e6d 100644
--- a/server/models/account/user.ts
+++ b/server/models/account/user.ts
@@ -23,6 +23,7 @@ import {
23} from 'sequelize-typescript' 23} from 'sequelize-typescript'
24import { 24import {
25 MMyUserFormattable, 25 MMyUserFormattable,
26 MUser,
26 MUserDefault, 27 MUserDefault,
27 MUserFormattable, 28 MUserFormattable,
28 MUserId, 29 MUserId,
@@ -70,6 +71,7 @@ import { VideoImportModel } from '../video/video-import'
70import { VideoPlaylistModel } from '../video/video-playlist' 71import { VideoPlaylistModel } from '../video/video-playlist'
71import { AccountModel } from './account' 72import { AccountModel } from './account'
72import { UserNotificationSettingModel } from './user-notification-setting' 73import { UserNotificationSettingModel } from './user-notification-setting'
74import { VideoLiveModel } from '../video/video-live'
73 75
74enum ScopeNames { 76enum ScopeNames {
75 FOR_ME_API = 'FOR_ME_API', 77 FOR_ME_API = 'FOR_ME_API',
@@ -540,7 +542,11 @@ export class UserModel extends Model<UserModel> {
540 return UserModel.findAll(query) 542 return UserModel.findAll(query)
541 } 543 }
542 544
543 static loadById (id: number, withStats = false): Bluebird<MUserDefault> { 545 static loadById (id: number): Bluebird<MUser> {
546 return UserModel.unscoped().findByPk(id)
547 }
548
549 static loadByIdWithChannels (id: number, withStats = false): Bluebird<MUserDefault> {
544 const scopes = [ 550 const scopes = [
545 ScopeNames.WITH_VIDEOCHANNELS 551 ScopeNames.WITH_VIDEOCHANNELS
546 ] 552 ]
@@ -685,26 +691,85 @@ export class UserModel extends Model<UserModel> {
685 return UserModel.findOne(query) 691 return UserModel.findOne(query)
686 } 692 }
687 693
688 static getOriginalVideoFileTotalFromUser (user: MUserId) { 694 static loadByLiveId (liveId: number): Bluebird<MUser> {
689 // Don't use sequelize because we need to use a sub query 695 const query = {
690 const query = UserModel.generateUserQuotaBaseSQL({ 696 include: [
691 withSelect: true, 697 {
692 whereUserId: '$userId' 698 attributes: [ 'id' ],
693 }) 699 model: AccountModel.unscoped(),
700 required: true,
701 include: [
702 {
703 attributes: [ 'id' ],
704 model: VideoChannelModel.unscoped(),
705 required: true,
706 include: [
707 {
708 attributes: [ 'id' ],
709 model: VideoModel.unscoped(),
710 required: true,
711 include: [
712 {
713 attributes: [ 'id', 'videoId' ],
714 model: VideoLiveModel.unscoped(),
715 required: true,
716 where: {
717 id: liveId
718 }
719 }
720 ]
721 }
722 ]
723 }
724 ]
725 }
726 ]
727 }
728
729 return UserModel.findOne(query)
730 }
731
732 static generateUserQuotaBaseSQL (options: {
733 whereUserId: '$userId' | '"UserModel"."id"'
734 withSelect: boolean
735 where?: string
736 }) {
737 const andWhere = options.where
738 ? 'AND ' + options.where
739 : ''
740
741 const videoChannelJoin = 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
742 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' +
743 `WHERE "account"."userId" = ${options.whereUserId} ${andWhere}`
744
745 const webtorrentFiles = 'SELECT "videoFile"."size" AS "size", "video"."id" AS "videoId" FROM "videoFile" ' +
746 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' +
747 videoChannelJoin
748
749 const hlsFiles = 'SELECT "videoFile"."size" AS "size", "video"."id" AS "videoId" FROM "videoFile" ' +
750 'INNER JOIN "videoStreamingPlaylist" ON "videoFile"."videoStreamingPlaylistId" = "videoStreamingPlaylist".id ' +
751 'INNER JOIN "video" ON "videoStreamingPlaylist"."videoId" = "video"."id" ' +
752 videoChannelJoin
694 753
695 return UserModel.getTotalRawQuery(query, user.id) 754 return 'SELECT COALESCE(SUM("size"), 0) AS "total" ' +
755 'FROM (' +
756 `SELECT MAX("t1"."size") AS "size" FROM (${webtorrentFiles} UNION ${hlsFiles}) t1 ` +
757 'GROUP BY "t1"."videoId"' +
758 ') t2'
696 } 759 }
697 760
698 // Returns cumulative size of all video files uploaded in the last 24 hours. 761 static getTotalRawQuery (query: string, userId: number) {
699 static getOriginalVideoFileTotalDailyFromUser (user: MUserId) { 762 const options = {
700 // Don't use sequelize because we need to use a sub query 763 bind: { userId },
701 const query = UserModel.generateUserQuotaBaseSQL({ 764 type: QueryTypes.SELECT as QueryTypes.SELECT
702 withSelect: true, 765 }
703 whereUserId: '$userId', 766
704 where: '"video"."createdAt" > now() - interval \'24 hours\'' 767 return UserModel.sequelize.query<{ total: string }>(query, options)
705 }) 768 .then(([ { total } ]) => {
769 if (total === null) return 0
706 770
707 return UserModel.getTotalRawQuery(query, user.id) 771 return parseInt(total, 10)
772 })
708 } 773 }
709 774
710 static async getStats () { 775 static async getStats () {
@@ -874,64 +939,4 @@ export class UserModel extends Model<UserModel> {
874 939
875 return Object.assign(formatted, { specialPlaylists }) 940 return Object.assign(formatted, { specialPlaylists })
876 } 941 }
877
878 async isAbleToUploadVideo (videoFile: { size: number }) {
879 if (this.videoQuota === -1 && this.videoQuotaDaily === -1) return Promise.resolve(true)
880
881 const [ totalBytes, totalBytesDaily ] = await Promise.all([
882 UserModel.getOriginalVideoFileTotalFromUser(this),
883 UserModel.getOriginalVideoFileTotalDailyFromUser(this)
884 ])
885
886 const uploadedTotal = videoFile.size + totalBytes
887 const uploadedDaily = videoFile.size + totalBytesDaily
888
889 if (this.videoQuotaDaily === -1) return uploadedTotal < this.videoQuota
890 if (this.videoQuota === -1) return uploadedDaily < this.videoQuotaDaily
891
892 return uploadedTotal < this.videoQuota && uploadedDaily < this.videoQuotaDaily
893 }
894
895 private static generateUserQuotaBaseSQL (options: {
896 whereUserId: '$userId' | '"UserModel"."id"'
897 withSelect: boolean
898 where?: string
899 }) {
900 const andWhere = options.where
901 ? 'AND ' + options.where
902 : ''
903
904 const videoChannelJoin = 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
905 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' +
906 `WHERE "account"."userId" = ${options.whereUserId} ${andWhere}`
907
908 const webtorrentFiles = 'SELECT "videoFile"."size" AS "size", "video"."id" AS "videoId" FROM "videoFile" ' +
909 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' +
910 videoChannelJoin
911
912 const hlsFiles = 'SELECT "videoFile"."size" AS "size", "video"."id" AS "videoId" FROM "videoFile" ' +
913 'INNER JOIN "videoStreamingPlaylist" ON "videoFile"."videoStreamingPlaylistId" = "videoStreamingPlaylist".id ' +
914 'INNER JOIN "video" ON "videoStreamingPlaylist"."videoId" = "video"."id" ' +
915 videoChannelJoin
916
917 return 'SELECT COALESCE(SUM("size"), 0) AS "total" ' +
918 'FROM (' +
919 `SELECT MAX("t1"."size") AS "size" FROM (${webtorrentFiles} UNION ${hlsFiles}) t1 ` +
920 'GROUP BY "t1"."videoId"' +
921 ') t2'
922 }
923
924 private static getTotalRawQuery (query: string, userId: number) {
925 const options = {
926 bind: { userId },
927 type: QueryTypes.SELECT as QueryTypes.SELECT
928 }
929
930 return UserModel.sequelize.query<{ total: string }>(query, options)
931 .then(([ { total } ]) => {
932 if (total === null) return 0
933
934 return parseInt(total, 10)
935 })
936 }
937} 942}