Better typescript typing for a better world

pull/76/head
Chocobozzz 2017-07-10 19:43:21 +02:00
parent 7a214f746b
commit 4771e0008d
59 changed files with 400 additions and 166 deletions

View File

@ -15,7 +15,7 @@ import { FriendService } from '../shared'
})
export class FriendAddComponent implements OnInit {
form: FormGroup
hosts = [ ]
hosts: string[] = [ ]
error: string = null
constructor (

View File

@ -3,6 +3,7 @@ import 'rxjs/add/operator/catch'
import 'rxjs/add/operator/map'
import { AuthHttp, RestExtractor, RestDataSource, User } from '../../../shared'
import { UserCreate } from '../../../../../../shared'
@Injectable()
export class UserService {
@ -13,14 +14,8 @@ export class UserService {
private restExtractor: RestExtractor
) {}
addUser (username: string, password: string, email: string) {
const body = {
username,
email,
password
}
return this.authHttp.post(UserService.BASE_USERS_URL, body)
addUser (userCreate: UserCreate) {
return this.authHttp.post(UserService.BASE_USERS_URL, userCreate)
.map(this.restExtractor.extractDataBool)
.catch(this.restExtractor.handleError)
}

View File

@ -11,6 +11,7 @@ import {
USER_EMAIL,
USER_PASSWORD
} from '../../../shared'
import { UserCreate } from '../../../../../../shared'
@Component({
selector: 'my-user-add',
@ -57,11 +58,11 @@ export class UserAddComponent extends FormReactive implements OnInit {
addUser () {
this.error = null
const { username, password, email } = this.form.value
const userCreate: UserCreate = this.form.value
this.userService.addUser(username, password, email).subscribe(
this.userService.addUser(userCreate).subscribe(
() => {
this.notificationsService.success('Success', `User ${username} created.`)
this.notificationsService.success('Success', `User ${userCreate.username} created.`)
this.router.navigate([ '/admin/users/list' ])
},

View File

@ -11,6 +11,7 @@ import {
UserService,
USER_PASSWORD
} from '../../shared'
import { UserUpdate } from '../../../../../shared'
@Component({
selector: 'my-account-details',
@ -50,7 +51,7 @@ export class AccountDetailsComponent extends FormReactive implements OnInit {
updateDetails () {
const displayNSFW = this.form.value['displayNSFW']
const details = {
const details: UserUpdate = {
displayNSFW
}

View File

@ -1,5 +1,5 @@
// Do not use the barrel (dependency loop)
import { UserRole } from '../../../../../shared/models/user.model'
import { UserRole } from '../../../../../shared/models/users/user-role.type'
import { User } from '../../shared/users/user.model'
export type TokenOptions = {

View File

@ -6,6 +6,7 @@ import 'rxjs/add/operator/map'
import { AuthService } from '../../core'
import { AuthHttp } from '../auth'
import { RestExtractor } from '../rest'
import { UserCreate, UserUpdate } from '../../../../../shared'
@Injectable()
export class UserService {
@ -27,7 +28,7 @@ export class UserService {
changePassword (newPassword: string) {
const url = UserService.BASE_USERS_URL + this.authService.getUser().id
const body = {
const body: UserUpdate = {
password: newPassword
}
@ -36,7 +37,7 @@ export class UserService {
.catch((res) => this.restExtractor.handleError(res))
}
updateDetails (details: { displayNSFW: boolean }) {
updateDetails (details: UserUpdate) {
const url = UserService.BASE_USERS_URL + this.authService.getUser().id
return this.authHttp.put(url, details)
@ -44,14 +45,8 @@ export class UserService {
.catch((res) => this.restExtractor.handleError(res))
}
signup (username: string, password: string, email: string) {
const body = {
username,
email,
password
}
return this.http.post(UserService.BASE_USERS_URL + 'register', body)
signup (userCreate: UserCreate) {
return this.http.post(UserService.BASE_USERS_URL + 'register', userCreate)
.map(this.restExtractor.extractDataBool)
.catch(this.restExtractor.handleError)
}

View File

@ -12,6 +12,7 @@ import {
USER_EMAIL,
USER_PASSWORD
} from '../shared'
import { UserCreate } from '../../../../shared'
@Component({
selector: 'my-signup',
@ -58,11 +59,11 @@ export class SignupComponent extends FormReactive implements OnInit {
signup () {
this.error = null
const { username, password, email } = this.form.value
const userCreate: UserCreate = this.form.value
this.userService.signup(username, password, email).subscribe(
this.userService.signup(userCreate).subscribe(
() => {
this.notificationsService.success('Success', `Registration for ${username} complete.`)
this.notificationsService.success('Success', `Registration for ${userCreate.username} complete.`)
this.router.navigate([ '/videos/list' ])
},

View File

@ -16,7 +16,13 @@ import {
UserService
} from '../../shared'
import { Video } from './video.model'
import { UserVideoRate, VideoRateType } from '../../../../../shared'
import {
UserVideoRate,
VideoRateType,
VideoUpdate,
VideoAbuseCreate,
UserVideoRateUpdate
} from '../../../../../shared'
@Injectable()
export class VideoService {
@ -35,42 +41,15 @@ export class VideoService {
) {}
loadVideoCategories () {
return this.http.get(VideoService.BASE_VIDEO_URL + 'categories')
.map(this.restExtractor.extractDataGet)
.subscribe(data => {
Object.keys(data).forEach(categoryKey => {
this.videoCategories.push({
id: parseInt(categoryKey, 10),
label: data[categoryKey]
})
})
})
return this.loadVideoAttributeEnum('categories', this.videoCategories)
}
loadVideoLicences () {
return this.http.get(VideoService.BASE_VIDEO_URL + 'licences')
.map(this.restExtractor.extractDataGet)
.subscribe(data => {
Object.keys(data).forEach(licenceKey => {
this.videoLicences.push({
id: parseInt(licenceKey, 10),
label: data[licenceKey]
})
})
})
return this.loadVideoAttributeEnum('licences', this.videoLicences)
}
loadVideoLanguages () {
return this.http.get(VideoService.BASE_VIDEO_URL + 'languages')
.map(this.restExtractor.extractDataGet)
.subscribe(data => {
Object.keys(data).forEach(languageKey => {
this.videoLanguages.push({
id: parseInt(languageKey, 10),
label: data[languageKey]
})
})
})
return this.loadVideoAttributeEnum('languages', this.videoLanguages)
}
getVideo (id: string): Observable<Video> {
@ -83,13 +62,14 @@ export class VideoService {
updateVideo (video: Video) {
const language = video.language ? video.language : null
const body = {
const body: VideoUpdate = {
name: video.name,
category: video.category,
licence: video.licence,
language,
description: video.description,
tags: video.tags
tags: video.tags,
nsfw: video.nsfw
}
const headers = new Headers({ 'Content-Type': 'application/json' })
@ -128,7 +108,7 @@ export class VideoService {
reportVideo (id: string, reason: string) {
const url = VideoService.BASE_VIDEO_URL + id + '/abuse'
const body = {
const body: VideoAbuseCreate = {
reason
}
@ -161,7 +141,7 @@ export class VideoService {
private setVideoRate (id: string, rateType: VideoRateType) {
const url = VideoService.BASE_VIDEO_URL + id + '/rate'
const body = {
const body: UserVideoRateUpdate = {
rating: rateType
}
@ -180,4 +160,17 @@ export class VideoService {
return { videos, totalVideos }
}
private loadVideoAttributeEnum (attributeName: 'categories' | 'licences' | 'languages', hashToPopulate: { id: number, label: string }[]) {
return this.http.get(VideoService.BASE_VIDEO_URL + attributeName)
.map(this.restExtractor.extractDataGet)
.subscribe(data => {
Object.keys(data).forEach(dataKey => {
hashToPopulate.push({
id: parseInt(dataKey, 10),
label: data[dataKey]
})
})
})
}
}

View File

@ -16,6 +16,7 @@ import {
VIDEO_TAGS
} from '../../shared'
import { VideoService } from '../shared'
import { VideoCreate } from '../../../../../shared'
@Component({
selector: 'my-videos-add',
@ -98,23 +99,25 @@ export class VideoAddComponent extends FormReactive implements OnInit {
removeAfterUpload: true
})
this.uploader.onBuildItemForm = (item, form) => {
const name = this.form.value['name']
const nsfw = this.form.value['nsfw']
const category = this.form.value['category']
const licence = this.form.value['licence']
const language = this.form.value['language']
const description = this.form.value['description']
const tags = this.form.value['tags']
this.uploader.onBuildItemForm = (item, form: FormData) => {
const formValue: VideoCreate = this.form.value
const name = formValue.name
const nsfw = formValue.nsfw
const category = formValue.category
const licence = formValue.licence
const language = formValue.language
const description = formValue.description
const tags = formValue.tags
form.append('name', name)
form.append('category', category)
form.append('nsfw', nsfw)
form.append('licence', licence)
form.append('category', '' + category)
form.append('nsfw', '' + nsfw)
form.append('licence', '' + licence)
// Language is optional
if (language) {
form.append('language', language)
form.append('language', '' + language)
}
form.append('description', description)

View File

@ -2,4 +2,4 @@
cd client || exit -1
npm run webpack-dev-server -- --config config/webpack.dev.js --progress --profile --colors --watch --content-base src/ --inline --hot
npm run webpack-dev-server -- --config config/webpack.dev.js --progress --profile --colors --watch --content-base src/ --inline --hot --open

View File

@ -1,5 +1,5 @@
#!/usr/bin/env sh
NODE_ENV=test concurrently \
NODE_ENV=test concurrently -k \
"npm run tsc -- --sourceMap && npm run nodemon -- --delay 2 --watch ./dist dist/server" \
"npm run tsc -- --sourceMap -w"

View File

@ -2,6 +2,7 @@ import * as express from 'express'
import { database as db } from '../../../initializers/database'
import { checkSignature, signatureValidator } from '../../../middlewares'
import { PodSignature } from '../../../../shared'
const remotePodsRouter = express.Router()
@ -21,12 +22,11 @@ export {
// ---------------------------------------------------------------------------
function removePods (req: express.Request, res: express.Response, next: express.NextFunction) {
const host = req.body.signature.host
const signature: PodSignature = req.body.signature
const host = signature.host
db.Pod.loadByHost(host)
.then(pod => {
return pod.destroy()
})
.then(pod => pod.destroy())
.then(() => res.type('json').status(204).end())
.catch(err => next(err))
}

View File

@ -18,6 +18,17 @@ import {
import { logger, retryTransactionWrapper } from '../../../helpers'
import { quickAndDirtyUpdatesVideoToFriends } from '../../../lib'
import { PodInstance, VideoInstance } from '../../../models'
import {
RemoteVideoRequest,
RemoteVideoCreateData,
RemoteVideoUpdateData,
RemoteVideoRemoveData,
RemoteVideoReportAbuseData,
RemoteQaduVideoRequest,
RemoteQaduVideoData,
RemoteVideoEventRequest,
RemoteVideoEventData
} from '../../../../shared'
const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS]
@ -60,11 +71,11 @@ export {
// ---------------------------------------------------------------------------
function remoteVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
const requests = req.body.data
const requests: RemoteVideoRequest[] = req.body.data
const fromPod = res.locals.secure.pod
// We need to process in the same order to keep consistency
Promise.each(requests, (request: any) => {
Promise.each(requests, request => {
const data = request.data
// Get the function we need to call in order to process the request
@ -83,10 +94,10 @@ function remoteVideos (req: express.Request, res: express.Response, next: expres
}
function remoteVideosQadu (req: express.Request, res: express.Response, next: express.NextFunction) {
const requests = req.body.data
const requests: RemoteQaduVideoRequest[] = req.body.data
const fromPod = res.locals.secure.pod
Promise.each(requests, (request: any) => {
Promise.each(requests, request => {
const videoData = request.data
return quickAndDirtyUpdateVideoRetryWrapper(videoData, fromPod)
@ -97,10 +108,10 @@ function remoteVideosQadu (req: express.Request, res: express.Response, next: ex
}
function remoteVideosEvents (req: express.Request, res: express.Response, next: express.NextFunction) {
const requests = req.body.data
const requests: RemoteVideoEventRequest[] = req.body.data
const fromPod = res.locals.secure.pod
Promise.each(requests, (request: any) => {
Promise.each(requests, request => {
const eventData = request.data
return processVideosEventsRetryWrapper(eventData, fromPod)
@ -110,7 +121,7 @@ function remoteVideosEvents (req: express.Request, res: express.Response, next:
return res.type('json').status(204).end()
}
function processVideosEventsRetryWrapper (eventData: any, fromPod: PodInstance) {
function processVideosEventsRetryWrapper (eventData: RemoteVideoEventData, fromPod: PodInstance) {
const options = {
arguments: [ eventData, fromPod ],
errorMessage: 'Cannot process videos events with many retries.'
@ -119,7 +130,7 @@ function processVideosEventsRetryWrapper (eventData: any, fromPod: PodInstance)
return retryTransactionWrapper(processVideosEvents, options)
}
function processVideosEvents (eventData: any, fromPod: PodInstance) {
function processVideosEvents (eventData: RemoteVideoEventData, fromPod: PodInstance) {
return db.sequelize.transaction(t => {
return fetchOwnedVideo(eventData.remoteId)
@ -172,7 +183,7 @@ function processVideosEvents (eventData: any, fromPod: PodInstance) {
})
}
function quickAndDirtyUpdateVideoRetryWrapper (videoData: any, fromPod: PodInstance) {
function quickAndDirtyUpdateVideoRetryWrapper (videoData: RemoteQaduVideoData, fromPod: PodInstance) {
const options = {
arguments: [ videoData, fromPod ],
errorMessage: 'Cannot update quick and dirty the remote video with many retries.'
@ -181,7 +192,7 @@ function quickAndDirtyUpdateVideoRetryWrapper (videoData: any, fromPod: PodInsta
return retryTransactionWrapper(quickAndDirtyUpdateVideo, options)
}
function quickAndDirtyUpdateVideo (videoData: any, fromPod: PodInstance) {
function quickAndDirtyUpdateVideo (videoData: RemoteQaduVideoData, fromPod: PodInstance) {
let videoName
return db.sequelize.transaction(t => {
@ -211,7 +222,7 @@ function quickAndDirtyUpdateVideo (videoData: any, fromPod: PodInstance) {
}
// Handle retries on fail
function addRemoteVideoRetryWrapper (videoToCreateData: any, fromPod: PodInstance) {
function addRemoteVideoRetryWrapper (videoToCreateData: RemoteVideoCreateData, fromPod: PodInstance) {
const options = {
arguments: [ videoToCreateData, fromPod ],
errorMessage: 'Cannot insert the remote video with many retries.'
@ -220,7 +231,7 @@ function addRemoteVideoRetryWrapper (videoToCreateData: any, fromPod: PodInstanc
return retryTransactionWrapper(addRemoteVideo, options)
}
function addRemoteVideo (videoToCreateData: any, fromPod: PodInstance) {
function addRemoteVideo (videoToCreateData: RemoteVideoCreateData, fromPod: PodInstance) {
logger.debug('Adding remote video "%s".', videoToCreateData.remoteId)
return db.sequelize.transaction(t => {
@ -293,7 +304,7 @@ function addRemoteVideo (videoToCreateData: any, fromPod: PodInstance) {
}
// Handle retries on fail
function updateRemoteVideoRetryWrapper (videoAttributesToUpdate: any, fromPod: PodInstance) {
function updateRemoteVideoRetryWrapper (videoAttributesToUpdate: RemoteVideoUpdateData, fromPod: PodInstance) {
const options = {
arguments: [ videoAttributesToUpdate, fromPod ],
errorMessage: 'Cannot update the remote video with many retries'
@ -302,7 +313,7 @@ function updateRemoteVideoRetryWrapper (videoAttributesToUpdate: any, fromPod: P
return retryTransactionWrapper(updateRemoteVideo, options)
}
function updateRemoteVideo (videoAttributesToUpdate: any, fromPod: PodInstance) {
function updateRemoteVideo (videoAttributesToUpdate: RemoteVideoUpdateData, fromPod: PodInstance) {
logger.debug('Updating remote video "%s".', videoAttributesToUpdate.remoteId)
return db.sequelize.transaction(t => {
@ -346,7 +357,7 @@ function updateRemoteVideo (videoAttributesToUpdate: any, fromPod: PodInstance)
})
}
function removeRemoteVideo (videoToRemoveData: any, fromPod: PodInstance) {
function removeRemoteVideo (videoToRemoveData: RemoteVideoRemoveData, fromPod: PodInstance) {
// We need the instance because we have to remove some other stuffs (thumbnail etc)
return fetchRemoteVideo(fromPod.host, videoToRemoveData.remoteId)
.then(video => {
@ -358,7 +369,7 @@ function removeRemoteVideo (videoToRemoveData: any, fromPod: PodInstance) {
})
}
function reportAbuseRemoteVideo (reportData: any, fromPod: PodInstance) {
function reportAbuseRemoteVideo (reportData: RemoteVideoReportAbuseData, fromPod: PodInstance) {
return fetchOwnedVideo(reportData.videoRemoteId)
.then(video => {
logger.debug('Reporting remote abuse for video %s.', video.id)

View File

@ -17,7 +17,7 @@ import {
setUsersSort,
token
} from '../../middlewares'
import { UserVideoRate as FormatedUserVideoRate } from '../../../shared'
import { UserVideoRate as FormatedUserVideoRate, UserCreate, UserUpdate } from '../../../shared'
const usersRouter = express.Router()
@ -78,10 +78,12 @@ export {
// ---------------------------------------------------------------------------
function createUser (req: express.Request, res: express.Response, next: express.NextFunction) {
const body: UserCreate = req.body
const user = db.User.build({
username: req.body.username,
password: req.body.password,
email: req.body.email,
username: body.username,
password: body.password,
email: body.email,
displayNSFW: false,
role: USER_ROLES.USER
})
@ -132,10 +134,12 @@ function removeUser (req: express.Request, res: express.Response, next: express.
}
function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) {
const body: UserUpdate = req.body
db.User.loadByUsername(res.locals.oauth.token.user.username)
.then(user => {
if (req.body.password) user.password = req.body.password
if (req.body.displayNSFW !== undefined) user.displayNSFW = req.body.displayNSFW
if (body.password) user.password = body.password
if (body.displayNSFW !== undefined) user.displayNSFW = body.displayNSFW
return user.save()
})

View File

@ -17,6 +17,7 @@ import {
setPagination
} from '../../../middlewares'
import { VideoInstance } from '../../../models'
import { VideoAbuseCreate } from '../../../../shared'
const abuseVideoRouter = express.Router()
@ -63,10 +64,11 @@ function reportVideoAbuseRetryWrapper (req: express.Request, res: express.Respon
function reportVideoAbuse (req: express.Request, res: express.Response) {
const videoInstance = res.locals.video
const reporterUsername = res.locals.oauth.token.User.username
const body: VideoAbuseCreate = req.body
const abuse = {
reporterUsername,
reason: req.body.reason,
reason: body.reason,
videoId: videoInstance.id,
reporterPodId: null // This is our pod that reported this abuse
}

View File

@ -39,6 +39,7 @@ import {
renamePromise
} from '../../../helpers'
import { TagInstance } from '../../../models'
import { VideoCreate, VideoUpdate } from '../../../../shared'
import { abuseVideoRouter } from './abuse'
import { blacklistRouter } from './blacklist'
@ -155,7 +156,7 @@ function addVideoRetryWrapper (req: express.Request, res: express.Response, next
}
function addVideo (req: express.Request, res: express.Response, videoFile: Express.Multer.File) {
const videoInfos = req.body
const videoInfos: VideoCreate = req.body
return db.sequelize.transaction(t => {
const user = res.locals.oauth.token.User
@ -257,7 +258,7 @@ function updateVideoRetryWrapper (req: express.Request, res: express.Response, n
function updateVideo (req: express.Request, res: express.Response) {
const videoInstance = res.locals.video
const videoFieldsSave = videoInstance.toJSON()
const videoInfosToUpdate = req.body
const videoInfosToUpdate: VideoUpdate = req.body
return db.sequelize.transaction(t => {
let tagsPromise: Promise<TagInstance[]>

View File

@ -1,4 +1,5 @@
import * as express from 'express'
import * as Promise from 'bluebird'
import { database as db } from '../../../initializers/database'
import {
@ -18,6 +19,7 @@ import {
authenticate,
videoRateValidator
} from '../../../middlewares'
import { UserVideoRateUpdate, VideoRateType } from '../../../../shared'
const rateVideoRouter = express.Router()
@ -47,7 +49,8 @@ function rateVideoRetryWrapper (req: express.Request, res: express.Response, nex
}
function rateVideo (req: express.Request, res: express.Response) {
const rateType = req.body.rating
const body: UserVideoRateUpdate = req.body
const rateType = body.rating
const videoInstance = res.locals.video
const userInstance = res.locals.oauth.token.User
@ -62,24 +65,34 @@ function rateVideo (req: express.Request, res: express.Response) {
if (rateType === VIDEO_RATE_TYPES.LIKE) likesToIncrement++
else if (rateType === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++
let promise: Promise<any>
// There was a previous rate, update it
if (previousRate) {
// We will remove the previous rate, so we will need to remove it from the video attribute
if (previousRate.type === VIDEO_RATE_TYPES.LIKE) likesToIncrement--
else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement--
previousRate.type = rateType
if (rateType === 'none') { // Destroy previous rate
promise = previousRate.destroy()
} else { // Update previous rate
previousRate.type = rateType as VideoRateType
return previousRate.save(options).then(() => ({ t, likesToIncrement, dislikesToIncrement }))
} else { // There was not a previous rate, insert a new one
promise = previousRate.save()
}
} else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate
const query = {
userId: userInstance.id,
videoId: videoInstance.id,
type: rateType
}
return db.UserVideoRate.create(query, options).then(() => ({ likesToIncrement, dislikesToIncrement }))
promise = db.UserVideoRate.create(query, options)
} else {
promise = Promise.resolve()
}
return promise.then(() => ({ likesToIncrement, dislikesToIncrement }))
})
.then(({ likesToIncrement, dislikesToIncrement }) => {
const options = { transaction: t }

View File

@ -8,6 +8,7 @@ import {
CONFIG
} from '../initializers'
import { PodInstance } from '../models'
import { PodSignature } from '../../shared'
import { sign } from './peertube-crypto'
type MakeRetryRequestParams = {
@ -37,9 +38,18 @@ type MakeSecureRequestParams = {
}
function makeSecureRequest (params: MakeSecureRequestParams) {
return new Promise<{ response: request.RequestResponse, body: any }>((res, rej) => {
const requestParams = {
const requestParams: {
url: string,
json: {
signature: PodSignature,
data: any
}
} = {
url: REMOTE_SCHEME.HTTP + '://' + params.toPod.host + params.path,
json: {}
json: {
signature: null,
data: null
}
}
if (params.method !== 'POST') {
@ -58,14 +68,14 @@ function makeSecureRequest (params: MakeSecureRequestParams) {
}
sign(dataToSign).then(signature => {
requestParams.json['signature'] = {
requestParams.json.signature = {
host, // Which host we pretend to be
signature
}
// If there are data informations
if (params.data) {
requestParams.json['data'] = params.data
requestParams.json.data = params.data
}
request.post(requestParams, (err, response, body) => err ? rej(err) : res({ response, body }))

View File

@ -34,7 +34,11 @@ import {
import {
RequestEndpoint,
RequestVideoEventType,
RequestVideoQaduType
RequestVideoQaduType,
RemoteVideoCreateData,
RemoteVideoUpdateData,
RemoteVideoRemoveData,
RemoteVideoReportAbuseData
} from '../../shared'
type QaduParam = { videoId: string, type: RequestVideoQaduType }
@ -52,7 +56,7 @@ function activateSchedulers () {
requestVideoEventScheduler.activate()
}
function addVideoToFriends (videoData: Object, transaction: Sequelize.Transaction) {
function addVideoToFriends (videoData: RemoteVideoCreateData, transaction: Sequelize.Transaction) {
const options = {
type: ENDPOINT_ACTIONS.ADD,
endpoint: REQUEST_ENDPOINTS.VIDEOS,
@ -62,7 +66,7 @@ function addVideoToFriends (videoData: Object, transaction: Sequelize.Transactio
return createRequest(options)
}
function updateVideoToFriends (videoData: Object, transaction: Sequelize.Transaction) {
function updateVideoToFriends (videoData: RemoteVideoUpdateData, transaction: Sequelize.Transaction) {
const options = {
type: ENDPOINT_ACTIONS.UPDATE,
endpoint: REQUEST_ENDPOINTS.VIDEOS,
@ -72,7 +76,7 @@ function updateVideoToFriends (videoData: Object, transaction: Sequelize.Transac
return createRequest(options)
}
function removeVideoToFriends (videoParams: Object) {
function removeVideoToFriends (videoParams: RemoteVideoRemoveData) {
const options = {
type: ENDPOINT_ACTIONS.REMOVE,
endpoint: REQUEST_ENDPOINTS.VIDEOS,
@ -82,7 +86,7 @@ function removeVideoToFriends (videoParams: Object) {
return createRequest(options)
}
function reportAbuseVideoToFriend (reportData: Object, video: VideoInstance, transaction: Sequelize.Transaction) {
function reportAbuseVideoToFriend (reportData: RemoteVideoReportAbuseData, video: VideoInstance, transaction: Sequelize.Transaction) {
const options = {
type: ENDPOINT_ACTIONS.REPORT_ABUSE,
endpoint: REQUEST_ENDPOINTS.VIDEOS,

View File

@ -10,6 +10,15 @@ import {
REQUESTS_INTERVAL
} from '../../initializers'
interface RequestsObjects<U> {
[ id: string ]: {
toPod: PodInstance
endpoint: string
ids: number[] // ids
datas: U[]
}
}
abstract class AbstractRequestScheduler <T> {
requestInterval: number
limitPods: number
@ -27,7 +36,7 @@ abstract class AbstractRequestScheduler <T> {
abstract getRequestModel (): AbstractRequestClass<T>
abstract getRequestToPodModel (): AbstractRequestToPodClass
abstract buildRequestObjects (requestsGrouped: T): {}
abstract buildRequestsObjects (requestsGrouped: T): RequestsObjects<any>
activate () {
logger.info('Requests scheduler activated.')
@ -67,7 +76,7 @@ abstract class AbstractRequestScheduler <T> {
// ---------------------------------------------------------------------------
// Make a requests to friends of a certain type
protected makeRequest (toPod: PodInstance, requestEndpoint: string, requestsToMake: Object) {
protected makeRequest (toPod: PodInstance, requestEndpoint: string, requestsToMake: any) {
const params = {
toPod: toPod,
method: 'POST' as 'POST',
@ -95,7 +104,7 @@ abstract class AbstractRequestScheduler <T> {
return this.getRequestModel().listWithLimitAndRandom(this.limitPods, this.limitPerPod)
.then((requestsGrouped: T) => {
// We want to group requests by destinations pod and endpoint
const requestsToMake = this.buildRequestObjects(requestsGrouped)
const requestsToMake = this.buildRequestsObjects(requestsGrouped)
// If there are no requests, abort
if (isEmpty(requestsToMake) === true) {
@ -105,8 +114,8 @@ abstract class AbstractRequestScheduler <T> {
logger.info('Making "%s" to friends.', this.description)
const goodPods = []
const badPods = []
const goodPods: number[] = []
const badPods: number[] = []
return Promise.map(Object.keys(requestsToMake), hashKey => {
const requestToMake = requestsToMake[hashKey]
@ -149,5 +158,6 @@ abstract class AbstractRequestScheduler <T> {
// ---------------------------------------------------------------------------
export {
AbstractRequestScheduler
AbstractRequestScheduler,
RequestsObjects
}

View File

@ -1,11 +1,11 @@
import * as Sequelize from 'sequelize'
import { database as db } from '../../initializers/database'
import { AbstractRequestScheduler } from './abstract-request-scheduler'
import { AbstractRequestScheduler, RequestsObjects } from './abstract-request-scheduler'
import { logger } from '../../helpers'
import { REQUESTS_LIMIT_PODS, REQUESTS_LIMIT_PER_POD } from '../../initializers'
import { RequestsGrouped } from '../../models'
import { RequestEndpoint } from '../../../shared'
import { RequestEndpoint, RemoteVideoRequest } from '../../../shared'
export type RequestSchedulerOptions = {
type: string
@ -34,8 +34,8 @@ class RequestScheduler extends AbstractRequestScheduler<RequestsGrouped> {
return db.RequestToPod
}
buildRequestObjects (requestsGrouped: RequestsGrouped) {
const requestsToMakeGrouped = {}
buildRequestsObjects (requestsGrouped: RequestsGrouped) {
const requestsToMakeGrouped: RequestsObjects<RemoteVideoRequest> = {}
Object.keys(requestsGrouped).forEach(toPodId => {
requestsGrouped[toPodId].forEach(data => {

View File

@ -1,14 +1,14 @@
import * as Sequelize from 'sequelize'
import { database as db } from '../../initializers/database'
import { AbstractRequestScheduler } from './abstract-request-scheduler'
import { AbstractRequestScheduler, RequestsObjects } from './abstract-request-scheduler'
import {
REQUESTS_VIDEO_EVENT_LIMIT_PODS,
REQUESTS_VIDEO_EVENT_LIMIT_PER_POD,
REQUEST_VIDEO_EVENT_ENDPOINT
} from '../../initializers'
import { RequestsVideoEventGrouped } from '../../models'
import { RequestVideoEventType } from '../../../shared'
import { RequestVideoEventType, RemoteVideoEventRequest, RemoteVideoEventType } from '../../../shared'
export type RequestVideoEventSchedulerOptions = {
type: RequestVideoEventType
@ -36,8 +36,8 @@ class RequestVideoEventScheduler extends AbstractRequestScheduler<RequestsVideoE
return db.RequestVideoEvent
}
buildRequestObjects (eventRequests: RequestsVideoEventGrouped) {
const requestsToMakeGrouped = {}
buildRequestsObjects (eventRequests: RequestsVideoEventGrouped) {
const requestsToMakeGrouped: RequestsObjects<RemoteVideoEventRequest> = {}
/* Example:
{
@ -47,7 +47,15 @@ class RequestVideoEventScheduler extends AbstractRequestScheduler<RequestsVideoE
}
}
*/
const eventsPerVideoPerPod = {}
const eventsPerVideoPerPod: {
[ podId: string ]: {
[ videoRemoteId: string ]: {
views?: number
likes?: number
dislikes?: number
}
}
} = {}
// We group video events per video and per pod
// We add the counts of the same event types
@ -87,8 +95,8 @@ class RequestVideoEventScheduler extends AbstractRequestScheduler<RequestsVideoE
requestsToMakeGrouped[toPodId].datas.push({
data: {
remoteId,
eventType,
count: eventsForVideo[eventType]
eventType: eventType as RemoteVideoEventType,
count: +eventsForVideo[eventType]
}
})
})

View File

@ -1,7 +1,7 @@
import * as Sequelize from 'sequelize'
import { database as db } from '../../initializers/database'
import { AbstractRequestScheduler } from './abstract-request-scheduler'
import { AbstractRequestScheduler, RequestsObjects } from './abstract-request-scheduler'
import { logger } from '../../helpers'
import {
REQUESTS_VIDEO_QADU_LIMIT_PODS,
@ -9,8 +9,27 @@ import {
REQUEST_VIDEO_QADU_ENDPOINT,
REQUEST_VIDEO_QADU_TYPES
} from '../../initializers'
import { RequestsVideoQaduGrouped } from '../../models'
import { RequestVideoQaduType } from '../../../shared'
import { RequestsVideoQaduGrouped, PodInstance } from '../../models'
import { RemoteQaduVideoRequest, RequestVideoQaduType } from '../../../shared'
// We create a custom interface because we need "videos" attribute for our computations
interface RequestsObjectsCustom<U> extends RequestsObjects<U> {
[ id: string ]: {
toPod: PodInstance
endpoint: string
ids: number[] // ids
datas: U[]
videos: {
[ id: string ]: {
remoteId: string
likes?: number
dislikes?: number
views?: number
}
}
}
}
export type RequestVideoQaduSchedulerOptions = {
type: RequestVideoQaduType
@ -37,8 +56,8 @@ class RequestVideoQaduScheduler extends AbstractRequestScheduler<RequestsVideoQa
return db.RequestVideoQadu
}
buildRequestObjects (requests: RequestsVideoQaduGrouped) {
const requestsToMakeGrouped = {}
buildRequestsObjects (requests: RequestsVideoQaduGrouped) {
const requestsToMakeGrouped: RequestsObjectsCustom<RemoteQaduVideoRequest> = {}
Object.keys(requests).forEach(toPodId => {
requests[toPodId].forEach(data => {
@ -59,7 +78,7 @@ class RequestVideoQaduScheduler extends AbstractRequestScheduler<RequestsVideoQa
// Maybe another attribute was filled for this video
let videoData = requestsToMakeGrouped[hashKey].videos[video.id]
if (!videoData) videoData = {}
if (!videoData) videoData = { remoteId: null }
switch (request.type) {
case REQUEST_VIDEO_QADU_TYPES.LIKES:

View File

@ -6,9 +6,12 @@ import {
logger,
checkSignature as peertubeCryptoCheckSignature
} from '../helpers'
import { PodSignature } from '../../shared'
function checkSignature (req: express.Request, res: express.Response, next: express.NextFunction) {
const host = req.body.signature.host
const signatureObject: PodSignature = req.body.signature
const host = signatureObject.host
db.Pod.loadByHost(host)
.then(pod => {
if (pod === null) {
@ -27,7 +30,7 @@ function checkSignature (req: express.Request, res: express.Response, next: expr
signatureShouldBe = host
}
const signatureOk = peertubeCryptoCheckSignature(pod.publicKey, signatureShouldBe, req.body.signature.signature)
const signatureOk = peertubeCryptoCheckSignature(pod.publicKey, signatureShouldBe, signatureObject.signature)
if (signatureOk === true) {
res.locals.secure = {
@ -37,11 +40,11 @@ function checkSignature (req: express.Request, res: express.Response, next: expr
return next()
}
logger.error('Signature is not okay in body for %s.', req.body.signature.host)
logger.error('Signature is not okay in body for %s.', signatureObject.host)
return res.sendStatus(403)
})
.catch(err => {
logger.error('Cannot get signed host in body.', { error: err.stack, signature: req.body.signature.signature })
logger.error('Cannot get signed host in body.', { error: err.stack, signature: signatureObject.signature })
return res.sendStatus(500)
})
}

View File

@ -2,7 +2,7 @@ import * as Sequelize from 'sequelize'
import * as Promise from 'bluebird'
// Don't use barrel, import just what we need
import { Pod as FormatedPod } from '../../../shared/models/pod.model'
import { Pod as FormatedPod } from '../../../shared/models/pods/pod.model'
export namespace PodMethods {
export type ToFormatedJSON = (this: PodInstance) => FormatedPod

View File

@ -2,7 +2,8 @@ import * as Sequelize from 'sequelize'
import * as Promise from 'bluebird'
// Don't use barrel, import just what we need
import { UserRole, User as FormatedUser } from '../../../shared/models/user.model'
import { User as FormatedUser } from '../../../shared/models/users/user.model'
import { UserRole } from '../../../shared/models/users/user-role.type'
import { ResultList } from '../../../shared/models/result-list.model'
export namespace UserMethods {

View File

@ -1,7 +1,7 @@
import * as Sequelize from 'sequelize'
import * as Promise from 'bluebird'
import { VideoRateType } from '../../../shared/models/user-video-rate.model'
import { VideoRateType } from '../../../shared/models/videos/video-rate.type'
export namespace UserVideoRateMethods {
export type Load = (userId: number, videoId: string, transaction: Sequelize.Transaction) => Promise<UserVideoRateInstance>

View File

@ -5,7 +5,7 @@ import { PodInstance } from '../pod'
import { ResultList } from '../../../shared'
// Don't use barrel, import just what we need
import { VideoAbuse as FormatedVideoAbuse } from '../../../shared/models/video-abuse.model'
import { VideoAbuse as FormatedVideoAbuse } from '../../../shared/models/videos/video-abuse.model'
export namespace VideoAbuseMethods {
export type ToFormatedJSON = (this: VideoAbuseInstance) => FormatedVideoAbuse

View File

@ -4,7 +4,7 @@ import * as Promise from 'bluebird'
import { ResultList } from '../../../shared'
// Don't use barrel, import just what we need
import { BlacklistedVideo as FormatedBlacklistedVideo } from '../../../shared/models/video-blacklist.model'
import { BlacklistedVideo as FormatedBlacklistedVideo } from '../../../shared/models/videos/video-blacklist.model'
export namespace BlacklistedVideoMethods {
export type ToFormatedJSON = (this: BlacklistedVideoInstance) => FormatedBlacklistedVideo

View File

@ -5,7 +5,7 @@ import { AuthorInstance } from './author-interface'
import { TagAttributes, TagInstance } from './tag-interface'
// Don't use barrel, import just what we need
import { Video as FormatedVideo } from '../../../shared/models/video.model'
import { Video as FormatedVideo } from '../../../shared/models/videos/video.model'
import { ResultList } from '../../../shared/models/result-list.model'
export type FormatedAddRemoteVideo = {

View File

@ -1,11 +1,8 @@
export * from './pods'
export * from './users'
export * from './videos'
export * from './job.model'
export * from './oauth-client-local.model'
export * from './pod.model'
export * from './result-list.model'
export * from './request-scheduler.model'
export * from './user-video-rate.model'
export * from './user.model'
export * from './video-abuse.model'
export * from './video-blacklist.model'
export * from './video.model'
export * from './server-config.model'

View File

@ -0,0 +1,3 @@
export * from './pod-signature.model'
export * from './pod.model'
export * from './remote-video'

View File

@ -0,0 +1,4 @@
export interface PodSignature {
host: string
signature: string
}

View File

@ -0,0 +1,7 @@
export * from './remote-qadu-video-request.model'
export * from './remote-video-event-request.model'
export * from './remote-video-request.model'
export * from './remote-video-create-request.model'
export * from './remote-video-update-request.model'
export * from './remote-video-remove-request.model'
export * from './remote-video-report-abuse-request.model'

View File

@ -0,0 +1,10 @@
export interface RemoteQaduVideoData {
remoteId: string
views?: number
likes?: number
dislikes?: number
}
export interface RemoteQaduVideoRequest {
data: RemoteQaduVideoData
}

View File

@ -0,0 +1,27 @@
import { RemoteVideoRequest } from './remote-video-request.model'
export interface RemoteVideoCreateData {
remoteId: string
author: string
tags: string[]
name: string
extname: string
infoHash: string
category: number
licence: number
language: number
nsfw: boolean
description: string
duration: number
createdAt: Date
updatedAt: Date
views: number
likes: number
dislikes: number
thumbnailData: string
}
export interface RemoteVideoCreateRequest extends RemoteVideoRequest {
type: 'add'
data: RemoteVideoCreateData
}

View File

@ -0,0 +1,11 @@
export type RemoteVideoEventType = 'views' | 'likes' | 'dislikes'
export interface RemoteVideoEventData {
remoteId: string
eventType: RemoteVideoEventType
count: number
}
export interface RemoteVideoEventRequest {
data: RemoteVideoEventData
}

View File

@ -0,0 +1,10 @@
import { RemoteVideoRequest } from './remote-video-request.model'
export interface RemoteVideoRemoveData {
remoteId: string
}
export interface RemoteVideoRemoveRequest extends RemoteVideoRequest {
type: 'remove'
data: RemoteVideoRemoveData
}

View File

@ -0,0 +1,12 @@
import { RemoteVideoRequest } from './remote-video-request.model'
export interface RemoteVideoReportAbuseData {
videoRemoteId: string
reporterUsername: string
reportReason: string
}
export interface RemoteVideoReportAbuseRequest extends RemoteVideoRequest {
type: 'report-abuse'
data: RemoteVideoReportAbuseData
}

View File

@ -0,0 +1,4 @@
export interface RemoteVideoRequest {
type: 'add' | 'update' | 'remove' | 'report-abuse'
data: any
}

View File

@ -0,0 +1,23 @@
export interface RemoteVideoUpdateData {
remoteId: string
tags: string[]
name: string
extname: string
infoHash: string
category: number
licence: number
language: number
nsfw: boolean
description: string
duration: number
createdAt: Date
updatedAt: Date
views: number
likes: number
dislikes: number
}
export interface RemoteVideoUpdateRequest {
type: 'update'
data: RemoteVideoUpdateData
}

View File

@ -1,7 +0,0 @@
export type VideoRateType = 'like' | 'dislike'
export type UserVideoRateType = 'like' | 'dislike' | 'none'
export interface UserVideoRate {
videoId: string
rating: UserVideoRateType
}

View File

@ -0,0 +1,4 @@
export * from './user.model'
export * from './user-create.model'
export * from './user-update.model'
export * from './user-role.type'

View File

@ -0,0 +1,5 @@
export interface UserCreate {
username: string
password: string
email: string
}

View File

@ -0,0 +1 @@
export type UserRole = 'admin' | 'user'

View File

@ -0,0 +1,4 @@
export interface UserUpdate {
displayNSFW?: boolean
password?: string
}

View File

@ -1,4 +1,4 @@
export type UserRole = 'admin' | 'user'
import { UserRole } from './user-role.type'
export interface User {
id: number

View File

@ -0,0 +1,10 @@
export * from './user-video-rate-update.model'
export * from './user-video-rate.model'
export * from './user-video-rate.type'
export * from './video-abuse-create.model'
export * from './video-abuse.model'
export * from './video-blacklist.model'
export * from './video-create.model'
export * from './video-rate.type'
export * from './video-update.model'
export * from './video.model'

View File

@ -0,0 +1,5 @@
import { UserVideoRateType } from './user-video-rate.type'
export interface UserVideoRateUpdate {
rating: UserVideoRateType
}

View File

@ -0,0 +1,6 @@
import { UserVideoRateType } from './user-video-rate.type'
export interface UserVideoRate {
videoId: string
rating: UserVideoRateType
}

View File

@ -0,0 +1 @@
export type UserVideoRateType = 'like' | 'dislike' | 'none'

View File

@ -0,0 +1,3 @@
export interface VideoAbuseCreate {
reason: string
}

View File

@ -0,0 +1,9 @@
export interface VideoCreate {
category: number
licence: number
language: number
description: string
nsfw: boolean
name: string
tags: string[]
}

View File

@ -0,0 +1 @@
export type VideoRateType = 'like' | 'dislike'

View File

@ -0,0 +1,9 @@
export interface VideoUpdate {
name?: string
category?: number
licence?: number
language?: number
description?: string
tags?: string[]
nsfw?: boolean
}