From 52b9ec3ceeb77ab283aa2879ee3e4d19705e1686 Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Wed, 10 Sep 2025 14:57:34 +0300 Subject: [PATCH 1/8] added customization deadline set for certificate expire reminder --- app/jobs/expire_certificate_reminder_job.rb | 8 ++-- ...112808_add_reminder_sent_to_certificate.rb | 5 +++ ...rtificate_reminder_deadline_to_settings.rb | 18 ++++++++ db/structure.sql | 13 ++++-- .../expire_certificate_reminder_job_test.rb | 43 +++++++++++++++++-- 5 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 db/migrate/20250910112808_add_reminder_sent_to_certificate.rb create mode 100644 db/migrate/20250910113941_add_certificate_reminder_deadline_to_settings.rb diff --git a/app/jobs/expire_certificate_reminder_job.rb b/app/jobs/expire_certificate_reminder_job.rb index 196c53d1a8..60df21beea 100644 --- a/app/jobs/expire_certificate_reminder_job.rb +++ b/app/jobs/expire_certificate_reminder_job.rb @@ -1,10 +1,11 @@ class ExpireCertificateReminderJob < ApplicationJob queue_as :default - - DEADLINE = 1.month def perform - Certificate.where('expires_at < ?', DEADLINE.from_now).each do |certificate| + deadline_days = Setting.certificate_reminder_deadline || 30 + deadline = deadline_days.days.from_now + + Certificate.where('expires_at < ?', deadline).where(reminder_sent: false).each do |certificate| send_reminder(certificate) end end @@ -19,5 +20,6 @@ def send_reminder(certificate) def send_email(registrar, certificate) CertificateMailer.certificate_expiring(email: registrar.email, certificate: certificate).deliver_now + certificate.update(reminder_sent: true) end end diff --git a/db/migrate/20250910112808_add_reminder_sent_to_certificate.rb b/db/migrate/20250910112808_add_reminder_sent_to_certificate.rb new file mode 100644 index 0000000000..a84bbde3a3 --- /dev/null +++ b/db/migrate/20250910112808_add_reminder_sent_to_certificate.rb @@ -0,0 +1,5 @@ +class AddReminderSentToCertificate < ActiveRecord::Migration[6.1] + def change + add_column :certificates, :reminder_sent, :boolean, default: false + end +end diff --git a/db/migrate/20250910113941_add_certificate_reminder_deadline_to_settings.rb b/db/migrate/20250910113941_add_certificate_reminder_deadline_to_settings.rb new file mode 100644 index 0000000000..a0292e0b70 --- /dev/null +++ b/db/migrate/20250910113941_add_certificate_reminder_deadline_to_settings.rb @@ -0,0 +1,18 @@ +class AddCertificateReminderDeadlineToSettings < ActiveRecord::Migration[6.1] + def up + unless SettingEntry.exists?(code: 'certificate_reminder_deadline') + SettingEntry.create!( + code: 'certificate_reminder_deadline', + value: '30', + format: 'integer', + group: 'certificate' + ) + else + puts "SettingEntry certificate_reminder_deadline already exists" + end + end + + def down + SettingEntry.where(code: 'certificate_reminder_deadline').destroy_all + end +end diff --git a/db/structure.sql b/db/structure.sql index faa3014b0d..329335122f 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -629,7 +629,8 @@ CREATE TABLE public.certificates ( serial character varying, revoked_at timestamp without time zone, revoked_reason integer, - p12_password character varying + p12_password character varying, + reminder_sent boolean DEFAULT false ); @@ -732,7 +733,8 @@ CREATE TABLE public.contacts ( company_register_status character varying, ident_request_sent_at timestamp without time zone, verified_at timestamp without time zone, - verification_id character varying + verification_id character varying, + system_disclosed_attributes character varying[] DEFAULT '{}'::character varying[] ); @@ -5779,12 +5781,17 @@ INSERT INTO "schema_migrations" (version) VALUES ('20241206085817'), ('20250204094550'), ('20250219102811'), +('20250310133151'), ('20250313122119'), ('20250319104749'), ('20250310133151'), ('20250314133357'), ('20240722085530'), ('20240723110208'), -('20241022121525'); +('20241022121525'), +('20250627084536'), +('20250910112808'), +('20250910113941'); + diff --git a/test/jobs/expire_certificate_reminder_job_test.rb b/test/jobs/expire_certificate_reminder_job_test.rb index 59df68afc0..036ff660cc 100644 --- a/test/jobs/expire_certificate_reminder_job_test.rb +++ b/test/jobs/expire_certificate_reminder_job_test.rb @@ -6,10 +6,12 @@ class ExpireCertificateReminderJobTest < ActiveJob::TestCase setup do ActionMailer::Base.deliveries.clear @certificate = certificates(:api) + + # Устанавливаем настройку по умолчанию для тестов (30 дней) + create_setting_if_not_exists('certificate_reminder_deadline', '30', 'integer', 'certificate') end def test_sends_reminder_for_expiring_certificate - # Устанавливаем дату истечения на 2 недели от текущего времени (меньше месяца) @certificate.update(expires_at: 2.weeks.from_now) perform_enqueued_jobs do @@ -18,14 +20,12 @@ def test_sends_reminder_for_expiring_certificate assert_emails 1 - # Проверяем, что письмо отправлено правильному получателю email = ActionMailer::Base.deliveries.last assert_equal @certificate.api_user.registrar.email, email.to.first assert_match 'Certificate Expiring', email.subject end def test_does_not_send_reminder_for_certificate_expiring_later - # Устанавливаем дату истечения на 2 месяца от текущего времени (больше месяца) @certificate.update(expires_at: 2.months.from_now) perform_enqueued_jobs do @@ -36,7 +36,6 @@ def test_does_not_send_reminder_for_certificate_expiring_later end def test_sends_reminder_for_multiple_expiring_certificates - # Создаем второй сертификат, который тоже скоро истекает second_certificate = certificates(:registrar) @certificate.update(expires_at: 1.week.from_now) second_certificate.update(expires_at: 3.weeks.from_now) @@ -47,4 +46,40 @@ def test_sends_reminder_for_multiple_expiring_certificates assert_emails 2 end + + def test_uses_custom_deadline_setting + # Изменяем настройку на 10 дней + update_setting('certificate_reminder_deadline', '10') + + # Сертификат истекает через 2 недели (больше 10 дней) + @certificate.update(expires_at: 2.weeks.from_now) + + perform_enqueued_jobs do + ExpireCertificateReminderJob.perform_now + end + + assert_emails 0 + + # Сертификат истекает через 5 дней (меньше 10 дней) + @certificate.update(expires_at: 5.days.from_now) + + perform_enqueued_jobs do + ExpireCertificateReminderJob.perform_now + end + + assert_emails 1 + end + + private + + def create_setting_if_not_exists(code, value, format, group) + unless SettingEntry.exists?(code: code) + SettingEntry.create!(code: code, value: value, format: format, group: group) + end + end + + def update_setting(code, value) + setting = SettingEntry.find_by(code: code) + setting.update!(value: value) if setting + end end From d3c821bbd2c55bf6baebbb2b696f4e57207da94f Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Thu, 11 Sep 2025 12:08:35 +0300 Subject: [PATCH 2/8] added certificate expire day reminding into the admin panel --- app/controllers/admin/settings_controller.rb | 1 + app/views/admin/settings/index.haml | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/app/controllers/admin/settings_controller.rb b/app/controllers/admin/settings_controller.rb index 1ebf2946d8..5ec7a91674 100644 --- a/app/controllers/admin/settings_controller.rb +++ b/app/controllers/admin/settings_controller.rb @@ -10,6 +10,7 @@ def index .where.not(code: 'default_language') @billing_settings = SettingEntry.with_group('billing') @contacts_settings = SettingEntry.with_group('contacts') + @certificate_settings = SettingEntry.with_group('certificate') end def create diff --git a/app/views/admin/settings/index.haml b/app/views/admin/settings/index.haml index c9a272a295..b9ba72f448 100644 --- a/app/views/admin/settings/index.haml +++ b/app/views/admin/settings/index.haml @@ -54,6 +54,15 @@ - @contacts_settings.each do |setting| = render 'setting_row', setting: setting + .panel.panel-default + .panel-heading + = t('.certificate') + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %tbody + - @certificate_settings.each do |setting| + = render 'setting_row', setting: setting + .row .col-md-12.text-right = submit_tag(t('.save_btn'), class: 'btn btn-success', name: nil) From 221c0bc160d82b35bee1e45ffeb6f3cb2dece83a Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Thu, 11 Sep 2025 12:16:15 +0300 Subject: [PATCH 3/8] added missing local title --- config/locales/admin/settings.en.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/admin/settings.en.yml b/config/locales/admin/settings.en.yml index bb042db013..21dbbf4fa0 100644 --- a/config/locales/admin/settings.en.yml +++ b/config/locales/admin/settings.en.yml @@ -9,6 +9,7 @@ en: billing: Billing contacts: Contacts save_btn: Save + certificate: Certificate create: saved: Settings have been successfully updated From 6175cb6aef745d9e605b755401509f8bce14ec59 Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Thu, 11 Sep 2025 12:26:27 +0300 Subject: [PATCH 4/8] refactor --- app/jobs/expire_certificate_reminder_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/expire_certificate_reminder_job.rb b/app/jobs/expire_certificate_reminder_job.rb index 60df21beea..838139a04a 100644 --- a/app/jobs/expire_certificate_reminder_job.rb +++ b/app/jobs/expire_certificate_reminder_job.rb @@ -16,10 +16,10 @@ def send_reminder(certificate) registrar = certificate.api_user.registrar send_email(registrar, certificate) + certificate.update(reminder_sent: true) end def send_email(registrar, certificate) CertificateMailer.certificate_expiring(email: registrar.email, certificate: certificate).deliver_now - certificate.update(reminder_sent: true) end end From 1c72bfaf943c86eea77b31887421cc831cbe043d Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Wed, 1 Oct 2025 10:24:19 +0300 Subject: [PATCH 5/8] remove useless comments --- test/jobs/expire_certificate_reminder_job_test.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/jobs/expire_certificate_reminder_job_test.rb b/test/jobs/expire_certificate_reminder_job_test.rb index 036ff660cc..0f1cd087d7 100644 --- a/test/jobs/expire_certificate_reminder_job_test.rb +++ b/test/jobs/expire_certificate_reminder_job_test.rb @@ -7,7 +7,6 @@ class ExpireCertificateReminderJobTest < ActiveJob::TestCase ActionMailer::Base.deliveries.clear @certificate = certificates(:api) - # Устанавливаем настройку по умолчанию для тестов (30 дней) create_setting_if_not_exists('certificate_reminder_deadline', '30', 'integer', 'certificate') end @@ -48,10 +47,8 @@ def test_sends_reminder_for_multiple_expiring_certificates end def test_uses_custom_deadline_setting - # Изменяем настройку на 10 дней update_setting('certificate_reminder_deadline', '10') - # Сертификат истекает через 2 недели (больше 10 дней) @certificate.update(expires_at: 2.weeks.from_now) perform_enqueued_jobs do @@ -60,7 +57,6 @@ def test_uses_custom_deadline_setting assert_emails 0 - # Сертификат истекает через 5 дней (меньше 10 дней) @certificate.update(expires_at: 5.days.from_now) perform_enqueued_jobs do From f915b3495ddd257ef3567040dfe40abf5ffc27c7 Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Fri, 12 Dec 2025 13:29:55 +0200 Subject: [PATCH 6/8] remove duplicate --- db/structure.sql | 1 - 1 file changed, 1 deletion(-) diff --git a/db/structure.sql b/db/structure.sql index 329335122f..639c5205a0 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -5784,7 +5784,6 @@ INSERT INTO "schema_migrations" (version) VALUES ('20250310133151'), ('20250313122119'), ('20250319104749'), -('20250310133151'), ('20250314133357'), ('20240722085530'), ('20240723110208'), From fa2114663bd7c75ee84715178c1d1b3229bfa70b Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Fri, 12 Dec 2025 13:33:20 +0200 Subject: [PATCH 7/8] reset structure sql --- db/structure.sql | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/db/structure.sql b/db/structure.sql index 639c5205a0..faa3014b0d 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -629,8 +629,7 @@ CREATE TABLE public.certificates ( serial character varying, revoked_at timestamp without time zone, revoked_reason integer, - p12_password character varying, - reminder_sent boolean DEFAULT false + p12_password character varying ); @@ -733,8 +732,7 @@ CREATE TABLE public.contacts ( company_register_status character varying, ident_request_sent_at timestamp without time zone, verified_at timestamp without time zone, - verification_id character varying, - system_disclosed_attributes character varying[] DEFAULT '{}'::character varying[] + verification_id character varying ); @@ -5781,16 +5779,12 @@ INSERT INTO "schema_migrations" (version) VALUES ('20241206085817'), ('20250204094550'), ('20250219102811'), -('20250310133151'), ('20250313122119'), ('20250319104749'), +('20250310133151'), ('20250314133357'), ('20240722085530'), ('20240723110208'), -('20241022121525'), -('20250627084536'), -('20250910112808'), -('20250910113941'); - +('20241022121525'); From 4346aae63ffd882703d6881bb185983480f213ea Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Fri, 12 Dec 2025 13:37:38 +0200 Subject: [PATCH 8/8] Update structure.sql with new migrations --- db/structure.sql | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/db/structure.sql b/db/structure.sql index faa3014b0d..1eea7020f1 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1,3 +1,8 @@ +\restrict 1nctSeWgAMeDygPpYdyeGcpf3SIlnwVyJaYVgeIkZgsmRdEvwgJ7hEgebG5zQ3v + +-- Dumped from database version 13.4 (Debian 13.4-4.pgdg110+1) +-- Dumped by pg_dump version 13.22 (Debian 13.22-0+deb11u1) + SET statement_timeout = 0; SET lock_timeout = 0; SET idle_in_transaction_session_timeout = 0; @@ -629,7 +634,8 @@ CREATE TABLE public.certificates ( serial character varying, revoked_at timestamp without time zone, revoked_reason integer, - p12_password character varying + p12_password character varying, + reminder_sent boolean DEFAULT false ); @@ -732,7 +738,8 @@ CREATE TABLE public.contacts ( company_register_status character varying, ident_request_sent_at timestamp without time zone, verified_at timestamp without time zone, - verification_id character varying + verification_id character varying, + system_disclosed_attributes character varying[] DEFAULT '{}'::character varying[] ); @@ -5279,6 +5286,8 @@ ALTER TABLE ONLY public.users -- PostgreSQL database dump complete -- +\unrestrict 1nctSeWgAMeDygPpYdyeGcpf3SIlnwVyJaYVgeIkZgsmRdEvwgJ7hEgebG5zQ3v + SET search_path TO "$user", public; INSERT INTO "schema_migrations" (version) VALUES @@ -5767,10 +5776,13 @@ INSERT INTO "schema_migrations" (version) VALUES ('20230707084741'), ('20230710120154'), ('20230711083811'), +('20240722085530'), +('20240723110208'), ('20240816091049'), ('20240816092636'), ('20240924103554'), ('20241015071505'), +('20241022121525'), ('20241030095636'), ('20241104104620'), ('20241112093540'), @@ -5779,12 +5791,12 @@ INSERT INTO "schema_migrations" (version) VALUES ('20241206085817'), ('20250204094550'), ('20250219102811'), -('20250313122119'), -('20250319104749'), ('20250310133151'), +('20250313122119'), ('20250314133357'), -('20240722085530'), -('20240723110208'), -('20241022121525'); +('20250319104749'), +('20250627084536'), +('20250910112808'), +('20250910113941');