Skip to content

Commit

Permalink
Adding a GraphQL mutation to send a custom message to a tipline user
Browse files Browse the repository at this point in the history
* New Smooch Bot class method to send a custom message to a tipline user (uses template for WhatsApp)
* Expose that method as a GraphQL mutation
* Permission check
* Functional tests
* Rake task to add a new tipline setting field for the new WhatsApp template

Reference: CV2-3677.
  • Loading branch information
caiosba authored Sep 27, 2023
1 parent 55beb5c commit b9d17be
Show file tree
Hide file tree
Showing 9 changed files with 276 additions and 2 deletions.
19 changes: 19 additions & 0 deletions app/graph/mutations/tipline_message_mutations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module TiplineMessageMutations
class Send < Mutations::BaseMutation
argument :uid, GraphQL::Types::ID, required: true
argument :message, GraphQL::Types::String, required: true
argument :timestamp, GraphQL::Types::Int, required: true
argument :language, GraphQL::Types::String, required: true

field :success, GraphQL::Types::Boolean, null: true

def resolve(uid: nil, message: nil, timestamp: nil, language: nil)
ability = context[:ability] || Ability.new
success = false
if Team.current&.id && User.current&.id && ability.can?(:send, TiplineMessage.new(team: Team.current))
success = Bot::Smooch.send_custom_message_to_user(Team.current, uid, timestamp, message, language)
end
{ success: success }
end
end
end
2 changes: 2 additions & 0 deletions app/graph/types/mutation_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,6 @@ class MutationType < BaseObject
field :createTiplineResource, mutation: TiplineResourceMutations::Create
field :updateTiplineResource, mutation: TiplineResourceMutations::Update
field :destroyTiplineResource, mutation: TiplineResourceMutations::Destroy

field :sendTiplineMessage, mutation: TiplineMessageMutations::Send
end
3 changes: 3 additions & 0 deletions app/models/ability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ def editor_perms
can :update, FeedTeam do |obj|
obj.team_id == @context_team.id
end
can :send, TiplineMessage do |obj|
obj.team_id == @context_team.id
end
end

def collaborator_perms
Expand Down
8 changes: 6 additions & 2 deletions app/models/bot/smooch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -624,8 +624,7 @@ def self.api_get_app_name(app_id)
def self.save_user_information(app_id, uid, payload_json)
payload = JSON.parse(payload_json)
self.get_installation(self.installation_setting_id_keys, app_id) if self.config.blank?
# FIXME Shouldn't we make sure this is an annotation in the right project?
field = DynamicAnnotation::Field.where('field_name = ? AND dynamic_annotation_fields_value(field_name, value) = ?', 'smooch_user_id', uid.to_json).last
field = DynamicAnnotation::Field.where(field_name: 'smooch_user_id', value: uid).last
if field.nil?
user = self.api_get_user_data(uid, payload)
app_name = self.api_get_app_name(app_id)
Expand Down Expand Up @@ -660,6 +659,11 @@ def self.save_user_information(app_id, uid, payload_json)
end
end

def self.get_user_platform(uid)
type = begin JSON.parse(DynamicAnnotation::Field.where(field_name: 'smooch_user_id', value: uid).last.annotation.load.get_field_value('smooch_user_data')).dig('raw', 'clients', 0, 'platform') rescue nil end
type ? ::Bot::Smooch::SUPPORTED_INTEGRATION_NAMES[type].to_s : 'Unknown'
end

def self.get_identifier(user, uid)
# This identifier is used on the Slack side in order to connect a Slack conversation to a Smooch user
identifier = case user.dig(:clients, 0, :platform)
Expand Down
12 changes: 12 additions & 0 deletions app/models/concerns/smooch_messages.rb
Original file line number Diff line number Diff line change
Expand Up @@ -436,5 +436,17 @@ def send_message_to_user_on_timeout(uid, language)
self.send_message_to_user(uid, message) if user_messages_count > 0 && sm.state.value != 'main'
sm.reset
end

def send_custom_message_to_user(team, uid, timestamp, message, language)
platform = self.get_user_platform(uid)
RequestStore.store[:smooch_bot_platform] = platform
tbi = TeamBotInstallation.where(team: team, user: BotUser.smooch_user).last
Bot::Smooch.get_installation('team_bot_installation_id', tbi&.id) { |i| i.id == tbi&.id }
date = I18n.l(Time.at(timestamp), locale: language, format: :short)
message = self.format_template_message('custom_message', [date, message.to_s.gsub(/\s+/, ' ')], nil, message, language, nil, true) if platform == 'WhatsApp'
response = self.send_message_to_user(uid, message)
success = (response.code.to_i < 400)
success
end
end
end
31 changes: 31 additions & 0 deletions lib/relay.idl
Original file line number Diff line number Diff line change
Expand Up @@ -9577,6 +9577,12 @@ type MutationType {
"""
input: SearchUploadInput!
): SearchUploadPayload
sendTiplineMessage(
"""
Parameters for Send
"""
input: SendInput!
): SendPayload
smoochBotAddIntegration(
"""
Parameters for SmoochBotAddIntegration
Expand Down Expand Up @@ -11952,6 +11958,31 @@ type SearchUploadPayload {
file_url: String
}

"""
Autogenerated input type of Send
"""
input SendInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
language: String!
message: String!
timestamp: Int!
uid: ID!
}

"""
Autogenerated return type of Send
"""
type SendPayload {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
success: Boolean
}

"""
Autogenerated input type of SmoochBotAddIntegration
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace :check do
namespace :migrate do
task add_custom_message_template_name_to_smooch_bot: :environment do |_t, _args|
tb = BotUser.smooch_user
unless tb.nil?
settings = tb.get_settings.clone || []
# Add new template setting for custom message
settings << {
name: 'smooch_template_name_for_custom_message',
label: "Template name for template 'custom_message'",
type: 'string',
default: ''
}
tb.set_settings(settings)
tb.save!
end
end
end
end
157 changes: 157 additions & 0 deletions public/relay.json
Original file line number Diff line number Diff line change
Expand Up @@ -51610,6 +51610,35 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "sendTiplineMessage",
"description": null,
"args": [
{
"name": "input",
"description": "Parameters for Send",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "SendInput",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"type": {
"kind": "OBJECT",
"name": "SendPayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "smoochBotAddIntegration",
"description": null,
Expand Down Expand Up @@ -62744,6 +62773,134 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "SendInput",
"description": "Autogenerated input type of Send",
"fields": null,
"inputFields": [
{
"name": "uid",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "message",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "timestamp",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "language",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "SendPayload",
"description": "Autogenerated return type of Send",
"fields": [
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"args": [

],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "success",
"description": null,
"args": [

],
"type": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [

],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "SmoochBotAddIntegrationInput",
Expand Down
27 changes: 27 additions & 0 deletions test/controllers/graphql_controller_10_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -778,4 +778,31 @@ def setup
assert_response :success
assert_equal [pm2.id], JSON.parse(@response.body)['data']['search']['medias']['edges'].collect{ |x| x['node']['dbid'] }
end

test "should send custom message to user" do
Bot::Smooch.stubs(:send_message_to_user).returns(OpenStruct.new(code: 200)).once
u = create_user
t = create_team
create_team_user user: u, team: t, role: 'editor'
authenticate_with_user(u)

query = 'mutation { sendTiplineMessage(input: { clientMutationId: "1", uid: "123456", message: "Hello", language: "en", timestamp: 1695692221 }) { success } }'
post :create, params: { query: query, team: t.slug }

assert_response :success
assert JSON.parse(@response.body)['data']['sendTiplineMessage']['success']
end

test "should not send custom message to user" do
Bot::Smooch.stubs(:send_message_to_user).returns(OpenStruct.new(code: 200)).never
u = create_user
t = create_team
authenticate_with_user(u)

query = 'mutation { sendTiplineMessage(input: { clientMutationId: "1", uid: "123456", message: "Hello", language: "en", timestamp: 1695692221 }) { success } }'
post :create, params: { query: query, team: t.slug }

assert_response :success
assert !JSON.parse(@response.body)['data']['sendTiplineMessage']['success']
end
end

0 comments on commit b9d17be

Please sign in to comment.