diff options
-rw-r--r-- | server/controllers/api/users/me.ts | 36 | ||||
-rw-r--r-- | server/middlewares/validators/user-subscriptions.ts | 8 | ||||
-rw-r--r-- | server/middlewares/validators/videos.ts | 2 | ||||
-rw-r--r-- | server/models/activitypub/actor-follow.ts | 27 | ||||
-rw-r--r-- | server/tests/api/check-params/user-subscriptions.ts | 59 | ||||
-rw-r--r-- | server/tests/api/users/user-subscriptions.ts | 27 | ||||
-rw-r--r-- | 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 { | |||
12 | setDefaultPagination, | 12 | setDefaultPagination, |
13 | setDefaultSort, | 13 | setDefaultSort, |
14 | userSubscriptionAddValidator, | 14 | userSubscriptionAddValidator, |
15 | userSubscriptionRemoveValidator, | 15 | userSubscriptionGetValidator, |
16 | usersUpdateMeValidator, | 16 | usersUpdateMeValidator, |
17 | usersVideoRatingValidator | 17 | usersVideoRatingValidator |
18 | } from '../../../middlewares' | 18 | } from '../../../middlewares' |
@@ -97,6 +97,17 @@ meRouter.post('/me/avatar/pick', | |||
97 | 97 | ||
98 | // ##### Subscriptions part ##### | 98 | // ##### Subscriptions part ##### |
99 | 99 | ||
100 | meRouter.get('/me/subscriptions/videos', | ||
101 | authenticate, | ||
102 | authenticate, | ||
103 | paginationValidator, | ||
104 | videosSortValidator, | ||
105 | setDefaultSort, | ||
106 | setDefaultPagination, | ||
107 | commonVideosFiltersValidator, | ||
108 | asyncMiddleware(getUserSubscriptionVideos) | ||
109 | ) | ||
110 | |||
100 | meRouter.get('/me/subscriptions', | 111 | meRouter.get('/me/subscriptions', |
101 | authenticate, | 112 | authenticate, |
102 | paginationValidator, | 113 | paginationValidator, |
@@ -112,21 +123,16 @@ meRouter.post('/me/subscriptions', | |||
112 | asyncMiddleware(addUserSubscription) | 123 | asyncMiddleware(addUserSubscription) |
113 | ) | 124 | ) |
114 | 125 | ||
115 | meRouter.delete('/me/subscriptions/:uri', | 126 | meRouter.get('/me/subscriptions/:uri', |
116 | authenticate, | 127 | authenticate, |
117 | userSubscriptionRemoveValidator, | 128 | userSubscriptionGetValidator, |
118 | asyncMiddleware(deleteUserSubscription) | 129 | getUserSubscription |
119 | ) | 130 | ) |
120 | 131 | ||
121 | meRouter.get('/me/subscriptions/videos', | 132 | meRouter.delete('/me/subscriptions/:uri', |
122 | authenticate, | ||
123 | authenticate, | 133 | authenticate, |
124 | paginationValidator, | 134 | userSubscriptionGetValidator, |
125 | videosSortValidator, | 135 | asyncMiddleware(deleteUserSubscription) |
126 | setDefaultSort, | ||
127 | setDefaultPagination, | ||
128 | commonVideosFiltersValidator, | ||
129 | asyncMiddleware(getUserSubscriptionVideos) | ||
130 | ) | 136 | ) |
131 | 137 | ||
132 | // --------------------------------------------------------------------------- | 138 | // --------------------------------------------------------------------------- |
@@ -153,6 +159,12 @@ async function addUserSubscription (req: express.Request, res: express.Response) | |||
153 | return res.status(204).end() | 159 | return res.status(204).end() |
154 | } | 160 | } |
155 | 161 | ||
162 | function getUserSubscription (req: express.Request, res: express.Response) { | ||
163 | const subscription: ActorFollowModel = res.locals.subscription | ||
164 | |||
165 | return res.json(subscription.ActorFollowing.VideoChannel.toFormattedJSON()) | ||
166 | } | ||
167 | |||
156 | async function deleteUserSubscription (req: express.Request, res: express.Response) { | 168 | async function deleteUserSubscription (req: express.Request, res: express.Response) { |
157 | const subscription: ActorFollowModel = res.locals.subscription | 169 | const subscription: ActorFollowModel = res.locals.subscription |
158 | 170 | ||
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 = [ | |||
20 | } | 20 | } |
21 | ] | 21 | ] |
22 | 22 | ||
23 | const userSubscriptionRemoveValidator = [ | 23 | const userSubscriptionGetValidator = [ |
24 | param('uri').custom(isValidActorHandle).withMessage('Should have a valid URI to unfollow'), | 24 | param('uri').custom(isValidActorHandle).withMessage('Should have a valid URI to unfollow'), |
25 | 25 | ||
26 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 26 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
27 | logger.debug('Checking unfollow parameters', { parameters: req.params }) | 27 | logger.debug('Checking userSubscriptionGetValidator parameters', { parameters: req.params }) |
28 | 28 | ||
29 | if (areValidationErrors(req, res)) return | 29 | if (areValidationErrors(req, res)) return |
30 | 30 | ||
@@ -34,7 +34,7 @@ const userSubscriptionRemoveValidator = [ | |||
34 | const user: UserModel = res.locals.oauth.token.User | 34 | const user: UserModel = res.locals.oauth.token.User |
35 | const subscription = await ActorFollowModel.loadByActorAndTargetNameAndHost(user.Account.Actor.id, name, host) | 35 | const subscription = await ActorFollowModel.loadByActorAndTargetNameAndHost(user.Account.Actor.id, name, host) |
36 | 36 | ||
37 | if (!subscription) { | 37 | if (!subscription || !subscription.ActorFollowing.VideoChannel) { |
38 | return res | 38 | return res |
39 | .status(404) | 39 | .status(404) |
40 | .json({ | 40 | .json({ |
@@ -52,7 +52,7 @@ const userSubscriptionRemoveValidator = [ | |||
52 | 52 | ||
53 | export { | 53 | export { |
54 | userSubscriptionAddValidator, | 54 | userSubscriptionAddValidator, |
55 | userSubscriptionRemoveValidator | 55 | userSubscriptionGetValidator |
56 | } | 56 | } |
57 | 57 | ||
58 | // --------------------------------------------------------------------------- | 58 | // --------------------------------------------------------------------------- |
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 = [ | |||
137 | 137 | ||
138 | // Video private or blacklisted | 138 | // Video private or blacklisted |
139 | if (video.privacy === VideoPrivacy.PRIVATE || video.VideoBlacklist) { | 139 | if (video.privacy === VideoPrivacy.PRIVATE || video.VideoBlacklist) { |
140 | authenticate(req, res, () => { | 140 | return authenticate(req, res, () => { |
141 | const user: UserModel = res.locals.oauth.token.User | 141 | const user: UserModel = res.locals.oauth.token.User |
142 | 142 | ||
143 | // Only the owner or a user that have blacklist rights can see the video | 143 | // 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' | |||
28 | import { getSort } from '../utils' | 28 | import { getSort } from '../utils' |
29 | import { ActorModel } from './actor' | 29 | import { ActorModel } from './actor' |
30 | import { VideoChannelModel } from '../video/video-channel' | 30 | import { VideoChannelModel } from '../video/video-channel' |
31 | import { IIncludeOptions } from '../../../node_modules/sequelize-typescript/lib/interfaces/IIncludeOptions' | ||
31 | 32 | ||
32 | @Table({ | 33 | @Table({ |
33 | tableName: 'actorFollow', | 34 | tableName: 'actorFollow', |
@@ -166,28 +167,30 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
166 | } | 167 | } |
167 | 168 | ||
168 | static loadByActorAndTargetNameAndHost (actorId: number, targetName: string, targetHost: string, t?: Sequelize.Transaction) { | 169 | static loadByActorAndTargetNameAndHost (actorId: number, targetName: string, targetHost: string, t?: Sequelize.Transaction) { |
169 | const actorFollowingPartInclude = { | 170 | const actorFollowingPartInclude: IIncludeOptions = { |
170 | model: ActorModel, | 171 | model: ActorModel, |
171 | required: true, | 172 | required: true, |
172 | as: 'ActorFollowing', | 173 | as: 'ActorFollowing', |
173 | where: { | 174 | where: { |
174 | preferredUsername: targetName | 175 | preferredUsername: targetName |
175 | } | 176 | }, |
177 | include: [ | ||
178 | { | ||
179 | model: VideoChannelModel, | ||
180 | required: false | ||
181 | } | ||
182 | ] | ||
176 | } | 183 | } |
177 | 184 | ||
178 | if (targetHost === null) { | 185 | if (targetHost === null) { |
179 | actorFollowingPartInclude.where['serverId'] = null | 186 | actorFollowingPartInclude.where['serverId'] = null |
180 | } else { | 187 | } else { |
181 | Object.assign(actorFollowingPartInclude, { | 188 | actorFollowingPartInclude.include.push({ |
182 | include: [ | 189 | model: ServerModel, |
183 | { | 190 | required: true, |
184 | model: ServerModel, | 191 | where: { |
185 | required: true, | 192 | host: targetHost |
186 | where: { | 193 | } |
187 | host: targetHost | ||
188 | } | ||
189 | } | ||
190 | ] | ||
191 | }) | 194 | }) |
192 | } | 195 | } |
193 | 196 | ||
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 () { | |||
61 | }) | 61 | }) |
62 | }) | 62 | }) |
63 | 63 | ||
64 | it('Should success with the correct parameters', async function () { | 64 | it('Should succeed with the correct parameters', async function () { |
65 | await makeGetRequest({ | 65 | await makeGetRequest({ |
66 | url: server.url, | 66 | url: server.url, |
67 | path, | 67 | path, |
@@ -94,7 +94,7 @@ describe('Test user subscriptions API validators', function () { | |||
94 | }) | 94 | }) |
95 | }) | 95 | }) |
96 | 96 | ||
97 | it('Should success with the correct parameters', async function () { | 97 | it('Should succeed with the correct parameters', async function () { |
98 | await makeGetRequest({ | 98 | await makeGetRequest({ |
99 | url: server.url, | 99 | url: server.url, |
100 | path, | 100 | path, |
@@ -140,7 +140,7 @@ describe('Test user subscriptions API validators', function () { | |||
140 | }) | 140 | }) |
141 | }) | 141 | }) |
142 | 142 | ||
143 | it('Should success with the correct parameters', async function () { | 143 | it('Should succeed with the correct parameters', async function () { |
144 | await makePostBodyRequest({ | 144 | await makePostBodyRequest({ |
145 | url: server.url, | 145 | url: server.url, |
146 | path, | 146 | path, |
@@ -151,6 +151,57 @@ describe('Test user subscriptions API validators', function () { | |||
151 | }) | 151 | }) |
152 | }) | 152 | }) |
153 | 153 | ||
154 | describe('When getting a subscription', function () { | ||
155 | it('Should fail with a non authenticated user', async function () { | ||
156 | await makeGetRequest({ | ||
157 | url: server.url, | ||
158 | path: path + '/user1_channel@localhost:9001', | ||
159 | statusCodeExpected: 401 | ||
160 | }) | ||
161 | }) | ||
162 | |||
163 | it('Should fail with bad URIs', async function () { | ||
164 | await makeGetRequest({ | ||
165 | url: server.url, | ||
166 | path: path + '/root', | ||
167 | token: server.accessToken, | ||
168 | statusCodeExpected: 400 | ||
169 | }) | ||
170 | |||
171 | await makeGetRequest({ | ||
172 | url: server.url, | ||
173 | path: path + '/root@', | ||
174 | token: server.accessToken, | ||
175 | statusCodeExpected: 400 | ||
176 | }) | ||
177 | |||
178 | await makeGetRequest({ | ||
179 | url: server.url, | ||
180 | path: path + '/root@hello@', | ||
181 | token: server.accessToken, | ||
182 | statusCodeExpected: 400 | ||
183 | }) | ||
184 | }) | ||
185 | |||
186 | it('Should fail with an unknown subscription', async function () { | ||
187 | await makeGetRequest({ | ||
188 | url: server.url, | ||
189 | path: path + '/root1@localhost:9001', | ||
190 | token: server.accessToken, | ||
191 | statusCodeExpected: 404 | ||
192 | }) | ||
193 | }) | ||
194 | |||
195 | it('Should succeed with the correct parameters', async function () { | ||
196 | await makeGetRequest({ | ||
197 | url: server.url, | ||
198 | path: path + '/user1_channel@localhost:9001', | ||
199 | token: server.accessToken, | ||
200 | statusCodeExpected: 200 | ||
201 | }) | ||
202 | }) | ||
203 | }) | ||
204 | |||
154 | describe('When removing a subscription', function () { | 205 | describe('When removing a subscription', function () { |
155 | it('Should fail with a non authenticated user', async function () { | 206 | it('Should fail with a non authenticated user', async function () { |
156 | await makeDeleteRequest({ | 207 | await makeDeleteRequest({ |
@@ -192,7 +243,7 @@ describe('Test user subscriptions API validators', function () { | |||
192 | }) | 243 | }) |
193 | }) | 244 | }) |
194 | 245 | ||
195 | it('Should success with the correct parameters', async function () { | 246 | it('Should succeed with the correct parameters', async function () { |
196 | await makeDeleteRequest({ | 247 | await makeDeleteRequest({ |
197 | url: server.url, | 248 | url: server.url, |
198 | path: path + '/user1_channel@localhost:9001', | 249 | 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 { | |||
11 | addUserSubscription, | 11 | addUserSubscription, |
12 | listUserSubscriptions, | 12 | listUserSubscriptions, |
13 | listUserSubscriptionVideos, | 13 | listUserSubscriptionVideos, |
14 | removeUserSubscription | 14 | removeUserSubscription, |
15 | getUserSubscription | ||
15 | } from '../../utils/users/user-subscriptions' | 16 | } from '../../utils/users/user-subscriptions' |
16 | 17 | ||
17 | const expect = chai.expect | 18 | const expect = chai.expect |
@@ -101,6 +102,30 @@ describe('Test users subscriptions', function () { | |||
101 | } | 102 | } |
102 | }) | 103 | }) |
103 | 104 | ||
105 | it('Should get subscription', async function () { | ||
106 | { | ||
107 | const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'user3_channel@localhost:9003') | ||
108 | const videoChannel: VideoChannel = res.body | ||
109 | |||
110 | expect(videoChannel.name).to.equal('user3_channel') | ||
111 | expect(videoChannel.host).to.equal('localhost:9003') | ||
112 | expect(videoChannel.displayName).to.equal('Main user3 channel') | ||
113 | expect(videoChannel.followingCount).to.equal(0) | ||
114 | expect(videoChannel.followersCount).to.equal(1) | ||
115 | } | ||
116 | |||
117 | { | ||
118 | const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'root_channel@localhost:9001') | ||
119 | const videoChannel: VideoChannel = res.body | ||
120 | |||
121 | expect(videoChannel.name).to.equal('root_channel') | ||
122 | expect(videoChannel.host).to.equal('localhost:9001') | ||
123 | expect(videoChannel.displayName).to.equal('Main root channel') | ||
124 | expect(videoChannel.followingCount).to.equal(0) | ||
125 | expect(videoChannel.followersCount).to.equal(1) | ||
126 | } | ||
127 | }) | ||
128 | |||
104 | it('Should list subscription videos', async function () { | 129 | it('Should list subscription videos', async function () { |
105 | { | 130 | { |
106 | const res = await listUserSubscriptionVideos(servers[0].url, servers[0].accessToken) | 131 | 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 | |||
36 | }) | 36 | }) |
37 | } | 37 | } |
38 | 38 | ||
39 | function getUserSubscription (url: string, token: string, uri: string, statusCodeExpected = 200) { | ||
40 | const path = '/api/v1/users/me/subscriptions/' + uri | ||
41 | |||
42 | return makeGetRequest({ | ||
43 | url, | ||
44 | path, | ||
45 | token, | ||
46 | statusCodeExpected | ||
47 | }) | ||
48 | } | ||
49 | |||
39 | function removeUserSubscription (url: string, token: string, uri: string, statusCodeExpected = 204) { | 50 | function removeUserSubscription (url: string, token: string, uri: string, statusCodeExpected = 204) { |
40 | const path = '/api/v1/users/me/subscriptions/' + uri | 51 | const path = '/api/v1/users/me/subscriptions/' + uri |
41 | 52 | ||
@@ -52,6 +63,7 @@ function removeUserSubscription (url: string, token: string, uri: string, status | |||
52 | export { | 63 | export { |
53 | addUserSubscription, | 64 | addUserSubscription, |
54 | listUserSubscriptions, | 65 | listUserSubscriptions, |
66 | getUserSubscription, | ||
55 | listUserSubscriptionVideos, | 67 | listUserSubscriptionVideos, |
56 | removeUserSubscription | 68 | removeUserSubscription |
57 | } | 69 | } |