Improve SQL query for my special playlists

This commit is contained in:
Chocobozzz 2020-01-03 14:17:57 +01:00
parent 35f28e94c7
commit ac0868bcc0
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
5 changed files with 64 additions and 43 deletions

View File

@ -126,14 +126,13 @@ async function getUserVideoImports (req: express.Request, res: express.Response)
async function getUserInformation (req: express.Request, res: express.Response) {
// We did not load channels in res.locals.user
const user = await UserModel.loadByUsernameAndPopulateChannels(res.locals.oauth.token.user.username)
const user = await UserModel.loadForMeAPI(res.locals.oauth.token.user.username)
return res.json(user.toFormattedJSON({ me: true }))
return res.json(user.toMeFormattedJSON())
}
async function getUserVideoQuotaUsed (req: express.Request, res: express.Response) {
// We did not load channels in res.locals.user
const user = await UserModel.loadByUsernameAndPopulateChannels(res.locals.oauth.token.user.username)
const user = res.locals.oauth.token.user
const videoQuotaUsed = await UserModel.getOriginalVideoFileTotalFromUser(user)
const videoQuotaUsedDaily = await UserModel.getOriginalVideoFileTotalDailyFromUser(user)

View File

@ -19,14 +19,15 @@ import {
Table,
UpdatedAt
} from 'sequelize-typescript'
import { hasUserRight, USER_ROLE_LABELS, UserRight, VideoPrivacy, MyUser } from '../../../shared'
import { hasUserRight, MyUser, USER_ROLE_LABELS, UserRight, VideoPlaylistType, VideoPrivacy } from '../../../shared'
import { User, UserRole } from '../../../shared/models/users'
import {
isNoInstanceConfigWarningModal,
isNoWelcomeModal,
isUserAdminFlagsValid,
isUserAutoPlayVideoValid,
isUserAutoPlayNextVideoValid,
isUserAutoPlayNextVideoPlaylistValid,
isUserAutoPlayNextVideoValid,
isUserAutoPlayVideoValid,
isUserBlockedReasonValid,
isUserBlockedValid,
isUserEmailVerifiedValid,
@ -38,8 +39,7 @@ import {
isUserVideoQuotaDailyValid,
isUserVideoQuotaValid,
isUserVideosHistoryEnabledValid,
isUserWebTorrentEnabledValid,
isNoWelcomeModal
isUserWebTorrentEnabledValid
} from '../../helpers/custom-validators/users'
import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto'
import { OAuthTokenModel } from '../oauth/oauth-token'
@ -61,16 +61,17 @@ import { isThemeNameValid } from '../../helpers/custom-validators/plugins'
import { getThemeOrDefault } from '../../lib/plugins/theme-utils'
import * as Bluebird from 'bluebird'
import {
MMyUserFormattable,
MUserDefault,
MUserFormattable,
MUserId,
MUserNotifSettingChannelDefault,
MUserWithNotificationSetting, MVideoFullLight
MUserWithNotificationSetting,
MVideoFullLight
} from '@server/typings/models'
enum ScopeNames {
WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL',
WITH_SPECIAL_PLAYLISTS = 'WITH_SPECIAL_PLAYLISTS'
FOR_ME_API = 'FOR_ME_API'
}
@DefaultScope(() => ({
@ -86,28 +87,31 @@ enum ScopeNames {
]
}))
@Scopes(() => ({
[ScopeNames.WITH_VIDEO_CHANNEL]: {
[ScopeNames.FOR_ME_API]: {
include: [
{
model: AccountModel,
required: true,
include: [ VideoChannelModel ]
include: [
{
model: VideoChannelModel
},
{
attributes: [ 'id', 'name', 'type' ],
model: VideoPlaylistModel.unscoped(),
required: true,
where: {
type: {
[ Op.ne ]: VideoPlaylistType.REGULAR
}
}
}
]
},
{
model: UserNotificationSettingModel,
required: true
}
]
},
[ScopeNames.WITH_SPECIAL_PLAYLISTS]: {
attributes: {
include: [
[
literal('(select array(select "id" from "videoPlaylist" where "ownerAccountId" in (select id from public.account where "userId" = "UserModel"."id") and name LIKE \'Watch later\'))'),
'specialPlaylists'
]
]
}
}
}))
@Table({
@ -436,17 +440,14 @@ export class UserModel extends Model<UserModel> {
return UserModel.findOne(query)
}
static loadByUsernameAndPopulateChannels (username: string): Bluebird<MUserNotifSettingChannelDefault> {
static loadForMeAPI (username: string): Bluebird<MUserNotifSettingChannelDefault> {
const query = {
where: {
username: { [ Op.iLike ]: username }
}
}
return UserModel.scope([
ScopeNames.WITH_VIDEO_CHANNEL,
ScopeNames.WITH_SPECIAL_PLAYLISTS
]).findOne(query)
return UserModel.scope(ScopeNames.FOR_ME_API).findOne(query)
}
static loadByEmail (email: string): Bluebird<MUserDefault> {
@ -625,11 +626,11 @@ export class UserModel extends Model<UserModel> {
return comparePassword(password, this.password)
}
toFormattedJSON (this: MUserFormattable, parameters: { withAdminFlags?: boolean, me?: boolean } = {}): User | MyUser {
toFormattedJSON (this: MUserFormattable, parameters: { withAdminFlags?: boolean } = {}): User {
const videoQuotaUsed = this.get('videoQuotaUsed')
const videoQuotaUsedDaily = this.get('videoQuotaUsedDaily')
const json: User | MyUser = {
const json: User = {
id: this.id,
username: this.username,
email: this.email,
@ -690,15 +691,18 @@ export class UserModel extends Model<UserModel> {
})
}
if (parameters.me) {
Object.assign(json, {
specialPlaylists: (this.get('specialPlaylists') as Array<number>).map(p => ({ id: p }))
})
}
return json
}
toMeFormattedJSON (this: MMyUserFormattable): MyUser {
const formatted = this.toFormattedJSON()
const specialPlaylists = this.Account.VideoPlaylists
.map(p => ({ id: p.id, name: p.name, type: p.type }))
return Object.assign(formatted, { specialPlaylists })
}
async isAbleToUploadVideo (videoFile: { size: number }) {
if (this.videoQuota === -1 && this.videoQuotaDaily === -1) return Promise.resolve(true)

View File

@ -2,7 +2,7 @@
import * as chai from 'chai'
import 'mocha'
import { User, UserRole, Video, MyUser } from '../../../../shared/index'
import { User, UserRole, Video, MyUser, VideoPlaylistType } from '../../../../shared/index'
import {
blockUser,
cleanupTests,
@ -251,7 +251,7 @@ describe('Test users', function () {
it('Should be able to get user information', async function () {
const res1 = await getMyUserInformation(server.url, accessTokenUser)
const userMe: User & MyUser = res1.body
const userMe: MyUser = res1.body
const res2 = await getUserInformation(server.url, server.accessToken, userMe.id)
const userGet: User = res2.body
@ -271,6 +271,7 @@ describe('Test users', function () {
expect(userGet.adminFlags).to.equal(UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST)
expect(userMe.specialPlaylists).to.have.lengthOf(1)
expect(userMe.specialPlaylists[0].type).to.equal(VideoPlaylistType.WATCH_LATER)
})
})

View File

@ -12,6 +12,7 @@ import {
import { MNotificationSetting, MNotificationSettingFormattable } from './user-notification-setting'
import { AccountModel } from '@server/models/account/account'
import { MChannelFormattable } from '../video/video-channels'
import { MVideoPlaylist } from '@server/typings/models'
type Use<K extends keyof UserModel, M> = PickWith<UserModel, K, M>
@ -65,6 +66,13 @@ export type MUserDefault = MUser &
// Format for API or AP object
type MAccountWithChannels = MAccountFormattable & PickWithOpt<AccountModel, 'VideoChannels', MChannelFormattable[]>
type MAccountWithChannelsAndSpecialPlaylists = MAccountWithChannels &
PickWithOpt<AccountModel, 'VideoPlaylists', MVideoPlaylist[]>
export type MUserFormattable = MUserQuotaUsed &
Use<'Account', MAccountFormattable & PickWithOpt<AccountModel, 'VideoChannels', MChannelFormattable[]>> &
Use<'Account', MAccountWithChannels> &
PickWithOpt<UserModel, 'NotificationSetting', MNotificationSettingFormattable>
export type MMyUserFormattable = MUserFormattable &
Use<'Account', MAccountWithChannelsAndSpecialPlaylists>

View File

@ -5,6 +5,7 @@ import { UserRole } from './user-role'
import { NSFWPolicyType } from '../videos/nsfw-policy.type'
import { UserNotificationSetting } from './user-notification-setting.model'
import { UserAdminFlag } from './user-flag.model'
import { VideoPlaylistType } from '@shared/models'
export interface User {
id: number
@ -47,6 +48,14 @@ export interface User {
createdAt: Date
}
export interface MyUser extends User {
specialPlaylists: Partial<VideoPlaylist>[]
export interface MyUserSpecialPlaylist {
id: number
name: string
type: VideoPlaylistType
}
export interface MyUser extends User {
specialPlaylists: MyUserSpecialPlaylist[]
}