]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/user.ts
Try to speed up server tests
[github/Chocobozzz/PeerTube.git] / server / lib / user.ts
CommitLineData
fb719404 1import { Transaction } from 'sequelize/types'
bdd428a6 2import { v4 as uuidv4 } from 'uuid'
fb719404 3import { UserModel } from '@server/models/account/user'
50d6de9c 4import { ActivityPubActorType } from '../../shared/models/activitypub'
fb719404 5import { UserNotificationSetting, UserNotificationSettingValue } from '../../shared/models/users'
d1ab89de 6import { SERVER_ACTOR_NAME, WEBSERVER } from '../initializers/constants'
fb719404 7import { sequelizeTypescript } from '../initializers/database'
3fd3ab2d 8import { AccountModel } from '../models/account/account'
cef534ed 9import { UserNotificationSettingModel } from '../models/account/user-notification-setting'
fb719404 10import { ActorModel } from '../models/activitypub/actor'
26d6bf65
C
11import { MAccountDefault, MActorDefault, MChannelActor } from '../types/models'
12import { MUser, MUserDefault, MUserId } from '../types/models/user'
fb719404 13import { buildActorInstance, setAsyncActorKeys } from './activitypub/actor'
de94ac86 14import { getLocalAccountActivityPubUrl } from './activitypub/url'
fb719404
C
15import { Emailer } from './emailer'
16import { LiveManager } from './live-manager'
17import { Redis } from './redis'
18import { createLocalVideoChannel } from './video-channel'
19import { createWatchLaterPlaylist } from './video-playlist'
20
e590b4a5 21type ChannelNames = { name: string, displayName: string }
453e83ea 22
1f20622f 23async function createUserAccountAndChannelAndPlaylist (parameters: {
a1587156
C
24 userToCreate: MUser
25 userDisplayName?: string
26 channelNames?: ChannelNames
1f20622f 27 validateUser?: boolean
1ca9f7c3 28}): Promise<{ user: MUserDefault, account: MAccountDefault, videoChannel: MChannelActor }> {
1f20622f
C
29 const { userToCreate, userDisplayName, channelNames, validateUser = true } = parameters
30
f05a1c30 31 const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => {
72c7248b
C
32 const userOptions = {
33 transaction: t,
34 validate: validateUser
35 }
36
1ca9f7c3 37 const userCreated: MUserDefault = await userToCreate.save(userOptions)
cef534ed
C
38 userCreated.NotificationSetting = await createDefaultUserNotificationSettings(userCreated, t)
39
1f20622f
C
40 const accountCreated = await createLocalAccountWithoutKeys({
41 name: userCreated.username,
42 displayName: userDisplayName,
43 userId: userCreated.id,
44 applicationId: null,
45 t: t
46 })
80e36cd9 47 userCreated.Account = accountCreated
f5028693 48
e590b4a5 49 const channelAttributes = await buildChannelAttributes(userCreated, channelNames)
1ca9f7c3 50 const videoChannel = await createLocalVideoChannel(channelAttributes, accountCreated, t)
f5028693 51
df0b219d
C
52 const videoPlaylist = await createWatchLaterPlaylist(accountCreated, t)
53
54 return { user: userCreated, account: accountCreated, videoChannel, videoPlaylist }
72c7248b 55 })
f5028693 56
453e83ea 57 const [ accountActorWithKeys, channelActorWithKeys ] = await Promise.all([
0b2f03d3
C
58 setAsyncActorKeys(account.Actor),
59 setAsyncActorKeys(videoChannel.Actor)
60 ])
61
453e83ea
C
62 account.Actor = accountActorWithKeys
63 videoChannel.Actor = channelActorWithKeys
47e0652b 64
453e83ea 65 return { user, account, videoChannel }
72c7248b
C
66}
67
1f20622f 68async function createLocalAccountWithoutKeys (parameters: {
a1587156
C
69 name: string
70 displayName?: string
71 userId: number | null
72 applicationId: number | null
73 t: Transaction | undefined
1f20622f
C
74 type?: ActivityPubActorType
75}) {
76 const { name, displayName, userId, applicationId, t, type = 'Person' } = parameters
de94ac86 77 const url = getLocalAccountActivityPubUrl(name)
571389d4 78
50d6de9c 79 const actorInstance = buildActorInstance(type, url, name)
1ca9f7c3 80 const actorInstanceCreated: MActorDefault = await actorInstance.save({ transaction: t })
fadf619a
C
81
82 const accountInstance = new AccountModel({
1f20622f 83 name: displayName || name,
571389d4
C
84 userId,
85 applicationId,
c39ea24b 86 actorId: actorInstanceCreated.id
1735c825 87 })
571389d4 88
1ca9f7c3 89 const accountInstanceCreated: MAccountDefault = await accountInstance.save({ transaction: t })
fadf619a
C
90 accountInstanceCreated.Actor = actorInstanceCreated
91
92 return accountInstanceCreated
571389d4
C
93}
94
50d6de9c 95async function createApplicationActor (applicationId: number) {
1f20622f
C
96 const accountCreated = await createLocalAccountWithoutKeys({
97 name: SERVER_ACTOR_NAME,
98 userId: null,
99 applicationId: applicationId,
100 t: undefined,
101 type: 'Application'
102 })
50d6de9c
C
103
104 accountCreated.Actor = await setAsyncActorKeys(accountCreated.Actor)
105
106 return accountCreated
107}
108
453e83ea 109async function sendVerifyUserEmail (user: MUser, isPendingEmail = false) {
d1ab89de
C
110 const verificationString = await Redis.Instance.setVerifyEmailVerificationString(user.id)
111 let url = WEBSERVER.URL + '/verify-account/email?userId=' + user.id + '&verificationString=' + verificationString
112
113 if (isPendingEmail) url += '&isPendingEmail=true'
114
115 const email = isPendingEmail ? user.pendingEmail : user.email
963023ab 116 const username = user.username
d1ab89de 117
963023ab 118 await Emailer.Instance.addVerifyEmailJob(username, email, url)
d1ab89de
C
119}
120
fb719404
C
121async function getOriginalVideoFileTotalFromUser (user: MUserId) {
122 // Don't use sequelize because we need to use a sub query
123 const query = UserModel.generateUserQuotaBaseSQL({
124 withSelect: true,
125 whereUserId: '$userId'
126 })
127
128 const base = await UserModel.getTotalRawQuery(query, user.id)
129
130 return base + LiveManager.Instance.getLiveQuotaUsedByUser(user.id)
131}
132
133// Returns cumulative size of all video files uploaded in the last 24 hours.
134async function getOriginalVideoFileTotalDailyFromUser (user: MUserId) {
135 // Don't use sequelize because we need to use a sub query
136 const query = UserModel.generateUserQuotaBaseSQL({
137 withSelect: true,
138 whereUserId: '$userId',
139 where: '"video"."createdAt" > now() - interval \'24 hours\''
140 })
141
142 const base = await UserModel.getTotalRawQuery(query, user.id)
143
144 return base + LiveManager.Instance.getLiveQuotaUsedByUser(user.id)
145}
146
147async function isAbleToUploadVideo (userId: number, size: number) {
148 const user = await UserModel.loadById(userId)
149
150 if (user.videoQuota === -1 && user.videoQuotaDaily === -1) return Promise.resolve(true)
151
152 const [ totalBytes, totalBytesDaily ] = await Promise.all([
97969c4e
C
153 getOriginalVideoFileTotalFromUser(user),
154 getOriginalVideoFileTotalDailyFromUser(user)
fb719404
C
155 ])
156
157 const uploadedTotal = size + totalBytes
158 const uploadedDaily = size + totalBytesDaily
159
160 if (user.videoQuotaDaily === -1) return uploadedTotal < user.videoQuota
161 if (user.videoQuota === -1) return uploadedDaily < user.videoQuotaDaily
162
163 return uploadedTotal < user.videoQuota && uploadedDaily < user.videoQuotaDaily
164}
165
72c7248b
C
166// ---------------------------------------------------------------------------
167
168export {
fb719404
C
169 getOriginalVideoFileTotalFromUser,
170 getOriginalVideoFileTotalDailyFromUser,
50d6de9c 171 createApplicationActor,
df0b219d 172 createUserAccountAndChannelAndPlaylist,
d1ab89de 173 createLocalAccountWithoutKeys,
fb719404
C
174 sendVerifyUserEmail,
175 isAbleToUploadVideo
72c7248b 176}
cef534ed
C
177
178// ---------------------------------------------------------------------------
179
453e83ea 180function createDefaultUserNotificationSettings (user: MUserId, t: Transaction | undefined) {
f7cc67b4 181 const values: UserNotificationSetting & { userId: number } = {
cef534ed 182 userId: user.id,
2f1548fd
C
183 newVideoFromSubscription: UserNotificationSettingValue.WEB,
184 newCommentOnMyVideo: UserNotificationSettingValue.WEB,
185 myVideoImportFinished: UserNotificationSettingValue.WEB,
186 myVideoPublished: UserNotificationSettingValue.WEB,
4f32032f 187 abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
7ccddd7b 188 videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
2f1548fd
C
189 blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
190 newUserRegistration: UserNotificationSettingValue.WEB,
191 commentMention: UserNotificationSettingValue.WEB,
883993c8 192 newFollow: UserNotificationSettingValue.WEB,
8424c402 193 newInstanceFollower: UserNotificationSettingValue.WEB,
594d3e48
C
194 abuseNewMessage: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
195 abuseStateChange: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
8424c402 196 autoInstanceFollowing: UserNotificationSettingValue.WEB
f7cc67b4
C
197 }
198
199 return UserNotificationSettingModel.create(values, { transaction: t })
cef534ed 200}
e590b4a5 201
453e83ea 202async function buildChannelAttributes (user: MUser, channelNames?: ChannelNames) {
e590b4a5
C
203 if (channelNames) return channelNames
204
205 let channelName = user.username + '_channel'
206
207 // Conflict, generate uuid instead
208 const actor = await ActorModel.loadLocalByName(channelName)
209 if (actor) channelName = uuidv4()
210
211 const videoChannelDisplayName = `Main ${user.username} channel`
212
213 return {
214 name: channelName,
215 displayName: videoChannelDisplayName
216 }
217}