Fix issues on server start
This commit is contained in:
parent
1e1265b36c
commit
e34c85e527
14 changed files with 96 additions and 65 deletions
|
@ -3,6 +3,7 @@ import * as validator from 'validator'
|
||||||
import { exists, isUUIDValid } from '../misc'
|
import { exists, isUUIDValid } from '../misc'
|
||||||
import { isActivityPubUrlValid } from './misc'
|
import { isActivityPubUrlValid } from './misc'
|
||||||
import { isUserUsernameValid } from '../users'
|
import { isUserUsernameValid } from '../users'
|
||||||
|
import { CONSTRAINTS_FIELDS } from '../../../initializers/constants'
|
||||||
|
|
||||||
function isAccountEndpointsObjectValid (endpointObject: any) {
|
function isAccountEndpointsObjectValid (endpointObject: any) {
|
||||||
return isAccountSharedInboxValid(endpointObject.sharedInbox)
|
return isAccountSharedInboxValid(endpointObject.sharedInbox)
|
||||||
|
@ -34,7 +35,8 @@ function isAccountPublicKeyValid (publicKey: string) {
|
||||||
return exists(publicKey) &&
|
return exists(publicKey) &&
|
||||||
typeof publicKey === 'string' &&
|
typeof publicKey === 'string' &&
|
||||||
publicKey.startsWith('-----BEGIN PUBLIC KEY-----') &&
|
publicKey.startsWith('-----BEGIN PUBLIC KEY-----') &&
|
||||||
publicKey.endsWith('-----END PUBLIC KEY-----')
|
publicKey.endsWith('-----END PUBLIC KEY-----') &&
|
||||||
|
validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACCOUNTS.PUBLIC_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isAccountIdValid (id: string) {
|
function isAccountIdValid (id: string) {
|
||||||
|
@ -73,7 +75,8 @@ function isAccountPrivateKeyValid (privateKey: string) {
|
||||||
return exists(privateKey) &&
|
return exists(privateKey) &&
|
||||||
typeof privateKey === 'string' &&
|
typeof privateKey === 'string' &&
|
||||||
privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') &&
|
privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') &&
|
||||||
privateKey.endsWith('-----END RSA PRIVATE KEY-----')
|
privateKey.endsWith('-----END RSA PRIVATE KEY-----') &&
|
||||||
|
validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACCOUNTS.PRIVATE_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isRemoteAccountValid (remoteAccount: any) {
|
function isRemoteAccountValid (remoteAccount: any) {
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
import * as validator from 'validator'
|
||||||
import { exists } from '../misc'
|
import { exists } from '../misc'
|
||||||
|
import { isTestInstance } from '../../core-utils'
|
||||||
|
import { CONSTRAINTS_FIELDS } from '../../../initializers/constants'
|
||||||
|
|
||||||
function isActivityPubUrlValid (url: string) {
|
function isActivityPubUrlValid (url: string) {
|
||||||
const isURLOptions = {
|
const isURLOptions = {
|
||||||
|
@ -9,7 +12,12 @@ function isActivityPubUrlValid (url: string) {
|
||||||
protocols: [ 'http', 'https' ]
|
protocols: [ 'http', 'https' ]
|
||||||
}
|
}
|
||||||
|
|
||||||
return exists(url) && validator.isURL(url, isURLOptions)
|
// We validate 'localhost', so we don't have the top level domain
|
||||||
|
if (isTestInstance()) {
|
||||||
|
isURLOptions.require_tld = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return exists(url) && validator.isURL(url, isURLOptions) && validator.isLength(url, CONSTRAINTS_FIELDS.ACCOUNTS.URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isBaseActivityValid (activity: any, type: string) {
|
function isBaseActivityValid (activity: any, type: string) {
|
||||||
|
|
|
@ -10,7 +10,8 @@ import {
|
||||||
isVideoTruncatedDescriptionValid,
|
isVideoTruncatedDescriptionValid,
|
||||||
isVideoDurationValid,
|
isVideoDurationValid,
|
||||||
isVideoNameValid,
|
isVideoNameValid,
|
||||||
isVideoTagValid
|
isVideoTagValid,
|
||||||
|
isVideoUrlValid
|
||||||
} from '../videos'
|
} from '../videos'
|
||||||
import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels'
|
import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels'
|
||||||
import { isBaseActivityValid } from './misc'
|
import { isBaseActivityValid } from './misc'
|
||||||
|
@ -93,7 +94,7 @@ function isRemoteVideoContentValid (mediaType: string, content: string) {
|
||||||
|
|
||||||
function isRemoteVideoIconValid (icon: any) {
|
function isRemoteVideoIconValid (icon: any) {
|
||||||
return icon.type === 'Image' &&
|
return icon.type === 'Image' &&
|
||||||
validator.isURL(icon.url) &&
|
isVideoUrlValid(icon.url) &&
|
||||||
icon.mediaType === 'image/jpeg' &&
|
icon.mediaType === 'image/jpeg' &&
|
||||||
validator.isInt(icon.width, { min: 0 }) &&
|
validator.isInt(icon.width, { min: 0 }) &&
|
||||||
validator.isInt(icon.height, { min: 0 })
|
validator.isInt(icon.height, { min: 0 })
|
||||||
|
@ -111,7 +112,7 @@ function setValidRemoteVideoUrls (video: any) {
|
||||||
function isRemoteVideoUrlValid (url: any) {
|
function isRemoteVideoUrlValid (url: any) {
|
||||||
return url.type === 'Link' &&
|
return url.type === 'Link' &&
|
||||||
ACTIVITY_PUB.VIDEO_URL_MIME_TYPES.indexOf(url.mimeType) !== -1 &&
|
ACTIVITY_PUB.VIDEO_URL_MIME_TYPES.indexOf(url.mimeType) !== -1 &&
|
||||||
validator.isURL(url.url) &&
|
isVideoUrlValid(url.url) &&
|
||||||
validator.isInt(url.width, { min: 0 }) &&
|
validator.isInt(url.width, { min: 0 }) &&
|
||||||
validator.isInt(url.size, { min: 0 })
|
validator.isInt(url.size, { min: 0 })
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,14 @@ import { database as db, CONSTRAINTS_FIELDS } from '../../initializers'
|
||||||
import { VideoChannelInstance } from '../../models'
|
import { VideoChannelInstance } from '../../models'
|
||||||
import { logger } from '../logger'
|
import { logger } from '../logger'
|
||||||
import { exists } from './misc'
|
import { exists } from './misc'
|
||||||
|
import { isActivityPubUrlValid } from './index'
|
||||||
|
|
||||||
const VIDEO_CHANNELS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_CHANNELS
|
const VIDEO_CHANNELS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_CHANNELS
|
||||||
|
|
||||||
|
function isVideoChannelUrlValid (value: string) {
|
||||||
|
return isActivityPubUrlValid(value)
|
||||||
|
}
|
||||||
|
|
||||||
function isVideoChannelDescriptionValid (value: string) {
|
function isVideoChannelDescriptionValid (value: string) {
|
||||||
return value === null || validator.isLength(value, VIDEO_CHANNELS_CONSTRAINTS_FIELDS.DESCRIPTION)
|
return value === null || validator.isLength(value, VIDEO_CHANNELS_CONSTRAINTS_FIELDS.DESCRIPTION)
|
||||||
}
|
}
|
||||||
|
@ -53,5 +58,6 @@ export {
|
||||||
isVideoChannelDescriptionValid,
|
isVideoChannelDescriptionValid,
|
||||||
isVideoChannelNameValid,
|
isVideoChannelNameValid,
|
||||||
isVideoChannelUUIDValid,
|
isVideoChannelUUIDValid,
|
||||||
checkVideoChannelExists
|
checkVideoChannelExists,
|
||||||
|
isVideoChannelUrlValid
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { isArray, exists } from './misc'
|
||||||
import { VideoInstance } from '../../models'
|
import { VideoInstance } from '../../models'
|
||||||
import { logger } from '../../helpers'
|
import { logger } from '../../helpers'
|
||||||
import { VideoRateType } from '../../../shared'
|
import { VideoRateType } from '../../../shared'
|
||||||
|
import { isActivityPubUrlValid } from './activitypub/misc'
|
||||||
|
|
||||||
const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
|
const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
|
||||||
const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
|
const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
|
||||||
|
@ -33,6 +34,10 @@ function isRemoteVideoCategoryValid (value: string) {
|
||||||
return validator.isInt('' + value)
|
return validator.isInt('' + value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isVideoUrlValid (value: string) {
|
||||||
|
return isActivityPubUrlValid(value)
|
||||||
|
}
|
||||||
|
|
||||||
function isVideoLicenceValid (value: number) {
|
function isVideoLicenceValid (value: number) {
|
||||||
return VIDEO_LICENCES[value] !== undefined
|
return VIDEO_LICENCES[value] !== undefined
|
||||||
}
|
}
|
||||||
|
@ -219,5 +224,6 @@ export {
|
||||||
isVideoTagValid,
|
isVideoTagValid,
|
||||||
isRemoteVideoCategoryValid,
|
isRemoteVideoCategoryValid,
|
||||||
isRemoteVideoLicenceValid,
|
isRemoteVideoLicenceValid,
|
||||||
|
isVideoUrlValid,
|
||||||
isRemoteVideoLanguageValid
|
isRemoteVideoLanguageValid
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,8 @@ const CONSTRAINTS_FIELDS = {
|
||||||
},
|
},
|
||||||
VIDEO_CHANNELS: {
|
VIDEO_CHANNELS: {
|
||||||
NAME: { min: 3, max: 120 }, // Length
|
NAME: { min: 3, max: 120 }, // Length
|
||||||
DESCRIPTION: { min: 3, max: 250 } // Length
|
DESCRIPTION: { min: 3, max: 250 }, // Length
|
||||||
|
URL: { min: 3, max: 2000 } // Length
|
||||||
},
|
},
|
||||||
VIDEOS: {
|
VIDEOS: {
|
||||||
NAME: { min: 3, max: 120 }, // Length
|
NAME: { min: 3, max: 120 }, // Length
|
||||||
|
@ -137,7 +138,13 @@ const CONSTRAINTS_FIELDS = {
|
||||||
VIEWS: { min: 0 },
|
VIEWS: { min: 0 },
|
||||||
LIKES: { min: 0 },
|
LIKES: { min: 0 },
|
||||||
DISLIKES: { min: 0 },
|
DISLIKES: { min: 0 },
|
||||||
FILE_SIZE: { min: 10, max: 1024 * 1024 * 1024 * 3 /* 3Go */ }
|
FILE_SIZE: { min: 10, max: 1024 * 1024 * 1024 * 3 /* 3Go */ },
|
||||||
|
URL: { min: 3, max: 2000 } // Length
|
||||||
|
},
|
||||||
|
ACCOUNTS: {
|
||||||
|
PUBLIC_KEY: { min: 10, max: 5000 }, // Length
|
||||||
|
PRIVATE_KEY: { min: 10, max: 5000 }, // Length
|
||||||
|
URL: { min: 3, max: 2000 } // Length
|
||||||
},
|
},
|
||||||
VIDEO_EVENTS: {
|
VIDEO_EVENTS: {
|
||||||
COUNT: { min: 0 }
|
COUNT: { min: 0 }
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
import * as passwordGenerator from 'password-generator'
|
import * as passwordGenerator from 'password-generator'
|
||||||
import { UserRole } from '../../shared'
|
import { UserRole } from '../../shared'
|
||||||
import { logger, mkdirpPromise, rimrafPromise } from '../helpers'
|
import { logger, mkdirpPromise, rimrafPromise } from '../helpers'
|
||||||
import { createPrivateAndPublicKeys } from '../helpers/peertube-crypto'
|
|
||||||
import { createUserAccountAndChannel } from '../lib'
|
import { createUserAccountAndChannel } from '../lib'
|
||||||
|
import { createLocalAccount } from '../lib/user'
|
||||||
import { clientsExist, usersExist } from './checker'
|
import { clientsExist, usersExist } from './checker'
|
||||||
import { CACHE, CONFIG, LAST_MIGRATION_VERSION } from './constants'
|
import { CACHE, CONFIG, LAST_MIGRATION_VERSION } from './constants'
|
||||||
|
|
||||||
import { database as db } from './database'
|
import { database as db } from './database'
|
||||||
import { createLocalAccount } from '../lib/user'
|
|
||||||
|
|
||||||
async function installApplication () {
|
async function installApplication () {
|
||||||
|
try {
|
||||||
await db.sequelize.sync()
|
await db.sequelize.sync()
|
||||||
await removeCacheDirectories()
|
await removeCacheDirectories()
|
||||||
await createDirectoriesIfNotExist()
|
await createDirectoriesIfNotExist()
|
||||||
await createOAuthClientIfNotExist()
|
await createOAuthClientIfNotExist()
|
||||||
await createOAuthAdminIfNotExist()
|
await createOAuthAdminIfNotExist()
|
||||||
await createApplicationIfNotExist()
|
await createApplicationIfNotExist()
|
||||||
|
} catch (err) {
|
||||||
|
logger.error('Cannot install application.', err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -16,8 +16,9 @@ async function createUserAccountAndChannel (user: UserInstance, validateUser = t
|
||||||
const userCreated = await user.save(userOptions)
|
const userCreated = await user.save(userOptions)
|
||||||
const accountCreated = await createLocalAccount(user.username, user.id, null, t)
|
const accountCreated = await createLocalAccount(user.username, user.id, null, t)
|
||||||
|
|
||||||
|
const videoChannelName = `Default ${userCreated.username} channel`
|
||||||
const videoChannelInfo = {
|
const videoChannelInfo = {
|
||||||
name: `Default ${userCreated.username} channel`
|
name: videoChannelName
|
||||||
}
|
}
|
||||||
const videoChannel = await createVideoChannel(videoChannelInfo, accountCreated, t)
|
const videoChannel = await createVideoChannel(videoChannelInfo, accountCreated, t)
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { logger } from '../helpers'
|
||||||
import { AccountInstance } from '../models'
|
import { AccountInstance } from '../models'
|
||||||
import { VideoChannelCreate } from '../../shared/models'
|
import { VideoChannelCreate } from '../../shared/models'
|
||||||
import { sendCreateVideoChannel } from './activitypub/send-request'
|
import { sendCreateVideoChannel } from './activitypub/send-request'
|
||||||
|
import { getActivityPubUrl } from '../helpers/activitypub'
|
||||||
|
|
||||||
async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountInstance, t: Sequelize.Transaction) {
|
async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountInstance, t: Sequelize.Transaction) {
|
||||||
const videoChannelData = {
|
const videoChannelData = {
|
||||||
|
@ -15,6 +16,8 @@ async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account
|
||||||
}
|
}
|
||||||
|
|
||||||
const videoChannel = db.VideoChannel.build(videoChannelData)
|
const videoChannel = db.VideoChannel.build(videoChannelData)
|
||||||
|
videoChannel.set('url', getActivityPubUrl('videoChannel', videoChannel.uuid))
|
||||||
|
|
||||||
const options = { transaction: t }
|
const options = { transaction: t }
|
||||||
|
|
||||||
const videoChannelCreated = await videoChannel.save(options)
|
const videoChannelCreated = await videoChannel.save(options)
|
||||||
|
|
|
@ -22,8 +22,8 @@ import {
|
||||||
|
|
||||||
AccountMethods
|
AccountMethods
|
||||||
} from './account-interface'
|
} from './account-interface'
|
||||||
import LoadApplication = AccountMethods.LoadApplication
|
|
||||||
import { sendDeleteAccount } from '../../lib/activitypub/send-request'
|
import { sendDeleteAccount } from '../../lib/activitypub/send-request'
|
||||||
|
import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
|
||||||
|
|
||||||
let Account: Sequelize.Model<AccountInstance, AccountAttributes>
|
let Account: Sequelize.Model<AccountInstance, AccountAttributes>
|
||||||
let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID
|
let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID
|
||||||
|
@ -60,14 +60,14 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
validate: {
|
validate: {
|
||||||
usernameValid: value => {
|
nameValid: value => {
|
||||||
const res = isUserUsernameValid(value)
|
const res = isUserUsernameValid(value)
|
||||||
if (res === false) throw new Error('Username is not valid.')
|
if (res === false) throw new Error('Name is not valid.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
url: {
|
url: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
validate: {
|
validate: {
|
||||||
urlValid: value => {
|
urlValid: value => {
|
||||||
|
@ -77,7 +77,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
publicKey: {
|
publicKey: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.PUBLIC_KEY.max),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
validate: {
|
validate: {
|
||||||
publicKeyValid: value => {
|
publicKeyValid: value => {
|
||||||
|
@ -87,7 +87,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
privateKey: {
|
privateKey: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.PRIVATE_KEY.max),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
validate: {
|
validate: {
|
||||||
privateKeyValid: value => {
|
privateKeyValid: value => {
|
||||||
|
@ -110,14 +110,14 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
|
||||||
type: DataTypes.INTEGER,
|
type: DataTypes.INTEGER,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
validate: {
|
validate: {
|
||||||
followersCountValid: value => {
|
followingCountValid: value => {
|
||||||
const res = isAccountFollowingCountValid(value)
|
const res = isAccountFollowingCountValid(value)
|
||||||
if (res === false) throw new Error('Following count is not valid.')
|
if (res === false) throw new Error('Following count is not valid.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
inboxUrl: {
|
inboxUrl: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
validate: {
|
validate: {
|
||||||
inboxUrlValid: value => {
|
inboxUrlValid: value => {
|
||||||
|
@ -127,7 +127,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
outboxUrl: {
|
outboxUrl: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
validate: {
|
validate: {
|
||||||
outboxUrlValid: value => {
|
outboxUrlValid: value => {
|
||||||
|
@ -137,7 +137,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sharedInboxUrl: {
|
sharedInboxUrl: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
validate: {
|
validate: {
|
||||||
sharedInboxUrlValid: value => {
|
sharedInboxUrlValid: value => {
|
||||||
|
@ -147,7 +147,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
followersUrl: {
|
followersUrl: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
validate: {
|
validate: {
|
||||||
followersUrlValid: value => {
|
followersUrlValid: value => {
|
||||||
|
@ -157,7 +157,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
followingUrl: {
|
followingUrl: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
validate: {
|
validate: {
|
||||||
followingUrlValid: value => {
|
followingUrlValid: value => {
|
||||||
|
@ -241,7 +241,7 @@ function associate (models) {
|
||||||
|
|
||||||
Account.belongsTo(models.Application, {
|
Account.belongsTo(models.Application, {
|
||||||
foreignKey: {
|
foreignKey: {
|
||||||
name: 'userId',
|
name: 'applicationId',
|
||||||
allowNull: true
|
allowNull: true
|
||||||
},
|
},
|
||||||
onDelete: 'cascade'
|
onDelete: 'cascade'
|
||||||
|
@ -256,7 +256,7 @@ function associate (models) {
|
||||||
hooks: true
|
hooks: true
|
||||||
})
|
})
|
||||||
|
|
||||||
Account.hasMany(models.AccountFollower, {
|
Account.hasMany(models.AccountFollow, {
|
||||||
foreignKey: {
|
foreignKey: {
|
||||||
name: 'accountId',
|
name: 'accountId',
|
||||||
allowNull: false
|
allowNull: false
|
||||||
|
@ -265,7 +265,7 @@ function associate (models) {
|
||||||
onDelete: 'cascade'
|
onDelete: 'cascade'
|
||||||
})
|
})
|
||||||
|
|
||||||
Account.hasMany(models.AccountFollower, {
|
Account.hasMany(models.AccountFollow, {
|
||||||
foreignKey: {
|
foreignKey: {
|
||||||
name: 'targetAccountId',
|
name: 'targetAccountId',
|
||||||
allowNull: false
|
allowNull: false
|
||||||
|
@ -329,7 +329,7 @@ getFollowerSharedInboxUrls = function (this: AccountInstance) {
|
||||||
attributes: [ 'sharedInboxUrl' ],
|
attributes: [ 'sharedInboxUrl' ],
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
model: Account['sequelize'].models.AccountFollower,
|
model: Account['sequelize'].models.AccountFollow,
|
||||||
where: {
|
where: {
|
||||||
targetAccountId: this.id
|
targetAccountId: this.id
|
||||||
}
|
}
|
||||||
|
@ -523,9 +523,9 @@ async function createListAcceptedFollowForApiQuery (type: 'followers' | 'followi
|
||||||
|
|
||||||
for (const selection of selections) {
|
for (const selection of selections) {
|
||||||
let query = 'SELECT ' + selection + ' FROM "Account" ' +
|
let query = 'SELECT ' + selection + ' FROM "Account" ' +
|
||||||
'INNER JOIN "AccountFollower" ON "AccountFollower"."' + firstJoin + '" = "Account"."id" ' +
|
'INNER JOIN "AccountFollow" ON "AccountFollow"."' + firstJoin + '" = "Account"."id" ' +
|
||||||
'INNER JOIN "Account" AS "Follows" ON "Followers"."id" = "Follows"."' + secondJoin + '" ' +
|
'INNER JOIN "Account" AS "Follows" ON "Followers"."id" = "Follows"."' + secondJoin + '" ' +
|
||||||
'WHERE "Account"."id" = $id AND "AccountFollower"."state" = \'accepted\' ' +
|
'WHERE "Account"."id" = $id AND "AccountFollow"."state" = \'accepted\' ' +
|
||||||
'LIMIT ' + start
|
'LIMIT ' + start
|
||||||
|
|
||||||
if (count !== undefined) query += ', ' + count
|
if (count !== undefined) query += ', ' + count
|
||||||
|
|
|
@ -1,23 +1,16 @@
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
|
import { hasUserRight, USER_ROLE_LABELS, UserRight } from '../../../shared'
|
||||||
import { getSort, addMethodsToModel } from '../utils'
|
|
||||||
import {
|
import {
|
||||||
cryptPassword,
|
|
||||||
comparePassword,
|
comparePassword,
|
||||||
isUserPasswordValid,
|
cryptPassword,
|
||||||
isUserUsernameValid,
|
|
||||||
isUserDisplayNSFWValid,
|
isUserDisplayNSFWValid,
|
||||||
isUserVideoQuotaValid,
|
isUserPasswordValid,
|
||||||
isUserRoleValid
|
isUserRoleValid,
|
||||||
|
isUserUsernameValid,
|
||||||
|
isUserVideoQuotaValid
|
||||||
} from '../../helpers'
|
} from '../../helpers'
|
||||||
import { UserRight, USER_ROLE_LABELS, hasUserRight } from '../../../shared'
|
import { addMethodsToModel, getSort } from '../utils'
|
||||||
|
import { UserAttributes, UserInstance, UserMethods } from './user-interface'
|
||||||
import {
|
|
||||||
UserInstance,
|
|
||||||
UserAttributes,
|
|
||||||
|
|
||||||
UserMethods
|
|
||||||
} from './user-interface'
|
|
||||||
|
|
||||||
let User: Sequelize.Model<UserInstance, UserAttributes>
|
let User: Sequelize.Model<UserInstance, UserAttributes>
|
||||||
let isPasswordMatch: UserMethods.IsPasswordMatch
|
let isPasswordMatch: UserMethods.IsPasswordMatch
|
||||||
|
|
|
@ -63,8 +63,6 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
|
||||||
)
|
)
|
||||||
|
|
||||||
const classMethods = [
|
const classMethods = [
|
||||||
associate,
|
|
||||||
|
|
||||||
countAll,
|
countAll,
|
||||||
incrementScores,
|
incrementScores,
|
||||||
list,
|
list,
|
||||||
|
@ -98,14 +96,6 @@ toFormattedJSON = function (this: PodInstance) {
|
||||||
|
|
||||||
// ------------------------------ Statics ------------------------------
|
// ------------------------------ Statics ------------------------------
|
||||||
|
|
||||||
function associate (models) {
|
|
||||||
Pod.belongsToMany(models.Request, {
|
|
||||||
foreignKey: 'podId',
|
|
||||||
through: models.RequestToPod,
|
|
||||||
onDelete: 'cascade'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
countAll = function () {
|
countAll = function () {
|
||||||
return Pod.count()
|
return Pod.count()
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ import {
|
||||||
VideoChannelMethods
|
VideoChannelMethods
|
||||||
} from './video-channel-interface'
|
} from './video-channel-interface'
|
||||||
import { sendDeleteVideoChannel } from '../../lib/activitypub/send-request'
|
import { sendDeleteVideoChannel } from '../../lib/activitypub/send-request'
|
||||||
|
import { isVideoChannelUrlValid } from '../../helpers/custom-validators/video-channels'
|
||||||
|
import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
|
||||||
|
|
||||||
let VideoChannel: Sequelize.Model<VideoChannelInstance, VideoChannelAttributes>
|
let VideoChannel: Sequelize.Model<VideoChannelInstance, VideoChannelAttributes>
|
||||||
let toFormattedJSON: VideoChannelMethods.ToFormattedJSON
|
let toFormattedJSON: VideoChannelMethods.ToFormattedJSON
|
||||||
|
@ -65,10 +67,13 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
|
||||||
defaultValue: false
|
defaultValue: false
|
||||||
},
|
},
|
||||||
url: {
|
url: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.URL.max),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
validate: {
|
validate: {
|
||||||
isUrl: true
|
urlValid: value => {
|
||||||
|
const res = isVideoChannelUrlValid(value)
|
||||||
|
if (res === false) throw new Error('Video channel URL is not valid.')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -46,6 +46,7 @@ import { TagInstance } from './tag-interface'
|
||||||
import { VideoFileInstance, VideoFileModel } from './video-file-interface'
|
import { VideoFileInstance, VideoFileModel } from './video-file-interface'
|
||||||
import { VideoAttributes, VideoInstance, VideoMethods } from './video-interface'
|
import { VideoAttributes, VideoInstance, VideoMethods } from './video-interface'
|
||||||
import { sendDeleteVideo } from '../../lib/activitypub/send-request'
|
import { sendDeleteVideo } from '../../lib/activitypub/send-request'
|
||||||
|
import { isVideoUrlValid } from '../../helpers/custom-validators/videos'
|
||||||
|
|
||||||
const Buffer = safeBuffer.Buffer
|
const Buffer = safeBuffer.Buffer
|
||||||
|
|
||||||
|
@ -220,10 +221,13 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
|
||||||
defaultValue: false
|
defaultValue: false
|
||||||
},
|
},
|
||||||
url: {
|
url: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING(CONSTRAINTS_FIELDS.VIDEOS.URL.max),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
validate: {
|
validate: {
|
||||||
isUrl: true
|
urlValid: value => {
|
||||||
|
const res = isVideoUrlValid(value)
|
||||||
|
if (res === false) throw new Error('Video URL is not valid.')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue