Add get subscription endpoint

pull/974/head
Chocobozzz 2018-08-21 10:34:18 +02:00
parent 8a19bee1a1
commit 99492dbc0d
7 changed files with 137 additions and 34 deletions

View File

@ -12,7 +12,7 @@ import {
setDefaultPagination, setDefaultPagination,
setDefaultSort, setDefaultSort,
userSubscriptionAddValidator, userSubscriptionAddValidator,
userSubscriptionRemoveValidator, userSubscriptionGetValidator,
usersUpdateMeValidator, usersUpdateMeValidator,
usersVideoRatingValidator usersVideoRatingValidator
} from '../../../middlewares' } from '../../../middlewares'
@ -97,6 +97,17 @@ meRouter.post('/me/avatar/pick',
// ##### Subscriptions part ##### // ##### Subscriptions part #####
meRouter.get('/me/subscriptions/videos',
authenticate,
authenticate,
paginationValidator,
videosSortValidator,
setDefaultSort,
setDefaultPagination,
commonVideosFiltersValidator,
asyncMiddleware(getUserSubscriptionVideos)
)
meRouter.get('/me/subscriptions', meRouter.get('/me/subscriptions',
authenticate, authenticate,
paginationValidator, paginationValidator,
@ -112,21 +123,16 @@ meRouter.post('/me/subscriptions',
asyncMiddleware(addUserSubscription) asyncMiddleware(addUserSubscription)
) )
meRouter.delete('/me/subscriptions/:uri', meRouter.get('/me/subscriptions/:uri',
authenticate, authenticate,
userSubscriptionRemoveValidator, userSubscriptionGetValidator,
asyncMiddleware(deleteUserSubscription) getUserSubscription
) )
meRouter.get('/me/subscriptions/videos', meRouter.delete('/me/subscriptions/:uri',
authenticate, authenticate,
authenticate, userSubscriptionGetValidator,
paginationValidator, asyncMiddleware(deleteUserSubscription)
videosSortValidator,
setDefaultSort,
setDefaultPagination,
commonVideosFiltersValidator,
asyncMiddleware(getUserSubscriptionVideos)
) )
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -153,6 +159,12 @@ async function addUserSubscription (req: express.Request, res: express.Response)
return res.status(204).end() return res.status(204).end()
} }
function getUserSubscription (req: express.Request, res: express.Response) {
const subscription: ActorFollowModel = res.locals.subscription
return res.json(subscription.ActorFollowing.VideoChannel.toFormattedJSON())
}
async function deleteUserSubscription (req: express.Request, res: express.Response) { async function deleteUserSubscription (req: express.Request, res: express.Response) {
const subscription: ActorFollowModel = res.locals.subscription const subscription: ActorFollowModel = res.locals.subscription

View File

@ -20,11 +20,11 @@ const userSubscriptionAddValidator = [
} }
] ]
const userSubscriptionRemoveValidator = [ const userSubscriptionGetValidator = [
param('uri').custom(isValidActorHandle).withMessage('Should have a valid URI to unfollow'), param('uri').custom(isValidActorHandle).withMessage('Should have a valid URI to unfollow'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => { async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking unfollow parameters', { parameters: req.params }) logger.debug('Checking userSubscriptionGetValidator parameters', { parameters: req.params })
if (areValidationErrors(req, res)) return if (areValidationErrors(req, res)) return
@ -34,7 +34,7 @@ const userSubscriptionRemoveValidator = [
const user: UserModel = res.locals.oauth.token.User const user: UserModel = res.locals.oauth.token.User
const subscription = await ActorFollowModel.loadByActorAndTargetNameAndHost(user.Account.Actor.id, name, host) const subscription = await ActorFollowModel.loadByActorAndTargetNameAndHost(user.Account.Actor.id, name, host)
if (!subscription) { if (!subscription || !subscription.ActorFollowing.VideoChannel) {
return res return res
.status(404) .status(404)
.json({ .json({
@ -52,7 +52,7 @@ const userSubscriptionRemoveValidator = [
export { export {
userSubscriptionAddValidator, userSubscriptionAddValidator,
userSubscriptionRemoveValidator userSubscriptionGetValidator
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -137,7 +137,7 @@ const videosGetValidator = [
// Video private or blacklisted // Video private or blacklisted
if (video.privacy === VideoPrivacy.PRIVATE || video.VideoBlacklist) { if (video.privacy === VideoPrivacy.PRIVATE || video.VideoBlacklist) {
authenticate(req, res, () => { return authenticate(req, res, () => {
const user: UserModel = res.locals.oauth.token.User const user: UserModel = res.locals.oauth.token.User
// Only the owner or a user that have blacklist rights can see the video // Only the owner or a user that have blacklist rights can see the video

View File

@ -28,6 +28,7 @@ import { ServerModel } from '../server/server'
import { getSort } from '../utils' import { getSort } from '../utils'
import { ActorModel } from './actor' import { ActorModel } from './actor'
import { VideoChannelModel } from '../video/video-channel' import { VideoChannelModel } from '../video/video-channel'
import { IIncludeOptions } from '../../../node_modules/sequelize-typescript/lib/interfaces/IIncludeOptions'
@Table({ @Table({
tableName: 'actorFollow', tableName: 'actorFollow',
@ -166,28 +167,30 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
} }
static loadByActorAndTargetNameAndHost (actorId: number, targetName: string, targetHost: string, t?: Sequelize.Transaction) { static loadByActorAndTargetNameAndHost (actorId: number, targetName: string, targetHost: string, t?: Sequelize.Transaction) {
const actorFollowingPartInclude = { const actorFollowingPartInclude: IIncludeOptions = {
model: ActorModel, model: ActorModel,
required: true, required: true,
as: 'ActorFollowing', as: 'ActorFollowing',
where: { where: {
preferredUsername: targetName preferredUsername: targetName
} },
include: [
{
model: VideoChannelModel,
required: false
}
]
} }
if (targetHost === null) { if (targetHost === null) {
actorFollowingPartInclude.where['serverId'] = null actorFollowingPartInclude.where['serverId'] = null
} else { } else {
Object.assign(actorFollowingPartInclude, { actorFollowingPartInclude.include.push({
include: [ model: ServerModel,
{ required: true,
model: ServerModel, where: {
required: true, host: targetHost
where: { }
host: targetHost
}
}
]
}) })
} }

View File

@ -61,7 +61,7 @@ describe('Test user subscriptions API validators', function () {
}) })
}) })
it('Should success with the correct parameters', async function () { it('Should succeed with the correct parameters', async function () {
await makeGetRequest({ await makeGetRequest({
url: server.url, url: server.url,
path, path,
@ -94,7 +94,7 @@ describe('Test user subscriptions API validators', function () {
}) })
}) })
it('Should success with the correct parameters', async function () { it('Should succeed with the correct parameters', async function () {
await makeGetRequest({ await makeGetRequest({
url: server.url, url: server.url,
path, path,
@ -140,7 +140,7 @@ describe('Test user subscriptions API validators', function () {
}) })
}) })
it('Should success with the correct parameters', async function () { it('Should succeed with the correct parameters', async function () {
await makePostBodyRequest({ await makePostBodyRequest({
url: server.url, url: server.url,
path, path,
@ -151,6 +151,57 @@ describe('Test user subscriptions API validators', function () {
}) })
}) })
describe('When getting a subscription', function () {
it('Should fail with a non authenticated user', async function () {
await makeGetRequest({
url: server.url,
path: path + '/user1_channel@localhost:9001',
statusCodeExpected: 401
})
})
it('Should fail with bad URIs', async function () {
await makeGetRequest({
url: server.url,
path: path + '/root',
token: server.accessToken,
statusCodeExpected: 400
})
await makeGetRequest({
url: server.url,
path: path + '/root@',
token: server.accessToken,
statusCodeExpected: 400
})
await makeGetRequest({
url: server.url,
path: path + '/root@hello@',
token: server.accessToken,
statusCodeExpected: 400
})
})
it('Should fail with an unknown subscription', async function () {
await makeGetRequest({
url: server.url,
path: path + '/root1@localhost:9001',
token: server.accessToken,
statusCodeExpected: 404
})
})
it('Should succeed with the correct parameters', async function () {
await makeGetRequest({
url: server.url,
path: path + '/user1_channel@localhost:9001',
token: server.accessToken,
statusCodeExpected: 200
})
})
})
describe('When removing a subscription', function () { describe('When removing a subscription', function () {
it('Should fail with a non authenticated user', async function () { it('Should fail with a non authenticated user', async function () {
await makeDeleteRequest({ await makeDeleteRequest({
@ -192,7 +243,7 @@ describe('Test user subscriptions API validators', function () {
}) })
}) })
it('Should success with the correct parameters', async function () { it('Should succeed with the correct parameters', async function () {
await makeDeleteRequest({ await makeDeleteRequest({
url: server.url, url: server.url,
path: path + '/user1_channel@localhost:9001', path: path + '/user1_channel@localhost:9001',

View File

@ -11,7 +11,8 @@ import {
addUserSubscription, addUserSubscription,
listUserSubscriptions, listUserSubscriptions,
listUserSubscriptionVideos, listUserSubscriptionVideos,
removeUserSubscription removeUserSubscription,
getUserSubscription
} from '../../utils/users/user-subscriptions' } from '../../utils/users/user-subscriptions'
const expect = chai.expect const expect = chai.expect
@ -101,6 +102,30 @@ describe('Test users subscriptions', function () {
} }
}) })
it('Should get subscription', async function () {
{
const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'user3_channel@localhost:9003')
const videoChannel: VideoChannel = res.body
expect(videoChannel.name).to.equal('user3_channel')
expect(videoChannel.host).to.equal('localhost:9003')
expect(videoChannel.displayName).to.equal('Main user3 channel')
expect(videoChannel.followingCount).to.equal(0)
expect(videoChannel.followersCount).to.equal(1)
}
{
const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'root_channel@localhost:9001')
const videoChannel: VideoChannel = res.body
expect(videoChannel.name).to.equal('root_channel')
expect(videoChannel.host).to.equal('localhost:9001')
expect(videoChannel.displayName).to.equal('Main root channel')
expect(videoChannel.followingCount).to.equal(0)
expect(videoChannel.followersCount).to.equal(1)
}
})
it('Should list subscription videos', async function () { it('Should list subscription videos', async function () {
{ {
const res = await listUserSubscriptionVideos(servers[0].url, servers[0].accessToken) const res = await listUserSubscriptionVideos(servers[0].url, servers[0].accessToken)

View File

@ -36,6 +36,17 @@ function listUserSubscriptionVideos (url: string, token: string, sort = '-create
}) })
} }
function getUserSubscription (url: string, token: string, uri: string, statusCodeExpected = 200) {
const path = '/api/v1/users/me/subscriptions/' + uri
return makeGetRequest({
url,
path,
token,
statusCodeExpected
})
}
function removeUserSubscription (url: string, token: string, uri: string, statusCodeExpected = 204) { function removeUserSubscription (url: string, token: string, uri: string, statusCodeExpected = 204) {
const path = '/api/v1/users/me/subscriptions/' + uri const path = '/api/v1/users/me/subscriptions/' + uri
@ -52,6 +63,7 @@ function removeUserSubscription (url: string, token: string, uri: string, status
export { export {
addUserSubscription, addUserSubscription,
listUserSubscriptions, listUserSubscriptions,
getUserSubscription,
listUserSubscriptionVideos, listUserSubscriptionVideos,
removeUserSubscription removeUserSubscription
} }