Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automation rule content matching and thread renaming action v1 #445

Merged
merged 11 commits into from
Aug 5, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
<%= @form.hidden_field :id %>
<div class="flex gap-1">
<p class="text-base font-medium text-left text-gray-900"><%= t @form.object.type %></p>
<p class="text-base text-left text-gray-900"><%= @form.object.action_object.name %></p>
<% if @form.object.object_based? %>
<p class="text-base text-left text-gray-900"><%= @form.object.action_object.name %></p>
jsuchal marked this conversation as resolved.
Show resolved Hide resolved
<%= @form.hidden_field :value %>
<% else %>
<p class="text-base text-left text-gray-900"><%= @form.object.value %></p>
<% end %>
<%= @form.hidden_field :type %>
<%= @form.hidden_field :value %>
</div>
<%= @form.hidden_field :action_object_type %>
<%= @form.hidden_field :action_object_id %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@
<p class="flex-grow-0 flex-shrink-0 text-base text-left text-gray-500">
<% @automation_rule.actions.each_with_index do |action, index| %>
<span class="flex-grow-0 flex-shrink-0 text-base text-left text-gray-500"><%= t action.type %></span>
<span class="flex-grow-0 flex-shrink-0 text-base font-medium text-left text-gray-500"><%= action.action_object&.name %></span>
<%if index < @automation_rule.actions.length - 1%><%= ', '%><% end %>
<% if action.object_based? %>
<span class="flex-grow-0 flex-shrink-0 text-base font-medium text-left text-gray-500"><%= action.action_object&.name %></span>
<% else %>
<span class="flex-grow-0 flex-shrink-0 text-base font-medium text-left text-gray-500"><%= action.value %></span>
<% end %>
<% if index < @automation_rule.actions.length - 1 %><%= ', ' %><% end %>
<% end %>
</p>
</div>
Expand Down
27 changes: 26 additions & 1 deletion app/models/automation/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Action < ApplicationRecord
belongs_to :action_object, polymorphic: true, optional: true
attr_accessor :delete_record

ACTION_LIST = ['Automation::AddMessageThreadTagAction', 'Automation::FireWebhookAction'].freeze
ACTION_LIST = ['Automation::AddMessageThreadTagAction', 'Automation::FireWebhookAction', 'Automation::ChangeMessageThreadTitleAction'].freeze

def tag_list
automation_rule.tenant.tags.pluck(:name, :id)
Expand All @@ -40,6 +40,27 @@ def run!(thing, _event)
end
object.tags << tag if tag && object.tags.exclude?(tag)
end

def object_based?
true
end
end

class ChangeMessageThreadTitleAction < Automation::Action
def run!(thing, _event)
object = if thing.respond_to? :thread
thing.thread
else
thing
end
new_value = value.gsub("{{title}}", object.title)
object.title = new_value
object.save!
end

def object_based?
false
end
end

class FireWebhookAction < Action
Expand All @@ -49,5 +70,9 @@ def run!(thing, event)

FireWebhookJob.perform_later(webhook, thing, event, DateTime.now)
end

def object_based?
true
end
end
end
45 changes: 44 additions & 1 deletion app/models/automation/condition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Condition < ApplicationRecord
attr_accessor :delete_record

# when adding items, check defaults in condition_form_component.rb
ATTR_LIST = %i[box sender_name recipient_name title sender_uri recipient_uri].freeze
ATTR_LIST = %i[box sender_name recipient_name title sender_uri recipient_uri attachment].freeze

def valid_condition_type_list_for_attr
Automation::Condition.subclasses.map do |subclass|
Expand Down Expand Up @@ -80,4 +80,47 @@ def cleanup_record
self.attr = 'box'
end
end

class AttachmentContentContainsCondition < Automation::Condition
validates :value, presence: true
VALID_ATTR_LIST = ['attachment'].freeze

def satisfied?(thing)
thing.objects.each do |message_object|
return true if content_match?(message_object, value)

message_object.nested_message_objects.each do |nested_message_object|
return true if content_match?(nested_message_object, value)
end
end
false
end

def cleanup_record
self.condition_object = nil
end

private

def content_match?(object, value)
blob = object.message_object_datum.blob
if object.pdf?
pdf_match?(blob, value)
elsif object.xml?
blob.match?(value)
end
end

def pdf_match?(object, value)
io = StringIO.new
io.set_encoding Encoding::BINARY
io.write object
pdf_string = ""
PDF::Reader.open(io) do |pdf|
pdf_string = pdf.pages.map(&:text).join(" ")
end
io.close
pdf_string.match?(value)
end
end
end
14 changes: 11 additions & 3 deletions app/models/message_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def content

def unsigned_content(mimetypes: Utils::XML_MIMETYPES)
if is_signed
nested_message_objects&.where("mimetype ILIKE ANY ( array[?] )", mimetypes.map {|val| "#{val}%" })&.first&.content
nested_message_objects&.where("mimetype ILIKE ANY ( array[?] )", mimetypes.map { |val| "#{val}%" })&.first&.content
else
content
end
Expand Down Expand Up @@ -117,8 +117,16 @@ def assign_tag(tag)
end

def fill_missing_info
self.update(name: name + Utils.file_extension_by_mimetype(mimetype).to_s) if Utils.file_name_without_extension?(self)
self.update(mimetype: Utils.file_mimetype_by_name(entry_name: name)) if mimetype == Utils::OCTET_STREAM_MIMETYPE
update(name: name + Utils.file_extension_by_mimetype(mimetype).to_s) if Utils.file_name_without_extension?(self)
update(mimetype: Utils.file_mimetype_by_name(entry_name: name)) if mimetype == Utils::OCTET_STREAM_MIMETYPE
end

def pdf?
mimetype == Utils::PDF_MIMETYPE
end

def xml?
Utils::XML_MIMETYPES.any? { |xml_mimetype| xml_mimetype == Utils.mimetype_without_optional_params(mimetype) }
end

private
Expand Down
4 changes: 4 additions & 0 deletions app/models/nested_message_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,8 @@ def xml?
def unsigned_content
content
end

def pdf?
mimetype == Utils::PDF_MIMETYPE
end
end
3 changes: 3 additions & 0 deletions config/locales/sk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ sk:
sender_uri: "URI odosielateľa"
recipient_uri: "URI prijímateľa"
box: "Schránka správy"
attachment: "Príloha"
boxes:
sync_all_requested: "Sťahovanie nových správ bolo spustené."
message_created: "Nová správa"
Expand All @@ -271,10 +272,12 @@ sk:
message_thread_changed: "Zmena vo vlákne správ"
message_draft_submitted: "Odoslaná správa"
"Automation::ContainsCondition": "obsahuje"
"Automation::AttachmentContentContainsCondition": "obsahuje"
jsuchal marked this conversation as resolved.
Show resolved Hide resolved
"Automation::MetadataValueCondition": "v metadátach obsahuje"
"Automation::BoxCondition": "je"
"Automation::AddMessageThreadTagAction": "Pridaj štítok na vlákno"
"Automation::AddTagAction": "Pridaj štítok"
"Automation::ChangeMessageThreadTitleAction": "Premenuj vlákno"
"Automation::FireWebhookAction": "Zavolaj integráciu"
group:
names:
Expand Down
10 changes: 10 additions & 0 deletions test/fixtures/automation/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,13 @@ four:
automation_rule: four
type: Automation::AddMessageThreadTagAction
action_object: ssd_external_visible (Tag)

five:
automation_rule: five
type: Automation::AddMessageThreadTagAction
action_object: ssd_attachment_matched (Tag)

six:
automation_rule: five
type: Automation::ChangeMessageThreadTitleAction
value: "New title - {{title}}"
5 changes: 5 additions & 0 deletions test/fixtures/automation/conditions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ five:
automation_rule: four
type: Automation::BoxCondition
condition_object: ssd_main (Box)

six:
automation_rule: five
type: Automation::AttachmentContentContainsCondition
value: "Test\\s*string"
6 changes: 6 additions & 0 deletions test/fixtures/automation/rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,9 @@ four:
tenant: ssd
name: BoxConditionAddMessageThreadTagTagFive
trigger_event: message_thread_created

five:
user: basic
tenant: ssd
name: AttachmentContentContainsCondition
trigger_event: message_created
Binary file added test/fixtures/files/lorem_ipsum.pdf
Binary file not shown.
Binary file added test/fixtures/files/multiline_test.pdf
Binary file not shown.
Binary file added test/fixtures/files/multipage_test.pdf
Binary file not shown.
Binary file added test/fixtures/files/test_string.pdf
Binary file not shown.
22 changes: 22 additions & 0 deletions test/fixtures/govbox/messages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,25 @@ solver_delivery_notification:
signed: true
class: MyClass
content: MyContent

ssd_general_agenda_with_lorem_pdf:
message_id: <%= SecureRandom.uuid %>
correlation_id: a50cbb56-4da8-4499-b57c-e53c41b44930
edesk_message_id: 10
delivered_at: <%= DateTime.current %>
edesk_class: TEST
folder: ssd_one
payload:
message_id: <%= SecureRandom.uuid %>
subject: MySubject
sender_name: MySender
sender_uri: MySenderURI
recipient_name: MyRecipient
delivered_at: <%= DateTime.current.to_s %>
original_html: MyHtml
objects:
- name: MyName
mime_type: application/pdf
signed: true
class: MyClass
content: Dummy
6 changes: 6 additions & 0 deletions test/fixtures/tags.yml
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,9 @@ accountants_basic_user_signature_requested:
tenant: ssd
icon: pencil
color: yellow

ssd_attachment_matched:
name: AttachmentMatched
type: SimpleTag
visible: true
tenant: ssd
58 changes: 58 additions & 0 deletions test/models/automation/attachment_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
require 'test_helper'

class Automation::RuleTest < ActiveSupport::TestCase
test 'should run an automation on message created AttachmentContentContainsCondition ChangeMessageThreadTitleAction and not match' do
govbox_message = govbox_messages(:ssd_general_agenda_with_lorem_pdf)
govbox_message.payload["objects"].first["content"] = File.read("test/fixtures/files/lorem_ipsum.pdf")
Govbox::Message.create_message_with_thread!(govbox_message)

travel_to(15.minutes.from_now) { GoodJob.perform_inline }

message = Message.last
message.reload

assert_not_includes message.thread.tags, tags(:ssd_attachment_matched)
assert_equal "MySubject", message.thread.title
end

test 'should run an automation on message created AttachmentContentContainsCondition ChangeMessageThreadTitleAction and match simple string' do
govbox_message = govbox_messages(:ssd_general_agenda_with_lorem_pdf)
govbox_message.payload["objects"].first["content"] = File.read("test/fixtures/files/test_string.pdf")
Govbox::Message.create_message_with_thread!(govbox_message)

travel_to(15.minutes.from_now) { GoodJob.perform_inline }

message = Message.last
message.reload

assert_includes message.thread.tags, tags(:ssd_attachment_matched)
assert_equal "New title - MySubject", message.thread.title
end

test 'should run an automation on message created AttachmentContentContainsCondition ChangeMessageThreadTitleAction and match multiline string' do
govbox_message = govbox_messages(:ssd_general_agenda_with_lorem_pdf)
govbox_message.payload["objects"].first["content"] = File.read("test/fixtures/files/multiline_test.pdf")
Govbox::Message.create_message_with_thread!(govbox_message)

travel_to(15.minutes.from_now) { GoodJob.perform_inline }

message = Message.last
message.reload

assert_includes message.thread.tags, tags(:ssd_attachment_matched)
assert_equal "New title - MySubject", message.thread.title
end
test 'should run an automation on message created AttachmentContentContainsCondition ChangeMessageThreadTitleAction and match multipage string' do
govbox_message = govbox_messages(:ssd_general_agenda_with_lorem_pdf)
govbox_message.payload["objects"].first["content"] = File.read("test/fixtures/files/multipage_test.pdf")
Govbox::Message.create_message_with_thread!(govbox_message)

travel_to(15.minutes.from_now) { GoodJob.perform_inline }
jsuchal marked this conversation as resolved.
Show resolved Hide resolved

message = Message.last
message.reload

assert_includes message.thread.tags, tags(:ssd_attachment_matched)
assert_equal "New title - MySubject", message.thread.title
end
end
Loading