From 99492dbc0d87ef54d0dab7d8d44f8d0de5722bdd Mon Sep 17 00:00:00 2001
From: Chocobozzz <me@florianbigard.com>
Date: Tue, 21 Aug 2018 10:34:18 +0200
Subject: Add get subscription endpoint

---
 server/controllers/api/users/me.ts                 | 36 ++++++++-----
 .../middlewares/validators/user-subscriptions.ts   |  8 +--
 server/middlewares/validators/videos.ts            |  2 +-
 server/models/activitypub/actor-follow.ts          | 27 +++++-----
 .../tests/api/check-params/user-subscriptions.ts   | 59 ++++++++++++++++++++--
 server/tests/api/users/user-subscriptions.ts       | 27 +++++++++-
 server/tests/utils/users/user-subscriptions.ts     | 12 +++++
 7 files changed, 137 insertions(+), 34 deletions(-)

diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts
index 403842163..2300f5dbe 100644
--- a/server/controllers/api/users/me.ts
+++ b/server/controllers/api/users/me.ts
@@ -12,7 +12,7 @@ import {
   setDefaultPagination,
   setDefaultSort,
   userSubscriptionAddValidator,
-  userSubscriptionRemoveValidator,
+  userSubscriptionGetValidator,
   usersUpdateMeValidator,
   usersVideoRatingValidator
 } from '../../../middlewares'
@@ -97,6 +97,17 @@ meRouter.post('/me/avatar/pick',
 
 // ##### Subscriptions part #####
 
+meRouter.get('/me/subscriptions/videos',
+  authenticate,
+  authenticate,
+  paginationValidator,
+  videosSortValidator,
+  setDefaultSort,
+  setDefaultPagination,
+  commonVideosFiltersValidator,
+  asyncMiddleware(getUserSubscriptionVideos)
+)
+
 meRouter.get('/me/subscriptions',
   authenticate,
   paginationValidator,
@@ -112,21 +123,16 @@ meRouter.post('/me/subscriptions',
   asyncMiddleware(addUserSubscription)
 )
 
-meRouter.delete('/me/subscriptions/:uri',
+meRouter.get('/me/subscriptions/:uri',
   authenticate,
-  userSubscriptionRemoveValidator,
-  asyncMiddleware(deleteUserSubscription)
+  userSubscriptionGetValidator,
+  getUserSubscription
 )
 
-meRouter.get('/me/subscriptions/videos',
-  authenticate,
+meRouter.delete('/me/subscriptions/:uri',
   authenticate,
-  paginationValidator,
-  videosSortValidator,
-  setDefaultSort,
-  setDefaultPagination,
-  commonVideosFiltersValidator,
-  asyncMiddleware(getUserSubscriptionVideos)
+  userSubscriptionGetValidator,
+  asyncMiddleware(deleteUserSubscription)
 )
 
 // ---------------------------------------------------------------------------
@@ -153,6 +159,12 @@ async function addUserSubscription (req: express.Request, res: express.Response)
   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) {
   const subscription: ActorFollowModel = res.locals.subscription
 
diff --git a/server/middlewares/validators/user-subscriptions.ts b/server/middlewares/validators/user-subscriptions.ts
index f331b6c34..d8c26c742 100644
--- a/server/middlewares/validators/user-subscriptions.ts
+++ b/server/middlewares/validators/user-subscriptions.ts
@@ -20,11 +20,11 @@ const userSubscriptionAddValidator = [
   }
 ]
 
-const userSubscriptionRemoveValidator = [
+const userSubscriptionGetValidator = [
   param('uri').custom(isValidActorHandle).withMessage('Should have a valid URI to unfollow'),
 
   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
 
@@ -34,7 +34,7 @@ const userSubscriptionRemoveValidator = [
     const user: UserModel = res.locals.oauth.token.User
     const subscription = await ActorFollowModel.loadByActorAndTargetNameAndHost(user.Account.Actor.id, name, host)
 
-    if (!subscription) {
+    if (!subscription || !subscription.ActorFollowing.VideoChannel) {
       return res
         .status(404)
         .json({
@@ -52,7 +52,7 @@ const userSubscriptionRemoveValidator = [
 
 export {
   userSubscriptionAddValidator,
-  userSubscriptionRemoveValidator
+  userSubscriptionGetValidator
 }
 
 // ---------------------------------------------------------------------------
diff --git a/server/middlewares/validators/videos.ts b/server/middlewares/validators/videos.ts
index 53c32abb8..a2c866152 100644
--- a/server/middlewares/validators/videos.ts
+++ b/server/middlewares/validators/videos.ts
@@ -137,7 +137,7 @@ const videosGetValidator = [
 
     // Video private or blacklisted
     if (video.privacy === VideoPrivacy.PRIVATE || video.VideoBlacklist) {
-      authenticate(req, res, () => {
+      return authenticate(req, res, () => {
         const user: UserModel = res.locals.oauth.token.User
 
         // Only the owner or a user that have blacklist rights can see the video
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts
index 90a8ac43c..20d3aa5fc 100644
--- a/server/models/activitypub/actor-follow.ts
+++ b/server/models/activitypub/actor-follow.ts
@@ -28,6 +28,7 @@ import { ServerModel } from '../server/server'
 import { getSort } from '../utils'
 import { ActorModel } from './actor'
 import { VideoChannelModel } from '../video/video-channel'
+import { IIncludeOptions } from '../../../node_modules/sequelize-typescript/lib/interfaces/IIncludeOptions'
 
 @Table({
   tableName: 'actorFollow',
@@ -166,28 +167,30 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
   }
 
   static loadByActorAndTargetNameAndHost (actorId: number, targetName: string, targetHost: string, t?: Sequelize.Transaction) {
-    const actorFollowingPartInclude = {
+    const actorFollowingPartInclude: IIncludeOptions = {
       model: ActorModel,
       required: true,
       as: 'ActorFollowing',
       where: {
         preferredUsername: targetName
-      }
+      },
+      include: [
+        {
+          model: VideoChannelModel,
+          required: false
+        }
+      ]
     }
 
     if (targetHost === null) {
       actorFollowingPartInclude.where['serverId'] = null
     } else {
-      Object.assign(actorFollowingPartInclude, {
-        include: [
-          {
-            model: ServerModel,
-            required: true,
-            where: {
-              host: targetHost
-            }
-          }
-        ]
+      actorFollowingPartInclude.include.push({
+        model: ServerModel,
+        required: true,
+        where: {
+          host: targetHost
+        }
       })
     }
 
diff --git a/server/tests/api/check-params/user-subscriptions.ts b/server/tests/api/check-params/user-subscriptions.ts
index 628a74476..6a6dd9a6f 100644
--- a/server/tests/api/check-params/user-subscriptions.ts
+++ b/server/tests/api/check-params/user-subscriptions.ts
@@ -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({
         url: server.url,
         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({
         url: server.url,
         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({
         url: server.url,
         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 () {
     it('Should fail with a non authenticated user', async function () {
       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({
         url: server.url,
         path: path + '/user1_channel@localhost:9001',
diff --git a/server/tests/api/users/user-subscriptions.ts b/server/tests/api/users/user-subscriptions.ts
index ba59a9a60..2fbda6828 100644
--- a/server/tests/api/users/user-subscriptions.ts
+++ b/server/tests/api/users/user-subscriptions.ts
@@ -11,7 +11,8 @@ import {
   addUserSubscription,
   listUserSubscriptions,
   listUserSubscriptionVideos,
-  removeUserSubscription
+  removeUserSubscription,
+  getUserSubscription
 } from '../../utils/users/user-subscriptions'
 
 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 () {
     {
       const res = await listUserSubscriptionVideos(servers[0].url, servers[0].accessToken)
diff --git a/server/tests/utils/users/user-subscriptions.ts b/server/tests/utils/users/user-subscriptions.ts
index 323e5de58..852f590cf 100644
--- a/server/tests/utils/users/user-subscriptions.ts
+++ b/server/tests/utils/users/user-subscriptions.ts
@@ -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) {
   const path = '/api/v1/users/me/subscriptions/' + uri
 
@@ -52,6 +63,7 @@ function removeUserSubscription (url: string, token: string, uri: string, status
 export {
   addUserSubscription,
   listUserSubscriptions,
+  getUserSubscription,
   listUserSubscriptionVideos,
   removeUserSubscription
 }
-- 
cgit v1.2.3