@stream-io/feeds-client 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/@react-bindings/hooks/search-state-hooks/index.ts +3 -0
- package/@react-bindings/index.ts +5 -0
- package/CHANGELOG.md +20 -0
- package/dist/@react-bindings/contexts/StreamFeedContext.d.ts +1 -1
- package/dist/@react-bindings/contexts/StreamFeedsContext.d.ts +1 -1
- package/dist/@react-bindings/contexts/StreamSearchContext.d.ts +12 -0
- package/dist/@react-bindings/contexts/StreamSearchResultsContext.d.ts +12 -0
- package/dist/@react-bindings/hooks/feed-state-hooks/useComments.d.ts +1 -1
- package/dist/@react-bindings/hooks/feed-state-hooks/useFeedActivities.d.ts +1 -1
- package/dist/@react-bindings/hooks/feed-state-hooks/useFeedMetadata.d.ts +1 -1
- package/dist/@react-bindings/hooks/feed-state-hooks/useFollowers.d.ts +1 -1
- package/dist/@react-bindings/hooks/feed-state-hooks/useFollowing.d.ts +1 -1
- package/dist/@react-bindings/hooks/feed-state-hooks/useOwnCapabilities.d.ts +1 -1
- package/dist/@react-bindings/hooks/feed-state-hooks/useOwnFollows.d.ts +1 -1
- package/dist/@react-bindings/hooks/search-state-hooks/index.d.ts +3 -0
- package/dist/@react-bindings/hooks/search-state-hooks/useSearchQuery.d.ts +4 -0
- package/dist/@react-bindings/hooks/search-state-hooks/useSearchResult.d.ts +8 -0
- package/dist/@react-bindings/hooks/search-state-hooks/useSearchSources.d.ts +4 -0
- package/dist/@react-bindings/hooks/useCreateFeedsClient.d.ts +1 -1
- package/dist/@react-bindings/index.d.ts +5 -0
- package/dist/@react-bindings/wrappers/StreamFeed.d.ts +1 -1
- package/dist/@react-bindings/wrappers/StreamSearch.d.ts +12 -0
- package/dist/@react-bindings/wrappers/StreamSearchResults.d.ts +12 -0
- package/dist/index-react-bindings.browser.cjs +1669 -1529
- package/dist/index-react-bindings.browser.cjs.map +1 -1
- package/dist/index-react-bindings.browser.js +1661 -1530
- package/dist/index-react-bindings.browser.js.map +1 -1
- package/dist/index-react-bindings.node.cjs +1669 -1529
- package/dist/index-react-bindings.node.cjs.map +1 -1
- package/dist/index-react-bindings.node.js +1661 -1530
- package/dist/index-react-bindings.node.js.map +1 -1
- package/dist/index.browser.cjs +1615 -1640
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +1613 -1641
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.node.cjs +1615 -1640
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +1613 -1641
- package/dist/index.node.js.map +1 -1
- package/dist/src/common/ActivitySearchSource.d.ts +1 -1
- package/dist/src/common/BaseSearchSource.d.ts +3 -1
- package/dist/src/common/FeedSearchSource.d.ts +7 -3
- package/dist/src/common/Poll.d.ts +1 -1
- package/dist/src/common/SearchController.d.ts +2 -0
- package/dist/src/common/UserSearchSource.d.ts +1 -1
- package/dist/src/common/real-time/StableWSConnection.d.ts +3 -3
- package/dist/src/feed/event-handlers/activity/handle-activity-added.d.ts +7 -0
- package/dist/src/feed/event-handlers/activity/handle-activity-deleted.d.ts +8 -0
- package/dist/src/feed/event-handlers/activity/handle-activity-reaction-added.d.ts +8 -0
- package/dist/src/feed/event-handlers/activity/handle-activity-reaction-deleted.d.ts +8 -0
- package/dist/src/feed/event-handlers/activity/handle-activity-removed-from-feed.d.ts +3 -0
- package/dist/src/feed/event-handlers/activity/handle-activity-updated.d.ts +8 -0
- package/dist/src/feed/event-handlers/activity/index.d.ts +6 -0
- package/dist/src/feed/event-handlers/bookmark/handle-bookmark-added.d.ts +8 -0
- package/dist/src/feed/event-handlers/bookmark/handle-bookmark-deleted.d.ts +9 -0
- package/dist/src/feed/event-handlers/bookmark/handle-bookmark-updated.d.ts +8 -0
- package/dist/src/feed/event-handlers/bookmark/index.d.ts +3 -0
- package/dist/src/feed/event-handlers/comment/handle-comment-added.d.ts +3 -0
- package/dist/src/feed/event-handlers/comment/handle-comment-deleted.d.ts +3 -0
- package/dist/src/feed/event-handlers/comment/handle-comment-reaction.d.ts +3 -0
- package/dist/src/feed/event-handlers/comment/handle-comment-updated.d.ts +3 -0
- package/dist/src/feed/event-handlers/comment/index.d.ts +4 -0
- package/dist/src/feed/event-handlers/feed/handle-feed-updated.d.ts +3 -0
- package/dist/src/feed/event-handlers/feed/index.d.ts +1 -0
- package/dist/src/feed/event-handlers/feed-member/handle-feed-member-added.d.ts +3 -0
- package/dist/src/feed/event-handlers/feed-member/handle-feed-member-removed.d.ts +3 -0
- package/dist/src/feed/event-handlers/feed-member/handle-feed-member-updated.d.ts +3 -0
- package/dist/src/feed/event-handlers/feed-member/index.d.ts +3 -0
- package/dist/src/feed/event-handlers/follow/handle-follow-created.d.ts +7 -0
- package/dist/src/feed/event-handlers/follow/handle-follow-deleted.d.ts +7 -0
- package/dist/src/feed/event-handlers/follow/handle-follow-updated.d.ts +3 -0
- package/dist/src/feed/event-handlers/follow/index.d.ts +3 -0
- package/dist/src/feed/event-handlers/index.d.ts +7 -0
- package/dist/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts +3 -0
- package/dist/src/feed/event-handlers/notification-feed/index.d.ts +1 -0
- package/dist/src/{Feed.d.ts → feed/feed.d.ts} +15 -34
- package/dist/src/feed/index.d.ts +2 -0
- package/dist/src/{FeedsClient.d.ts → feeds-client.d.ts} +6 -5
- package/dist/src/gen/models/index.d.ts +5 -0
- package/dist/src/gen-imports.d.ts +1 -1
- package/dist/src/test-utils/index.d.ts +1 -0
- package/dist/src/test-utils/response-generators.d.ts +9 -0
- package/dist/src/types-internal.d.ts +7 -0
- package/dist/src/types.d.ts +1 -1
- package/dist/src/utils/check-has-another-page.d.ts +1 -0
- package/dist/src/utils/constants.d.ts +3 -0
- package/dist/src/utils/index.d.ts +5 -0
- package/dist/src/utils/state-update-queue.d.ts +6 -0
- package/dist/src/utils/type-assertions.d.ts +7 -0
- package/dist/src/utils/unique-array-merge.d.ts +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/index.ts +2 -2
- package/package.json +2 -1
- package/src/common/ActivitySearchSource.ts +6 -16
- package/src/common/BaseSearchSource.ts +9 -9
- package/src/common/FeedSearchSource.ts +22 -67
- package/src/common/Poll.ts +1 -1
- package/src/common/SearchController.ts +2 -0
- package/src/common/UserSearchSource.ts +10 -62
- package/src/{state-updates → feed/event-handlers/activity}/activity-reaction-utils.test.ts +12 -2
- package/src/{state-updates → feed/event-handlers/activity}/activity-utils.test.ts +3 -2
- package/src/{state-updates/activity-utils.ts → feed/event-handlers/activity/handle-activity-added.ts} +16 -36
- package/src/feed/event-handlers/activity/handle-activity-deleted.ts +30 -0
- package/src/feed/event-handlers/activity/handle-activity-reaction-added.ts +67 -0
- package/src/feed/event-handlers/activity/handle-activity-reaction-deleted.ts +75 -0
- package/src/feed/event-handlers/activity/handle-activity-removed-from-feed.ts +16 -0
- package/src/feed/event-handlers/activity/handle-activity-updated.ts +47 -0
- package/src/feed/event-handlers/activity/index.ts +6 -0
- package/src/{state-updates → feed/event-handlers/bookmark}/bookmark-utils.test.ts +2 -2
- package/src/feed/event-handlers/bookmark/handle-bookmark-added.ts +63 -0
- package/src/feed/event-handlers/bookmark/handle-bookmark-deleted.ts +84 -0
- package/src/feed/event-handlers/bookmark/handle-bookmark-updated.ts +76 -0
- package/src/feed/event-handlers/bookmark/index.ts +3 -0
- package/src/feed/event-handlers/comment/handle-comment-added.ts +38 -0
- package/src/feed/event-handlers/comment/handle-comment-deleted.ts +35 -0
- package/src/feed/event-handlers/comment/handle-comment-reaction.ts +61 -0
- package/src/feed/event-handlers/comment/handle-comment-updated.ts +35 -0
- package/src/feed/event-handlers/comment/index.ts +4 -0
- package/src/feed/event-handlers/feed/handle-feed-updated.ts +9 -0
- package/src/feed/event-handlers/feed/index.ts +1 -0
- package/src/feed/event-handlers/feed-member/handle-feed-member-added.ts +31 -0
- package/src/feed/event-handlers/feed-member/handle-feed-member-removed.ts +24 -0
- package/src/feed/event-handlers/feed-member/handle-feed-member-updated.ts +40 -0
- package/src/feed/event-handlers/feed-member/index.ts +3 -0
- package/src/feed/event-handlers/follow/handle-follow-created.test.ts +246 -0
- package/src/feed/event-handlers/follow/handle-follow-created.ts +93 -0
- package/src/feed/event-handlers/follow/handle-follow-deleted.test.ts +264 -0
- package/src/feed/event-handlers/follow/handle-follow-deleted.ts +95 -0
- package/src/feed/event-handlers/follow/handle-follow-updated.test.ts +174 -0
- package/src/feed/event-handlers/follow/handle-follow-updated.ts +88 -0
- package/src/feed/event-handlers/follow/index.ts +3 -0
- package/src/feed/event-handlers/index.ts +7 -0
- package/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.ts +10 -0
- package/src/feed/event-handlers/notification-feed/index.ts +1 -0
- package/src/{Feed.ts → feed/feed.ts} +72 -483
- package/src/feed/index.ts +2 -0
- package/src/{FeedsClient.ts → feeds-client.ts} +26 -8
- package/src/gen/model-decoders/decoders.ts +7 -0
- package/src/gen/models/index.ts +10 -0
- package/src/gen-imports.ts +1 -1
- package/src/test-utils/index.ts +1 -0
- package/src/test-utils/response-generators.ts +102 -0
- package/src/types-internal.ts +11 -0
- package/src/types.ts +1 -1
- package/src/utils/check-has-another-page.ts +6 -0
- package/src/utils/constants.ts +3 -0
- package/src/utils/index.ts +5 -0
- package/src/{state-updates → utils}/state-update-queue.test.ts +6 -6
- package/src/utils/state-update-queue.ts +42 -0
- package/src/utils/type-assertions.ts +22 -0
- package/src/{utils.test.ts → utils/unique-array-merge.test.ts} +7 -3
- package/src/utils/unique-array-merge.ts +19 -0
- package/dist/src/state-updates/activity-reaction-utils.d.ts +0 -10
- package/dist/src/state-updates/activity-utils.d.ts +0 -13
- package/dist/src/state-updates/bookmark-utils.d.ts +0 -14
- package/dist/src/state-updates/follow-utils.d.ts +0 -19
- package/dist/src/state-updates/state-update-queue.d.ts +0 -15
- package/dist/src/utils.d.ts +0 -10
- package/src/state-updates/activity-reaction-utils.ts +0 -107
- package/src/state-updates/bookmark-utils.ts +0 -167
- package/src/state-updates/follow-utils.test.ts +0 -552
- package/src/state-updates/follow-utils.ts +0 -126
- package/src/state-updates/state-update-queue.ts +0 -35
- package/src/utils.ts +0 -48
- /package/dist/src/{ModerationClient.d.ts → moderation-client.d.ts} +0 -0
- /package/src/{ModerationClient.ts → moderation-client.ts} +0 -0
package/dist/index.browser.cjs
CHANGED
|
@@ -1231,6 +1231,12 @@ decoders.ThreadedCommentResponse = (input) => {
|
|
|
1231
1231
|
};
|
|
1232
1232
|
return decode(typeMappings, input);
|
|
1233
1233
|
};
|
|
1234
|
+
decoders.UnfollowResponse = (input) => {
|
|
1235
|
+
const typeMappings = {
|
|
1236
|
+
follow: { type: 'FollowResponse', isSingle: true },
|
|
1237
|
+
};
|
|
1238
|
+
return decode(typeMappings, input);
|
|
1239
|
+
};
|
|
1234
1240
|
decoders.UnpinActivityResponse = (input) => {
|
|
1235
1241
|
const typeMappings = {
|
|
1236
1242
|
activity: { type: 'ActivityResponse', isSingle: true },
|
|
@@ -3751,411 +3757,469 @@ const decodeWSEvent = (data) => {
|
|
|
3751
3757
|
}
|
|
3752
3758
|
};
|
|
3753
3759
|
|
|
3754
|
-
class
|
|
3755
|
-
constructor(
|
|
3756
|
-
this.
|
|
3757
|
-
this.group = group;
|
|
3758
|
-
this.id = id;
|
|
3759
|
-
}
|
|
3760
|
-
delete(request) {
|
|
3761
|
-
return this.feedsApi.deleteFeed({
|
|
3762
|
-
feed_id: this.id,
|
|
3763
|
-
feed_group_id: this.group,
|
|
3764
|
-
...request,
|
|
3765
|
-
});
|
|
3766
|
-
}
|
|
3767
|
-
getOrCreate(request) {
|
|
3768
|
-
return this.feedsApi.getOrCreateFeed({
|
|
3769
|
-
feed_id: this.id,
|
|
3770
|
-
feed_group_id: this.group,
|
|
3771
|
-
...request,
|
|
3772
|
-
});
|
|
3773
|
-
}
|
|
3774
|
-
update(request) {
|
|
3775
|
-
return this.feedsApi.updateFeed({
|
|
3776
|
-
feed_id: this.id,
|
|
3777
|
-
feed_group_id: this.group,
|
|
3778
|
-
...request,
|
|
3779
|
-
});
|
|
3780
|
-
}
|
|
3781
|
-
markActivity(request) {
|
|
3782
|
-
return this.feedsApi.markActivity({
|
|
3783
|
-
feed_id: this.id,
|
|
3784
|
-
feed_group_id: this.group,
|
|
3785
|
-
...request,
|
|
3786
|
-
});
|
|
3787
|
-
}
|
|
3788
|
-
unpinActivity(request) {
|
|
3789
|
-
return this.feedsApi.unpinActivity({
|
|
3790
|
-
feed_id: this.id,
|
|
3791
|
-
feed_group_id: this.group,
|
|
3792
|
-
...request,
|
|
3793
|
-
});
|
|
3794
|
-
}
|
|
3795
|
-
pinActivity(request) {
|
|
3796
|
-
return this.feedsApi.pinActivity({
|
|
3797
|
-
feed_id: this.id,
|
|
3798
|
-
feed_group_id: this.group,
|
|
3799
|
-
...request,
|
|
3800
|
-
});
|
|
3801
|
-
}
|
|
3802
|
-
updateFeedMembers(request) {
|
|
3803
|
-
return this.feedsApi.updateFeedMembers({
|
|
3804
|
-
feed_id: this.id,
|
|
3805
|
-
feed_group_id: this.group,
|
|
3806
|
-
...request,
|
|
3807
|
-
});
|
|
3808
|
-
}
|
|
3809
|
-
acceptFeedMemberInvite(request) {
|
|
3810
|
-
return this.feedsApi.acceptFeedMemberInvite({
|
|
3811
|
-
feed_id: this.id,
|
|
3812
|
-
feed_group_id: this.group,
|
|
3813
|
-
...request,
|
|
3814
|
-
});
|
|
3815
|
-
}
|
|
3816
|
-
queryFeedMembers(request) {
|
|
3817
|
-
return this.feedsApi.queryFeedMembers({
|
|
3818
|
-
feed_id: this.id,
|
|
3819
|
-
feed_group_id: this.group,
|
|
3820
|
-
...request,
|
|
3821
|
-
});
|
|
3760
|
+
class ModerationApi {
|
|
3761
|
+
constructor(apiClient) {
|
|
3762
|
+
this.apiClient = apiClient;
|
|
3822
3763
|
}
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3764
|
+
async ban(request) {
|
|
3765
|
+
const body = {
|
|
3766
|
+
target_user_id: request?.target_user_id,
|
|
3767
|
+
banned_by_id: request?.banned_by_id,
|
|
3768
|
+
channel_cid: request?.channel_cid,
|
|
3769
|
+
delete_messages: request?.delete_messages,
|
|
3770
|
+
ip_ban: request?.ip_ban,
|
|
3771
|
+
reason: request?.reason,
|
|
3772
|
+
shadow: request?.shadow,
|
|
3773
|
+
timeout: request?.timeout,
|
|
3774
|
+
banned_by: request?.banned_by,
|
|
3775
|
+
};
|
|
3776
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/ban', undefined, undefined, body, 'application/json');
|
|
3777
|
+
decoders.BanResponse?.(response.body);
|
|
3778
|
+
return { ...response.body, metadata: response.metadata };
|
|
3829
3779
|
}
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3780
|
+
async upsertConfig(request) {
|
|
3781
|
+
const body = {
|
|
3782
|
+
key: request?.key,
|
|
3783
|
+
async: request?.async,
|
|
3784
|
+
team: request?.team,
|
|
3785
|
+
ai_image_config: request?.ai_image_config,
|
|
3786
|
+
ai_text_config: request?.ai_text_config,
|
|
3787
|
+
ai_video_config: request?.ai_video_config,
|
|
3788
|
+
automod_platform_circumvention_config: request?.automod_platform_circumvention_config,
|
|
3789
|
+
automod_semantic_filters_config: request?.automod_semantic_filters_config,
|
|
3790
|
+
automod_toxicity_config: request?.automod_toxicity_config,
|
|
3791
|
+
aws_rekognition_config: request?.aws_rekognition_config,
|
|
3792
|
+
block_list_config: request?.block_list_config,
|
|
3793
|
+
bodyguard_config: request?.bodyguard_config,
|
|
3794
|
+
google_vision_config: request?.google_vision_config,
|
|
3795
|
+
rule_builder_config: request?.rule_builder_config,
|
|
3796
|
+
velocity_filter_config: request?.velocity_filter_config,
|
|
3797
|
+
video_call_rule_config: request?.video_call_rule_config,
|
|
3798
|
+
};
|
|
3799
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/config', undefined, undefined, body, 'application/json');
|
|
3800
|
+
decoders.UpsertConfigResponse?.(response.body);
|
|
3801
|
+
return { ...response.body, metadata: response.metadata };
|
|
3836
3802
|
}
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
result = {
|
|
3844
|
-
changed: true,
|
|
3845
|
-
activities,
|
|
3803
|
+
async deleteConfig(request) {
|
|
3804
|
+
const queryParams = {
|
|
3805
|
+
team: request?.team,
|
|
3806
|
+
};
|
|
3807
|
+
const pathParams = {
|
|
3808
|
+
key: request?.key,
|
|
3846
3809
|
};
|
|
3810
|
+
const response = await this.apiClient.sendRequest('DELETE', '/api/v2/moderation/config/{key}', pathParams, queryParams);
|
|
3811
|
+
decoders.DeleteModerationConfigResponse?.(response.body);
|
|
3812
|
+
return { ...response.body, metadata: response.metadata };
|
|
3847
3813
|
}
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3814
|
+
async getConfig(request) {
|
|
3815
|
+
const queryParams = {
|
|
3816
|
+
team: request?.team,
|
|
3817
|
+
};
|
|
3818
|
+
const pathParams = {
|
|
3819
|
+
key: request?.key,
|
|
3852
3820
|
};
|
|
3821
|
+
const response = await this.apiClient.sendRequest('GET', '/api/v2/moderation/config/{key}', pathParams, queryParams);
|
|
3822
|
+
decoders.GetConfigResponse?.(response.body);
|
|
3823
|
+
return { ...response.body, metadata: response.metadata };
|
|
3853
3824
|
}
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
...(position === 'start' ? newActivitiesDeduplicated : []),
|
|
3866
|
-
...activities,
|
|
3867
|
-
...(position === 'end' ? newActivitiesDeduplicated : []),
|
|
3868
|
-
];
|
|
3869
|
-
result = { changed: true, activities: updatedActivities };
|
|
3825
|
+
async queryModerationConfigs(request) {
|
|
3826
|
+
const body = {
|
|
3827
|
+
limit: request?.limit,
|
|
3828
|
+
next: request?.next,
|
|
3829
|
+
prev: request?.prev,
|
|
3830
|
+
sort: request?.sort,
|
|
3831
|
+
filter: request?.filter,
|
|
3832
|
+
};
|
|
3833
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/configs', undefined, undefined, body, 'application/json');
|
|
3834
|
+
decoders.QueryModerationConfigsResponse?.(response.body);
|
|
3835
|
+
return { ...response.body, metadata: response.metadata };
|
|
3870
3836
|
}
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
...updatedActivityResponse,
|
|
3880
|
-
own_reactions: activity.own_reactions,
|
|
3881
|
-
own_bookmarks: activity.own_bookmarks,
|
|
3882
|
-
latest_reactions: activity.latest_reactions,
|
|
3883
|
-
reaction_groups: activity.reaction_groups,
|
|
3837
|
+
async flag(request) {
|
|
3838
|
+
const body = {
|
|
3839
|
+
entity_id: request?.entity_id,
|
|
3840
|
+
entity_type: request?.entity_type,
|
|
3841
|
+
entity_creator_id: request?.entity_creator_id,
|
|
3842
|
+
reason: request?.reason,
|
|
3843
|
+
custom: request?.custom,
|
|
3844
|
+
moderation_payload: request?.moderation_payload,
|
|
3884
3845
|
};
|
|
3885
|
-
|
|
3846
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/flag', undefined, undefined, body, 'application/json');
|
|
3847
|
+
decoders.FlagResponse?.(response.body);
|
|
3848
|
+
return { ...response.body, metadata: response.metadata };
|
|
3886
3849
|
}
|
|
3887
|
-
|
|
3888
|
-
|
|
3850
|
+
async mute(request) {
|
|
3851
|
+
const body = {
|
|
3852
|
+
target_ids: request?.target_ids,
|
|
3853
|
+
timeout: request?.timeout,
|
|
3854
|
+
};
|
|
3855
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/mute', undefined, undefined, body, 'application/json');
|
|
3856
|
+
decoders.MuteResponse?.(response.body);
|
|
3857
|
+
return { ...response.body, metadata: response.metadata };
|
|
3889
3858
|
}
|
|
3890
|
-
|
|
3891
|
-
const
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3859
|
+
async queryReviewQueue(request) {
|
|
3860
|
+
const body = {
|
|
3861
|
+
limit: request?.limit,
|
|
3862
|
+
lock_count: request?.lock_count,
|
|
3863
|
+
lock_duration: request?.lock_duration,
|
|
3864
|
+
lock_items: request?.lock_items,
|
|
3865
|
+
next: request?.next,
|
|
3866
|
+
prev: request?.prev,
|
|
3867
|
+
stats_only: request?.stats_only,
|
|
3868
|
+
sort: request?.sort,
|
|
3869
|
+
filter: request?.filter,
|
|
3870
|
+
};
|
|
3871
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/review_queue', undefined, undefined, body, 'application/json');
|
|
3872
|
+
decoders.QueryReviewQueueResponse?.(response.body);
|
|
3873
|
+
return { ...response.body, metadata: response.metadata };
|
|
3897
3874
|
}
|
|
3898
|
-
|
|
3899
|
-
|
|
3875
|
+
async submitAction(request) {
|
|
3876
|
+
const body = {
|
|
3877
|
+
action_type: request?.action_type,
|
|
3878
|
+
item_id: request?.item_id,
|
|
3879
|
+
ban: request?.ban,
|
|
3880
|
+
custom: request?.custom,
|
|
3881
|
+
delete_activity: request?.delete_activity,
|
|
3882
|
+
delete_message: request?.delete_message,
|
|
3883
|
+
delete_reaction: request?.delete_reaction,
|
|
3884
|
+
delete_user: request?.delete_user,
|
|
3885
|
+
mark_reviewed: request?.mark_reviewed,
|
|
3886
|
+
unban: request?.unban,
|
|
3887
|
+
};
|
|
3888
|
+
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/submit_action', undefined, undefined, body, 'application/json');
|
|
3889
|
+
decoders.SubmitActionResponse?.(response.body);
|
|
3890
|
+
return { ...response.body, metadata: response.metadata };
|
|
3900
3891
|
}
|
|
3901
|
-
}
|
|
3892
|
+
}
|
|
3902
3893
|
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
if (index !== -1) {
|
|
3906
|
-
const newActivities = [...activities];
|
|
3907
|
-
newActivities[index] = updatedActivity;
|
|
3908
|
-
return { changed: true, activities: newActivities };
|
|
3909
|
-
}
|
|
3910
|
-
else {
|
|
3911
|
-
return { changed: false, activities };
|
|
3912
|
-
}
|
|
3913
|
-
};
|
|
3914
|
-
const addReactionToActivity = (event, activity, isCurrentUser) => {
|
|
3915
|
-
// Update own_reactions if the reaction is from the current user
|
|
3916
|
-
const ownReactions = [...(activity.own_reactions || [])];
|
|
3917
|
-
if (isCurrentUser) {
|
|
3918
|
-
ownReactions.push(event.reaction);
|
|
3919
|
-
}
|
|
3920
|
-
return {
|
|
3921
|
-
...activity,
|
|
3922
|
-
own_reactions: ownReactions,
|
|
3923
|
-
latest_reactions: event.activity.latest_reactions,
|
|
3924
|
-
reaction_groups: event.activity.reaction_groups,
|
|
3925
|
-
changed: true,
|
|
3926
|
-
};
|
|
3927
|
-
};
|
|
3928
|
-
const removeReactionFromActivity = (event, activity, isCurrentUser) => {
|
|
3929
|
-
// Update own_reactions if the reaction is from the current user
|
|
3930
|
-
const ownReactions = isCurrentUser
|
|
3931
|
-
? (activity.own_reactions || []).filter((r) => !(r.type === event.reaction.type &&
|
|
3932
|
-
r.user.id === event.reaction.user.id))
|
|
3933
|
-
: activity.own_reactions;
|
|
3934
|
-
return {
|
|
3935
|
-
...activity,
|
|
3936
|
-
own_reactions: ownReactions,
|
|
3937
|
-
latest_reactions: event.activity.latest_reactions,
|
|
3938
|
-
reaction_groups: event.activity.reaction_groups,
|
|
3939
|
-
changed: true,
|
|
3940
|
-
};
|
|
3941
|
-
};
|
|
3942
|
-
const addReactionToActivities = (event, activities, isCurrentUser) => {
|
|
3943
|
-
if (!activities) {
|
|
3944
|
-
return { changed: false, activities: [] };
|
|
3945
|
-
}
|
|
3946
|
-
const activityIndex = activities.findIndex((a) => a.id === event.activity.id);
|
|
3947
|
-
if (activityIndex === -1) {
|
|
3948
|
-
return { changed: false, activities };
|
|
3949
|
-
}
|
|
3950
|
-
const activity = activities[activityIndex];
|
|
3951
|
-
const updatedActivity = addReactionToActivity(event, activity, isCurrentUser);
|
|
3952
|
-
return updateActivityInActivities$1(updatedActivity, activities);
|
|
3953
|
-
};
|
|
3954
|
-
const removeReactionFromActivities = (event, activities, isCurrentUser) => {
|
|
3955
|
-
if (!activities) {
|
|
3956
|
-
return { changed: false, activities: [] };
|
|
3957
|
-
}
|
|
3958
|
-
const activityIndex = activities.findIndex((a) => a.id === event.activity.id);
|
|
3959
|
-
if (activityIndex === -1) {
|
|
3960
|
-
return { changed: false, activities };
|
|
3961
|
-
}
|
|
3962
|
-
const activity = activities[activityIndex];
|
|
3963
|
-
const updatedActivity = removeReactionFromActivity(event, activity, isCurrentUser);
|
|
3964
|
-
return updateActivityInActivities$1(updatedActivity, activities);
|
|
3965
|
-
};
|
|
3894
|
+
class ModerationClient extends ModerationApi {
|
|
3895
|
+
}
|
|
3966
3896
|
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
const
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3897
|
+
const isPollUpdatedEvent = (e) => e.type === 'feeds.poll.updated';
|
|
3898
|
+
const isPollClosedEventEvent = (e) => e.type === 'feeds.poll.closed';
|
|
3899
|
+
const isPollVoteCastedEvent = (e) => e.type === 'feeds.poll.vote_casted';
|
|
3900
|
+
const isPollVoteChangedEvent = (e) => e.type === 'feeds.poll.vote_changed';
|
|
3901
|
+
const isPollVoteRemovedEvent = (e) => e.type === 'feeds.poll.vote_removed';
|
|
3902
|
+
const isVoteAnswer = (vote) => !!vote?.answer_text;
|
|
3903
|
+
class StreamPoll {
|
|
3904
|
+
constructor({ client, poll }) {
|
|
3905
|
+
this.getInitialStateFromPollResponse = (poll) => {
|
|
3906
|
+
const { own_votes, id, ...pollResponseForState } = poll;
|
|
3907
|
+
const { ownAnswer, ownVotes } = own_votes?.reduce((acc, voteOrAnswer) => {
|
|
3908
|
+
if (isVoteAnswer(voteOrAnswer)) {
|
|
3909
|
+
acc.ownAnswer = voteOrAnswer;
|
|
3910
|
+
}
|
|
3911
|
+
else {
|
|
3912
|
+
acc.ownVotes.push(voteOrAnswer);
|
|
3913
|
+
}
|
|
3914
|
+
return acc;
|
|
3915
|
+
}, { ownVotes: [] }) ?? { ownVotes: [] };
|
|
3916
|
+
return {
|
|
3917
|
+
...pollResponseForState,
|
|
3918
|
+
last_activity_at: new Date(),
|
|
3919
|
+
max_voted_option_ids: getMaxVotedOptionIds(pollResponseForState.vote_counts_by_option),
|
|
3920
|
+
own_answer: ownAnswer,
|
|
3921
|
+
own_votes_by_option_id: getOwnVotesByOptionId(ownVotes),
|
|
3922
|
+
};
|
|
3923
|
+
};
|
|
3924
|
+
this.reinitializeState = (poll) => {
|
|
3925
|
+
this.state.partialNext(this.getInitialStateFromPollResponse(poll));
|
|
3926
|
+
};
|
|
3927
|
+
this.handlePollUpdated = (event) => {
|
|
3928
|
+
if (event.poll?.id && event.poll.id !== this.id)
|
|
3929
|
+
return;
|
|
3930
|
+
if (!isPollUpdatedEvent(event))
|
|
3931
|
+
return;
|
|
3932
|
+
const { id, ...pollData } = event.poll;
|
|
3933
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3934
|
+
this.state.partialNext({
|
|
3935
|
+
...pollData,
|
|
3936
|
+
last_activity_at: new Date(event.created_at),
|
|
3937
|
+
});
|
|
3938
|
+
};
|
|
3939
|
+
this.handlePollClosed = (event) => {
|
|
3940
|
+
if (event.poll?.id && event.poll.id !== this.id)
|
|
3941
|
+
return;
|
|
3942
|
+
if (!isPollClosedEventEvent(event))
|
|
3943
|
+
return;
|
|
3944
|
+
this.state.partialNext({
|
|
3945
|
+
is_closed: true,
|
|
3946
|
+
last_activity_at: new Date(event.created_at),
|
|
3947
|
+
});
|
|
3948
|
+
};
|
|
3949
|
+
this.handleVoteCasted = (event) => {
|
|
3950
|
+
if (event.poll?.id && event.poll.id !== this.id)
|
|
3951
|
+
return;
|
|
3952
|
+
if (!isPollVoteCastedEvent(event))
|
|
3953
|
+
return;
|
|
3954
|
+
const currentState = this.data;
|
|
3955
|
+
const isOwnVote = event.poll_vote.user_id ===
|
|
3956
|
+
this.client.state.getLatestValue().connected_user?.id;
|
|
3957
|
+
let latestAnswers = [...currentState.latest_answers];
|
|
3958
|
+
let ownAnswer = currentState.own_answer;
|
|
3959
|
+
const ownVotesByOptionId = currentState.own_votes_by_option_id;
|
|
3960
|
+
let maxVotedOptionIds = currentState.max_voted_option_ids;
|
|
3961
|
+
if (isOwnVote) {
|
|
3962
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3963
|
+
if (isVoteAnswer(event.poll_vote)) {
|
|
3964
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3965
|
+
ownAnswer = event.poll_vote;
|
|
3966
|
+
}
|
|
3967
|
+
else if (event.poll_vote.option_id) {
|
|
3968
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3969
|
+
ownVotesByOptionId[event.poll_vote.option_id] = event.poll_vote;
|
|
3970
|
+
}
|
|
3971
|
+
}
|
|
3972
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3973
|
+
if (isVoteAnswer(event.poll_vote)) {
|
|
3974
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3975
|
+
latestAnswers = [event.poll_vote, ...latestAnswers];
|
|
3976
|
+
}
|
|
3977
|
+
else {
|
|
3978
|
+
maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
|
|
3979
|
+
}
|
|
3980
|
+
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
|
|
3981
|
+
this.state.partialNext({
|
|
3982
|
+
answers_count,
|
|
3983
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
3984
|
+
latest_votes_by_option,
|
|
3985
|
+
vote_count,
|
|
3986
|
+
vote_counts_by_option,
|
|
3987
|
+
latest_answers: latestAnswers,
|
|
3988
|
+
last_activity_at: new Date(event.created_at),
|
|
3989
|
+
own_answer: ownAnswer,
|
|
3990
|
+
own_votes_by_option_id: ownVotesByOptionId,
|
|
3991
|
+
max_voted_option_ids: maxVotedOptionIds,
|
|
3992
|
+
});
|
|
3993
|
+
};
|
|
3994
|
+
this.handleVoteChanged = (event) => {
|
|
3995
|
+
// this event is triggered only when event.poll.enforce_unique_vote === true
|
|
3996
|
+
if (event.poll?.id && event.poll.id !== this.id)
|
|
3997
|
+
return;
|
|
3998
|
+
if (!isPollVoteChangedEvent(event))
|
|
3999
|
+
return;
|
|
4000
|
+
const currentState = this.data;
|
|
4001
|
+
const isOwnVote = event.poll_vote.user_id ===
|
|
4002
|
+
this.client.state.getLatestValue().connected_user?.id;
|
|
4003
|
+
let latestAnswers = [...currentState.latest_answers];
|
|
4004
|
+
let ownAnswer = currentState.own_answer;
|
|
4005
|
+
let ownVotesByOptionId = currentState.own_votes_by_option_id;
|
|
4006
|
+
let maxVotedOptionIds = currentState.max_voted_option_ids;
|
|
4007
|
+
if (isOwnVote) {
|
|
4008
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4009
|
+
if (isVoteAnswer(event.poll_vote)) {
|
|
4010
|
+
latestAnswers = [
|
|
4011
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4012
|
+
event.poll_vote,
|
|
4013
|
+
...latestAnswers.filter((answer) => answer.id !== event.poll_vote.id),
|
|
4014
|
+
];
|
|
4015
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4016
|
+
ownAnswer = event.poll_vote;
|
|
4017
|
+
}
|
|
4018
|
+
else if (event.poll_vote.option_id) {
|
|
4019
|
+
if (event.poll.enforce_unique_vote) {
|
|
4020
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4021
|
+
ownVotesByOptionId = { [event.poll_vote.option_id]: event.poll_vote };
|
|
4022
|
+
}
|
|
4023
|
+
else {
|
|
4024
|
+
ownVotesByOptionId = Object.entries(ownVotesByOptionId).reduce((acc, [optionId, vote]) => {
|
|
4025
|
+
if (optionId !== event.poll_vote.option_id &&
|
|
4026
|
+
vote.id === event.poll_vote.id) {
|
|
4027
|
+
return acc;
|
|
4028
|
+
}
|
|
4029
|
+
acc[optionId] = vote;
|
|
4030
|
+
return acc;
|
|
4031
|
+
}, {});
|
|
4032
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4033
|
+
ownVotesByOptionId[event.poll_vote.option_id] = event.poll_vote;
|
|
4034
|
+
}
|
|
4035
|
+
if (ownAnswer?.id === event.poll_vote.id) {
|
|
4036
|
+
ownAnswer = undefined;
|
|
4037
|
+
}
|
|
4038
|
+
maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
|
|
4039
|
+
}
|
|
4040
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4041
|
+
}
|
|
4042
|
+
else if (isVoteAnswer(event.poll_vote)) {
|
|
4043
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4044
|
+
latestAnswers = [event.poll_vote, ...latestAnswers];
|
|
4045
|
+
}
|
|
4046
|
+
else {
|
|
4047
|
+
maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
|
|
4048
|
+
}
|
|
4049
|
+
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
|
|
4050
|
+
this.state.partialNext({
|
|
4051
|
+
answers_count,
|
|
4052
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4053
|
+
latest_votes_by_option,
|
|
4054
|
+
vote_count,
|
|
4055
|
+
vote_counts_by_option,
|
|
4056
|
+
latest_answers: latestAnswers,
|
|
4057
|
+
last_activity_at: new Date(event.created_at),
|
|
4058
|
+
own_answer: ownAnswer,
|
|
4059
|
+
own_votes_by_option_id: ownVotesByOptionId,
|
|
4060
|
+
max_voted_option_ids: maxVotedOptionIds,
|
|
4061
|
+
});
|
|
4062
|
+
};
|
|
4063
|
+
this.handleVoteRemoved = (event) => {
|
|
4064
|
+
if (event.poll?.id && event.poll.id !== this.id)
|
|
4065
|
+
return;
|
|
4066
|
+
if (!isPollVoteRemovedEvent(event))
|
|
4067
|
+
return;
|
|
4068
|
+
const currentState = this.data;
|
|
4069
|
+
const isOwnVote = event.poll_vote.user_id ===
|
|
4070
|
+
this.client.state.getLatestValue().connected_user?.id;
|
|
4071
|
+
let latestAnswers = [...currentState.latest_answers];
|
|
4072
|
+
let ownAnswer = currentState.own_answer;
|
|
4073
|
+
const ownVotesByOptionId = { ...currentState.own_votes_by_option_id };
|
|
4074
|
+
let maxVotedOptionIds = currentState.max_voted_option_ids;
|
|
4075
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4076
|
+
if (isVoteAnswer(event.poll_vote)) {
|
|
4077
|
+
latestAnswers = latestAnswers.filter((answer) => answer.id !== event.poll_vote.id);
|
|
4078
|
+
if (isOwnVote) {
|
|
4079
|
+
ownAnswer = undefined;
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
else {
|
|
4083
|
+
maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
|
|
4084
|
+
if (isOwnVote && event.poll_vote.option_id) {
|
|
4085
|
+
delete ownVotesByOptionId[event.poll_vote.option_id];
|
|
4086
|
+
}
|
|
4087
|
+
}
|
|
4088
|
+
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
|
|
4089
|
+
this.state.partialNext({
|
|
4090
|
+
answers_count,
|
|
4091
|
+
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
4092
|
+
latest_votes_by_option,
|
|
4093
|
+
vote_count,
|
|
4094
|
+
vote_counts_by_option,
|
|
4095
|
+
latest_answers: latestAnswers,
|
|
4096
|
+
last_activity_at: new Date(event.created_at),
|
|
4097
|
+
own_answer: ownAnswer,
|
|
4098
|
+
own_votes_by_option_id: ownVotesByOptionId,
|
|
4099
|
+
max_voted_option_ids: maxVotedOptionIds,
|
|
4100
|
+
});
|
|
4101
|
+
};
|
|
4102
|
+
this.client = client;
|
|
4103
|
+
this.id = poll.id;
|
|
4104
|
+
this.state = new StateStore(this.getInitialStateFromPollResponse(poll));
|
|
3983
4105
|
}
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
// Update own_bookmarks if the bookmark is from the current user
|
|
3987
|
-
const ownBookmarks = [...(activity.own_bookmarks || [])];
|
|
3988
|
-
if (isCurrentUser) {
|
|
3989
|
-
ownBookmarks.push(event.bookmark);
|
|
4106
|
+
get data() {
|
|
4107
|
+
return this.state.getLatestValue();
|
|
3990
4108
|
}
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
}
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
return {
|
|
4003
|
-
...activity,
|
|
4004
|
-
own_bookmarks: ownBookmarks,
|
|
4005
|
-
changed: true,
|
|
4006
|
-
};
|
|
4007
|
-
};
|
|
4008
|
-
const updateBookmarkInActivity = (event, activity, isCurrentUser) => {
|
|
4009
|
-
// Update own_bookmarks if the bookmark is from the current user
|
|
4010
|
-
let ownBookmarks = activity.own_bookmarks || [];
|
|
4011
|
-
if (isCurrentUser) {
|
|
4012
|
-
const bookmarkIndex = ownBookmarks.findIndex((bookmark) => isSameBookmark(bookmark, event.bookmark));
|
|
4013
|
-
if (bookmarkIndex !== -1) {
|
|
4014
|
-
ownBookmarks = [...ownBookmarks];
|
|
4015
|
-
ownBookmarks[bookmarkIndex] = event.bookmark;
|
|
4109
|
+
}
|
|
4110
|
+
function getMaxVotedOptionIds(voteCountsByOption) {
|
|
4111
|
+
let maxVotes = 0;
|
|
4112
|
+
let winningOptions = [];
|
|
4113
|
+
for (const [id, count] of Object.entries(voteCountsByOption ?? {})) {
|
|
4114
|
+
if (count > maxVotes) {
|
|
4115
|
+
winningOptions = [id];
|
|
4116
|
+
maxVotes = count;
|
|
4117
|
+
}
|
|
4118
|
+
else if (count === maxVotes) {
|
|
4119
|
+
winningOptions.push(id);
|
|
4016
4120
|
}
|
|
4017
4121
|
}
|
|
4018
|
-
return
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4122
|
+
return winningOptions;
|
|
4123
|
+
}
|
|
4124
|
+
function getOwnVotesByOptionId(ownVotes) {
|
|
4125
|
+
return !ownVotes
|
|
4126
|
+
? {}
|
|
4127
|
+
: ownVotes.reduce((acc, vote) => {
|
|
4128
|
+
if (isVoteAnswer(vote) || !vote.option_id)
|
|
4129
|
+
return acc;
|
|
4130
|
+
acc[vote.option_id] = vote;
|
|
4131
|
+
return acc;
|
|
4132
|
+
}, {});
|
|
4133
|
+
}
|
|
4134
|
+
|
|
4135
|
+
class FeedApi {
|
|
4136
|
+
constructor(feedsApi, group, id) {
|
|
4137
|
+
this.feedsApi = feedsApi;
|
|
4138
|
+
this.group = group;
|
|
4139
|
+
this.id = id;
|
|
4027
4140
|
}
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4141
|
+
delete(request) {
|
|
4142
|
+
return this.feedsApi.deleteFeed({
|
|
4143
|
+
feed_id: this.id,
|
|
4144
|
+
feed_group_id: this.group,
|
|
4145
|
+
...request,
|
|
4146
|
+
});
|
|
4031
4147
|
}
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
return { changed: false, activities: [] };
|
|
4148
|
+
getOrCreate(request) {
|
|
4149
|
+
return this.feedsApi.getOrCreateFeed({
|
|
4150
|
+
feed_id: this.id,
|
|
4151
|
+
feed_group_id: this.group,
|
|
4152
|
+
...request,
|
|
4153
|
+
});
|
|
4039
4154
|
}
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4155
|
+
update(request) {
|
|
4156
|
+
return this.feedsApi.updateFeed({
|
|
4157
|
+
feed_id: this.id,
|
|
4158
|
+
feed_group_id: this.group,
|
|
4159
|
+
...request,
|
|
4160
|
+
});
|
|
4043
4161
|
}
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
return { changed: false, activities: [] };
|
|
4162
|
+
markActivity(request) {
|
|
4163
|
+
return this.feedsApi.markActivity({
|
|
4164
|
+
feed_id: this.id,
|
|
4165
|
+
feed_group_id: this.group,
|
|
4166
|
+
...request,
|
|
4167
|
+
});
|
|
4051
4168
|
}
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4169
|
+
unpinActivity(request) {
|
|
4170
|
+
return this.feedsApi.unpinActivity({
|
|
4171
|
+
feed_id: this.id,
|
|
4172
|
+
feed_group_id: this.group,
|
|
4173
|
+
...request,
|
|
4174
|
+
});
|
|
4055
4175
|
}
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
return 'created_by' in follow;
|
|
4063
|
-
};
|
|
4064
|
-
const handleFollowCreated = (follow, currentState, currentFeedId, connectedUserId) => {
|
|
4065
|
-
// filter non-accepted follows (the way getOrCreate does by default)
|
|
4066
|
-
if (follow.status !== 'accepted') {
|
|
4067
|
-
return { changed: false, data: currentState };
|
|
4176
|
+
pinActivity(request) {
|
|
4177
|
+
return this.feedsApi.pinActivity({
|
|
4178
|
+
feed_id: this.id,
|
|
4179
|
+
feed_group_id: this.group,
|
|
4180
|
+
...request,
|
|
4181
|
+
});
|
|
4068
4182
|
}
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
...
|
|
4074
|
-
|
|
4075
|
-
...follow.source_feed,
|
|
4076
|
-
};
|
|
4077
|
-
// Only update if following array already exists
|
|
4078
|
-
if (currentState.following !== undefined) {
|
|
4079
|
-
newState.following = [follow, ...currentState.following];
|
|
4080
|
-
}
|
|
4183
|
+
updateFeedMembers(request) {
|
|
4184
|
+
return this.feedsApi.updateFeedMembers({
|
|
4185
|
+
feed_id: this.id,
|
|
4186
|
+
feed_group_id: this.group,
|
|
4187
|
+
...request,
|
|
4188
|
+
});
|
|
4081
4189
|
}
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
// Update FeedResponse fields, that has the new follower/following count
|
|
4089
|
-
...follow.target_feed,
|
|
4090
|
-
};
|
|
4091
|
-
if (source.created_by.id === connectedUserId) {
|
|
4092
|
-
newState.own_follows = currentState.own_follows
|
|
4093
|
-
? currentState.own_follows.concat(follow)
|
|
4094
|
-
: [follow];
|
|
4095
|
-
}
|
|
4096
|
-
// Only update if followers array already exists
|
|
4097
|
-
if (currentState.followers !== undefined) {
|
|
4098
|
-
newState.followers = [follow, ...currentState.followers];
|
|
4099
|
-
}
|
|
4190
|
+
acceptFeedMemberInvite(request) {
|
|
4191
|
+
return this.feedsApi.acceptFeedMemberInvite({
|
|
4192
|
+
feed_id: this.id,
|
|
4193
|
+
feed_group_id: this.group,
|
|
4194
|
+
...request,
|
|
4195
|
+
});
|
|
4100
4196
|
}
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
newState = {
|
|
4108
|
-
...newState,
|
|
4109
|
-
// Update FeedResponse fields, that has the new follower/following count
|
|
4110
|
-
...follow.source_feed,
|
|
4111
|
-
};
|
|
4112
|
-
// Only update if following array already exists
|
|
4113
|
-
if (currentState.following !== undefined) {
|
|
4114
|
-
newState.following = currentState.following.filter((followItem) => followItem.target_feed.fid !== follow.target_feed.fid);
|
|
4115
|
-
}
|
|
4197
|
+
queryFeedMembers(request) {
|
|
4198
|
+
return this.feedsApi.queryFeedMembers({
|
|
4199
|
+
feed_id: this.id,
|
|
4200
|
+
feed_group_id: this.group,
|
|
4201
|
+
...request,
|
|
4202
|
+
});
|
|
4116
4203
|
}
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
// Update FeedResponse fields, that has the new follower/following count
|
|
4124
|
-
...follow.target_feed,
|
|
4125
|
-
};
|
|
4126
|
-
if (isFeedResponse(source) &&
|
|
4127
|
-
source.created_by.id === connectedUserId &&
|
|
4128
|
-
currentState.own_follows !== undefined) {
|
|
4129
|
-
newState.own_follows = currentState.own_follows.filter((followItem) => followItem.source_feed.fid !== follow.source_feed.fid);
|
|
4130
|
-
}
|
|
4131
|
-
// Only update if followers array already exists
|
|
4132
|
-
if (currentState.followers !== undefined) {
|
|
4133
|
-
newState.followers = currentState.followers.filter((followItem) => followItem.source_feed.fid !== follow.source_feed.fid);
|
|
4134
|
-
}
|
|
4204
|
+
rejectFeedMemberInvite(request) {
|
|
4205
|
+
return this.feedsApi.rejectFeedMemberInvite({
|
|
4206
|
+
feed_id: this.id,
|
|
4207
|
+
feed_group_id: this.group,
|
|
4208
|
+
...request,
|
|
4209
|
+
});
|
|
4135
4210
|
}
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
}
|
|
4211
|
+
stopWatching(request) {
|
|
4212
|
+
return this.feedsApi.stopWatchingFeed({
|
|
4213
|
+
feed_id: this.id,
|
|
4214
|
+
feed_group_id: this.group,
|
|
4215
|
+
...request,
|
|
4216
|
+
});
|
|
4217
|
+
}
|
|
4218
|
+
}
|
|
4143
4219
|
|
|
4144
|
-
const isImageFile = (file) => {
|
|
4145
|
-
// photoshop files begin with 'image/'
|
|
4146
|
-
return file.type.startsWith('image/') && !file.type.endsWith('.photoshop');
|
|
4147
|
-
};
|
|
4148
|
-
const isVideoFile = (file) => {
|
|
4149
|
-
return file.type.startsWith('video/');
|
|
4150
|
-
};
|
|
4151
4220
|
const checkHasAnotherPage = (v, cursor) => (typeof v === 'undefined' && typeof cursor === 'undefined') ||
|
|
4152
4221
|
typeof cursor === 'string';
|
|
4153
|
-
|
|
4154
|
-
return typeof entity?.object_id === 'string';
|
|
4155
|
-
};
|
|
4156
|
-
const Constants = {
|
|
4157
|
-
DEFAULT_COMMENT_PAGINATION: 'first',
|
|
4158
|
-
};
|
|
4222
|
+
|
|
4159
4223
|
const uniqueArrayMerge = (existingArray, arrayToMerge, getKey) => {
|
|
4160
4224
|
const existing = new Set();
|
|
4161
4225
|
existingArray.forEach((value) => {
|
|
@@ -4169,1214 +4233,1214 @@ const uniqueArrayMerge = (existingArray, arrayToMerge, getKey) => {
|
|
|
4169
4233
|
return existingArray.concat(filteredArrayToMerge);
|
|
4170
4234
|
};
|
|
4171
4235
|
|
|
4172
|
-
const
|
|
4173
|
-
|
|
4174
|
-
return true;
|
|
4175
|
-
}
|
|
4176
|
-
if (watch && stateUpdateQueue.has(stateUpdateId)) {
|
|
4177
|
-
stateUpdateQueue.delete(stateUpdateId);
|
|
4178
|
-
return false;
|
|
4179
|
-
}
|
|
4180
|
-
stateUpdateQueue.add(stateUpdateId);
|
|
4181
|
-
return true;
|
|
4236
|
+
const Constants = {
|
|
4237
|
+
DEFAULT_COMMENT_PAGINATION: 'first',
|
|
4182
4238
|
};
|
|
4183
|
-
|
|
4184
|
-
|
|
4239
|
+
|
|
4240
|
+
const isFollowResponse = (data) => {
|
|
4241
|
+
return 'source_feed' in data && 'target_feed' in data;
|
|
4185
4242
|
};
|
|
4186
|
-
const
|
|
4187
|
-
return
|
|
4243
|
+
const isCommentResponse = (entity) => {
|
|
4244
|
+
return typeof entity?.object_id === 'string';
|
|
4188
4245
|
};
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
this.state.partialNext({ activities: result.activities });
|
|
4201
|
-
}
|
|
4202
|
-
},
|
|
4203
|
-
'feeds.activity.deleted': (event) => {
|
|
4204
|
-
const currentActivities = this.currentState.activities;
|
|
4205
|
-
if (currentActivities) {
|
|
4206
|
-
const result = removeActivityFromState(event.activity, currentActivities);
|
|
4207
|
-
if (result.changed) {
|
|
4208
|
-
this.state.partialNext({ activities: result.activities });
|
|
4209
|
-
}
|
|
4210
|
-
}
|
|
4211
|
-
},
|
|
4212
|
-
'feeds.activity.reaction.added': (event) => {
|
|
4213
|
-
const currentActivities = this.currentState.activities;
|
|
4214
|
-
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4215
|
-
const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
|
|
4216
|
-
const result = addReactionToActivities(event, currentActivities, isCurrentUser);
|
|
4217
|
-
if (result.changed) {
|
|
4218
|
-
this.state.partialNext({ activities: result.activities });
|
|
4219
|
-
}
|
|
4220
|
-
},
|
|
4221
|
-
'feeds.activity.reaction.deleted': (event) => {
|
|
4222
|
-
const currentActivities = this.currentState.activities;
|
|
4223
|
-
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4224
|
-
const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
|
|
4225
|
-
const result = removeReactionFromActivities(event, currentActivities, isCurrentUser);
|
|
4226
|
-
if (result.changed) {
|
|
4227
|
-
this.state.partialNext({ activities: result.activities });
|
|
4228
|
-
}
|
|
4229
|
-
},
|
|
4230
|
-
'feeds.activity.reaction.updated': Feed.noop,
|
|
4231
|
-
'feeds.activity.removed_from_feed': (event) => {
|
|
4232
|
-
const currentActivities = this.currentState.activities;
|
|
4233
|
-
if (currentActivities) {
|
|
4234
|
-
const result = removeActivityFromState(event.activity, currentActivities);
|
|
4235
|
-
if (result.changed) {
|
|
4236
|
-
this.state.partialNext({ activities: result.activities });
|
|
4237
|
-
}
|
|
4238
|
-
}
|
|
4239
|
-
},
|
|
4240
|
-
'feeds.activity.updated': (event) => {
|
|
4241
|
-
const currentActivities = this.currentState.activities;
|
|
4242
|
-
if (currentActivities) {
|
|
4243
|
-
const result = updateActivityInState(event.activity, currentActivities);
|
|
4244
|
-
if (result.changed) {
|
|
4245
|
-
this.client.hydratePollCache([event.activity]);
|
|
4246
|
-
this.state.partialNext({ activities: result.activities });
|
|
4247
|
-
}
|
|
4248
|
-
}
|
|
4249
|
-
},
|
|
4250
|
-
'feeds.bookmark.added': this.handleBookmarkAdded.bind(this),
|
|
4251
|
-
'feeds.bookmark.deleted': this.handleBookmarkDeleted.bind(this),
|
|
4252
|
-
'feeds.bookmark.updated': this.handleBookmarkUpdated.bind(this),
|
|
4253
|
-
'feeds.bookmark_folder.deleted': Feed.noop,
|
|
4254
|
-
'feeds.bookmark_folder.updated': Feed.noop,
|
|
4255
|
-
'feeds.comment.added': (event) => {
|
|
4256
|
-
const { comment } = event;
|
|
4257
|
-
const forId = comment.parent_id ?? comment.object_id;
|
|
4258
|
-
this.state.next((currentState) => {
|
|
4259
|
-
const entityState = currentState.comments_by_entity_id[forId];
|
|
4260
|
-
const newComments = entityState?.comments?.concat([]) ?? [];
|
|
4261
|
-
if (entityState?.pagination?.sort === 'last' &&
|
|
4262
|
-
!checkHasAnotherPage(entityState.comments, entityState?.pagination.next)) {
|
|
4263
|
-
newComments.unshift(comment);
|
|
4264
|
-
}
|
|
4265
|
-
else if (entityState?.pagination?.sort === 'first') {
|
|
4266
|
-
newComments.push(comment);
|
|
4267
|
-
}
|
|
4268
|
-
else {
|
|
4269
|
-
// no other sorting option is supported yet
|
|
4270
|
-
return currentState;
|
|
4271
|
-
}
|
|
4272
|
-
return {
|
|
4273
|
-
...currentState,
|
|
4274
|
-
comments_by_entity_id: {
|
|
4275
|
-
...currentState.comments_by_entity_id,
|
|
4276
|
-
[forId]: {
|
|
4277
|
-
...currentState.comments_by_entity_id[forId],
|
|
4278
|
-
comments: newComments,
|
|
4279
|
-
},
|
|
4280
|
-
},
|
|
4281
|
-
};
|
|
4282
|
-
});
|
|
4283
|
-
},
|
|
4284
|
-
'feeds.comment.deleted': ({ comment }) => {
|
|
4285
|
-
const forId = comment.parent_id ?? comment.object_id;
|
|
4286
|
-
this.state.next((currentState) => {
|
|
4287
|
-
const newCommentsByEntityId = {
|
|
4288
|
-
...currentState.comments_by_entity_id,
|
|
4289
|
-
[forId]: {
|
|
4290
|
-
...currentState.comments_by_entity_id[forId],
|
|
4291
|
-
},
|
|
4292
|
-
};
|
|
4293
|
-
const index = this.getCommentIndex(comment, currentState);
|
|
4294
|
-
if (newCommentsByEntityId?.[forId]?.comments?.length && index !== -1) {
|
|
4295
|
-
newCommentsByEntityId[forId].comments = [
|
|
4296
|
-
...newCommentsByEntityId[forId].comments,
|
|
4297
|
-
];
|
|
4298
|
-
newCommentsByEntityId[forId]?.comments?.splice(index, 1);
|
|
4299
|
-
}
|
|
4300
|
-
delete newCommentsByEntityId[comment.id];
|
|
4301
|
-
return {
|
|
4302
|
-
...currentState,
|
|
4303
|
-
comments_by_entity_id: newCommentsByEntityId,
|
|
4304
|
-
};
|
|
4305
|
-
});
|
|
4306
|
-
},
|
|
4307
|
-
'feeds.comment.updated': (event) => {
|
|
4308
|
-
const { comment } = event;
|
|
4309
|
-
const forId = comment.parent_id ?? comment.object_id;
|
|
4310
|
-
this.state.next((currentState) => {
|
|
4311
|
-
const entityState = currentState.comments_by_entity_id[forId];
|
|
4312
|
-
if (!entityState?.comments?.length)
|
|
4313
|
-
return currentState;
|
|
4314
|
-
const index = this.getCommentIndex(comment, currentState);
|
|
4315
|
-
if (index === -1)
|
|
4316
|
-
return currentState;
|
|
4317
|
-
const newComments = [...entityState.comments];
|
|
4318
|
-
newComments[index] = comment;
|
|
4319
|
-
return {
|
|
4320
|
-
...currentState,
|
|
4321
|
-
comments_by_entity_id: {
|
|
4322
|
-
...currentState.comments_by_entity_id,
|
|
4323
|
-
[forId]: {
|
|
4324
|
-
...currentState.comments_by_entity_id[forId],
|
|
4325
|
-
comments: newComments,
|
|
4326
|
-
},
|
|
4327
|
-
},
|
|
4328
|
-
};
|
|
4329
|
-
});
|
|
4330
|
-
},
|
|
4331
|
-
'feeds.feed.created': Feed.noop,
|
|
4332
|
-
'feeds.feed.deleted': Feed.noop,
|
|
4333
|
-
'feeds.feed.updated': (event) => {
|
|
4334
|
-
this.state.partialNext({ ...event.feed });
|
|
4335
|
-
},
|
|
4336
|
-
'feeds.feed_group.changed': Feed.noop,
|
|
4337
|
-
'feeds.feed_group.deleted': Feed.noop,
|
|
4338
|
-
'feeds.follow.created': (event) => {
|
|
4339
|
-
this.handleFollowCreated(event.follow);
|
|
4340
|
-
},
|
|
4341
|
-
'feeds.follow.deleted': (event) => {
|
|
4342
|
-
this.handleFollowDeleted(event.follow);
|
|
4343
|
-
},
|
|
4344
|
-
'feeds.follow.updated': (_event) => {
|
|
4345
|
-
handleFollowUpdated(this.currentState);
|
|
4346
|
-
},
|
|
4347
|
-
'feeds.comment.reaction.added': this.handleCommentReactionEvent.bind(this),
|
|
4348
|
-
'feeds.comment.reaction.deleted': this.handleCommentReactionEvent.bind(this),
|
|
4349
|
-
'feeds.comment.reaction.updated': Feed.noop,
|
|
4350
|
-
'feeds.feed_member.added': (event) => {
|
|
4351
|
-
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4352
|
-
this.state.next((currentState) => {
|
|
4353
|
-
let newState;
|
|
4354
|
-
if (typeof currentState.members !== 'undefined') {
|
|
4355
|
-
newState ?? (newState = {
|
|
4356
|
-
...currentState,
|
|
4357
|
-
});
|
|
4358
|
-
newState.members = [event.member, ...currentState.members];
|
|
4359
|
-
}
|
|
4360
|
-
if (connectedUser?.id === event.member.user.id) {
|
|
4361
|
-
newState ?? (newState = {
|
|
4362
|
-
...currentState,
|
|
4363
|
-
});
|
|
4364
|
-
newState.own_membership = event.member;
|
|
4365
|
-
}
|
|
4366
|
-
return newState ?? currentState;
|
|
4367
|
-
});
|
|
4368
|
-
},
|
|
4369
|
-
'feeds.feed_member.removed': (event) => {
|
|
4370
|
-
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4371
|
-
this.state.next((currentState) => {
|
|
4372
|
-
const newState = {
|
|
4373
|
-
...currentState,
|
|
4374
|
-
members: currentState.members?.filter((member) => member.user.id !== event.user?.id),
|
|
4375
|
-
};
|
|
4376
|
-
if (connectedUser?.id === event.member_id) {
|
|
4377
|
-
delete newState.own_membership;
|
|
4378
|
-
}
|
|
4379
|
-
return newState;
|
|
4380
|
-
});
|
|
4381
|
-
},
|
|
4382
|
-
'feeds.feed_member.updated': (event) => {
|
|
4383
|
-
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4384
|
-
this.state.next((currentState) => {
|
|
4385
|
-
const memberIndex = currentState.members?.findIndex((member) => member.user.id === event.member.user.id) ?? -1;
|
|
4386
|
-
let newState;
|
|
4387
|
-
if (memberIndex !== -1) {
|
|
4388
|
-
// if there's an index, there's a member to update
|
|
4389
|
-
const newMembers = [...currentState.members];
|
|
4390
|
-
newMembers[memberIndex] = event.member;
|
|
4391
|
-
newState ?? (newState = {
|
|
4392
|
-
...currentState,
|
|
4393
|
-
});
|
|
4394
|
-
newState.members = newMembers;
|
|
4395
|
-
}
|
|
4396
|
-
if (connectedUser?.id === event.member.user.id) {
|
|
4397
|
-
newState ?? (newState = {
|
|
4398
|
-
...currentState,
|
|
4399
|
-
});
|
|
4400
|
-
newState.own_membership = event.member;
|
|
4401
|
-
}
|
|
4402
|
-
return newState ?? currentState;
|
|
4403
|
-
});
|
|
4404
|
-
},
|
|
4405
|
-
'feeds.notification_feed.updated': (event) => {
|
|
4406
|
-
console.info('notification feed updated', event);
|
|
4407
|
-
// TODO: handle notification feed updates
|
|
4408
|
-
},
|
|
4409
|
-
// the poll events should be removed from here
|
|
4410
|
-
'feeds.poll.closed': Feed.noop,
|
|
4411
|
-
'feeds.poll.deleted': Feed.noop,
|
|
4412
|
-
'feeds.poll.updated': Feed.noop,
|
|
4413
|
-
'feeds.poll.vote_casted': Feed.noop,
|
|
4414
|
-
'feeds.poll.vote_changed': Feed.noop,
|
|
4415
|
-
'feeds.poll.vote_removed': Feed.noop,
|
|
4416
|
-
'feeds.activity.pinned': Feed.noop,
|
|
4417
|
-
'feeds.activity.unpinned': Feed.noop,
|
|
4418
|
-
'feeds.activity.marked': Feed.noop,
|
|
4419
|
-
'moderation.custom_action': Feed.noop,
|
|
4420
|
-
'moderation.flagged': Feed.noop,
|
|
4421
|
-
'moderation.mark_reviewed': Feed.noop,
|
|
4422
|
-
'health.check': Feed.noop,
|
|
4423
|
-
'app.updated': Feed.noop,
|
|
4424
|
-
'user.banned': Feed.noop,
|
|
4425
|
-
'user.deactivated': Feed.noop,
|
|
4426
|
-
'user.muted': Feed.noop,
|
|
4427
|
-
'user.reactivated': Feed.noop,
|
|
4428
|
-
'user.updated': Feed.noop,
|
|
4429
|
-
};
|
|
4430
|
-
this.eventDispatcher = new EventDispatcher();
|
|
4431
|
-
this.on = this.eventDispatcher.on;
|
|
4432
|
-
this.off = this.eventDispatcher.off;
|
|
4433
|
-
this.state = new StateStore({
|
|
4434
|
-
fid: `${groupId}:${id}`,
|
|
4435
|
-
group_id: groupId,
|
|
4436
|
-
id,
|
|
4437
|
-
...(data ?? {}),
|
|
4438
|
-
is_loading: false,
|
|
4439
|
-
is_loading_activities: false,
|
|
4440
|
-
comments_by_entity_id: {},
|
|
4441
|
-
watch,
|
|
4442
|
-
});
|
|
4443
|
-
this.client = client;
|
|
4444
|
-
}
|
|
4445
|
-
get fid() {
|
|
4446
|
-
return `${this.group}:${this.id}`;
|
|
4447
|
-
}
|
|
4448
|
-
get currentState() {
|
|
4449
|
-
return this.state.getLatestValue();
|
|
4450
|
-
}
|
|
4451
|
-
handleCommentReactionEvent(event) {
|
|
4452
|
-
const { comment, reaction } = event;
|
|
4453
|
-
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4454
|
-
this.state.next((currentState) => {
|
|
4455
|
-
const forId = comment.parent_id ?? comment.object_id;
|
|
4456
|
-
const entityState = currentState.comments_by_entity_id[forId];
|
|
4457
|
-
const commentIndex = this.getCommentIndex(comment, currentState);
|
|
4458
|
-
if (commentIndex === -1)
|
|
4459
|
-
return currentState;
|
|
4460
|
-
const newComments = entityState?.comments?.concat([]) ?? [];
|
|
4461
|
-
const commentCopy = { ...comment };
|
|
4462
|
-
delete commentCopy.own_reactions;
|
|
4463
|
-
const newComment = {
|
|
4464
|
-
...newComments[commentIndex],
|
|
4465
|
-
...commentCopy,
|
|
4466
|
-
// TODO: FIXME this should be handled by the backend
|
|
4467
|
-
latest_reactions: commentCopy.latest_reactions ?? [],
|
|
4468
|
-
reaction_groups: commentCopy.reaction_groups ?? {},
|
|
4469
|
-
};
|
|
4470
|
-
newComments[commentIndex] = newComment;
|
|
4471
|
-
if (reaction.user.id === connectedUser?.id) {
|
|
4472
|
-
if (event.type === 'feeds.comment.reaction.added') {
|
|
4473
|
-
newComment.own_reactions = newComment.own_reactions.concat(reaction) ?? [reaction];
|
|
4474
|
-
}
|
|
4475
|
-
else if (event.type === 'feeds.comment.reaction.deleted') {
|
|
4476
|
-
newComment.own_reactions = newComment.own_reactions.filter((r) => r.type !== reaction.type);
|
|
4477
|
-
}
|
|
4478
|
-
}
|
|
4479
|
-
return {
|
|
4480
|
-
...currentState,
|
|
4481
|
-
comments_by_entity_id: {
|
|
4482
|
-
...currentState.comments_by_entity_id,
|
|
4483
|
-
[forId]: {
|
|
4484
|
-
...entityState,
|
|
4485
|
-
comments: newComments,
|
|
4486
|
-
},
|
|
4487
|
-
},
|
|
4488
|
-
};
|
|
4489
|
-
});
|
|
4490
|
-
}
|
|
4491
|
-
async synchronize() {
|
|
4492
|
-
const { last_get_or_create_request_config } = this.state.getLatestValue();
|
|
4493
|
-
if (last_get_or_create_request_config?.watch) {
|
|
4494
|
-
await this.getOrCreate(last_get_or_create_request_config);
|
|
4495
|
-
}
|
|
4496
|
-
}
|
|
4497
|
-
async getOrCreate(request) {
|
|
4498
|
-
if (this.currentState.is_loading_activities) {
|
|
4499
|
-
throw new Error('Only one getOrCreate call is allowed at a time');
|
|
4500
|
-
}
|
|
4501
|
-
this.state.partialNext({
|
|
4502
|
-
is_loading: !request?.next,
|
|
4503
|
-
is_loading_activities: true,
|
|
4504
|
-
});
|
|
4505
|
-
// TODO: pull comments/comment_pagination from activities and comment_sort from request
|
|
4506
|
-
// and pre-populate comments_by_entity_id (once comment_sort and comment_limit are supported)
|
|
4507
|
-
try {
|
|
4508
|
-
const response = await super.getOrCreate(request);
|
|
4509
|
-
if (request?.next) {
|
|
4510
|
-
const { activities: currentActivities = [] } = this.currentState;
|
|
4511
|
-
const result = addActivitiesToState(response.activities, currentActivities, 'end');
|
|
4512
|
-
if (result.changed) {
|
|
4513
|
-
this.state.partialNext({
|
|
4514
|
-
activities: result.activities,
|
|
4515
|
-
next: response.next,
|
|
4516
|
-
prev: response.prev,
|
|
4517
|
-
});
|
|
4518
|
-
}
|
|
4519
|
-
}
|
|
4520
|
-
else {
|
|
4521
|
-
// Empty queue when reinitializing the state
|
|
4522
|
-
this.stateUpdateQueue.clear();
|
|
4523
|
-
const responseCopy = {
|
|
4524
|
-
...response,
|
|
4525
|
-
...response.feed,
|
|
4526
|
-
};
|
|
4527
|
-
delete responseCopy.feed;
|
|
4528
|
-
delete responseCopy.metadata;
|
|
4529
|
-
delete responseCopy.duration;
|
|
4530
|
-
this.state.next((currentState) => {
|
|
4531
|
-
const nextState = {
|
|
4532
|
-
...currentState,
|
|
4533
|
-
...responseCopy,
|
|
4534
|
-
};
|
|
4535
|
-
if (!request?.followers_pagination?.limit) {
|
|
4536
|
-
delete nextState.followers;
|
|
4537
|
-
}
|
|
4538
|
-
if (!request?.following_pagination?.limit) {
|
|
4539
|
-
delete nextState.following;
|
|
4540
|
-
}
|
|
4541
|
-
if (response.members.length === 0 && response.feed.member_count > 0) {
|
|
4542
|
-
delete nextState.members;
|
|
4543
|
-
}
|
|
4544
|
-
nextState.last_get_or_create_request_config = request;
|
|
4545
|
-
nextState.watch = request?.watch ? request.watch : currentState.watch;
|
|
4546
|
-
return nextState;
|
|
4547
|
-
});
|
|
4548
|
-
}
|
|
4549
|
-
this.client.hydratePollCache(response.activities);
|
|
4550
|
-
return response;
|
|
4551
|
-
}
|
|
4552
|
-
finally {
|
|
4553
|
-
this.state.partialNext({
|
|
4554
|
-
is_loading: false,
|
|
4555
|
-
is_loading_activities: false,
|
|
4556
|
-
});
|
|
4557
|
-
}
|
|
4558
|
-
}
|
|
4559
|
-
/**
|
|
4560
|
-
* @internal
|
|
4561
|
-
*/
|
|
4562
|
-
handleFollowCreated(follow) {
|
|
4563
|
-
if (!shouldUpdateState({
|
|
4564
|
-
stateUpdateId: getStateUpdateQueueIdForFollow(follow),
|
|
4565
|
-
stateUpdateQueue: this.stateUpdateQueue,
|
|
4566
|
-
watch: this.currentState.watch,
|
|
4567
|
-
})) {
|
|
4568
|
-
return;
|
|
4569
|
-
}
|
|
4570
|
-
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4571
|
-
const result = handleFollowCreated(follow, this.currentState, this.fid, connectedUser?.id);
|
|
4572
|
-
if (result.changed) {
|
|
4573
|
-
this.state.next(result.data);
|
|
4574
|
-
}
|
|
4575
|
-
}
|
|
4576
|
-
/**
|
|
4577
|
-
* @internal
|
|
4578
|
-
*/
|
|
4579
|
-
handleFollowDeleted(follow) {
|
|
4580
|
-
if (!shouldUpdateState({
|
|
4581
|
-
stateUpdateId: getStateUpdateQueueIdForUnfollow(follow),
|
|
4582
|
-
stateUpdateQueue: this.stateUpdateQueue,
|
|
4583
|
-
watch: this.currentState.watch,
|
|
4584
|
-
})) {
|
|
4585
|
-
return;
|
|
4586
|
-
}
|
|
4587
|
-
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4588
|
-
const result = handleFollowDeleted(follow, this.currentState, this.fid, connectedUser?.id);
|
|
4589
|
-
{
|
|
4590
|
-
this.state.next(result.data);
|
|
4591
|
-
}
|
|
4592
|
-
}
|
|
4593
|
-
/**
|
|
4594
|
-
* @internal
|
|
4595
|
-
*/
|
|
4596
|
-
handleWatchStopped() {
|
|
4597
|
-
this.state.partialNext({
|
|
4598
|
-
watch: false,
|
|
4599
|
-
});
|
|
4600
|
-
}
|
|
4601
|
-
/**
|
|
4602
|
-
* @internal
|
|
4603
|
-
*/
|
|
4604
|
-
handleWatchStarted() {
|
|
4605
|
-
this.state.partialNext({
|
|
4606
|
-
watch: true,
|
|
4607
|
-
});
|
|
4246
|
+
const isImageFile = (file) => {
|
|
4247
|
+
// photoshop files begin with 'image/'
|
|
4248
|
+
return file.type.startsWith('image/') && !file.type.endsWith('.photoshop');
|
|
4249
|
+
};
|
|
4250
|
+
const isVideoFile = (file) => {
|
|
4251
|
+
return file.type.startsWith('video/');
|
|
4252
|
+
};
|
|
4253
|
+
|
|
4254
|
+
const shouldUpdateState = ({ stateUpdateQueueId, stateUpdateQueue, watch, }) => {
|
|
4255
|
+
if (!watch) {
|
|
4256
|
+
return true;
|
|
4608
4257
|
}
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
|
|
4613
|
-
const result = addBookmarkToActivities(event, currentActivities, isCurrentUser);
|
|
4614
|
-
if (result.changed) {
|
|
4615
|
-
this.state.partialNext({ activities: result.activities });
|
|
4616
|
-
}
|
|
4258
|
+
if (watch && stateUpdateQueue.has(stateUpdateQueueId)) {
|
|
4259
|
+
stateUpdateQueue.delete(stateUpdateQueueId);
|
|
4260
|
+
return false;
|
|
4617
4261
|
}
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4262
|
+
stateUpdateQueue.add(stateUpdateQueueId);
|
|
4263
|
+
return true;
|
|
4264
|
+
};
|
|
4265
|
+
function getStateUpdateQueueId(data, prefix) {
|
|
4266
|
+
if (isFollowResponse(data)) {
|
|
4267
|
+
const toJoin = [data.source_feed.fid, data.target_feed.fid];
|
|
4268
|
+
if (prefix) {
|
|
4269
|
+
toJoin.unshift(prefix);
|
|
4625
4270
|
}
|
|
4271
|
+
return toJoin.join('-');
|
|
4626
4272
|
}
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4273
|
+
// else if (isMemberResponse(data)) {
|
|
4274
|
+
// }
|
|
4275
|
+
throw new Error(`Cannot create state update queueId for data: ${JSON.stringify(data)}`);
|
|
4276
|
+
}
|
|
4277
|
+
|
|
4278
|
+
const updateStateFollowCreated = (follow, currentState, currentFeedId, connectedUserId) => {
|
|
4279
|
+
// filter non-accepted follows (the way getOrCreate does by default)
|
|
4280
|
+
if (follow.status !== 'accepted') {
|
|
4281
|
+
return { changed: false, data: currentState };
|
|
4635
4282
|
}
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
// fast lookup failed, try slower approach
|
|
4648
|
-
if (commentIndex === -1) {
|
|
4649
|
-
commentIndex = currentComments.findIndex((comment_) => comment_.id === comment.id);
|
|
4283
|
+
let newState = { ...currentState };
|
|
4284
|
+
// this feed followed someone
|
|
4285
|
+
if (follow.source_feed.fid === currentFeedId) {
|
|
4286
|
+
newState = {
|
|
4287
|
+
...newState,
|
|
4288
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4289
|
+
...follow.source_feed,
|
|
4290
|
+
};
|
|
4291
|
+
// Only update if following array already exists
|
|
4292
|
+
if (currentState.following !== undefined) {
|
|
4293
|
+
newState.following = [follow, ...currentState.following];
|
|
4650
4294
|
}
|
|
4651
|
-
return commentIndex;
|
|
4652
|
-
}
|
|
4653
|
-
/**
|
|
4654
|
-
* Load child comments of entity (activity or comment) into the state, if the target entity is comment,
|
|
4655
|
-
* `entityParentId` should be provided (`CommentResponse.parent_id ?? CommentResponse.object_id`).
|
|
4656
|
-
*/
|
|
4657
|
-
loadCommentsIntoState(data) {
|
|
4658
|
-
// add initial (top level) object for processing
|
|
4659
|
-
const traverseArray = [
|
|
4660
|
-
{
|
|
4661
|
-
entityId: data.entityId,
|
|
4662
|
-
entityParentId: data.entityParentId,
|
|
4663
|
-
comments: data.comments,
|
|
4664
|
-
next: data.next,
|
|
4665
|
-
},
|
|
4666
|
-
];
|
|
4667
|
-
this.state.next((currentState) => {
|
|
4668
|
-
const newCommentsByEntityId = {
|
|
4669
|
-
...currentState.comments_by_entity_id,
|
|
4670
|
-
};
|
|
4671
|
-
while (traverseArray.length) {
|
|
4672
|
-
const item = traverseArray.pop();
|
|
4673
|
-
const entityId = item.entityId;
|
|
4674
|
-
// go over entity comments and generate new objects
|
|
4675
|
-
// for further processing if there are any replies
|
|
4676
|
-
item.comments.forEach((comment) => {
|
|
4677
|
-
if (!comment.replies?.length)
|
|
4678
|
-
return;
|
|
4679
|
-
traverseArray.push({
|
|
4680
|
-
entityId: comment.id,
|
|
4681
|
-
entityParentId: entityId,
|
|
4682
|
-
comments: comment.replies,
|
|
4683
|
-
next: comment.meta?.next_cursor,
|
|
4684
|
-
});
|
|
4685
|
-
});
|
|
4686
|
-
// omit replies & meta from the comments (transform ThreadedCommentResponse to CommentResponse)
|
|
4687
|
-
// this is somehow faster than copying the whole
|
|
4688
|
-
// object and deleting the desired properties
|
|
4689
|
-
const newComments = item.comments.map(({ replies: _r, meta: _m, ...restOfTheCommentResponse }) => restOfTheCommentResponse);
|
|
4690
|
-
newCommentsByEntityId[entityId] = {
|
|
4691
|
-
...newCommentsByEntityId[entityId],
|
|
4692
|
-
entity_parent_id: item.entityParentId,
|
|
4693
|
-
pagination: {
|
|
4694
|
-
...newCommentsByEntityId[entityId]?.pagination,
|
|
4695
|
-
next: item.next,
|
|
4696
|
-
sort: data.sort,
|
|
4697
|
-
},
|
|
4698
|
-
comments: newCommentsByEntityId[entityId]?.comments
|
|
4699
|
-
? newCommentsByEntityId[entityId].comments?.concat(newComments)
|
|
4700
|
-
: newComments,
|
|
4701
|
-
};
|
|
4702
|
-
}
|
|
4703
|
-
return {
|
|
4704
|
-
...currentState,
|
|
4705
|
-
comments_by_entity_id: newCommentsByEntityId,
|
|
4706
|
-
};
|
|
4707
|
-
});
|
|
4708
4295
|
}
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
},
|
|
4723
|
-
},
|
|
4724
|
-
}));
|
|
4725
|
-
const { next, comments } = await base();
|
|
4726
|
-
this.loadCommentsIntoState({
|
|
4727
|
-
entityId,
|
|
4728
|
-
comments,
|
|
4729
|
-
entityParentId,
|
|
4730
|
-
next,
|
|
4731
|
-
sort,
|
|
4732
|
-
});
|
|
4733
|
-
}
|
|
4734
|
-
catch (e) {
|
|
4735
|
-
error = e;
|
|
4736
|
-
}
|
|
4737
|
-
finally {
|
|
4738
|
-
this.state.next((currentState) => ({
|
|
4739
|
-
...currentState,
|
|
4740
|
-
comments_by_entity_id: {
|
|
4741
|
-
...currentState.comments_by_entity_id,
|
|
4742
|
-
[entityId]: {
|
|
4743
|
-
...currentState.comments_by_entity_id[entityId],
|
|
4744
|
-
pagination: {
|
|
4745
|
-
...currentState.comments_by_entity_id[entityId]?.pagination,
|
|
4746
|
-
loading_next_page: false,
|
|
4747
|
-
},
|
|
4748
|
-
},
|
|
4749
|
-
},
|
|
4750
|
-
}));
|
|
4296
|
+
else if (
|
|
4297
|
+
// someone followed this feed
|
|
4298
|
+
follow.target_feed.fid === currentFeedId) {
|
|
4299
|
+
const source = follow.source_feed;
|
|
4300
|
+
newState = {
|
|
4301
|
+
...newState,
|
|
4302
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4303
|
+
...follow.target_feed,
|
|
4304
|
+
};
|
|
4305
|
+
if (source.created_by.id === connectedUserId) {
|
|
4306
|
+
newState.own_follows = currentState.own_follows
|
|
4307
|
+
? currentState.own_follows.concat(follow)
|
|
4308
|
+
: [follow];
|
|
4751
4309
|
}
|
|
4752
|
-
if
|
|
4753
|
-
|
|
4310
|
+
// Only update if followers array already exists
|
|
4311
|
+
if (currentState.followers !== undefined) {
|
|
4312
|
+
newState.followers = [follow, ...currentState.followers];
|
|
4754
4313
|
}
|
|
4755
4314
|
}
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
}
|
|
4767
|
-
await this.loadNextPageComments({
|
|
4768
|
-
entityId: activity.id,
|
|
4769
|
-
base: () => this.client.getComments({
|
|
4770
|
-
...request,
|
|
4771
|
-
sort,
|
|
4772
|
-
object_id: activity.id,
|
|
4773
|
-
object_type: 'activity',
|
|
4774
|
-
next: currentNextCursor,
|
|
4775
|
-
}),
|
|
4776
|
-
sort,
|
|
4777
|
-
});
|
|
4315
|
+
return { changed: true, data: newState };
|
|
4316
|
+
};
|
|
4317
|
+
function handleFollowCreated(eventOrResponse) {
|
|
4318
|
+
const follow = eventOrResponse.follow;
|
|
4319
|
+
if (!shouldUpdateState({
|
|
4320
|
+
stateUpdateQueueId: getStateUpdateQueueId(follow, 'created'),
|
|
4321
|
+
stateUpdateQueue: this.stateUpdateQueue,
|
|
4322
|
+
watch: this.currentState.watch,
|
|
4323
|
+
})) {
|
|
4324
|
+
return;
|
|
4778
4325
|
}
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
const currentSort = currentPagination?.sort;
|
|
4784
|
-
const isLoading = currentPagination?.loading_next_page;
|
|
4785
|
-
const sort = currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
4786
|
-
if (isLoading ||
|
|
4787
|
-
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
|
|
4788
|
-
return;
|
|
4789
|
-
}
|
|
4790
|
-
await this.loadNextPageComments({
|
|
4791
|
-
entityId: comment.id,
|
|
4792
|
-
base: () => this.client.getCommentReplies({
|
|
4793
|
-
...request,
|
|
4794
|
-
comment_id: comment.id,
|
|
4795
|
-
// use known sort first (prevents broken pagination)
|
|
4796
|
-
sort: currentSort ??
|
|
4797
|
-
request?.sort ??
|
|
4798
|
-
Constants.DEFAULT_COMMENT_PAGINATION,
|
|
4799
|
-
next: currentNextCursor,
|
|
4800
|
-
}),
|
|
4801
|
-
entityParentId: comment.parent_id ?? comment.object_id,
|
|
4802
|
-
sort,
|
|
4803
|
-
});
|
|
4326
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4327
|
+
const result = updateStateFollowCreated(follow, this.currentState, this.fid, connectedUser?.id);
|
|
4328
|
+
if (result.changed) {
|
|
4329
|
+
this.state.next(result.data);
|
|
4804
4330
|
}
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
}
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
...currentState,
|
|
4820
|
-
[paginationKey]: {
|
|
4821
|
-
...currentState[paginationKey],
|
|
4822
|
-
loading_next_page: true,
|
|
4823
|
-
},
|
|
4824
|
-
};
|
|
4825
|
-
});
|
|
4826
|
-
const { next: newNextCursor, follows } = await this[method]({
|
|
4827
|
-
...request,
|
|
4828
|
-
next: currentNextCursor,
|
|
4829
|
-
sort,
|
|
4830
|
-
});
|
|
4831
|
-
this.state.next((currentState) => {
|
|
4832
|
-
return {
|
|
4833
|
-
...currentState,
|
|
4834
|
-
[type]: currentState[type] === undefined
|
|
4835
|
-
? follows
|
|
4836
|
-
: uniqueArrayMerge(currentState[type], follows, (follow) => `${follow.source_feed.fid}-${follow.target_feed.fid}`),
|
|
4837
|
-
[paginationKey]: {
|
|
4838
|
-
...currentState[paginationKey],
|
|
4839
|
-
next: newNextCursor,
|
|
4840
|
-
sort,
|
|
4841
|
-
},
|
|
4842
|
-
};
|
|
4843
|
-
});
|
|
4844
|
-
}
|
|
4845
|
-
catch (e) {
|
|
4846
|
-
error = e;
|
|
4331
|
+
}
|
|
4332
|
+
|
|
4333
|
+
const updateStateFollowDeleted = (follow, currentState, currentFeedId, connectedUserId) => {
|
|
4334
|
+
let newState = { ...currentState };
|
|
4335
|
+
// this feed unfollowed someone
|
|
4336
|
+
if (follow.source_feed.fid === currentFeedId) {
|
|
4337
|
+
newState = {
|
|
4338
|
+
...newState,
|
|
4339
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4340
|
+
...follow.source_feed,
|
|
4341
|
+
};
|
|
4342
|
+
// Only update if following array already exists
|
|
4343
|
+
if (currentState.following !== undefined) {
|
|
4344
|
+
newState.following = currentState.following.filter((followItem) => followItem.target_feed.fid !== follow.target_feed.fid);
|
|
4847
4345
|
}
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4346
|
+
}
|
|
4347
|
+
else if (
|
|
4348
|
+
// someone unfollowed this feed
|
|
4349
|
+
follow.target_feed.fid === currentFeedId) {
|
|
4350
|
+
const source = follow.source_feed;
|
|
4351
|
+
newState = {
|
|
4352
|
+
...newState,
|
|
4353
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4354
|
+
...follow.target_feed,
|
|
4355
|
+
};
|
|
4356
|
+
if (source.created_by.id === connectedUserId &&
|
|
4357
|
+
currentState.own_follows !== undefined) {
|
|
4358
|
+
newState.own_follows = currentState.own_follows.filter((followItem) => followItem.source_feed.fid !== follow.source_feed.fid);
|
|
4858
4359
|
}
|
|
4859
|
-
if
|
|
4860
|
-
|
|
4360
|
+
// Only update if followers array already exists
|
|
4361
|
+
if (currentState.followers !== undefined) {
|
|
4362
|
+
newState.followers = currentState.followers.filter((followItem) => followItem.source_feed.fid !== follow.source_feed.fid);
|
|
4861
4363
|
}
|
|
4862
4364
|
}
|
|
4863
|
-
|
|
4864
|
-
|
|
4365
|
+
return { changed: true, data: newState };
|
|
4366
|
+
};
|
|
4367
|
+
function handleFollowDeleted(eventOrResponse) {
|
|
4368
|
+
const follow = eventOrResponse.follow;
|
|
4369
|
+
if (!shouldUpdateState({
|
|
4370
|
+
stateUpdateQueueId: getStateUpdateQueueId(follow, 'deleted'),
|
|
4371
|
+
stateUpdateQueue: this.stateUpdateQueue,
|
|
4372
|
+
watch: this.currentState.watch,
|
|
4373
|
+
})) {
|
|
4374
|
+
return;
|
|
4865
4375
|
}
|
|
4866
|
-
|
|
4867
|
-
|
|
4376
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4377
|
+
const result = updateStateFollowDeleted(follow, this.currentState, this.fid, connectedUser?.id);
|
|
4378
|
+
{
|
|
4379
|
+
this.state.next(result.data);
|
|
4868
4380
|
}
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4383
|
+
function handleFollowUpdated(eventOrResponse) {
|
|
4384
|
+
const follow = eventOrResponse.follow;
|
|
4385
|
+
const connectedUserId = this.client.state.getLatestValue().connected_user?.id;
|
|
4386
|
+
const currentFeedId = this.fid;
|
|
4387
|
+
if (!shouldUpdateState({
|
|
4388
|
+
stateUpdateQueueId: getStateUpdateQueueId(follow, 'updated'),
|
|
4389
|
+
stateUpdateQueue: this.stateUpdateQueue,
|
|
4390
|
+
watch: this.currentState.watch,
|
|
4391
|
+
})) {
|
|
4392
|
+
return;
|
|
4393
|
+
}
|
|
4394
|
+
this.state.next((currentState) => {
|
|
4395
|
+
let newState;
|
|
4396
|
+
// this feed followed someone
|
|
4397
|
+
if (follow.source_feed.fid === currentFeedId) {
|
|
4398
|
+
newState ?? (newState = {
|
|
4399
|
+
...currentState,
|
|
4400
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4401
|
+
...follow.source_feed,
|
|
4402
|
+
});
|
|
4403
|
+
const index = currentState.following?.findIndex((f) => f.target_feed.fid === follow.target_feed.fid) ?? -1;
|
|
4404
|
+
if (index >= 0) {
|
|
4405
|
+
newState.following = [...newState.following];
|
|
4406
|
+
newState.following[index] = follow;
|
|
4407
|
+
}
|
|
4877
4408
|
}
|
|
4878
|
-
|
|
4879
|
-
|
|
4409
|
+
else if (
|
|
4410
|
+
// someone followed this feed
|
|
4411
|
+
follow.target_feed.fid === currentFeedId) {
|
|
4412
|
+
const source = follow.source_feed;
|
|
4413
|
+
newState ?? (newState = {
|
|
4880
4414
|
...currentState,
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4415
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4416
|
+
...follow.target_feed,
|
|
4417
|
+
});
|
|
4418
|
+
if (source.created_by.id === connectedUserId &&
|
|
4419
|
+
currentState.own_follows) {
|
|
4420
|
+
const index = currentState.own_follows.findIndex((f) => f.source_feed.fid === follow.source_feed.fid);
|
|
4421
|
+
if (index >= 0) {
|
|
4422
|
+
newState.own_follows = [...currentState.own_follows];
|
|
4423
|
+
newState.own_follows[index] = follow;
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
const index = currentState.followers?.findIndex((f) => f.source_feed.fid === follow.source_feed.fid) ?? -1;
|
|
4427
|
+
if (index >= 0) {
|
|
4428
|
+
newState.followers = [...newState.followers];
|
|
4429
|
+
newState.followers[index] = follow;
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
return newState ?? currentState;
|
|
4433
|
+
});
|
|
4434
|
+
}
|
|
4435
|
+
|
|
4436
|
+
function handleCommentAdded(event) {
|
|
4437
|
+
const { comment } = event;
|
|
4438
|
+
const entityId = comment.parent_id ?? comment.object_id;
|
|
4439
|
+
this.state.next((currentState) => {
|
|
4440
|
+
const entityState = currentState.comments_by_entity_id[entityId];
|
|
4441
|
+
if (typeof entityState?.comments === 'undefined') {
|
|
4442
|
+
return currentState;
|
|
4443
|
+
}
|
|
4444
|
+
const newComments = entityState?.comments ? [...entityState.comments] : [];
|
|
4445
|
+
if (entityState.pagination?.sort === 'last') {
|
|
4446
|
+
newComments.unshift(comment);
|
|
4447
|
+
}
|
|
4448
|
+
else {
|
|
4449
|
+
// 'first' and other sort options
|
|
4450
|
+
newComments.push(comment);
|
|
4451
|
+
}
|
|
4452
|
+
return {
|
|
4453
|
+
...currentState,
|
|
4454
|
+
comments_by_entity_id: {
|
|
4455
|
+
...currentState.comments_by_entity_id,
|
|
4456
|
+
[entityId]: {
|
|
4457
|
+
...currentState.comments_by_entity_id[entityId],
|
|
4458
|
+
comments: newComments,
|
|
4884
4459
|
},
|
|
4885
|
-
}
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4460
|
+
},
|
|
4461
|
+
};
|
|
4462
|
+
});
|
|
4463
|
+
}
|
|
4464
|
+
|
|
4465
|
+
function handleCommentDeleted({ comment }) {
|
|
4466
|
+
const entityId = comment.parent_id ?? comment.object_id;
|
|
4467
|
+
this.state.next((currentState) => {
|
|
4468
|
+
const newCommentsByEntityId = {
|
|
4469
|
+
...currentState.comments_by_entity_id,
|
|
4470
|
+
[entityId]: {
|
|
4471
|
+
...currentState.comments_by_entity_id[entityId],
|
|
4472
|
+
},
|
|
4473
|
+
};
|
|
4474
|
+
const index = this.getCommentIndex(comment, currentState);
|
|
4475
|
+
if (newCommentsByEntityId?.[entityId]?.comments?.length && index !== -1) {
|
|
4476
|
+
newCommentsByEntityId[entityId].comments = [
|
|
4477
|
+
...newCommentsByEntityId[entityId].comments,
|
|
4478
|
+
];
|
|
4479
|
+
newCommentsByEntityId[entityId]?.comments?.splice(index, 1);
|
|
4480
|
+
}
|
|
4481
|
+
delete newCommentsByEntityId[comment.id];
|
|
4482
|
+
return {
|
|
4483
|
+
...currentState,
|
|
4484
|
+
comments_by_entity_id: newCommentsByEntityId,
|
|
4485
|
+
};
|
|
4486
|
+
});
|
|
4487
|
+
}
|
|
4488
|
+
|
|
4489
|
+
function handleCommentUpdated(event) {
|
|
4490
|
+
const { comment } = event;
|
|
4491
|
+
const entityId = comment.parent_id ?? comment.object_id;
|
|
4492
|
+
this.state.next((currentState) => {
|
|
4493
|
+
const entityState = currentState.comments_by_entity_id[entityId];
|
|
4494
|
+
if (!entityState?.comments?.length)
|
|
4495
|
+
return currentState;
|
|
4496
|
+
const index = this.getCommentIndex(comment, currentState);
|
|
4497
|
+
if (index === -1)
|
|
4498
|
+
return currentState;
|
|
4499
|
+
const newComments = [...entityState.comments];
|
|
4500
|
+
newComments[index] = comment;
|
|
4501
|
+
return {
|
|
4502
|
+
...currentState,
|
|
4503
|
+
comments_by_entity_id: {
|
|
4504
|
+
...currentState.comments_by_entity_id,
|
|
4505
|
+
[entityId]: {
|
|
4506
|
+
...currentState.comments_by_entity_id[entityId],
|
|
4507
|
+
comments: newComments,
|
|
4508
|
+
},
|
|
4509
|
+
},
|
|
4510
|
+
};
|
|
4511
|
+
});
|
|
4512
|
+
}
|
|
4513
|
+
|
|
4514
|
+
function handleCommentReaction(event) {
|
|
4515
|
+
const { comment, reaction } = event;
|
|
4516
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4517
|
+
this.state.next((currentState) => {
|
|
4518
|
+
const forId = comment.parent_id ?? comment.object_id;
|
|
4519
|
+
const entityState = currentState.comments_by_entity_id[forId];
|
|
4520
|
+
const commentIndex = this.getCommentIndex(comment, currentState);
|
|
4521
|
+
if (commentIndex === -1)
|
|
4522
|
+
return currentState;
|
|
4523
|
+
const newComments = entityState?.comments?.concat([]) ?? [];
|
|
4524
|
+
const commentCopy = { ...comment };
|
|
4525
|
+
delete commentCopy.own_reactions;
|
|
4526
|
+
const newComment = {
|
|
4527
|
+
...newComments[commentIndex],
|
|
4528
|
+
...commentCopy,
|
|
4529
|
+
// TODO: FIXME this should be handled by the backend
|
|
4530
|
+
latest_reactions: commentCopy.latest_reactions ?? [],
|
|
4531
|
+
reaction_groups: commentCopy.reaction_groups ?? {},
|
|
4532
|
+
};
|
|
4533
|
+
newComments[commentIndex] = newComment;
|
|
4534
|
+
if (reaction.user.id === connectedUser?.id) {
|
|
4535
|
+
if (event.type === 'feeds.comment.reaction.added') {
|
|
4536
|
+
newComment.own_reactions = newComment.own_reactions.concat(reaction) ?? [reaction];
|
|
4537
|
+
}
|
|
4538
|
+
else if (event.type === 'feeds.comment.reaction.deleted') {
|
|
4539
|
+
newComment.own_reactions = newComment.own_reactions.filter((r) => r.type !== reaction.type);
|
|
4540
|
+
}
|
|
4541
|
+
}
|
|
4542
|
+
return {
|
|
4543
|
+
...currentState,
|
|
4544
|
+
comments_by_entity_id: {
|
|
4545
|
+
...currentState.comments_by_entity_id,
|
|
4546
|
+
[forId]: {
|
|
4547
|
+
...entityState,
|
|
4548
|
+
comments: newComments,
|
|
4549
|
+
},
|
|
4550
|
+
},
|
|
4551
|
+
};
|
|
4552
|
+
});
|
|
4553
|
+
}
|
|
4554
|
+
|
|
4555
|
+
function handleFeedMemberAdded(event) {
|
|
4556
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4557
|
+
this.state.next((currentState) => {
|
|
4558
|
+
let newState;
|
|
4559
|
+
if (typeof currentState.members !== 'undefined') {
|
|
4560
|
+
newState ?? (newState = {
|
|
4561
|
+
...currentState,
|
|
4892
4562
|
});
|
|
4893
|
-
|
|
4563
|
+
newState.members = [event.member, ...currentState.members];
|
|
4564
|
+
}
|
|
4565
|
+
if (connectedUser?.id === event.member.user.id) {
|
|
4566
|
+
newState ?? (newState = {
|
|
4894
4567
|
...currentState,
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
: members,
|
|
4898
|
-
member_pagination: {
|
|
4899
|
-
...currentState.member_pagination,
|
|
4900
|
-
next: newNextCursor,
|
|
4901
|
-
// set sort if not defined yet
|
|
4902
|
-
sort: currentState.member_pagination?.sort ?? request.sort,
|
|
4903
|
-
},
|
|
4904
|
-
}));
|
|
4568
|
+
});
|
|
4569
|
+
newState.own_membership = event.member;
|
|
4905
4570
|
}
|
|
4906
|
-
|
|
4907
|
-
|
|
4571
|
+
return newState ?? currentState;
|
|
4572
|
+
});
|
|
4573
|
+
}
|
|
4574
|
+
|
|
4575
|
+
function handleFeedMemberUpdated(event) {
|
|
4576
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4577
|
+
this.state.next((currentState) => {
|
|
4578
|
+
const memberIndex = currentState.members?.findIndex((member) => member.user.id === event.member.user.id) ?? -1;
|
|
4579
|
+
let newState;
|
|
4580
|
+
if (memberIndex !== -1) {
|
|
4581
|
+
// if there's an index, there's a member to update
|
|
4582
|
+
const newMembers = [...currentState.members];
|
|
4583
|
+
newMembers[memberIndex] = event.member;
|
|
4584
|
+
newState ?? (newState = {
|
|
4585
|
+
...currentState,
|
|
4586
|
+
});
|
|
4587
|
+
newState.members = newMembers;
|
|
4908
4588
|
}
|
|
4909
|
-
|
|
4910
|
-
|
|
4589
|
+
if (connectedUser?.id === event.member.user.id) {
|
|
4590
|
+
newState ?? (newState = {
|
|
4911
4591
|
...currentState,
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
loading_next_page: false,
|
|
4915
|
-
},
|
|
4916
|
-
}));
|
|
4592
|
+
});
|
|
4593
|
+
newState.own_membership = event.member;
|
|
4917
4594
|
}
|
|
4918
|
-
|
|
4919
|
-
|
|
4595
|
+
return newState ?? currentState;
|
|
4596
|
+
});
|
|
4597
|
+
}
|
|
4598
|
+
|
|
4599
|
+
function handleFeedMemberRemoved(event) {
|
|
4600
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4601
|
+
this.state.next((currentState) => {
|
|
4602
|
+
const newState = {
|
|
4603
|
+
...currentState,
|
|
4604
|
+
members: currentState.members?.filter((member) => member.user.id !== event.user?.id),
|
|
4605
|
+
};
|
|
4606
|
+
if (connectedUser?.id === event.member_id) {
|
|
4607
|
+
delete newState.own_membership;
|
|
4920
4608
|
}
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4609
|
+
return newState;
|
|
4610
|
+
});
|
|
4611
|
+
}
|
|
4612
|
+
|
|
4613
|
+
const addActivitiesToState = (newActivities, activities, position) => {
|
|
4614
|
+
let result;
|
|
4615
|
+
if (activities === undefined) {
|
|
4616
|
+
activities = [];
|
|
4617
|
+
result = {
|
|
4618
|
+
changed: true,
|
|
4619
|
+
activities,
|
|
4930
4620
|
};
|
|
4931
|
-
const response = await this.client.queryFollows({
|
|
4932
|
-
filter,
|
|
4933
|
-
...request,
|
|
4934
|
-
});
|
|
4935
|
-
return response;
|
|
4936
4621
|
}
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
*/
|
|
4942
|
-
async queryFollowing(request) {
|
|
4943
|
-
const filter = {
|
|
4944
|
-
source_feed: this.fid,
|
|
4622
|
+
else {
|
|
4623
|
+
result = {
|
|
4624
|
+
changed: false,
|
|
4625
|
+
activities,
|
|
4945
4626
|
};
|
|
4946
|
-
const response = await this.client.queryFollows({
|
|
4947
|
-
filter,
|
|
4948
|
-
...request,
|
|
4949
|
-
});
|
|
4950
|
-
return response;
|
|
4951
4627
|
}
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
const
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4628
|
+
const newActivitiesDeduplicated = [];
|
|
4629
|
+
newActivities.forEach((newActivityResponse) => {
|
|
4630
|
+
const index = activities.findIndex((a) => a.id === newActivityResponse.id);
|
|
4631
|
+
if (index === -1) {
|
|
4632
|
+
newActivitiesDeduplicated.push(newActivityResponse);
|
|
4633
|
+
}
|
|
4634
|
+
});
|
|
4635
|
+
if (newActivitiesDeduplicated.length > 0) {
|
|
4636
|
+
// TODO: since feed activities are not necessarily ordered by created_at (personalization) we don't order by created_at
|
|
4637
|
+
// Maybe we can add a flag to the JS client to support order by created_at
|
|
4638
|
+
const updatedActivities = [
|
|
4639
|
+
...(position === 'start' ? newActivitiesDeduplicated : []),
|
|
4640
|
+
...activities,
|
|
4641
|
+
...(position === 'end' ? newActivitiesDeduplicated : []),
|
|
4642
|
+
];
|
|
4643
|
+
result = { changed: true, activities: updatedActivities };
|
|
4644
|
+
}
|
|
4645
|
+
return result;
|
|
4646
|
+
};
|
|
4647
|
+
function handleActivityAdded(event) {
|
|
4648
|
+
const currentActivities = this.currentState.activities;
|
|
4649
|
+
const result = addActivitiesToState([event.activity], currentActivities, 'start');
|
|
4650
|
+
if (result.changed) {
|
|
4651
|
+
this.client.hydratePollCache([event.activity]);
|
|
4652
|
+
this.state.partialNext({ activities: result.activities });
|
|
4653
|
+
}
|
|
4654
|
+
}
|
|
4655
|
+
|
|
4656
|
+
const removeActivityFromState = (activityResponse, activities) => {
|
|
4657
|
+
const index = activities.findIndex((a) => a.id === activityResponse.id);
|
|
4658
|
+
if (index !== -1) {
|
|
4659
|
+
const newActivities = [...activities];
|
|
4660
|
+
newActivities.splice(index, 1);
|
|
4661
|
+
return { changed: true, activities: newActivities };
|
|
4662
|
+
}
|
|
4663
|
+
else {
|
|
4664
|
+
return { changed: false, activities };
|
|
4665
|
+
}
|
|
4666
|
+
};
|
|
4667
|
+
function handleActivityDeleted(event) {
|
|
4668
|
+
const currentActivities = this.currentState.activities;
|
|
4669
|
+
if (currentActivities) {
|
|
4670
|
+
const result = removeActivityFromState(event.activity, currentActivities);
|
|
4671
|
+
if (result.changed) {
|
|
4672
|
+
this.state.partialNext({ activities: result.activities });
|
|
4673
|
+
}
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
|
|
4677
|
+
function handleActivityRemovedFromFeed(event) {
|
|
4678
|
+
const currentActivities = this.currentState.activities;
|
|
4679
|
+
if (currentActivities) {
|
|
4680
|
+
const result = removeActivityFromState(event.activity, currentActivities);
|
|
4681
|
+
if (result.changed) {
|
|
4682
|
+
this.state.partialNext({ activities: result.activities });
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
}
|
|
4686
|
+
|
|
4687
|
+
const updateActivityInState = (updatedActivityResponse, activities, replaceCompletely = false) => {
|
|
4688
|
+
const index = activities.findIndex((a) => a.id === updatedActivityResponse.id);
|
|
4689
|
+
if (index !== -1) {
|
|
4690
|
+
const newActivities = [...activities];
|
|
4691
|
+
const activity = activities[index];
|
|
4692
|
+
if (replaceCompletely) {
|
|
4693
|
+
newActivities[index] = updatedActivityResponse;
|
|
4694
|
+
}
|
|
4695
|
+
else {
|
|
4696
|
+
newActivities[index] = {
|
|
4697
|
+
...updatedActivityResponse,
|
|
4698
|
+
own_reactions: activity.own_reactions,
|
|
4699
|
+
own_bookmarks: activity.own_bookmarks,
|
|
4700
|
+
latest_reactions: activity.latest_reactions,
|
|
4701
|
+
reaction_groups: activity.reaction_groups,
|
|
4702
|
+
};
|
|
4703
|
+
}
|
|
4704
|
+
return { changed: true, activities: newActivities };
|
|
4705
|
+
}
|
|
4706
|
+
else {
|
|
4707
|
+
return { changed: false, activities };
|
|
4708
|
+
}
|
|
4709
|
+
};
|
|
4710
|
+
function handleActivityUpdated(event) {
|
|
4711
|
+
const currentActivities = this.currentState.activities;
|
|
4712
|
+
if (currentActivities) {
|
|
4713
|
+
const result = updateActivityInState(event.activity, currentActivities);
|
|
4714
|
+
if (result.changed) {
|
|
4715
|
+
this.client.hydratePollCache([event.activity]);
|
|
4716
|
+
this.state.partialNext({ activities: result.activities });
|
|
4717
|
+
}
|
|
4718
|
+
}
|
|
4719
|
+
}
|
|
4720
|
+
|
|
4721
|
+
const addReactionToActivity = (event, activity, isCurrentUser) => {
|
|
4722
|
+
// Update own_reactions if the reaction is from the current user
|
|
4723
|
+
const ownReactions = [...(activity.own_reactions || [])];
|
|
4724
|
+
if (isCurrentUser) {
|
|
4725
|
+
ownReactions.push(event.reaction);
|
|
4960
4726
|
}
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4727
|
+
return {
|
|
4728
|
+
...activity,
|
|
4729
|
+
own_reactions: ownReactions,
|
|
4730
|
+
latest_reactions: event.activity.latest_reactions,
|
|
4731
|
+
reaction_groups: event.activity.reaction_groups,
|
|
4732
|
+
changed: true,
|
|
4733
|
+
};
|
|
4734
|
+
};
|
|
4735
|
+
const addReactionToActivities = (event, activities, isCurrentUser) => {
|
|
4736
|
+
if (!activities) {
|
|
4737
|
+
return { changed: false, activities: [] };
|
|
4968
4738
|
}
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
return
|
|
4972
|
-
member_pagination: {
|
|
4973
|
-
limit: 0,
|
|
4974
|
-
},
|
|
4975
|
-
followers_pagination: {
|
|
4976
|
-
limit: 0,
|
|
4977
|
-
},
|
|
4978
|
-
following_pagination: {
|
|
4979
|
-
limit: 0,
|
|
4980
|
-
},
|
|
4981
|
-
next: currentState.next,
|
|
4982
|
-
limit: currentState.last_get_or_create_request_config?.limit ?? 20,
|
|
4983
|
-
});
|
|
4739
|
+
const activityIndex = activities.findIndex((a) => a.id === event.activity.id);
|
|
4740
|
+
if (activityIndex === -1) {
|
|
4741
|
+
return { changed: false, activities };
|
|
4984
4742
|
}
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4743
|
+
const activity = activities[activityIndex];
|
|
4744
|
+
const updatedActivity = addReactionToActivity(event, activity, isCurrentUser);
|
|
4745
|
+
return updateActivityInState(updatedActivity, activities, true);
|
|
4746
|
+
};
|
|
4747
|
+
function handleActivityReactionAdded(event) {
|
|
4748
|
+
const currentActivities = this.currentState.activities;
|
|
4749
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4750
|
+
const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
|
|
4751
|
+
const result = addReactionToActivities(event, currentActivities, isCurrentUser);
|
|
4752
|
+
if (result.changed) {
|
|
4753
|
+
this.state.partialNext({ activities: result.activities });
|
|
4990
4754
|
}
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
4755
|
+
}
|
|
4756
|
+
|
|
4757
|
+
const removeReactionFromActivity = (event, activity, isCurrentUser) => {
|
|
4758
|
+
// Update own_reactions if the reaction is from the current user
|
|
4759
|
+
const ownReactions = isCurrentUser
|
|
4760
|
+
? (activity.own_reactions || []).filter((r) => !(r.type === event.reaction.type &&
|
|
4761
|
+
r.user.id === event.reaction.user.id))
|
|
4762
|
+
: activity.own_reactions;
|
|
4763
|
+
return {
|
|
4764
|
+
...activity,
|
|
4765
|
+
own_reactions: ownReactions,
|
|
4766
|
+
latest_reactions: event.activity.latest_reactions,
|
|
4767
|
+
reaction_groups: event.activity.reaction_groups,
|
|
4768
|
+
changed: true,
|
|
4769
|
+
};
|
|
4770
|
+
};
|
|
4771
|
+
const removeReactionFromActivities = (event, activities, isCurrentUser) => {
|
|
4772
|
+
if (!activities) {
|
|
4773
|
+
return { changed: false, activities: [] };
|
|
4774
|
+
}
|
|
4775
|
+
const activityIndex = activities.findIndex((a) => a.id === event.activity.id);
|
|
4776
|
+
if (activityIndex === -1) {
|
|
4777
|
+
return { changed: false, activities };
|
|
4778
|
+
}
|
|
4779
|
+
const activity = activities[activityIndex];
|
|
4780
|
+
const updatedActivity = removeReactionFromActivity(event, activity, isCurrentUser);
|
|
4781
|
+
return updateActivityInState(updatedActivity, activities, true);
|
|
4782
|
+
};
|
|
4783
|
+
function handleActivityReactionDeleted(event) {
|
|
4784
|
+
const currentActivities = this.currentState.activities;
|
|
4785
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4786
|
+
const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
|
|
4787
|
+
const result = removeReactionFromActivities(event, currentActivities, isCurrentUser);
|
|
4788
|
+
if (result.changed) {
|
|
4789
|
+
this.state.partialNext({ activities: result.activities });
|
|
5002
4790
|
}
|
|
5003
4791
|
}
|
|
5004
|
-
Feed.noop = () => { };
|
|
5005
4792
|
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
4793
|
+
const addBookmarkToActivity = (event, activity, isCurrentUser) => {
|
|
4794
|
+
// Update own_bookmarks if the bookmark is from the current user
|
|
4795
|
+
const ownBookmarks = [...(activity.own_bookmarks || [])];
|
|
4796
|
+
if (isCurrentUser) {
|
|
4797
|
+
ownBookmarks.push(event.bookmark);
|
|
5009
4798
|
}
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
timeout: request?.timeout,
|
|
5020
|
-
banned_by: request?.banned_by,
|
|
5021
|
-
};
|
|
5022
|
-
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/ban', undefined, undefined, body, 'application/json');
|
|
5023
|
-
decoders.BanResponse?.(response.body);
|
|
5024
|
-
return { ...response.body, metadata: response.metadata };
|
|
4799
|
+
return {
|
|
4800
|
+
...activity,
|
|
4801
|
+
own_bookmarks: ownBookmarks,
|
|
4802
|
+
changed: true,
|
|
4803
|
+
};
|
|
4804
|
+
};
|
|
4805
|
+
const addBookmarkToActivities = (event, activities, isCurrentUser) => {
|
|
4806
|
+
if (!activities) {
|
|
4807
|
+
return { changed: false, activities: [] };
|
|
5025
4808
|
}
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
async: request?.async,
|
|
5030
|
-
team: request?.team,
|
|
5031
|
-
ai_image_config: request?.ai_image_config,
|
|
5032
|
-
ai_text_config: request?.ai_text_config,
|
|
5033
|
-
ai_video_config: request?.ai_video_config,
|
|
5034
|
-
automod_platform_circumvention_config: request?.automod_platform_circumvention_config,
|
|
5035
|
-
automod_semantic_filters_config: request?.automod_semantic_filters_config,
|
|
5036
|
-
automod_toxicity_config: request?.automod_toxicity_config,
|
|
5037
|
-
aws_rekognition_config: request?.aws_rekognition_config,
|
|
5038
|
-
block_list_config: request?.block_list_config,
|
|
5039
|
-
bodyguard_config: request?.bodyguard_config,
|
|
5040
|
-
google_vision_config: request?.google_vision_config,
|
|
5041
|
-
rule_builder_config: request?.rule_builder_config,
|
|
5042
|
-
velocity_filter_config: request?.velocity_filter_config,
|
|
5043
|
-
video_call_rule_config: request?.video_call_rule_config,
|
|
5044
|
-
};
|
|
5045
|
-
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/config', undefined, undefined, body, 'application/json');
|
|
5046
|
-
decoders.UpsertConfigResponse?.(response.body);
|
|
5047
|
-
return { ...response.body, metadata: response.metadata };
|
|
4809
|
+
const activityIndex = activities.findIndex((a) => a.id === event.bookmark.activity.id);
|
|
4810
|
+
if (activityIndex === -1) {
|
|
4811
|
+
return { changed: false, activities };
|
|
5048
4812
|
}
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
4813
|
+
const activity = activities[activityIndex];
|
|
4814
|
+
const updatedActivity = addBookmarkToActivity(event, activity, isCurrentUser);
|
|
4815
|
+
return updateActivityInState(updatedActivity, activities, true);
|
|
4816
|
+
};
|
|
4817
|
+
function handleBookmarkAdded(event) {
|
|
4818
|
+
const currentActivities = this.currentState.activities;
|
|
4819
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4820
|
+
const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
|
|
4821
|
+
const result = addBookmarkToActivities(event, currentActivities, isCurrentUser);
|
|
4822
|
+
if (result.changed) {
|
|
4823
|
+
this.state.partialNext({ activities: result.activities });
|
|
5059
4824
|
}
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
4825
|
+
}
|
|
4826
|
+
|
|
4827
|
+
// Helper function to check if two bookmarks are the same
|
|
4828
|
+
// A bookmark is identified by activity_id + folder_id + user_id
|
|
4829
|
+
const isSameBookmark = (bookmark1, bookmark2) => {
|
|
4830
|
+
return (bookmark1.user.id === bookmark2.user.id &&
|
|
4831
|
+
bookmark1.activity.id === bookmark2.activity.id &&
|
|
4832
|
+
bookmark1.folder?.id === bookmark2.folder?.id);
|
|
4833
|
+
};
|
|
4834
|
+
const removeBookmarkFromActivities = (event, activities, isCurrentUser) => {
|
|
4835
|
+
if (!activities) {
|
|
4836
|
+
return { changed: false, activities: [] };
|
|
5070
4837
|
}
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
next: request?.next,
|
|
5075
|
-
prev: request?.prev,
|
|
5076
|
-
sort: request?.sort,
|
|
5077
|
-
filter: request?.filter,
|
|
5078
|
-
};
|
|
5079
|
-
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/configs', undefined, undefined, body, 'application/json');
|
|
5080
|
-
decoders.QueryModerationConfigsResponse?.(response.body);
|
|
5081
|
-
return { ...response.body, metadata: response.metadata };
|
|
4838
|
+
const activityIndex = activities.findIndex((a) => a.id === event.bookmark.activity.id);
|
|
4839
|
+
if (activityIndex === -1) {
|
|
4840
|
+
return { changed: false, activities };
|
|
5082
4841
|
}
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
4842
|
+
const activity = activities[activityIndex];
|
|
4843
|
+
const updatedActivity = removeBookmarkFromActivity(event, activity, isCurrentUser);
|
|
4844
|
+
return updateActivityInState(updatedActivity, activities, true);
|
|
4845
|
+
};
|
|
4846
|
+
const removeBookmarkFromActivity = (event, activity, isCurrentUser) => {
|
|
4847
|
+
// Update own_bookmarks if the bookmark is from the current user
|
|
4848
|
+
const ownBookmarks = isCurrentUser
|
|
4849
|
+
? (activity.own_bookmarks || []).filter((bookmark) => !isSameBookmark(bookmark, event.bookmark))
|
|
4850
|
+
: activity.own_bookmarks;
|
|
4851
|
+
return {
|
|
4852
|
+
...activity,
|
|
4853
|
+
own_bookmarks: ownBookmarks,
|
|
4854
|
+
changed: true,
|
|
4855
|
+
};
|
|
4856
|
+
};
|
|
4857
|
+
function handleBookmarkDeleted(event) {
|
|
4858
|
+
const currentActivities = this.currentState.activities;
|
|
4859
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4860
|
+
const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
|
|
4861
|
+
const result = removeBookmarkFromActivities(event, currentActivities, isCurrentUser);
|
|
4862
|
+
if (result.changed) {
|
|
4863
|
+
this.state.partialNext({ activities: result.activities });
|
|
5095
4864
|
}
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
4865
|
+
}
|
|
4866
|
+
|
|
4867
|
+
const updateBookmarkInActivity = (event, activity, isCurrentUser) => {
|
|
4868
|
+
// Update own_bookmarks if the bookmark is from the current user
|
|
4869
|
+
let ownBookmarks = activity.own_bookmarks || [];
|
|
4870
|
+
if (isCurrentUser) {
|
|
4871
|
+
const bookmarkIndex = ownBookmarks.findIndex((bookmark) => isSameBookmark(bookmark, event.bookmark));
|
|
4872
|
+
if (bookmarkIndex !== -1) {
|
|
4873
|
+
ownBookmarks = [...ownBookmarks];
|
|
4874
|
+
ownBookmarks[bookmarkIndex] = event.bookmark;
|
|
4875
|
+
}
|
|
4876
|
+
}
|
|
4877
|
+
return {
|
|
4878
|
+
...activity,
|
|
4879
|
+
own_bookmarks: ownBookmarks,
|
|
4880
|
+
changed: true,
|
|
4881
|
+
};
|
|
4882
|
+
};
|
|
4883
|
+
const updateBookmarkInActivities = (event, activities, isCurrentUser) => {
|
|
4884
|
+
if (!activities) {
|
|
4885
|
+
return { changed: false, activities: [] };
|
|
5104
4886
|
}
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
lock_count: request?.lock_count,
|
|
5109
|
-
lock_duration: request?.lock_duration,
|
|
5110
|
-
lock_items: request?.lock_items,
|
|
5111
|
-
next: request?.next,
|
|
5112
|
-
prev: request?.prev,
|
|
5113
|
-
stats_only: request?.stats_only,
|
|
5114
|
-
sort: request?.sort,
|
|
5115
|
-
filter: request?.filter,
|
|
5116
|
-
};
|
|
5117
|
-
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/review_queue', undefined, undefined, body, 'application/json');
|
|
5118
|
-
decoders.QueryReviewQueueResponse?.(response.body);
|
|
5119
|
-
return { ...response.body, metadata: response.metadata };
|
|
4887
|
+
const activityIndex = activities.findIndex((a) => a.id === event.bookmark.activity.id);
|
|
4888
|
+
if (activityIndex === -1) {
|
|
4889
|
+
return { changed: false, activities };
|
|
5120
4890
|
}
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
unban: request?.unban,
|
|
5133
|
-
};
|
|
5134
|
-
const response = await this.apiClient.sendRequest('POST', '/api/v2/moderation/submit_action', undefined, undefined, body, 'application/json');
|
|
5135
|
-
decoders.SubmitActionResponse?.(response.body);
|
|
5136
|
-
return { ...response.body, metadata: response.metadata };
|
|
4891
|
+
const activity = activities[activityIndex];
|
|
4892
|
+
const updatedActivity = updateBookmarkInActivity(event, activity, isCurrentUser);
|
|
4893
|
+
return updateActivityInState(updatedActivity, activities, true);
|
|
4894
|
+
};
|
|
4895
|
+
function handleBookmarkUpdated(event) {
|
|
4896
|
+
const currentActivities = this.currentState.activities;
|
|
4897
|
+
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4898
|
+
const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
|
|
4899
|
+
const result = updateBookmarkInActivities(event, currentActivities, isCurrentUser);
|
|
4900
|
+
if (result.changed) {
|
|
4901
|
+
this.state.partialNext({ activities: result.activities });
|
|
5137
4902
|
}
|
|
5138
4903
|
}
|
|
5139
4904
|
|
|
5140
|
-
|
|
4905
|
+
function handleFeedUpdated(event) {
|
|
4906
|
+
this.state.partialNext({ ...event.feed });
|
|
5141
4907
|
}
|
|
5142
4908
|
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
this.
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
let latestAnswers = [...currentState.latest_answers];
|
|
5204
|
-
let ownAnswer = currentState.own_answer;
|
|
5205
|
-
const ownVotesByOptionId = currentState.own_votes_by_option_id;
|
|
5206
|
-
let maxVotedOptionIds = currentState.max_voted_option_ids;
|
|
5207
|
-
if (isOwnVote) {
|
|
5208
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5209
|
-
if (isVoteAnswer(event.poll_vote)) {
|
|
5210
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5211
|
-
ownAnswer = event.poll_vote;
|
|
5212
|
-
}
|
|
5213
|
-
else if (event.poll_vote.option_id) {
|
|
5214
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5215
|
-
ownVotesByOptionId[event.poll_vote.option_id] = event.poll_vote;
|
|
5216
|
-
}
|
|
5217
|
-
}
|
|
5218
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5219
|
-
if (isVoteAnswer(event.poll_vote)) {
|
|
5220
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5221
|
-
latestAnswers = [event.poll_vote, ...latestAnswers];
|
|
5222
|
-
}
|
|
5223
|
-
else {
|
|
5224
|
-
maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
|
|
5225
|
-
}
|
|
5226
|
-
const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
|
|
5227
|
-
this.state.partialNext({
|
|
5228
|
-
answers_count,
|
|
5229
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5230
|
-
latest_votes_by_option,
|
|
5231
|
-
vote_count,
|
|
5232
|
-
vote_counts_by_option,
|
|
5233
|
-
latest_answers: latestAnswers,
|
|
5234
|
-
last_activity_at: new Date(event.created_at),
|
|
5235
|
-
own_answer: ownAnswer,
|
|
5236
|
-
own_votes_by_option_id: ownVotesByOptionId,
|
|
5237
|
-
max_voted_option_ids: maxVotedOptionIds,
|
|
5238
|
-
});
|
|
4909
|
+
function handleNotificationFeedUpdated(event) {
|
|
4910
|
+
console.info('notification feed updated', event);
|
|
4911
|
+
// TODO: handle notification feed updates
|
|
4912
|
+
}
|
|
4913
|
+
|
|
4914
|
+
class Feed extends FeedApi {
|
|
4915
|
+
constructor(client, groupId, id, data, watch = false) {
|
|
4916
|
+
super(client, groupId, id);
|
|
4917
|
+
this.stateUpdateQueue = new Set();
|
|
4918
|
+
this.eventHandlers = {
|
|
4919
|
+
'feeds.activity.added': handleActivityAdded.bind(this),
|
|
4920
|
+
'feeds.activity.deleted': handleActivityDeleted.bind(this),
|
|
4921
|
+
'feeds.activity.reaction.added': handleActivityReactionAdded.bind(this),
|
|
4922
|
+
'feeds.activity.reaction.deleted': handleActivityReactionDeleted.bind(this),
|
|
4923
|
+
'feeds.activity.reaction.updated': Feed.noop,
|
|
4924
|
+
'feeds.activity.removed_from_feed': handleActivityRemovedFromFeed.bind(this),
|
|
4925
|
+
'feeds.activity.updated': handleActivityUpdated.bind(this),
|
|
4926
|
+
'feeds.bookmark.added': handleBookmarkAdded.bind(this),
|
|
4927
|
+
'feeds.bookmark.deleted': handleBookmarkDeleted.bind(this),
|
|
4928
|
+
'feeds.bookmark.updated': handleBookmarkUpdated.bind(this),
|
|
4929
|
+
'feeds.bookmark_folder.deleted': Feed.noop,
|
|
4930
|
+
'feeds.bookmark_folder.updated': Feed.noop,
|
|
4931
|
+
'feeds.comment.added': handleCommentAdded.bind(this),
|
|
4932
|
+
'feeds.comment.deleted': handleCommentDeleted.bind(this),
|
|
4933
|
+
'feeds.comment.updated': handleCommentUpdated.bind(this),
|
|
4934
|
+
'feeds.feed.created': Feed.noop,
|
|
4935
|
+
'feeds.feed.deleted': Feed.noop,
|
|
4936
|
+
'feeds.feed.updated': handleFeedUpdated.bind(this),
|
|
4937
|
+
'feeds.feed_group.changed': Feed.noop,
|
|
4938
|
+
'feeds.feed_group.deleted': Feed.noop,
|
|
4939
|
+
'feeds.follow.created': handleFollowCreated.bind(this),
|
|
4940
|
+
'feeds.follow.deleted': handleFollowDeleted.bind(this),
|
|
4941
|
+
'feeds.follow.updated': handleFollowUpdated.bind(this),
|
|
4942
|
+
'feeds.comment.reaction.added': handleCommentReaction.bind(this),
|
|
4943
|
+
'feeds.comment.reaction.deleted': handleCommentReaction.bind(this),
|
|
4944
|
+
'feeds.comment.reaction.updated': Feed.noop,
|
|
4945
|
+
'feeds.feed_member.added': handleFeedMemberAdded.bind(this),
|
|
4946
|
+
'feeds.feed_member.removed': handleFeedMemberRemoved.bind(this),
|
|
4947
|
+
'feeds.feed_member.updated': handleFeedMemberUpdated.bind(this),
|
|
4948
|
+
'feeds.notification_feed.updated': handleNotificationFeedUpdated.bind(this),
|
|
4949
|
+
// the poll events should be removed from here
|
|
4950
|
+
'feeds.poll.closed': Feed.noop,
|
|
4951
|
+
'feeds.poll.deleted': Feed.noop,
|
|
4952
|
+
'feeds.poll.updated': Feed.noop,
|
|
4953
|
+
'feeds.poll.vote_casted': Feed.noop,
|
|
4954
|
+
'feeds.poll.vote_changed': Feed.noop,
|
|
4955
|
+
'feeds.poll.vote_removed': Feed.noop,
|
|
4956
|
+
'feeds.activity.pinned': Feed.noop,
|
|
4957
|
+
'feeds.activity.unpinned': Feed.noop,
|
|
4958
|
+
'feeds.activity.marked': Feed.noop,
|
|
4959
|
+
'moderation.custom_action': Feed.noop,
|
|
4960
|
+
'moderation.flagged': Feed.noop,
|
|
4961
|
+
'moderation.mark_reviewed': Feed.noop,
|
|
4962
|
+
'health.check': Feed.noop,
|
|
4963
|
+
'app.updated': Feed.noop,
|
|
4964
|
+
'user.banned': Feed.noop,
|
|
4965
|
+
'user.deactivated': Feed.noop,
|
|
4966
|
+
'user.muted': Feed.noop,
|
|
4967
|
+
'user.reactivated': Feed.noop,
|
|
4968
|
+
'user.updated': Feed.noop,
|
|
5239
4969
|
};
|
|
5240
|
-
this.
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
4970
|
+
this.eventDispatcher = new EventDispatcher();
|
|
4971
|
+
this.on = this.eventDispatcher.on;
|
|
4972
|
+
this.off = this.eventDispatcher.off;
|
|
4973
|
+
this.state = new StateStore({
|
|
4974
|
+
fid: `${groupId}:${id}`,
|
|
4975
|
+
group_id: groupId,
|
|
4976
|
+
id,
|
|
4977
|
+
...(data ?? {}),
|
|
4978
|
+
is_loading: false,
|
|
4979
|
+
is_loading_activities: false,
|
|
4980
|
+
comments_by_entity_id: {},
|
|
4981
|
+
watch,
|
|
4982
|
+
});
|
|
4983
|
+
this.client = client;
|
|
4984
|
+
}
|
|
4985
|
+
get fid() {
|
|
4986
|
+
return `${this.group}:${this.id}`;
|
|
4987
|
+
}
|
|
4988
|
+
get currentState() {
|
|
4989
|
+
return this.state.getLatestValue();
|
|
4990
|
+
}
|
|
4991
|
+
async synchronize() {
|
|
4992
|
+
const { last_get_or_create_request_config } = this.state.getLatestValue();
|
|
4993
|
+
if (last_get_or_create_request_config?.watch) {
|
|
4994
|
+
await this.getOrCreate(last_get_or_create_request_config);
|
|
4995
|
+
}
|
|
4996
|
+
}
|
|
4997
|
+
async getOrCreate(request) {
|
|
4998
|
+
if (this.currentState.is_loading_activities) {
|
|
4999
|
+
throw new Error('Only one getOrCreate call is allowed at a time');
|
|
5000
|
+
}
|
|
5001
|
+
this.state.partialNext({
|
|
5002
|
+
is_loading: !request?.next,
|
|
5003
|
+
is_loading_activities: true,
|
|
5004
|
+
});
|
|
5005
|
+
// TODO: pull comments/comment_pagination from activities and comment_sort from request
|
|
5006
|
+
// and pre-populate comments_by_entity_id (once comment_sort and comment_limit are supported)
|
|
5007
|
+
try {
|
|
5008
|
+
const response = await super.getOrCreate(request);
|
|
5009
|
+
if (request?.next) {
|
|
5010
|
+
const { activities: currentActivities = [] } = this.currentState;
|
|
5011
|
+
const result = addActivitiesToState(response.activities, currentActivities, 'end');
|
|
5012
|
+
if (result.changed) {
|
|
5013
|
+
this.state.partialNext({
|
|
5014
|
+
activities: result.activities,
|
|
5015
|
+
next: response.next,
|
|
5016
|
+
prev: response.prev,
|
|
5017
|
+
});
|
|
5285
5018
|
}
|
|
5286
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5287
|
-
}
|
|
5288
|
-
else if (isVoteAnswer(event.poll_vote)) {
|
|
5289
|
-
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
|
|
5290
|
-
latestAnswers = [event.poll_vote, ...latestAnswers];
|
|
5291
5019
|
}
|
|
5292
5020
|
else {
|
|
5293
|
-
|
|
5021
|
+
// Empty queue when reinitializing the state
|
|
5022
|
+
this.stateUpdateQueue.clear();
|
|
5023
|
+
const responseCopy = {
|
|
5024
|
+
...response,
|
|
5025
|
+
...response.feed,
|
|
5026
|
+
};
|
|
5027
|
+
delete responseCopy.feed;
|
|
5028
|
+
delete responseCopy.metadata;
|
|
5029
|
+
delete responseCopy.duration;
|
|
5030
|
+
// TODO: lazy-load comments from activities when comment_sort and comment_pagination are supported
|
|
5031
|
+
this.state.next((currentState) => {
|
|
5032
|
+
const nextState = {
|
|
5033
|
+
...currentState,
|
|
5034
|
+
...responseCopy,
|
|
5035
|
+
};
|
|
5036
|
+
if (!request?.followers_pagination?.limit) {
|
|
5037
|
+
delete nextState.followers;
|
|
5038
|
+
}
|
|
5039
|
+
if (!request?.following_pagination?.limit) {
|
|
5040
|
+
delete nextState.following;
|
|
5041
|
+
}
|
|
5042
|
+
if (response.members.length === 0 && response.feed.member_count > 0) {
|
|
5043
|
+
delete nextState.members;
|
|
5044
|
+
}
|
|
5045
|
+
nextState.last_get_or_create_request_config = request;
|
|
5046
|
+
nextState.watch = request?.watch ? request.watch : currentState.watch;
|
|
5047
|
+
return nextState;
|
|
5048
|
+
});
|
|
5294
5049
|
}
|
|
5295
|
-
|
|
5050
|
+
this.client.hydratePollCache(response.activities);
|
|
5051
|
+
return response;
|
|
5052
|
+
}
|
|
5053
|
+
finally {
|
|
5296
5054
|
this.state.partialNext({
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5055
|
+
is_loading: false,
|
|
5056
|
+
is_loading_activities: false,
|
|
5057
|
+
});
|
|
5058
|
+
}
|
|
5059
|
+
}
|
|
5060
|
+
/**
|
|
5061
|
+
* @internal
|
|
5062
|
+
*/
|
|
5063
|
+
handleWatchStopped() {
|
|
5064
|
+
this.state.partialNext({
|
|
5065
|
+
watch: false,
|
|
5066
|
+
});
|
|
5067
|
+
}
|
|
5068
|
+
/**
|
|
5069
|
+
* @internal
|
|
5070
|
+
*/
|
|
5071
|
+
handleWatchStarted() {
|
|
5072
|
+
this.state.partialNext({
|
|
5073
|
+
watch: true,
|
|
5074
|
+
});
|
|
5075
|
+
}
|
|
5076
|
+
/**
|
|
5077
|
+
* Returns index of the provided comment object.
|
|
5078
|
+
*/
|
|
5079
|
+
getCommentIndex(comment, state) {
|
|
5080
|
+
const { comments_by_entity_id = {} } = state ?? this.currentState;
|
|
5081
|
+
const currentComments = comments_by_entity_id[comment.parent_id ?? comment.object_id]?.comments;
|
|
5082
|
+
if (!currentComments?.length) {
|
|
5083
|
+
return -1;
|
|
5084
|
+
}
|
|
5085
|
+
// @ts-expect-error this will just fail if the comment is not object from state
|
|
5086
|
+
let commentIndex = currentComments.indexOf(comment);
|
|
5087
|
+
// fast lookup failed, try slower approach
|
|
5088
|
+
if (commentIndex === -1) {
|
|
5089
|
+
commentIndex = currentComments.findIndex((comment_) => comment_.id === comment.id);
|
|
5090
|
+
}
|
|
5091
|
+
return commentIndex;
|
|
5092
|
+
}
|
|
5093
|
+
/**
|
|
5094
|
+
* Load child comments of entity (activity or comment) into the state, if the target entity is comment,
|
|
5095
|
+
* `entityParentId` should be provided (`CommentResponse.parent_id ?? CommentResponse.object_id`).
|
|
5096
|
+
*/
|
|
5097
|
+
loadCommentsIntoState(data) {
|
|
5098
|
+
// add initial (top level) object for processing
|
|
5099
|
+
const traverseArray = [
|
|
5100
|
+
{
|
|
5101
|
+
entityId: data.entityId,
|
|
5102
|
+
entityParentId: data.entityParentId,
|
|
5103
|
+
comments: data.comments,
|
|
5104
|
+
next: data.next,
|
|
5105
|
+
},
|
|
5106
|
+
];
|
|
5107
|
+
this.state.next((currentState) => {
|
|
5108
|
+
const newCommentsByEntityId = {
|
|
5109
|
+
...currentState.comments_by_entity_id,
|
|
5110
|
+
};
|
|
5111
|
+
while (traverseArray.length) {
|
|
5112
|
+
const item = traverseArray.pop();
|
|
5113
|
+
const entityId = item.entityId;
|
|
5114
|
+
// go over entity comments and generate new objects
|
|
5115
|
+
// for further processing if there are any replies
|
|
5116
|
+
item.comments.forEach((comment) => {
|
|
5117
|
+
if (!comment.replies?.length)
|
|
5118
|
+
return;
|
|
5119
|
+
traverseArray.push({
|
|
5120
|
+
entityId: comment.id,
|
|
5121
|
+
entityParentId: entityId,
|
|
5122
|
+
comments: comment.replies,
|
|
5123
|
+
next: comment.meta?.next_cursor,
|
|
5124
|
+
});
|
|
5125
|
+
});
|
|
5126
|
+
// omit replies & meta from the comments (transform ThreadedCommentResponse to CommentResponse)
|
|
5127
|
+
// this is somehow faster than copying the whole
|
|
5128
|
+
// object and deleting the desired properties
|
|
5129
|
+
const newComments = item.comments.map(({ replies: _r, meta: _m, ...restOfTheCommentResponse }) => restOfTheCommentResponse);
|
|
5130
|
+
const existingComments = newCommentsByEntityId[entityId]?.comments;
|
|
5131
|
+
newCommentsByEntityId[entityId] = {
|
|
5132
|
+
...newCommentsByEntityId[entityId],
|
|
5133
|
+
entity_parent_id: item.entityParentId,
|
|
5134
|
+
pagination: {
|
|
5135
|
+
...newCommentsByEntityId[entityId]?.pagination,
|
|
5136
|
+
next: item.next,
|
|
5137
|
+
sort: data.sort,
|
|
5138
|
+
},
|
|
5139
|
+
comments: existingComments
|
|
5140
|
+
? uniqueArrayMerge(existingComments, newComments, (comment) => comment.id)
|
|
5141
|
+
: newComments,
|
|
5142
|
+
};
|
|
5143
|
+
}
|
|
5144
|
+
return {
|
|
5145
|
+
...currentState,
|
|
5146
|
+
comments_by_entity_id: newCommentsByEntityId,
|
|
5147
|
+
};
|
|
5148
|
+
});
|
|
5149
|
+
}
|
|
5150
|
+
async loadNextPageComments({ entityId, base, sort, entityParentId, }) {
|
|
5151
|
+
let error;
|
|
5152
|
+
try {
|
|
5153
|
+
this.state.next((currentState) => ({
|
|
5154
|
+
...currentState,
|
|
5155
|
+
comments_by_entity_id: {
|
|
5156
|
+
...currentState.comments_by_entity_id,
|
|
5157
|
+
[entityId]: {
|
|
5158
|
+
...currentState.comments_by_entity_id[entityId],
|
|
5159
|
+
pagination: {
|
|
5160
|
+
...currentState.comments_by_entity_id[entityId]?.pagination,
|
|
5161
|
+
loading_next_page: true,
|
|
5162
|
+
},
|
|
5163
|
+
},
|
|
5164
|
+
},
|
|
5165
|
+
}));
|
|
5166
|
+
const { next, comments } = await base();
|
|
5167
|
+
this.loadCommentsIntoState({
|
|
5168
|
+
entityId,
|
|
5169
|
+
comments,
|
|
5170
|
+
entityParentId,
|
|
5171
|
+
next,
|
|
5172
|
+
sort,
|
|
5173
|
+
});
|
|
5174
|
+
}
|
|
5175
|
+
catch (e) {
|
|
5176
|
+
error = e;
|
|
5177
|
+
}
|
|
5178
|
+
finally {
|
|
5179
|
+
this.state.next((currentState) => ({
|
|
5180
|
+
...currentState,
|
|
5181
|
+
comments_by_entity_id: {
|
|
5182
|
+
...currentState.comments_by_entity_id,
|
|
5183
|
+
[entityId]: {
|
|
5184
|
+
...currentState.comments_by_entity_id[entityId],
|
|
5185
|
+
pagination: {
|
|
5186
|
+
...currentState.comments_by_entity_id[entityId]?.pagination,
|
|
5187
|
+
loading_next_page: false,
|
|
5188
|
+
},
|
|
5189
|
+
},
|
|
5190
|
+
},
|
|
5191
|
+
}));
|
|
5192
|
+
}
|
|
5193
|
+
if (error) {
|
|
5194
|
+
throw error;
|
|
5195
|
+
}
|
|
5196
|
+
}
|
|
5197
|
+
async loadNextPageActivityComments(activity, request) {
|
|
5198
|
+
const currentEntityState = this.currentState.comments_by_entity_id[activity.id];
|
|
5199
|
+
const currentPagination = currentEntityState?.pagination;
|
|
5200
|
+
const currentNextCursor = currentPagination?.next;
|
|
5201
|
+
const currentSort = currentPagination?.sort;
|
|
5202
|
+
const isLoading = currentPagination?.loading_next_page;
|
|
5203
|
+
const sort = currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
5204
|
+
if (isLoading ||
|
|
5205
|
+
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
|
|
5206
|
+
return;
|
|
5207
|
+
}
|
|
5208
|
+
await this.loadNextPageComments({
|
|
5209
|
+
entityId: activity.id,
|
|
5210
|
+
base: () => this.client.getComments({
|
|
5211
|
+
...request,
|
|
5212
|
+
sort,
|
|
5213
|
+
object_id: activity.id,
|
|
5214
|
+
object_type: 'activity',
|
|
5215
|
+
next: currentNextCursor,
|
|
5216
|
+
}),
|
|
5217
|
+
sort,
|
|
5218
|
+
});
|
|
5219
|
+
}
|
|
5220
|
+
async loadNextPageCommentReplies(comment, request) {
|
|
5221
|
+
const currentEntityState = this.currentState.comments_by_entity_id[comment.id];
|
|
5222
|
+
const currentPagination = currentEntityState?.pagination;
|
|
5223
|
+
const currentNextCursor = currentPagination?.next;
|
|
5224
|
+
const currentSort = currentPagination?.sort;
|
|
5225
|
+
const isLoading = currentPagination?.loading_next_page;
|
|
5226
|
+
const sort = currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
5227
|
+
if (isLoading ||
|
|
5228
|
+
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
|
|
5229
|
+
return;
|
|
5230
|
+
}
|
|
5231
|
+
await this.loadNextPageComments({
|
|
5232
|
+
entityId: comment.id,
|
|
5233
|
+
base: () => this.client.getCommentReplies({
|
|
5234
|
+
...request,
|
|
5235
|
+
comment_id: comment.id,
|
|
5236
|
+
// use known sort first (prevents broken pagination)
|
|
5237
|
+
sort,
|
|
5238
|
+
next: currentNextCursor,
|
|
5239
|
+
}),
|
|
5240
|
+
entityParentId: comment.parent_id ?? comment.object_id,
|
|
5241
|
+
sort,
|
|
5242
|
+
});
|
|
5243
|
+
}
|
|
5244
|
+
async loadNextPageFollows(type, request) {
|
|
5245
|
+
const paginationKey = `${type}_pagination`;
|
|
5246
|
+
const method = `query${capitalize(type)}`;
|
|
5247
|
+
const currentFollows = this.currentState[type];
|
|
5248
|
+
const currentNextCursor = this.currentState[paginationKey]?.next;
|
|
5249
|
+
const isLoading = this.currentState[paginationKey]?.loading_next_page;
|
|
5250
|
+
const sort = this.currentState[paginationKey]?.sort ?? request.sort;
|
|
5251
|
+
let error;
|
|
5252
|
+
if (isLoading || !checkHasAnotherPage(currentFollows, currentNextCursor)) {
|
|
5253
|
+
return;
|
|
5254
|
+
}
|
|
5255
|
+
try {
|
|
5256
|
+
this.state.next((currentState) => {
|
|
5257
|
+
return {
|
|
5258
|
+
...currentState,
|
|
5259
|
+
[paginationKey]: {
|
|
5260
|
+
...currentState[paginationKey],
|
|
5261
|
+
loading_next_page: true,
|
|
5262
|
+
},
|
|
5263
|
+
};
|
|
5307
5264
|
});
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5265
|
+
const { next: newNextCursor, follows } = await this[method]({
|
|
5266
|
+
...request,
|
|
5267
|
+
next: currentNextCursor,
|
|
5268
|
+
sort,
|
|
5269
|
+
});
|
|
5270
|
+
this.state.next((currentState) => {
|
|
5271
|
+
return {
|
|
5272
|
+
...currentState,
|
|
5273
|
+
[type]: currentState[type] === undefined
|
|
5274
|
+
? follows
|
|
5275
|
+
: uniqueArrayMerge(currentState[type], follows, (follow) => `${follow.source_feed.fid}-${follow.target_feed.fid}`),
|
|
5276
|
+
[paginationKey]: {
|
|
5277
|
+
...currentState[paginationKey],
|
|
5278
|
+
next: newNextCursor,
|
|
5279
|
+
sort,
|
|
5280
|
+
},
|
|
5281
|
+
};
|
|
5282
|
+
});
|
|
5283
|
+
}
|
|
5284
|
+
catch (e) {
|
|
5285
|
+
error = e;
|
|
5286
|
+
}
|
|
5287
|
+
finally {
|
|
5288
|
+
this.state.next((currentState) => {
|
|
5289
|
+
return {
|
|
5290
|
+
...currentState,
|
|
5291
|
+
[paginationKey]: {
|
|
5292
|
+
...currentState[paginationKey],
|
|
5293
|
+
loading_next_page: false,
|
|
5294
|
+
},
|
|
5295
|
+
};
|
|
5296
|
+
});
|
|
5297
|
+
}
|
|
5298
|
+
if (error) {
|
|
5299
|
+
throw error;
|
|
5300
|
+
}
|
|
5301
|
+
}
|
|
5302
|
+
async loadNextPageFollowers(request) {
|
|
5303
|
+
await this.loadNextPageFollows('followers', request);
|
|
5304
|
+
}
|
|
5305
|
+
async loadNextPageFollowing(request) {
|
|
5306
|
+
await this.loadNextPageFollows('following', request);
|
|
5307
|
+
}
|
|
5308
|
+
async loadNextPageMembers(request) {
|
|
5309
|
+
const currentMembers = this.currentState.members;
|
|
5310
|
+
const currentNextCursor = this.currentState.member_pagination?.next;
|
|
5311
|
+
const isLoading = this.currentState.member_pagination?.loading_next_page;
|
|
5312
|
+
const sort = this.currentState.member_pagination?.sort ?? request.sort;
|
|
5313
|
+
let error;
|
|
5314
|
+
if (isLoading || !checkHasAnotherPage(currentMembers, currentNextCursor)) {
|
|
5315
|
+
return;
|
|
5316
|
+
}
|
|
5317
|
+
try {
|
|
5318
|
+
this.state.next((currentState) => ({
|
|
5319
|
+
...currentState,
|
|
5320
|
+
member_pagination: {
|
|
5321
|
+
...currentState.member_pagination,
|
|
5322
|
+
loading_next_page: true,
|
|
5323
|
+
},
|
|
5324
|
+
}));
|
|
5325
|
+
const { next: newNextCursor, members } = await this.client.queryFeedMembers({
|
|
5326
|
+
...request,
|
|
5327
|
+
sort,
|
|
5328
|
+
feed_id: this.id,
|
|
5329
|
+
feed_group_id: this.group,
|
|
5330
|
+
next: currentNextCursor,
|
|
5346
5331
|
});
|
|
5332
|
+
this.state.next((currentState) => ({
|
|
5333
|
+
...currentState,
|
|
5334
|
+
members: currentState.members
|
|
5335
|
+
? uniqueArrayMerge(currentState.members, members, ({ user }) => user.id)
|
|
5336
|
+
: members,
|
|
5337
|
+
member_pagination: {
|
|
5338
|
+
...currentState.member_pagination,
|
|
5339
|
+
next: newNextCursor,
|
|
5340
|
+
// set sort if not defined yet
|
|
5341
|
+
sort: currentState.member_pagination?.sort ?? request.sort,
|
|
5342
|
+
},
|
|
5343
|
+
}));
|
|
5344
|
+
}
|
|
5345
|
+
catch (e) {
|
|
5346
|
+
error = e;
|
|
5347
|
+
}
|
|
5348
|
+
finally {
|
|
5349
|
+
this.state.next((currentState) => ({
|
|
5350
|
+
...currentState,
|
|
5351
|
+
member_pagination: {
|
|
5352
|
+
...currentState.member_pagination,
|
|
5353
|
+
loading_next_page: false,
|
|
5354
|
+
},
|
|
5355
|
+
}));
|
|
5356
|
+
}
|
|
5357
|
+
if (error) {
|
|
5358
|
+
throw error;
|
|
5359
|
+
}
|
|
5360
|
+
}
|
|
5361
|
+
/**
|
|
5362
|
+
* Method which queries followers of this feed (feeds which target this feed).
|
|
5363
|
+
*
|
|
5364
|
+
* _Note: Useful only for feeds with `groupId` of `user` value._
|
|
5365
|
+
*/
|
|
5366
|
+
async queryFollowers(request) {
|
|
5367
|
+
const filter = {
|
|
5368
|
+
target_feed: this.fid,
|
|
5347
5369
|
};
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5370
|
+
const response = await this.client.queryFollows({
|
|
5371
|
+
filter,
|
|
5372
|
+
...request,
|
|
5373
|
+
});
|
|
5374
|
+
return response;
|
|
5351
5375
|
}
|
|
5352
|
-
|
|
5353
|
-
|
|
5376
|
+
/**
|
|
5377
|
+
* Method which queries following of this feed (target feeds of this feed).
|
|
5378
|
+
*
|
|
5379
|
+
* _Note: Useful only for feeds with `groupId` of `timeline` value._
|
|
5380
|
+
*/
|
|
5381
|
+
async queryFollowing(request) {
|
|
5382
|
+
const filter = {
|
|
5383
|
+
source_feed: this.fid,
|
|
5384
|
+
};
|
|
5385
|
+
const response = await this.client.queryFollows({
|
|
5386
|
+
filter,
|
|
5387
|
+
...request,
|
|
5388
|
+
});
|
|
5389
|
+
return response;
|
|
5354
5390
|
}
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5391
|
+
async follow(feedOrFid, options) {
|
|
5392
|
+
const fid = typeof feedOrFid === 'string' ? feedOrFid : feedOrFid.fid;
|
|
5393
|
+
const response = await this.client.follow({
|
|
5394
|
+
...options,
|
|
5395
|
+
source: this.fid,
|
|
5396
|
+
target: fid,
|
|
5397
|
+
});
|
|
5398
|
+
return response;
|
|
5399
|
+
}
|
|
5400
|
+
async unfollow(feedOrFid) {
|
|
5401
|
+
const fid = typeof feedOrFid === 'string' ? feedOrFid : feedOrFid.fid;
|
|
5402
|
+
const response = await this.client.unfollow({
|
|
5403
|
+
source: this.fid,
|
|
5404
|
+
target: fid,
|
|
5405
|
+
});
|
|
5406
|
+
return response;
|
|
5407
|
+
}
|
|
5408
|
+
async getNextPage() {
|
|
5409
|
+
const currentState = this.currentState;
|
|
5410
|
+
return await this.getOrCreate({
|
|
5411
|
+
member_pagination: {
|
|
5412
|
+
limit: 0,
|
|
5413
|
+
},
|
|
5414
|
+
followers_pagination: {
|
|
5415
|
+
limit: 0,
|
|
5416
|
+
},
|
|
5417
|
+
following_pagination: {
|
|
5418
|
+
limit: 0,
|
|
5419
|
+
},
|
|
5420
|
+
next: currentState.next,
|
|
5421
|
+
limit: currentState.last_get_or_create_request_config?.limit ?? 20,
|
|
5422
|
+
});
|
|
5423
|
+
}
|
|
5424
|
+
addActivity(request) {
|
|
5425
|
+
return this.feedsApi.addActivity({
|
|
5426
|
+
...request,
|
|
5427
|
+
fids: [this.fid],
|
|
5428
|
+
});
|
|
5429
|
+
}
|
|
5430
|
+
handleWSEvent(event) {
|
|
5431
|
+
const eventHandler = this.eventHandlers[event.type];
|
|
5432
|
+
// no need to run noop function
|
|
5433
|
+
if (eventHandler !== Feed.noop) {
|
|
5434
|
+
// @ts-expect-error intersection of handler arguments results to never
|
|
5435
|
+
eventHandler?.(event);
|
|
5363
5436
|
}
|
|
5364
|
-
|
|
5365
|
-
|
|
5437
|
+
if (typeof eventHandler === 'undefined') {
|
|
5438
|
+
console.warn(`Received unknown event type: ${event.type}`, event);
|
|
5366
5439
|
}
|
|
5440
|
+
this.eventDispatcher.dispatch(event);
|
|
5367
5441
|
}
|
|
5368
|
-
return winningOptions;
|
|
5369
|
-
}
|
|
5370
|
-
function getOwnVotesByOptionId(ownVotes) {
|
|
5371
|
-
return !ownVotes
|
|
5372
|
-
? {}
|
|
5373
|
-
: ownVotes.reduce((acc, vote) => {
|
|
5374
|
-
if (isVoteAnswer(vote) || !vote.option_id)
|
|
5375
|
-
return acc;
|
|
5376
|
-
acc[vote.option_id] = vote;
|
|
5377
|
-
return acc;
|
|
5378
|
-
}, {});
|
|
5379
5442
|
}
|
|
5443
|
+
Feed.noop = () => { };
|
|
5380
5444
|
|
|
5381
5445
|
class FeedsClient extends FeedsApi {
|
|
5382
5446
|
constructor(apiKey, options) {
|
|
@@ -5636,13 +5700,23 @@ class FeedsClient extends FeedsApi {
|
|
|
5636
5700
|
duration: response.duration,
|
|
5637
5701
|
};
|
|
5638
5702
|
}
|
|
5703
|
+
async updateFollow(request) {
|
|
5704
|
+
const response = await super.updateFollow(request);
|
|
5705
|
+
[response.follow.source_feed.fid, response.follow.target_feed.fid].forEach((fid) => {
|
|
5706
|
+
const feed = this.activeFeeds[fid];
|
|
5707
|
+
if (feed) {
|
|
5708
|
+
handleFollowUpdated.bind(feed)(response);
|
|
5709
|
+
}
|
|
5710
|
+
});
|
|
5711
|
+
return response;
|
|
5712
|
+
}
|
|
5639
5713
|
// For follow API endpoints we update the state after HTTP response to allow queryFeeds with watch: false
|
|
5640
5714
|
async follow(request) {
|
|
5641
5715
|
const response = await super.follow(request);
|
|
5642
5716
|
[response.follow.source_feed.fid, response.follow.target_feed.fid].forEach((fid) => {
|
|
5643
5717
|
const feed = this.activeFeeds[fid];
|
|
5644
5718
|
if (feed) {
|
|
5645
|
-
|
|
5719
|
+
handleFollowCreated.bind(feed)(response);
|
|
5646
5720
|
}
|
|
5647
5721
|
});
|
|
5648
5722
|
return response;
|
|
@@ -5652,7 +5726,7 @@ class FeedsClient extends FeedsApi {
|
|
|
5652
5726
|
response.follows.forEach((follow) => {
|
|
5653
5727
|
const feed = this.activeFeeds[follow.source_feed.fid];
|
|
5654
5728
|
if (feed) {
|
|
5655
|
-
|
|
5729
|
+
handleFollowCreated.bind(feed)({ follow });
|
|
5656
5730
|
}
|
|
5657
5731
|
});
|
|
5658
5732
|
return response;
|
|
@@ -5662,10 +5736,7 @@ class FeedsClient extends FeedsApi {
|
|
|
5662
5736
|
[request.source, request.target].forEach((fid) => {
|
|
5663
5737
|
const feed = this.activeFeeds[fid];
|
|
5664
5738
|
if (feed) {
|
|
5665
|
-
|
|
5666
|
-
source_feed: { fid: request.source },
|
|
5667
|
-
target_feed: { fid: request.target },
|
|
5668
|
-
});
|
|
5739
|
+
handleFollowDeleted.bind(feed)(response);
|
|
5669
5740
|
}
|
|
5670
5741
|
});
|
|
5671
5742
|
return response;
|
|
@@ -5761,6 +5832,7 @@ const FeedOwnCapability = {
|
|
|
5761
5832
|
const DEFAULT_SEARCH_SOURCE_OPTIONS = {
|
|
5762
5833
|
debounceMs: 300,
|
|
5763
5834
|
pageSize: 10,
|
|
5835
|
+
allowEmptySearchString: false,
|
|
5764
5836
|
};
|
|
5765
5837
|
class BaseSearchSource {
|
|
5766
5838
|
constructor(options) {
|
|
@@ -5783,14 +5855,15 @@ class BaseSearchSource {
|
|
|
5783
5855
|
return !!(this.isActive &&
|
|
5784
5856
|
!this.isLoading &&
|
|
5785
5857
|
(this.hasNext || hasNewSearchQuery) &&
|
|
5786
|
-
searchString);
|
|
5858
|
+
(this.allowEmptySearchString || searchString));
|
|
5787
5859
|
};
|
|
5788
5860
|
this.search = (searchQuery) => this.searchDebounced(searchQuery);
|
|
5789
|
-
const { debounceMs, pageSize } = {
|
|
5861
|
+
const { debounceMs, pageSize, allowEmptySearchString } = {
|
|
5790
5862
|
...DEFAULT_SEARCH_SOURCE_OPTIONS,
|
|
5791
5863
|
...options,
|
|
5792
5864
|
};
|
|
5793
5865
|
this.pageSize = pageSize;
|
|
5866
|
+
this.allowEmptySearchString = allowEmptySearchString;
|
|
5794
5867
|
this.state = new StateStore(this.initialState);
|
|
5795
5868
|
this.setDebounceOptions({ debounceMs });
|
|
5796
5869
|
}
|
|
@@ -6006,12 +6079,6 @@ class SearchController {
|
|
|
6006
6079
|
}
|
|
6007
6080
|
|
|
6008
6081
|
class ActivitySearchSource extends BaseSearchSource {
|
|
6009
|
-
// messageSearchChannelFilters: ChannelFilters | undefined;
|
|
6010
|
-
// messageSearchFilters: MessageFilters | undefined;
|
|
6011
|
-
// messageSearchSort: SearchMessageSort | undefined;
|
|
6012
|
-
// channelQueryFilters: ChannelFilters | undefined;
|
|
6013
|
-
// channelQuerySort: ChannelSort | undefined;
|
|
6014
|
-
// channelQueryOptions: Omit<ChannelOptions, 'limit' | 'offset'> | undefined;
|
|
6015
6082
|
constructor(client, options) {
|
|
6016
6083
|
super(options);
|
|
6017
6084
|
this.type = 'activity';
|
|
@@ -6023,7 +6090,9 @@ class ActivitySearchSource extends BaseSearchSource {
|
|
|
6023
6090
|
return { items: [] };
|
|
6024
6091
|
const { activities: items, next } = await this.client.queryActivities({
|
|
6025
6092
|
sort: [{ direction: -1, field: 'created_at' }],
|
|
6026
|
-
|
|
6093
|
+
...(!this.allowEmptySearchString || searchQuery.length > 0
|
|
6094
|
+
? { filter: { text: { $autocomplete: searchQuery } } }
|
|
6095
|
+
: {}),
|
|
6027
6096
|
limit: 10,
|
|
6028
6097
|
next: this.next ?? undefined,
|
|
6029
6098
|
});
|
|
@@ -6033,19 +6102,8 @@ class ActivitySearchSource extends BaseSearchSource {
|
|
|
6033
6102
|
return items;
|
|
6034
6103
|
}
|
|
6035
6104
|
}
|
|
6036
|
-
// filter: {
|
|
6037
|
-
// 'feed.name': { $autocomplete: searchQuery }
|
|
6038
|
-
// 'feed.description': { $autocomplete: searchQuery }
|
|
6039
|
-
// 'created_by.name': { $autocomplete: searchQuery }
|
|
6040
|
-
// },
|
|
6041
6105
|
|
|
6042
6106
|
class UserSearchSource extends BaseSearchSource {
|
|
6043
|
-
// messageSearchChannelFilters: ChannelFilters | undefined;
|
|
6044
|
-
// messageSearchFilters: MessageFilters | undefined;
|
|
6045
|
-
// messageSearchSort: SearchMessageSort | undefined;
|
|
6046
|
-
// channelQueryFilters: ChannelFilters | undefined;
|
|
6047
|
-
// channelQuerySort: ChannelSort | undefined;
|
|
6048
|
-
// channelQueryOptions: Omit<ChannelOptions, 'limit' | 'offset'> | undefined;
|
|
6049
6107
|
constructor(client, options) {
|
|
6050
6108
|
super(options);
|
|
6051
6109
|
this.type = 'user';
|
|
@@ -6055,57 +6113,16 @@ class UserSearchSource extends BaseSearchSource {
|
|
|
6055
6113
|
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
6056
6114
|
if (!connectedUser)
|
|
6057
6115
|
return { items: [] };
|
|
6058
|
-
// const channelFilters: ChannelFilters = {
|
|
6059
|
-
// members: { $in: [this.client.userID] },
|
|
6060
|
-
// ...this.messageSearchChannelFilters,
|
|
6061
|
-
// } as ChannelFilters;
|
|
6062
|
-
// const messageFilters: MessageFilters = {
|
|
6063
|
-
// text: searchQuery,
|
|
6064
|
-
// type: 'regular', // FIXME: type: 'reply' resp. do not filter by type and allow to jump to a message in a thread - missing support
|
|
6065
|
-
// ...this.messageSearchFilters,
|
|
6066
|
-
// } as MessageFilters;
|
|
6067
|
-
// const sort: SearchMessageSort = {
|
|
6068
|
-
// created_at: -1,
|
|
6069
|
-
// ...this.messageSearchSort,
|
|
6070
|
-
// };
|
|
6071
|
-
// const options = {
|
|
6072
|
-
// limit: this.pageSize,
|
|
6073
|
-
// next: this.next,
|
|
6074
|
-
// sort,
|
|
6075
|
-
// } as SearchOptions;
|
|
6076
|
-
// const { next, results } = await this.client.search(
|
|
6077
|
-
// channelFilters,
|
|
6078
|
-
// messageFilters,
|
|
6079
|
-
// options,
|
|
6080
|
-
// );
|
|
6081
|
-
// const items = results.map(({ message }) => message);
|
|
6082
|
-
// const cids = Array.from(
|
|
6083
|
-
// items.reduce((acc, message) => {
|
|
6084
|
-
// if (message.cid && !this.client.activeChannels[message.cid])
|
|
6085
|
-
// acc.add(message.cid);
|
|
6086
|
-
// return acc;
|
|
6087
|
-
// }, new Set<string>()), // keep the cids unique
|
|
6088
|
-
// );
|
|
6089
|
-
// const allChannelsLoadedLocally = cids.length === 0;
|
|
6090
|
-
// if (!allChannelsLoadedLocally) {
|
|
6091
|
-
// await this.client.queryChannels(
|
|
6092
|
-
// {
|
|
6093
|
-
// cid: { $in: cids },
|
|
6094
|
-
// ...this.channelQueryFilters,
|
|
6095
|
-
// } as ChannelFilters,
|
|
6096
|
-
// {
|
|
6097
|
-
// last_message_at: -1,
|
|
6098
|
-
// ...this.channelQuerySort,
|
|
6099
|
-
// },
|
|
6100
|
-
// this.channelQueryOptions,
|
|
6101
|
-
// );
|
|
6102
|
-
// }
|
|
6103
6116
|
const { users: items } = await this.client.queryUsers({
|
|
6104
6117
|
payload: {
|
|
6105
6118
|
filter_conditions: {
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6119
|
+
...(!this.allowEmptySearchString || searchQuery.length > 0
|
|
6120
|
+
? {
|
|
6121
|
+
name: {
|
|
6122
|
+
$autocomplete: searchQuery,
|
|
6123
|
+
},
|
|
6124
|
+
}
|
|
6125
|
+
: {}),
|
|
6109
6126
|
},
|
|
6110
6127
|
},
|
|
6111
6128
|
});
|
|
@@ -6117,75 +6134,30 @@ class UserSearchSource extends BaseSearchSource {
|
|
|
6117
6134
|
}
|
|
6118
6135
|
|
|
6119
6136
|
class FeedSearchSource extends BaseSearchSource {
|
|
6120
|
-
// messageSearchChannelFilters: ChannelFilters | undefined;
|
|
6121
|
-
// messageSearchFilters: MessageFilters | undefined;
|
|
6122
|
-
// messageSearchSort: SearchMessageSort | undefined;
|
|
6123
|
-
// channelQueryFilters: ChannelFilters | undefined;
|
|
6124
|
-
// channelQuerySort: ChannelSort | undefined;
|
|
6125
|
-
// channelQueryOptions: Omit<ChannelOptions, 'limit' | 'offset'> | undefined;
|
|
6126
6137
|
constructor(client, options) {
|
|
6127
6138
|
super(options);
|
|
6128
6139
|
this.type = 'feed';
|
|
6129
6140
|
this.client = client;
|
|
6141
|
+
this.feedGroupId = options?.groupId;
|
|
6130
6142
|
}
|
|
6131
6143
|
async query(searchQuery) {
|
|
6132
6144
|
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
6133
6145
|
if (!connectedUser)
|
|
6134
6146
|
return { items: [] };
|
|
6135
|
-
// const channelFilters: ChannelFilters = {
|
|
6136
|
-
// members: { $in: [this.client.userID] },
|
|
6137
|
-
// ...this.messageSearchChannelFilters,
|
|
6138
|
-
// } as ChannelFilters;
|
|
6139
|
-
// const messageFilters: MessageFilters = {
|
|
6140
|
-
// text: searchQuery,
|
|
6141
|
-
// type: 'regular', // FIXME: type: 'reply' resp. do not filter by type and allow to jump to a message in a thread - missing support
|
|
6142
|
-
// ...this.messageSearchFilters,
|
|
6143
|
-
// } as MessageFilters;
|
|
6144
|
-
// const sort: SearchMessageSort = {
|
|
6145
|
-
// created_at: -1,
|
|
6146
|
-
// ...this.messageSearchSort,
|
|
6147
|
-
// };
|
|
6148
|
-
// const options = {
|
|
6149
|
-
// limit: this.pageSize,
|
|
6150
|
-
// next: this.next,
|
|
6151
|
-
// sort,
|
|
6152
|
-
// } as SearchOptions;
|
|
6153
|
-
// const { next, results } = await this.client.search(
|
|
6154
|
-
// channelFilters,
|
|
6155
|
-
// messageFilters,
|
|
6156
|
-
// options,
|
|
6157
|
-
// );
|
|
6158
|
-
// const items = results.map(({ message }) => message);
|
|
6159
|
-
// const cids = Array.from(
|
|
6160
|
-
// items.reduce((acc, message) => {
|
|
6161
|
-
// if (message.cid && !this.client.activeChannels[message.cid])
|
|
6162
|
-
// acc.add(message.cid);
|
|
6163
|
-
// return acc;
|
|
6164
|
-
// }, new Set<string>()), // keep the cids unique
|
|
6165
|
-
// );
|
|
6166
|
-
// const allChannelsLoadedLocally = cids.length === 0;
|
|
6167
|
-
// if (!allChannelsLoadedLocally) {
|
|
6168
|
-
// await this.client.queryChannels(
|
|
6169
|
-
// {
|
|
6170
|
-
// cid: { $in: cids },
|
|
6171
|
-
// ...this.channelQueryFilters,
|
|
6172
|
-
// } as ChannelFilters,
|
|
6173
|
-
// {
|
|
6174
|
-
// last_message_at: -1,
|
|
6175
|
-
// ...this.channelQuerySort,
|
|
6176
|
-
// },
|
|
6177
|
-
// this.channelQueryOptions,
|
|
6178
|
-
// );
|
|
6179
|
-
// }
|
|
6180
6147
|
const { feeds: items, next } = await this.client.queryFeeds({
|
|
6181
6148
|
filter: {
|
|
6182
|
-
group_id:
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6149
|
+
...(this.feedGroupId ? { group_id: this.feedGroupId } : {}),
|
|
6150
|
+
...(!this.allowEmptySearchString || searchQuery.length > 0
|
|
6151
|
+
? {
|
|
6152
|
+
$or: [
|
|
6153
|
+
{ name: { $autocomplete: searchQuery } },
|
|
6154
|
+
{ description: { $autocomplete: searchQuery } },
|
|
6155
|
+
{ 'created_by.name': { $autocomplete: searchQuery } },
|
|
6156
|
+
],
|
|
6157
|
+
}
|
|
6158
|
+
: {}),
|
|
6188
6159
|
},
|
|
6160
|
+
next: this.next ?? undefined,
|
|
6189
6161
|
});
|
|
6190
6162
|
return { items, next };
|
|
6191
6163
|
}
|
|
@@ -6209,10 +6181,13 @@ exports.StreamApiError = StreamApiError;
|
|
|
6209
6181
|
exports.StreamPoll = StreamPoll;
|
|
6210
6182
|
exports.UserSearchSource = UserSearchSource;
|
|
6211
6183
|
exports.checkHasAnotherPage = checkHasAnotherPage;
|
|
6184
|
+
exports.getStateUpdateQueueId = getStateUpdateQueueId;
|
|
6212
6185
|
exports.isCommentResponse = isCommentResponse;
|
|
6186
|
+
exports.isFollowResponse = isFollowResponse;
|
|
6213
6187
|
exports.isImageFile = isImageFile;
|
|
6214
6188
|
exports.isPatch = isPatch;
|
|
6215
6189
|
exports.isVideoFile = isVideoFile;
|
|
6216
6190
|
exports.isVoteAnswer = isVoteAnswer;
|
|
6191
|
+
exports.shouldUpdateState = shouldUpdateState;
|
|
6217
6192
|
exports.uniqueArrayMerge = uniqueArrayMerge;
|
|
6218
6193
|
//# sourceMappingURL=index.browser.cjs.map
|