mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2024-12-01 04:49:16 -06:00
Improve SQL query for my special playlists
This commit is contained in:
parent
35f28e94c7
commit
ac0868bcc0
@ -126,14 +126,13 @@ async function getUserVideoImports (req: express.Request, res: express.Response)
|
|||||||
|
|
||||||
async function getUserInformation (req: express.Request, res: express.Response) {
|
async function getUserInformation (req: express.Request, res: express.Response) {
|
||||||
// We did not load channels in res.locals.user
|
// 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) {
|
async function getUserVideoQuotaUsed (req: express.Request, res: express.Response) {
|
||||||
// We did not load channels in res.locals.user
|
const user = res.locals.oauth.token.user
|
||||||
const user = await UserModel.loadByUsernameAndPopulateChannels(res.locals.oauth.token.user.username)
|
|
||||||
const videoQuotaUsed = await UserModel.getOriginalVideoFileTotalFromUser(user)
|
const videoQuotaUsed = await UserModel.getOriginalVideoFileTotalFromUser(user)
|
||||||
const videoQuotaUsedDaily = await UserModel.getOriginalVideoFileTotalDailyFromUser(user)
|
const videoQuotaUsedDaily = await UserModel.getOriginalVideoFileTotalDailyFromUser(user)
|
||||||
|
|
||||||
|
@ -19,14 +19,15 @@ import {
|
|||||||
Table,
|
Table,
|
||||||
UpdatedAt
|
UpdatedAt
|
||||||
} from 'sequelize-typescript'
|
} 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 { User, UserRole } from '../../../shared/models/users'
|
||||||
import {
|
import {
|
||||||
isNoInstanceConfigWarningModal,
|
isNoInstanceConfigWarningModal,
|
||||||
|
isNoWelcomeModal,
|
||||||
isUserAdminFlagsValid,
|
isUserAdminFlagsValid,
|
||||||
isUserAutoPlayVideoValid,
|
|
||||||
isUserAutoPlayNextVideoValid,
|
|
||||||
isUserAutoPlayNextVideoPlaylistValid,
|
isUserAutoPlayNextVideoPlaylistValid,
|
||||||
|
isUserAutoPlayNextVideoValid,
|
||||||
|
isUserAutoPlayVideoValid,
|
||||||
isUserBlockedReasonValid,
|
isUserBlockedReasonValid,
|
||||||
isUserBlockedValid,
|
isUserBlockedValid,
|
||||||
isUserEmailVerifiedValid,
|
isUserEmailVerifiedValid,
|
||||||
@ -38,8 +39,7 @@ import {
|
|||||||
isUserVideoQuotaDailyValid,
|
isUserVideoQuotaDailyValid,
|
||||||
isUserVideoQuotaValid,
|
isUserVideoQuotaValid,
|
||||||
isUserVideosHistoryEnabledValid,
|
isUserVideosHistoryEnabledValid,
|
||||||
isUserWebTorrentEnabledValid,
|
isUserWebTorrentEnabledValid
|
||||||
isNoWelcomeModal
|
|
||||||
} from '../../helpers/custom-validators/users'
|
} from '../../helpers/custom-validators/users'
|
||||||
import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto'
|
import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto'
|
||||||
import { OAuthTokenModel } from '../oauth/oauth-token'
|
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 { getThemeOrDefault } from '../../lib/plugins/theme-utils'
|
||||||
import * as Bluebird from 'bluebird'
|
import * as Bluebird from 'bluebird'
|
||||||
import {
|
import {
|
||||||
|
MMyUserFormattable,
|
||||||
MUserDefault,
|
MUserDefault,
|
||||||
MUserFormattable,
|
MUserFormattable,
|
||||||
MUserId,
|
MUserId,
|
||||||
MUserNotifSettingChannelDefault,
|
MUserNotifSettingChannelDefault,
|
||||||
MUserWithNotificationSetting, MVideoFullLight
|
MUserWithNotificationSetting,
|
||||||
|
MVideoFullLight
|
||||||
} from '@server/typings/models'
|
} from '@server/typings/models'
|
||||||
|
|
||||||
enum ScopeNames {
|
enum ScopeNames {
|
||||||
WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL',
|
FOR_ME_API = 'FOR_ME_API'
|
||||||
WITH_SPECIAL_PLAYLISTS = 'WITH_SPECIAL_PLAYLISTS'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@DefaultScope(() => ({
|
@DefaultScope(() => ({
|
||||||
@ -86,28 +87,31 @@ enum ScopeNames {
|
|||||||
]
|
]
|
||||||
}))
|
}))
|
||||||
@Scopes(() => ({
|
@Scopes(() => ({
|
||||||
[ScopeNames.WITH_VIDEO_CHANNEL]: {
|
[ScopeNames.FOR_ME_API]: {
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
model: AccountModel,
|
model: AccountModel,
|
||||||
required: true,
|
include: [
|
||||||
include: [ VideoChannelModel ]
|
{
|
||||||
|
model: VideoChannelModel
|
||||||
|
},
|
||||||
|
{
|
||||||
|
attributes: [ 'id', 'name', 'type' ],
|
||||||
|
model: VideoPlaylistModel.unscoped(),
|
||||||
|
required: true,
|
||||||
|
where: {
|
||||||
|
type: {
|
||||||
|
[ Op.ne ]: VideoPlaylistType.REGULAR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
model: UserNotificationSettingModel,
|
model: UserNotificationSettingModel,
|
||||||
required: true
|
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({
|
@Table({
|
||||||
@ -436,17 +440,14 @@ export class UserModel extends Model<UserModel> {
|
|||||||
return UserModel.findOne(query)
|
return UserModel.findOne(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
static loadByUsernameAndPopulateChannels (username: string): Bluebird<MUserNotifSettingChannelDefault> {
|
static loadForMeAPI (username: string): Bluebird<MUserNotifSettingChannelDefault> {
|
||||||
const query = {
|
const query = {
|
||||||
where: {
|
where: {
|
||||||
username: { [ Op.iLike ]: username }
|
username: { [ Op.iLike ]: username }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return UserModel.scope([
|
return UserModel.scope(ScopeNames.FOR_ME_API).findOne(query)
|
||||||
ScopeNames.WITH_VIDEO_CHANNEL,
|
|
||||||
ScopeNames.WITH_SPECIAL_PLAYLISTS
|
|
||||||
]).findOne(query)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static loadByEmail (email: string): Bluebird<MUserDefault> {
|
static loadByEmail (email: string): Bluebird<MUserDefault> {
|
||||||
@ -625,11 +626,11 @@ export class UserModel extends Model<UserModel> {
|
|||||||
return comparePassword(password, this.password)
|
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 videoQuotaUsed = this.get('videoQuotaUsed')
|
||||||
const videoQuotaUsedDaily = this.get('videoQuotaUsedDaily')
|
const videoQuotaUsedDaily = this.get('videoQuotaUsedDaily')
|
||||||
|
|
||||||
const json: User | MyUser = {
|
const json: User = {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
username: this.username,
|
username: this.username,
|
||||||
email: this.email,
|
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
|
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 }) {
|
async isAbleToUploadVideo (videoFile: { size: number }) {
|
||||||
if (this.videoQuota === -1 && this.videoQuotaDaily === -1) return Promise.resolve(true)
|
if (this.videoQuota === -1 && this.videoQuotaDaily === -1) return Promise.resolve(true)
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import * as chai from 'chai'
|
import * as chai from 'chai'
|
||||||
import 'mocha'
|
import 'mocha'
|
||||||
import { User, UserRole, Video, MyUser } from '../../../../shared/index'
|
import { User, UserRole, Video, MyUser, VideoPlaylistType } from '../../../../shared/index'
|
||||||
import {
|
import {
|
||||||
blockUser,
|
blockUser,
|
||||||
cleanupTests,
|
cleanupTests,
|
||||||
@ -251,7 +251,7 @@ describe('Test users', function () {
|
|||||||
|
|
||||||
it('Should be able to get user information', async function () {
|
it('Should be able to get user information', async function () {
|
||||||
const res1 = await getMyUserInformation(server.url, accessTokenUser)
|
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 res2 = await getUserInformation(server.url, server.accessToken, userMe.id)
|
||||||
const userGet: User = res2.body
|
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(userGet.adminFlags).to.equal(UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST)
|
||||||
|
|
||||||
expect(userMe.specialPlaylists).to.have.lengthOf(1)
|
expect(userMe.specialPlaylists).to.have.lengthOf(1)
|
||||||
|
expect(userMe.specialPlaylists[0].type).to.equal(VideoPlaylistType.WATCH_LATER)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
import { MNotificationSetting, MNotificationSettingFormattable } from './user-notification-setting'
|
import { MNotificationSetting, MNotificationSettingFormattable } from './user-notification-setting'
|
||||||
import { AccountModel } from '@server/models/account/account'
|
import { AccountModel } from '@server/models/account/account'
|
||||||
import { MChannelFormattable } from '../video/video-channels'
|
import { MChannelFormattable } from '../video/video-channels'
|
||||||
|
import { MVideoPlaylist } from '@server/typings/models'
|
||||||
|
|
||||||
type Use<K extends keyof UserModel, M> = PickWith<UserModel, K, M>
|
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
|
// Format for API or AP object
|
||||||
|
|
||||||
|
type MAccountWithChannels = MAccountFormattable & PickWithOpt<AccountModel, 'VideoChannels', MChannelFormattable[]>
|
||||||
|
type MAccountWithChannelsAndSpecialPlaylists = MAccountWithChannels &
|
||||||
|
PickWithOpt<AccountModel, 'VideoPlaylists', MVideoPlaylist[]>
|
||||||
|
|
||||||
export type MUserFormattable = MUserQuotaUsed &
|
export type MUserFormattable = MUserQuotaUsed &
|
||||||
Use<'Account', MAccountFormattable & PickWithOpt<AccountModel, 'VideoChannels', MChannelFormattable[]>> &
|
Use<'Account', MAccountWithChannels> &
|
||||||
PickWithOpt<UserModel, 'NotificationSetting', MNotificationSettingFormattable>
|
PickWithOpt<UserModel, 'NotificationSetting', MNotificationSettingFormattable>
|
||||||
|
|
||||||
|
export type MMyUserFormattable = MUserFormattable &
|
||||||
|
Use<'Account', MAccountWithChannelsAndSpecialPlaylists>
|
||||||
|
@ -5,6 +5,7 @@ import { UserRole } from './user-role'
|
|||||||
import { NSFWPolicyType } from '../videos/nsfw-policy.type'
|
import { NSFWPolicyType } from '../videos/nsfw-policy.type'
|
||||||
import { UserNotificationSetting } from './user-notification-setting.model'
|
import { UserNotificationSetting } from './user-notification-setting.model'
|
||||||
import { UserAdminFlag } from './user-flag.model'
|
import { UserAdminFlag } from './user-flag.model'
|
||||||
|
import { VideoPlaylistType } from '@shared/models'
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
id: number
|
id: number
|
||||||
@ -47,6 +48,14 @@ export interface User {
|
|||||||
createdAt: Date
|
createdAt: Date
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MyUser extends User {
|
export interface MyUserSpecialPlaylist {
|
||||||
specialPlaylists: Partial<VideoPlaylist>[]
|
id: number
|
||||||
|
name: string
|
||||||
|
type: VideoPlaylistType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MyUser extends User {
|
||||||
|
specialPlaylists: MyUserSpecialPlaylist[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user