From 2a11f03ce4e4002355e88bda103d1a633f7218af Mon Sep 17 00:00:00 2001 From: Varsh Date: Wed, 4 Jun 2025 17:21:15 +0200 Subject: [PATCH 1/4] add userprofile to moderation entity types --- lib/stream-chat/moderation.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/stream-chat/moderation.rb b/lib/stream-chat/moderation.rb index 1e77b44..58c3175 100644 --- a/lib/stream-chat/moderation.rb +++ b/lib/stream-chat/moderation.rb @@ -14,7 +14,8 @@ class Moderation MODERATION_ENTITY_TYPES = T.let( { user: 'stream:user', - message: 'stream:chat:v1:message' + message: 'stream:chat:v1:message', + userprofile: 'stream:v1:user_profile', }.freeze, T::Hash[Symbol, String] ) From 72a5713f5ee9766673ac97d8849a3a5947e292fe Mon Sep 17 00:00:00 2001 From: Varsh Date: Thu, 5 Jun 2025 12:19:24 +0200 Subject: [PATCH 2/4] add check_user_profile function --- lib/stream-chat/moderation.rb | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lib/stream-chat/moderation.rb b/lib/stream-chat/moderation.rb index 58c3175..cf758bb 100644 --- a/lib/stream-chat/moderation.rb +++ b/lib/stream-chat/moderation.rb @@ -25,6 +25,45 @@ def initialize(client) @client = client end + # Experimental: Check user profile + # + # Warning: This is an experimental feature and the API is subject to change. + # + # This function is used to check a user profile for moderation. + # This will not create any review queue items for the user profile. + # You can just use this to check whether to allow a certain user profile to be created or not. + # + # @param [string] user_id User ID to be checked + # @param [Hash] profile Profile data to be checked + # @option profile [String] :username Username to be checked + # @option profile [String] :image Image URL to be checked + # @return [StreamChat::StreamResponse] + sig do + params( + user_id: String, + profile: T::Hash[Symbol, T.nilable(String)] + ).returns(StreamChat::StreamResponse) + end + def check_user_profile(user_id, profile) + raise ArgumentError, 'Either username or image must be provided' if profile[:username].nil? && profile[:image].nil? + + moderation_payload = {} + moderation_payload[:texts] = [profile[:username]] if profile[:username] + moderation_payload[:images] = [profile[:image]] if profile[:image] + + check( + T.must(MODERATION_ENTITY_TYPES[:userprofile]), + user_id, + moderation_payload, + 'user_profile:default', + entity_creator_id: user_id, + options: { + force_sync: true, + test_mode: true + } + ) + end + # Flags a user with a reason # # @param [string] flagged_user_id User ID to be flagged From 3ca082bf605edceb23d98824fef76945d344ce93 Mon Sep 17 00:00:00 2001 From: Varsh Date: Thu, 5 Jun 2025 12:45:33 +0200 Subject: [PATCH 3/4] add tests --- lib/stream-chat/moderation.rb | 5 ++++- spec/moderation_spec.rb | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/stream-chat/moderation.rb b/lib/stream-chat/moderation.rb index cf758bb..6802f5c 100644 --- a/lib/stream-chat/moderation.rb +++ b/lib/stream-chat/moderation.rb @@ -15,7 +15,7 @@ class Moderation { user: 'stream:user', message: 'stream:chat:v1:message', - userprofile: 'stream:v1:user_profile', + userprofile: 'stream:v1:user_profile' }.freeze, T::Hash[Symbol, String] ) @@ -38,6 +38,9 @@ def initialize(client) # @option profile [String] :username Username to be checked # @option profile [String] :image Image URL to be checked # @return [StreamChat::StreamResponse] + # + # example: + # client.moderation.check_user_profile('user-id', {username: 'bad_username', image: 'https://example.com/profile.jpg'}) sig do params( user_id: String, diff --git a/spec/moderation_spec.rb b/spec/moderation_spec.rb index 6b0bc74..20b05ce 100644 --- a/spec/moderation_spec.rb +++ b/spec/moderation_spec.rb @@ -159,6 +159,24 @@ def loop_times(times) expect(response['duration']).not_to be_nil end + it 'check user profile' do + response = @moderation.check_user_profile( + @test_user_id, + { username: 'fuck_you_123' } + ) + expect(response['duration']).not_to be_nil + expect(response['status']).to eq('complete') + expect(response['recommended_action']).to eq('remove') + + response = @moderation.check_user_profile( + @test_user_id, + { username: 'hi' } + ) + expect(response['duration']).not_to be_nil + expect(response['status']).to eq('complete') + expect(response['recommended_action']).to eq('keep') + end + it 'config test' do # Create moderation config moderation_config = { From 495624d9433aba3c1d9db32c8efe5af3e7b891c1 Mon Sep 17 00:00:00 2001 From: Varsh Date: Thu, 5 Jun 2025 13:06:28 +0200 Subject: [PATCH 4/4] silence C: Naming/PredicateMethod --- .rubocop.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.rubocop.yml b/.rubocop.yml index 72100a7..819d3c9 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -35,3 +35,5 @@ Style/FrozenStringLiteralComment: Gemspec/RequireMFA: Enabled: false +Naming/PredicateMethod: + Enabled: false