diff --git a/app/components/message_state_component.html.erb b/app/components/message_state_component.html.erb index b142f2482..447e2aa77 100644 --- a/app/components/message_state_component.html.erb +++ b/app/components/message_state_component.html.erb @@ -1,11 +1,17 @@ <% if @message.form_object&.is_signed? || @message.form_object.present? || @message.authorized? %> -
- <% if @message.form_object&.is_signed? %> +
+ <% if @message.form_object&.tags&.signed_by&.any? %> + <% @message.form_object.tags.signed_by.each do |tag| %> + <%= render Common::BadgeComponent.new(tag.name, "green", "fingerprint") %> + <% end %> + <% elsif @message.form_object&.is_signed? %> <%= render Common::BadgeComponent.new("Podpísané", "green", "fingerprint") %> <% end %> + <% if @message.authorized? %> <%= render Common::BadgeComponent.new("Prevzatá doručenka", "purple") %> <% end %> + <% if @message.thread.archived? %> <%= render ArchivedObjectTagComponent.new(@message.form_object&.archived_object) %> <% end %> diff --git a/app/jobs/govbox/process_message_job.rb b/app/jobs/govbox/process_message_job.rb index 02ce40d19..65ac73700 100644 --- a/app/jobs/govbox/process_message_job.rb +++ b/app/jobs/govbox/process_message_job.rb @@ -10,8 +10,6 @@ def perform(govbox_message) processed_message = ::Message.where(type: [nil, 'Message']).where(uuid: govbox_message.message_id).joins(:thread).where(thread: { box_id: govbox_message.box.id }).take ActiveRecord::Base.transaction do - destroy_associated_message_draft(govbox_message) - message = Govbox::Message.create_message_with_thread!(govbox_message) mark_delivery_notification_authorized(govbox_message) @@ -24,11 +22,6 @@ def perform(govbox_message) private - def destroy_associated_message_draft(govbox_message) - message_draft = Upvs::MessageDraft.where(uuid: govbox_message.message_id).joins(:thread).where(thread: { box_id: govbox_message.box.id }).take - message_draft&.destroy - end - def mark_delivery_notification_authorized(govbox_message) return unless govbox_message.delivery_notification diff --git a/app/jobs/govbox/submit_message_draft_job.rb b/app/jobs/govbox/submit_message_draft_job.rb index 6615204da..d265b8417 100644 --- a/app/jobs/govbox/submit_message_draft_job.rb +++ b/app/jobs/govbox/submit_message_draft_job.rb @@ -51,7 +51,7 @@ def build_objects(message_draft) objects = [] message_draft.objects.each do |object| objects << { - id: SecureRandom.uuid, + id: object.uuid, name: object.name, encoding: "Base64", signed: object.is_signed, diff --git a/app/models/govbox/message.rb b/app/models/govbox/message.rb index fb48bb937..1de014cbd 100644 --- a/app/models/govbox/message.rb +++ b/app/models/govbox/message.rb @@ -27,11 +27,13 @@ class Govbox::Message < ApplicationRecord def self.create_message_with_thread!(govbox_message) message = nil + message_draft = Upvs::MessageDraft.where(uuid: govbox_message.message_id).joins(:thread).where(thread: { box_id: govbox_message.box.id }).take MessageThread.with_advisory_lock!(govbox_message.correlation_id, transaction: true, timeout_seconds: 10) do message = create_message(govbox_message) - message.thread = govbox_message.box.message_threads.find_or_create_by_merge_uuid!( + message.thread = message_draft&.thread + message.thread ||= govbox_message.box.message_threads.find_or_create_by_merge_uuid!( box: govbox_message.box, merge_uuid: govbox_message.correlation_id, title: message.metadata.dig("delivery_notification", "consignment", "subject").presence || message.title, @@ -40,10 +42,17 @@ def self.create_message_with_thread!(govbox_message) message.save! + create_message_objects(message, govbox_message.payload) + add_upvs_related_tags(message, govbox_message) - end - create_message_objects(message, govbox_message.payload) + if message_draft + copy_tags_from_draft(message, message_draft) + message_draft.destroy + end + + MessageObject.mark_message_objects_externally_signed(message.objects) + end EventBus.publish(:message_thread_created, message.thread) if message.thread.previously_new_record? EventBus.publish(:message_created, message) @@ -103,15 +112,14 @@ def self.create_message_objects(message, raw_message) raw_message["objects"].each do |raw_object| message_object_type = raw_object["class"] visualizable = (message_object_type == "FORM" && message.html_visualization.present?) ? true : nil - tags = raw_object["signed"] ? [message.thread.box.tenant.signed_externally_tag!] : [] message_object = message.objects.create!( + uuid: raw_object["id"], name: raw_object["name"], mimetype: raw_object["mime_type"], is_signed: raw_object["signed"], object_type: message_object_type, - visualizable: visualizable, - tags: tags + visualizable: visualizable ) if raw_object["encoding"] == "Base64" @@ -140,6 +148,15 @@ def self.add_upvs_related_tags(message, govbox_message) add_delivery_notification_tag(message) if message.can_be_authorized? end + def self.copy_tags_from_draft(message, message_draft) + message_draft.objects.map do |message_draft_object| + message_object = message.objects.find_by(uuid: message_draft_object.uuid) + message_draft_object.tags.signed.each { |tag| message_object.assign_tag(tag) } + end + + (message_draft.tags.simple + message_draft.tags.signed).each { |tag| message.assign_tag(tag) } + end + def self.add_delivery_notification_tag(message) message.add_cascading_tag(delivery_notification_tag(message)) end diff --git a/app/models/message_draft.rb b/app/models/message_draft.rb index 5dbd4839d..2e03797a8 100644 --- a/app/models/message_draft.rb +++ b/app/models/message_draft.rb @@ -79,7 +79,6 @@ def update_content(parameters) def submit raise NotImplementedError end - def draft? true end diff --git a/app/models/message_object.rb b/app/models/message_object.rb index 08579fd15..33e763609 100644 --- a/app/models/message_object.rb +++ b/app/models/message_object.rb @@ -8,6 +8,7 @@ # name :string # object_type :string not null # to_be_signed :boolean default(FALSE), not null +# uuid :uuid # visualizable :boolean # created_at :datetime not null # updated_at :datetime not null @@ -57,6 +58,14 @@ def self.create_message_objects(message, objects) end end + def self.mark_message_objects_externally_signed(objects) + objects.find_each do |object| + next unless object.is_signed? + + object.assign_tag(object.message.tenant.signed_externally_tag!) unless object.tags.signed_internally.present? + end + end + def mark_signed_by_user(user) assign_tag(user.signed_by_tag) unassign_tag(user.signature_requested_from_tag) @@ -117,6 +126,7 @@ def assign_tag(tag) end def fill_missing_info + update(uuid: SecureRandom.uuid) unless uuid.present? 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 diff --git a/app/models/tag.rb b/app/models/tag.rb index 3f28c1fc1..9df1e434f 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -37,6 +37,9 @@ class Tag < ApplicationRecord scope :simple, -> { where(type: SimpleTag.to_s) } scope :visible, -> { where(visible: true) } scope :signing_tags, -> { where(type: ["SignedTag", "SignedByTag", "SignatureRequestedTag", "SignatureRequestedFromTag"]) } + scope :signed, -> { where(type: ["SignedTag", "SignedByTag", "SignedExternallyTag"]) } + scope :signed_by, -> { where(type: "SignedByTag") } + scope :signed_internally, -> { where(type: ["SignedTag", "SignedByTag"]) } scope :archived, -> { where(type: ArchivedTag.to_s) } after_update_commit ->(tag) { EventBus.publish(:tag_renamed, tag) if previous_changes.key?("name") } diff --git a/db/migrate/20240927104543_add_uuid_to_message_objects.rb b/db/migrate/20240927104543_add_uuid_to_message_objects.rb new file mode 100644 index 000000000..a535f4a20 --- /dev/null +++ b/db/migrate/20240927104543_add_uuid_to_message_objects.rb @@ -0,0 +1,5 @@ +class AddUuidToMessageObjects < ActiveRecord::Migration[7.1] + def change + add_column :message_objects, :uuid, :uuid + end +end diff --git a/db/migrate/20241025151903_update_index_on_uuid_message_thread_id_to_messages.rb b/db/migrate/20241025151903_update_index_on_uuid_message_thread_id_to_messages.rb new file mode 100644 index 000000000..92362e8c1 --- /dev/null +++ b/db/migrate/20241025151903_update_index_on_uuid_message_thread_id_to_messages.rb @@ -0,0 +1,8 @@ +class UpdateIndexOnUuidMessageThreadIdToMessages < ActiveRecord::Migration[7.1] + def change + remove_index :messages, name: 'index_messages_on_uuid_and_message_thread_id' + + add_unique_constraint :messages, [:uuid, :message_thread_id], deferrable: :deferred + end +end + diff --git a/db/schema.rb b/db/schema.rb index b22c56b6d..a42c507fa 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_08_20_143244) do +ActiveRecord::Schema[7.1].define(version: 2024_10_25_151903) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -389,6 +389,7 @@ t.boolean "is_signed" t.boolean "to_be_signed", default: false, null: false t.boolean "visualizable" + t.uuid "uuid" t.index ["message_id"], name: "index_message_objects_on_message_id" end @@ -486,6 +487,7 @@ t.index ["author_id"], name: "index_messages_on_author_id" t.index ["import_id"], name: "index_messages_on_import_id" t.index ["message_thread_id"], name: "index_messages_on_message_thread_id" + t.unique_constraint ["uuid", "message_thread_id"], deferrable: :deferred end create_table "messages_tags", force: :cascade do |t| diff --git a/test/fixtures/govbox/messages.yml b/test/fixtures/govbox/messages.yml index ac834c646..1ba47166f 100644 --- a/test/fixtures/govbox/messages.yml +++ b/test/fixtures/govbox/messages.yml @@ -139,6 +139,39 @@ ssd_referring_to_outbox_message: class: MyClass content: MyContent +ssd_general_created_from_draft: + message_id: 9b1b718a-c06c-487c-86c2-b68b8606aa5c + correlation_id: 7a364355-882c-41d2-b1b3-e215644f805b + edesk_message_id: 7 + delivered_at: <%= DateTime.current %> + edesk_class: TEST + folder: ssd_sent + payload: + message_id: 9b1b718a-c06c-487c-86c2-b68b8606aa5c + subject: Title is not shown + sender_name: MySender + sender_uri: MySenderURIq + recipient_name: MyRecipient + delivered_at: <%= DateTime.current.to_s %> + original_html: Reply to something + objects: + - id: 6a0f716a-c284-4680-ad7e-ed2bde769dd2 + name: MyString + mime_type: MyString + class: FORM + content: MyContent + - id: af0e1c11-d226-45b7-8816-a5c24e139d35 + name: Attachment + mime_type: MyString + class: ATTACHMENT + content: MyContent + - id: 57c9954c-93e2-470c-833c-fd2bc6d8c70f + name: Attachment2 + mime_type: MyString + signed: true + class: ATTACHMENT + content: MyContent + ssd_without_recipient_name: message_id: <%= SecureRandom.uuid %> correlation_id: <%= SecureRandom.uuid %> diff --git a/test/fixtures/message_objects.yml b/test/fixtures/message_objects.yml index 4358c11f6..c6e355c1f 100644 --- a/test/fixtures/message_objects.yml +++ b/test/fixtures/message_objects.yml @@ -50,17 +50,27 @@ ssd_main_fs_one_form: object_type: FORM ssd_main_draft_to_be_signed_draft_one_form: + uuid: 6a0f716a-c284-4680-ad7e-ed2bde769dd2 message: ssd_main_draft_to_be_signed_draft_one name: MyString mimetype: MyString object_type: FORM ssd_main_draft_to_be_signed_draft_one_attachment: + uuid: af0e1c11-d226-45b7-8816-a5c24e139d35 message: ssd_main_draft_to_be_signed_draft_one name: Attachment mimetype: MyString object_type: ATTACHMENT +ssd_main_draft_to_be_signed_draft_one_attachment2: + uuid: 57c9954c-93e2-470c-833c-fd2bc6d8c70f + message: ssd_main_draft_to_be_signed_draft_one + name: Attachment2 + mimetype: MyString + is_signed: true + object_type: ATTACHMENT + ssd_main_draft_to_be_signed_draft_two_form: message: ssd_main_draft_to_be_signed_draft_two name: MyString diff --git a/test/fixtures/message_objects_tags.yml b/test/fixtures/message_objects_tags.yml index 7def4cd62..c77cdc905 100644 --- a/test/fixtures/message_objects_tags.yml +++ b/test/fixtures/message_objects_tags.yml @@ -4,6 +4,10 @@ ssd_main_draft_to_be_signed_draft_one_form_signature_requested: message_object: ssd_main_draft_to_be_signed_draft_one_form tag: ssd_signer_user_signature_requested +ssd_main_draft_to_be_signed_draft_one_attachment2_signed_ssd_signer: + message_object: ssd_main_draft_to_be_signed_draft_one_attachment2 + tag: ssd_signer_user_signed + ssd_main_draft_to_be_signed_draft_two_form_signature_requested: message_object: ssd_main_draft_to_be_signed_draft_two_form tag: ssd_signer_user_signature_requested diff --git a/test/fixtures/message_thread_merge_identifiers.yml b/test/fixtures/message_thread_merge_identifiers.yml index 73d80505d..5951701c6 100644 --- a/test/fixtures/message_thread_merge_identifiers.yml +++ b/test/fixtures/message_thread_merge_identifiers.yml @@ -19,3 +19,8 @@ ssd_main_issue_one: message_thread: ssd_main_issue uuid: <%= SecureRandom.uuid %> box: ssd_main + +ssd_main_draft_to_be_signed: + message_thread: ssd_main_draft_to_be_signed + uuid: 7a364355-882c-41d2-b1b3-e215644f805b + box: ssd_main diff --git a/test/fixtures/message_threads_tags.yml b/test/fixtures/message_threads_tags.yml index 2110dbcc1..28b65ed05 100644 --- a/test/fixtures/message_threads_tags.yml +++ b/test/fixtures/message_threads_tags.yml @@ -64,6 +64,18 @@ ssd_main_draft_to_be_signed_ssd_signer_user_signature_requested: message_thread: ssd_main_draft_to_be_signed tag: ssd_signer_user_signature_requested +ssd_main_draft_to_be_signed_ssd_signer_user_signed: + message_thread: ssd_main_draft_to_be_signed + tag: ssd_signer_user_signed + +ssd_main_draft_to_be_signed_ssd_signed: + message_thread: ssd_main_draft_to_be_signed + tag: ssd_signed + +ssd_main_draft_to_be_signed_ssd_submitted: + message_thread: ssd_main_draft_to_be_signed + tag: ssd_submitted + ssd_main_draft_to_be_signed2_finance: message_thread: ssd_main_draft_to_be_signed2 tag: ssd_finance diff --git a/test/fixtures/messages.yml b/test/fixtures/messages.yml index 1c2dce92d..e189d0928 100644 --- a/test/fixtures/messages.yml +++ b/test/fixtures/messages.yml @@ -186,8 +186,8 @@ ssd_main_collapsed_two: collapsed: true ssd_main_draft_to_be_signed_draft_one: - type: MessageDraft - uuid: <%= SecureRandom.uuid %> + type: Upvs::MessageDraft + uuid: 9b1b718a-c06c-487c-86c2-b68b8606aa5c title: Title is not shown html_visualization: Reply to something delivered_at: 2023-05-18 16:18:26 @@ -195,6 +195,7 @@ ssd_main_draft_to_be_signed_draft_one: replyable: false metadata: status: created + correlation_id: 7a364355-882c-41d2-b1b3-e215644f805b author: basic ssd_main_draft_to_be_signed_draft_two: @@ -203,7 +204,7 @@ ssd_main_draft_to_be_signed_draft_two: title: MyStringDraft2 html_visualization: MyString delivered_at: 2023-05-18 16:18:26 - thread: ssd_main_draft_to_be_signed + thread: ssd_main_draft_to_be_signed2 replyable: false metadata: status: created diff --git a/test/models/govbox/message_test.rb b/test/models/govbox/message_test.rb index 69a5eea08..b73a07764 100644 --- a/test/models/govbox/message_test.rb +++ b/test/models/govbox/message_test.rb @@ -1,7 +1,7 @@ require "test_helper" class Govbox::MessageTest < ActiveSupport::TestCase - test "should create message, its objects and not visible tag" do + test "#create_message_with_thread! should create message, its objects and not visible tag" do govbox_message = govbox_messages(:one) Govbox::Message.create_message_with_thread!(govbox_message) @@ -29,7 +29,27 @@ class Govbox::MessageTest < ActiveSupport::TestCase assert_equal message.tags.first, message.thread.tags.simple.first end - test "should take name from box as recipient_name if no recipient_name in govbox message" do + test "#create_message_with_thread! migrates tags from associated MessageDraft" do + govbox_message = govbox_messages(:ssd_general_created_from_draft) + + Govbox::Message.create_message_with_thread!(govbox_message) + + message = Message.last + + # Simple and Signed tags copied to MessageThread + assert ['Finance', 'Podpísané', 'Podpísané: Signer user'].map { |tag_name| message.thread.tags.include?(tag_name) } + + # No SignatureRequested, Submiited tags copied to MessageThread + assert message.thread.tags.where(type: ['SignatureRequestedTag', 'SignatureRequestedFromTag', 'Submitted']).none? + + # Signed tags copied to MessageObjects + assert message.objects.find_by(name: 'Attachment2').tags.include?(tags(:ssd_signer_user_signed)) + + # No SignatureRequested tags copied to MessageObjects + assert message.form_object.tags.where(type: ['SignatureRequestedTag', 'SignatureRequestedFromTag']).none? + end + + test "#create_message_with_thread! should take name from box as recipient_name if no recipient_name in govbox message" do govbox_message = govbox_messages(:ssd_without_recipient_name) Govbox::Message.create_message_with_thread!(govbox_message) @@ -41,7 +61,7 @@ class Govbox::MessageTest < ActiveSupport::TestCase assert_equal message.recipient_name, "SSD main" end - test "should include general agenda subject in message title" do + test "#create_message_with_thread! should include general agenda subject in message title" do govbox_message = govbox_messages(:ssd_general_agenda) Govbox::Message.create_message_with_thread!(govbox_message) @@ -51,7 +71,7 @@ class Govbox::MessageTest < ActiveSupport::TestCase assert_equal message.title, "Všeobecná Agenda - Rozhodnutie ..." end - test "should not create new tag if already exists" do + test "#create_message_with_thread! should not create new tag if already exists" do govbox_message = govbox_messages(:one) tag = SimpleTag.create!(external_name: "slovensko.sk:#{govbox_message.folder.name}", name: "slovensko.sk:#{govbox_message.folder.name}", tenant: govbox_message.folder.box.tenant, visible: false) @@ -66,7 +86,7 @@ class Govbox::MessageTest < ActiveSupport::TestCase assert_equal tag, message.thread.tags.simple.first end - test "should not duplicate message thread tags" do + test "#create_message_with_thread! should not duplicate message thread tags" do govbox_message1 = govbox_messages(:one) govbox_message2 = govbox_messages(:three) @@ -88,7 +108,7 @@ class Govbox::MessageTest < ActiveSupport::TestCase assert_equal tag, message2.thread.tags.simple.first end - test "should not use delivery notification title for message thread title" do + test "#create_message_with_thread! should not use delivery notification title for message thread title" do govbox_message = govbox_messages(:solver_delivery_notification) Govbox::Message.create_message_with_thread!(govbox_message)