diff --git a/README.md b/README.md index 44732d8..4802a87 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,9 @@ const api = new TikTokAPI(params, { signURL }); * [.listFollowing(params)](#listfollowingparams) * [.follow(id)](#followid) * [.unfollow(id)](#unfollowid) +* [.listReceivedFollowRequests(params)](#listreceivedfollowrequestsparams) +* [.approveFollowRequest(id)](#approvefollowrequestid) +* [.rejectFollowRequest(id)](#rejectfollowrequestid) * [.likePost(id)](#likepostid) * [.unlikePost(id)](#unlikepostid) * [.listComments(params)](#listcommentsparams) @@ -209,6 +212,57 @@ api.unfollow('') See the [follow types](src/types/follow.d.ts) for the response data. +#### .listReceivedFollowRequests(params) + +Lists the users that have requested to follow the logged in user. + +```javascript +api.listReceivedFollowRequests({ + max_time: Math.floor(new Date().getTime() / 1000), + count: 10, +}) + .then(res => console.log(res.data.request_users)) + .catch(console.log); + +// Outputs: +// [{ unique_id: 'user1' }, { unique_id: 'user2' }, ...] + +``` + +See the [follow types](src/types/follow.d.ts) for the complete request/response objects. + +#### .approveFollowRequest(id) + +Approves a user's request to follow you. + +```javascript +api.approveFollowRequest('') + .then(res => console.log(res.data.approve_status)) + .catch(console.log); + +// Outputs: +// 0 + +``` + +See the [follow types](src/types/follow.d.ts) for the response data. + +#### .rejectFollowRequest(id) + +Rejects a user's request to follow you. + +```javascript +api.rejectFollowRequest('') + .then(res => console.log(res.data.reject_status)) + .catch(console.log); + +// Outputs: +// 0 + +``` + +See the [follow types](src/types/follow.d.ts) for the response data. + #### .likePost(id) Likes a post. diff --git a/src/index.ts b/src/index.ts index 0832aab..d1ce1ae 100644 --- a/src/index.ts +++ b/src/index.ts @@ -164,6 +164,44 @@ export default class TikTokAPI { }, }) + /** + * Lists the users who have requested to follow the logged in user. + * + * @param {ListReceivedFollowRequestsRequest} params + * @returns {AxiosPromise} + */ + listReceivedFollowRequests = (params: API.ListReceivedFollowRequestsRequest) => + this.request.get( + 'aweme/v1/user/following/request/list/', + { params: withDefaultListParams(params) }, + ) + + /** + * Approves a request from a user to follow you. + * + * @param userId + * @returns {AxiosPromise} + */ + approveFollowRequest = (userId: string) => + this.request.get('aweme/v1/commit/follow/request/approve/', { + params: { + from_user_id: userId, + }, + }) + + /** + * Rejects a request from a user to follow you. + * + * @param userId + * @returns {AxiosPromise} + */ + rejectFollowRequest = (userId: string) => + this.request.get('aweme/v1/commit/follow/request/reject/', { + params: { + from_user_id: userId, + }, + }) + /** * Likes a post. * diff --git a/src/types/follow.d.ts b/src/types/follow.d.ts index 7d96fbb..c3678c5 100644 --- a/src/types/follow.d.ts +++ b/src/types/follow.d.ts @@ -1,4 +1,11 @@ -import { BaseResponseData } from './request'; +import { CommonUserDetails } from './user'; +import { + BaseResponseData, + ListRequestParams, + ListResponseData, + TimeOffsetRequestParams, + TimeOffsetResponseParams, +} from './request'; export interface FollowRequest extends BaseResponseData { /** The id of the user to follow */ @@ -15,3 +22,31 @@ export interface FollowResponse extends BaseResponseData { /** 0 if not watching, 1 if watching */ watch_status: 0 | 1; } + +export interface ListReceivedFollowRequestsRequest extends ListRequestParams, TimeOffsetRequestParams { +} + +export interface ListReceivedFollowRequestsResponse extends ListResponseData, TimeOffsetResponseParams { + /** A list of users who have requested to follow you */ + request_users: CommonUserDetails[]; +} + +export interface ApproveFollowRequest { + /** The id of the user to approve */ + from_user_id: string; +} + +export interface ApproveFollowResponse extends BaseResponseData { + /** 0 if the user was successfully approved */ + approve_status: number; +} + +export interface RejectFollowRequest { + /** The id of the user to reject */ + from_user_id: string; +} + +export interface RejectFollowResponse extends BaseResponseData { + /** 0 if the user was successfully rejected */ + reject_status: number; +} diff --git a/test/follow.spec.ts b/test/follow.spec.ts index ecb931a..e90af4e 100644 --- a/test/follow.spec.ts +++ b/test/follow.spec.ts @@ -3,7 +3,10 @@ import { assert } from 'chai'; import { describe, it } from 'mocha'; import TikTokAPI, { + ApproveFollowResponse, FollowResponse, + ListReceivedFollowRequestsResponse, + RejectFollowResponse, } from '../src'; import { loadTestData, @@ -58,3 +61,73 @@ describe('#unfollow()', () => { assert.deepStrictEqual(res.data, expected); }); }); + +describe('#listReceivedFollowRequests()', () => { + it('a successful response should match the interface', async () => { + const api = new TikTokAPI(mockParams, mockConfig); + const mock = new MockAdapter(api.request); + mock + .onGet(new RegExp('aweme/v1/user/following/request/list/\?.*')) + .reply(200, loadTestData('listReceivedFollowRequests.json'), {}); + + const res = await api.listReceivedFollowRequests({ count: 10, max_time: 1000000000 }); + const expected: ListReceivedFollowRequestsResponse = { + extra: { + fatal_item_ids: [], + logid: '20180101000000000000000000000000', + now: 1000000000000, + }, + request_users: [], + has_more: false, + max_time: 1000000000, + min_time: 1000000001, + status_code: 0, + total: 1, + }; + assert.deepStrictEqual(res.data, expected); + }); +}); + +describe('#approveFollowRequest()', () => { + it('a successful response should match the interface', async () => { + const api = new TikTokAPI(mockParams, mockConfig); + const mock = new MockAdapter(api.request); + mock + .onGet(new RegExp('aweme/v1/commit/follow/request/approve/\?.*')) + .reply(200, loadTestData('approveFollowRequest.json'), {}); + + const res = await api.approveFollowRequest(userId); + const expected: ApproveFollowResponse = { + extra: { + fatal_item_ids: [], + logid: '20180101000000000000000000000000', + now: 1000000000000, + }, + approve_status: 0, + status_code: 0, + }; + assert.deepStrictEqual(res.data, expected); + }); +}); + +describe('#rejectFollowRequest()', () => { + it('a successful response should match the interface', async () => { + const api = new TikTokAPI(mockParams, mockConfig); + const mock = new MockAdapter(api.request); + mock + .onGet(new RegExp('aweme/v1/commit/follow/request/reject/\?.*')) + .reply(200, loadTestData('rejectFollowRequest.json'), {}); + + const res = await api.rejectFollowRequest(userId); + const expected: RejectFollowResponse = { + extra: { + fatal_item_ids: [], + logid: '20180101000000000000000000000000', + now: 1000000000000, + }, + reject_status: 0, + status_code: 0, + }; + assert.deepStrictEqual(res.data, expected); + }); +}); diff --git a/test/testdata/approveFollowRequest.json b/test/testdata/approveFollowRequest.json new file mode 100644 index 0000000..316fd60 --- /dev/null +++ b/test/testdata/approveFollowRequest.json @@ -0,0 +1,9 @@ +{ + "extra": { + "fatal_item_ids": [], + "logid": "20180101000000000000000000000000", + "now": 1000000000000 + }, + "approve_status": 0, + "status_code": 0 +} diff --git a/test/testdata/listReceivedFollowRequests.json b/test/testdata/listReceivedFollowRequests.json new file mode 100644 index 0000000..cf717ce --- /dev/null +++ b/test/testdata/listReceivedFollowRequests.json @@ -0,0 +1,13 @@ +{ + "extra": { + "fatal_item_ids": [], + "logid": "20180101000000000000000000000000", + "now": 1000000000000 + }, + "request_users": [], + "has_more": false, + "max_time": 1000000000, + "min_time": 1000000001, + "status_code": 0, + "total": 1 +} diff --git a/test/testdata/rejectFollowRequest.json b/test/testdata/rejectFollowRequest.json new file mode 100644 index 0000000..7cbde2d --- /dev/null +++ b/test/testdata/rejectFollowRequest.json @@ -0,0 +1,9 @@ +{ + "extra": { + "fatal_item_ids": [], + "logid": "20180101000000000000000000000000", + "now": 1000000000000 + }, + "reject_status": 0, + "status_code": 0 +}