From 4c7fde582b8e4676871a8476b375ff40a7875842 Mon Sep 17 00:00:00 2001 From: Jamil Date: Wed, 11 Dec 2024 12:32:15 +0600 Subject: [PATCH 1/6] chore: add translations for v2 pages (#336) * chore: add translations for v2 review page * chore: add translations for event config * chore: remove duplicate translation --- src/translations/client.csv | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/translations/client.csv b/src/translations/client.csv index f634e7454..bc9f86e13 100644 --- a/src/translations/client.csv +++ b/src/translations/client.csv @@ -168,6 +168,10 @@ certificate.receipt.service.targetDay,,{event} registration after 45 days of eve certificate.receipt.service.targetDay.amount,,৳ 25.00,৳ 25.00 certificate.receipt.subheader,Subheader for receipt on payment on certificate,{event} Registration after {DOBDiff} of {DOE},{event} Déclaration après {DOBDiff} de {DOE} changeEmail.validation.msg,Phone number validation message,Must be a valid email address,Doit être une adresse e-mail valide +changeModal.cancel,The label for cancel button of change modal,Cancel,Annuler +changeModal.continue,The label for continue button of change modal,Continue,Continuer +changeModal.description,The description for change modal,A record will be created of any changes you make,Un enregistrement sera créé pour chaque modification que vous apporterez. +changeModal.title,The title for change modal,Edit declaration?,Modifier la déclaration? changePhone.validation.msg,Phone number validation message,Must be a valid 10 digit number that starts with 0,Doit être un numéro valide à {num} chiffres qui commence par {start}. config.advanced.search,This is used for the advanced search,Advanced Search,Recherche avancée config.advanced.search.instruction,This is used for the advanced search,Select the options to build an advanced search. A minimum of two search parameters is required.,Sélectionnez les options pour construire une recherche avancée. Un minimum de deux paramètres de recherche est requis. @@ -786,6 +790,21 @@ error.title,Error title,Oops!,Oups ! error.title.unauthorized,Error title unauthorized,Unauthorized!,Non autorisé ! error.userListError,Error message when user list loads fails,Failed to load users,Impossible de charger les utilisateurs error.weAreTryingToFixThisError,Error description,This page could not be found,"Ce n'est pas vous, c'est nous. C'est notre faute." +event.tennis-club-membership.action.declare.form.label,This is what this form is referred as in the system,Tennis club membership application,Demande d'adhésion au club de tennis +event.tennis-club-membership.action.declare.form.section.recommender.field.firstname.label,This is the label for the field,Recommender's first name,Prénom du recommandeur +event.tennis-club-membership.action.declare.form.section.recommender.field.id.label,This is the label for the field,Recommender's membership ID,ID d'adhésion du recommandeur +event.tennis-club-membership.action.declare.form.section.recommender.field.surname.label,This is the label for the field,Recommender's surname,Nom de famille du recommandeur +event.tennis-club-membership.action.declare.form.section.recommender.title,This is the title of the section,Who is recommending the applicant?,Qui recommande le demandeur? +event.tennis-club-membership.action.declare.form.section.who.field.dob.label,This is the label for the field,Applicant's date of birth,Date de naissance du demandeur +event.tennis-club-membership.action.declare.form.section.who.field.firstname.label,This is the label for the field,Applicant's first name,Prénom du demandeur +event.tennis-club-membership.action.declare.form.section.who.field.surname.label,This is the label for the field,Applicant's surname,Nom de famille du demandeur +event.tennis-club-membership.action.declare.form.section.who.title,This is the title of the section,Who is applying for the membership?,Qui postule pour l'adhésion? +event.tennis-club-membership.action.declare.form.version.1,This is the first version of the form,Version 1,Version 1 +event.tennis-club-membership.action.declare.label,This is shown as the action name anywhere the user can trigger the action from,Send an application,Envoyer une demande +event.tennis-club-membership.label,This is what this event is referred as in the system,Tennis club membership application,Demande d'adhésion au club de tennis +exitModal.cancel,The label for cancel button in exit modal,Cancel,Annuler +exitModal.exitWithoutSaving,The title for exit without saving modal,Exit without saving changes?,Quitter sans enregistrer les modifications? +exitModal.exitWithoutSavingDescription,The description for exit without saving modal,You have unsaved changes on your declaration form. Are you sure you want to exit without saving?,Vous avez des modifications non enregistrées sur votre formulaire de déclaration. Êtes-vous sûr de vouloir quitter sans enregistrer? fieldAgentHome.allUpdatesText,,Great job! You have updated all declarations,Bon travail ! Vous avez mis à jour toutes les déclarations fieldAgentHome.inProgressCount,,In progress ({total}),En cours ({total}) fieldAgentHome.queryError,The text when error ocurred loading rejected declarations,An error occurred while loading declarations,Une erreur s'est produite lors du chargement des déclarations @@ -1761,6 +1780,16 @@ register.selectVitalEvent.registerNewEventHeading,The section heading on the pag register.selectVitalEvent.registerNewEventTitle,The title that appears on the select vital event page,New declaration,Nouvelle déclaration register.selectinformant.legalGuardian,,Legal guardian,Tuteur légal register.workQueue.declarations.banner,,Declarations to register in your area,Déclarations à enregistrer dans votre région +registerModal.cancel,The label for cancel button of register modal,Cancel,Annuler +registerModal.description,The description for register modal,The declarant will be notified of this correction and a record of this decision will be recorded,Le déclarant sera informé de cette correction et un enregistrement de cette décision sera créé. +registerModal.register,The label for register button of register modal,Register,Enregistrer +registerModal.title,The title for register modal,Register the member?,Enregistrer le membre? +rejectModal.archive,The label for archive button of reject modal,Archive,Archiver +rejectModal.cancel,The label for cancel button of reject modal,Cancel,Annuler +rejectModal.description,The description for reject modal,Please describe the updates required to this record for follow up action.,Veuillez décrire les mises à jour nécessaires à ce dossier pour un suivi. +rejectModal.markAsDuplicate,The label for mark as duplicate checkbox of reject modal,Mark as a duplicate,Marquer comme doublon +rejectModal.sendForUpdate,The label for send For Update button of reject modal,Send For Update,Envoyer pour mise à jour +rejectModal.title,The title for reject modal,Reason for rejection?,Raison du rejet? reloadmodal.body,Body of reload modal,There’s a new version of {app_name} available. Please update to continue.,Une nouvelle version de {app_name} est disponible. Veuillez effectuer la mise à jour pour continuer. reloadmodal.button.update,Label of update button,Update,Mise à jour reloadmodal.title,Title when update is available,Update available,Mise à jour disponible @@ -1817,6 +1846,10 @@ review.signature.delete,Label for button that deletes signature,Delete,Supprimer review.signature.description,Label awknowledging the correctness of the declaration,"I, the undersigned, hereby declare that the particulars in this form are true and correct to the best of my knowledge.","Je soussigné(e) déclare par la présente que les informations contenues dans ce formulaire sont, à ma connaissance, vraies et correctes." review.signature.input.description,Description awknowledging the correctness of the declaration,"By signing this document with an electronic signature, I agree that such signature will be valid as handwritten signatures to the extent allowed by the laws of Farajaland.","En signant ce document avec une signature électronique, j'accepte que cette signature soit valable comme les signatures manuscrites dans la mesure où les lois du Farajaland le permettent." review.signature.open,Label for button that opens the signature input,Sign,Signer +reviewAction.description,The description for review action,"By clicking register, you confirm that the information entered is correct and the member can be registered.","En cliquant sur enregistrer, vous confirmez que les informations saisies sont correctes et que le membre peut être enregistré." +reviewAction.register,The label for register button of review action,Register,Enregistrer +reviewAction.reject,The label for reject button of review action,Reject,Rejeter +reviewAction.title,The title for review action,Register member,Enregistrer un membre search.bookmark.error.notification,Error Notification messages for bookmark advanced search result,"Sorry, something went wrong. Please try again","Désolé, quelque chose s'est mal passé. Veuillez réessayer" search.bookmark.loading.notification,Loading Notification messages for bookmark advanced search result,Bookmarking your advanced search results...,Mettre en signet les résultats de votre recherche avancée... search.bookmark.remove.loading.notification,Loading Notification messages for remove advanced search bookmark,Removing your advanced search bookmark...,Suppression de votre signet de recherche avancée... From 180ea298cbc34138316b07a63711eaf03ff5c310 Mon Sep 17 00:00:00 2001 From: Riku Rouvila Date: Tue, 17 Dec 2024 10:26:18 +0200 Subject: [PATCH 2/6] Events v2: add config for summary and workqueues (#344) * feat: add config for summary and workqueues * configure statusm created at, modified at to be default columns * feat: move review title to config * feat: add form for register * add conditional rules for action visibility * add more actions and conditionality * do not show register action after a record already has a register action * Events v2: form field validation example (#343) * add conditional rules for action visibility * add more actions and conditionality * do not show register action after a record already has a register action * add example form field validation * comment out file field for now * remove conditionals * update toolkit version --------- Co-authored-by: Markus Co-authored-by: jamil314 --- package.json | 2 +- src/form/tennis-club-membership.ts | 384 +++++++++++++++++++++-------- 2 files changed, 283 insertions(+), 103 deletions(-) diff --git a/package.json b/package.json index de35fc4b0..fd4ac8e66 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@hapi/boom": "^9.1.1", "@hapi/hapi": "^20.0.1", "@hapi/inert": "^6.0.3", - "@opencrvs/toolkit": "^0.0.5", + "@opencrvs/toolkit": "0.0.6-events", "@types/chalk": "^2.2.0", "@types/csv2json": "^1.4.0", "@types/fhir": "^0.0.30", diff --git a/src/form/tennis-club-membership.ts b/src/form/tennis-club-membership.ts index 7cd31b438..efb0ec55d 100644 --- a/src/form/tennis-club-membership.ts +++ b/src/form/tennis-club-membership.ts @@ -9,7 +9,142 @@ * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. */ -import { defineConfig } from '@opencrvs/toolkit/events' +import { defineConfig, defineForm } from '@opencrvs/toolkit/events' +import { + defineConditional, + or, + eventHasAction, + userHasScope, + and, + not, + field +} from '@opencrvs/toolkit/conditionals' + +const TENNIS_CLUB_FORM = defineForm({ + label: { + id: 'event.tennis-club-membership.action.declare.form.label', + defaultMessage: 'Tennis club membership application', + description: 'This is what this form is referred as in the system' + }, + review: { + title: { + id: 'event.tennis-club-membership.action.declare.form.review.title', + defaultMessage: 'Member declaration for {firstname} {surname}', + description: 'Title of the form to show in review page' + } + }, + active: true, + version: { + id: '1.0.0', + label: { + id: 'event.tennis-club-membership.action.declare.form.version.1', + defaultMessage: 'Version 1', + description: 'This is the first version of the form' + } + }, + pages: [ + { + id: 'applicant', + title: { + id: 'event.tennis-club-membership.action.declare.form.section.who.title', + defaultMessage: 'Who is applying for the membership?', + description: 'This is the title of the section' + }, + fields: [ + { + id: 'applicant.firstname', + type: 'TEXT', + required: true, + label: { + defaultMessage: "Applicant's first name", + description: 'This is the label for the field', + id: 'event.tennis-club-membership.action.declare.form.section.who.field.firstname.label' + } + }, + { + id: 'applicant.surname', + type: 'TEXT', + required: true, + label: { + defaultMessage: "Applicant's surname", + description: 'This is the label for the field', + id: 'event.tennis-club-membership.action.declare.form.section.who.field.surname.label' + } + }, + { + id: 'applicant.dob', + type: 'DATE', + required: true, + validation: [ + { + message: { + defaultMessage: 'Please enter a valid date', + description: 'This is the error message for invalid date', + id: 'event.tennis-club-membership.action.declare.form.section.who.field.dob.error' + }, + validator: field('applicant.dob').isBeforeNow() + } + ], + label: { + defaultMessage: "Applicant's date of birth", + description: 'This is the label for the field', + id: 'event.tennis-club-membership.action.declare.form.section.who.field.dob.label' + } + } + // { + // id: 'applicant.image', + // type: 'FILE', + // required: false, + // label: { + // defaultMessage: "Applicant's profile picture", + // description: 'This is the label for the field', + // id: 'event.tennis-club-membership.action.declare.form.section.who.field.image.label' + // } + // } + ] + }, + { + id: 'recommender', + title: { + id: 'event.tennis-club-membership.action.declare.form.section.recommender.title', + defaultMessage: 'Who is recommending the applicant?', + description: 'This is the title of the section' + }, + fields: [ + { + id: 'recommender.firstname', + type: 'TEXT', + required: true, + label: { + defaultMessage: "Recommender's first name", + description: 'This is the label for the field', + id: 'event.tennis-club-membership.action.declare.form.section.recommender.field.firstname.label' + } + }, + { + id: 'recommender.surname', + type: 'TEXT', + required: true, + label: { + defaultMessage: "Recommender's surname", + description: 'This is the label for the field', + id: 'event.tennis-club-membership.action.declare.form.section.recommender.field.surname.label' + } + }, + { + id: 'recommender.id', + type: 'TEXT', + required: true, + label: { + defaultMessage: "Recommender's membership ID", + description: 'This is the label for the field', + id: 'event.tennis-club-membership.action.declare.form.section.recommender.field.id.label' + } + } + ] + } + ] +}) export const tennisClubMembershipEvent = defineConfig({ id: 'TENNIS_CLUB_MEMBERSHIP', @@ -18,115 +153,160 @@ export const tennisClubMembershipEvent = defineConfig({ description: 'This is what this event is referred as in the system', id: 'event.tennis-club-membership.label' }, + summary: { + title: { + defaultMessage: '{applicant.firstname} {applicant.surname}', + description: 'This is the title of the summary', + id: 'event.tennis-club-membership.summary.title' + }, + fields: [ + { + id: 'applicant.firstname' + }, + { + id: 'applicant.surname' + }, + { + id: 'recommender.firstname' + }, + { + id: 'recommender.surname' + }, + { + id: 'recommender.id' + } + ] + }, + workqueues: [ + { + id: 'all', + title: { + defaultMessage: 'All events', + description: 'Label for in progress workqueue', + id: 'event.tennis-club-membership.workqueue.all.label' + }, + fields: [ + { + id: 'applicant.firstname' + }, + { + id: 'applicant.surname' + } + ], + filters: [] + }, + { + id: 'ready-for-review', + title: { + defaultMessage: 'Ready for review', + description: 'Label for in review workqueue', + id: 'event.tennis-club-membership.workqueue.in-review.label' + }, + fields: [ + { + id: 'applicant.firstname' + }, + { + id: 'event.type' + }, + { + id: 'event.createdAt' + }, + { + id: 'event.modifiedAt' + } + ], + filters: [ + { + status: ['DECLARED'] + } + ] + }, + { + id: 'registered', + title: { + defaultMessage: 'Ready to print', + description: 'Label for registered workqueue', + id: 'event.tennis-club-membership.workqueue.registered.label' + }, + fields: [ + { + id: 'applicant.firstname' + }, + { + id: 'event.type' + }, + { + id: 'event.createdAt' + }, + { + id: 'event.modifiedAt' + } + ], + filters: [ + { + status: ['REGISTERED'] + } + ] + } + ], actions: [ { type: 'DECLARE', label: { - defaultMessage: 'Send an application', + defaultMessage: 'Declare', description: 'This is shown as the action name anywhere the user can trigger the action from', id: 'event.tennis-club-membership.action.declare.label' }, - forms: [ - { - label: { - id: 'event.tennis-club-membership.action.declare.form.label', - defaultMessage: 'Tennis club membership application', - description: 'This is what this form is referred as in the system' - }, - active: true, - version: { - id: '1.0.0', - label: { - id: 'event.tennis-club-membership.action.declare.form.version.1', - defaultMessage: 'Version 1', - description: 'This is the first version of the form' - } - }, - pages: [ - { - id: 'applicant', - title: { - id: 'event.tennis-club-membership.action.declare.form.section.who.title', - defaultMessage: 'Who is applying for the membership?', - description: 'This is the title of the section' - }, - fields: [ - { - id: 'applicant.firstname', - type: 'TEXT', - required: true, - label: { - defaultMessage: "Applicant's first name", - description: 'This is the label for the field', - id: 'event.tennis-club-membership.action.declare.form.section.who.field.firstname.label' - } - }, - { - id: 'applicant.surname', - type: 'TEXT', - required: true, - label: { - defaultMessage: "Applicant's surname", - description: 'This is the label for the field', - id: 'event.tennis-club-membership.action.declare.form.section.who.field.surname.label' - } - }, - { - id: 'applicant.dob', - type: 'DATE', - required: true, - label: { - defaultMessage: "Applicant's date of birth", - description: 'This is the label for the field', - id: 'event.tennis-club-membership.action.declare.form.section.who.field.dob.label' - } - } - ] - }, - { - id: 'recommender', - title: { - id: 'event.tennis-club-membership.action.declare.form.section.recommender.title', - defaultMessage: 'Who is recommending the applicant?', - description: 'This is the title of the section' - }, - fields: [ - { - id: 'recommender.firstname', - type: 'TEXT', - required: true, - label: { - defaultMessage: "Recommender's first name", - description: 'This is the label for the field', - id: 'event.tennis-club-membership.action.declare.form.section.recommender.field.firstname.label' - } - }, - { - id: 'recommender.surname', - type: 'TEXT', - required: true, - label: { - defaultMessage: "Recommender's surname", - description: 'This is the label for the field', - id: 'event.tennis-club-membership.action.declare.form.section.recommender.field.surname.label' - } - }, - { - id: 'recommender.id', - type: 'TEXT', - required: true, - label: { - defaultMessage: "Recommender's membership ID", - description: 'This is the label for the field', - id: 'event.tennis-club-membership.action.declare.form.section.recommender.field.id.label' - } - } - ] - } - ] - } - ] + forms: [TENNIS_CLUB_FORM], + allowedWhen: defineConditional(not(eventHasAction('DECLARE'))) + }, + { + type: 'VALIDATE', + label: { + defaultMessage: 'Validate', + description: + 'This is shown as the action name anywhere the user can trigger the action from', + id: 'event.tennis-club-membership.action.validate.label' + }, + allowedWhen: defineConditional(eventHasAction('DECLARE')), + forms: [TENNIS_CLUB_FORM] + }, + { + type: 'REGISTER', + label: { + defaultMessage: 'Register', + description: + 'This is shown as the action name anywhere the user can trigger the action from', + id: 'event.tennis-club-membership.action.register.label' + }, + allowedWhen: defineConditional( + and( + or( + eventHasAction('VALIDATE'), + and(eventHasAction('DECLARE'), userHasScope('register')) + ), + not(eventHasAction('REGISTER')) + ) + ), + forms: [TENNIS_CLUB_FORM] + }, + { + type: 'CUSTOM', + label: { + defaultMessage: 'My custom action', + description: + 'This is shown as the action name anywhere the user can trigger the action from', + id: 'event.tennis-club-membership.action.sdf.label' + }, + allowedWhen: defineConditional( + or( + eventHasAction('VALIDATE'), + and(eventHasAction('DECLARE'), userHasScope('register')) + ) + ), + forms: [] } ] }) From 54b74103e4135290652c4ef9da4a6af3883f5032 Mon Sep 17 00:00:00 2001 From: "Al hel md. shahriar zaman" Date: Fri, 20 Dec 2024 17:01:15 +0600 Subject: [PATCH 3/6] path added in filebeat --- infrastructure/monitoring/filebeat/filebeat.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/infrastructure/monitoring/filebeat/filebeat.yml b/infrastructure/monitoring/filebeat/filebeat.yml index 8f75ec4b9..9ffef5a6f 100644 --- a/infrastructure/monitoring/filebeat/filebeat.yml +++ b/infrastructure/monitoring/filebeat/filebeat.yml @@ -11,6 +11,10 @@ filebeat.inputs: enabled: true paths: - /var/log/opencrvs-backup.log + - type: log + enabled: true + paths: + - /var/log/opencrvs-backup.error.log - type: log enabled: true paths: From a7bb2f43516acaf0b314a2a41eb68f202bfd5041 Mon Sep 17 00:00:00 2001 From: "Al hel md. shahriar zaman" Date: Fri, 20 Dec 2024 17:15:00 +0600 Subject: [PATCH 4/6] make sure backup error file exists --- infrastructure/server-setup/tasks/application.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/infrastructure/server-setup/tasks/application.yml b/infrastructure/server-setup/tasks/application.yml index 4d70e66b4..a1a441de3 100644 --- a/infrastructure/server-setup/tasks/application.yml +++ b/infrastructure/server-setup/tasks/application.yml @@ -49,6 +49,14 @@ state: touch mode: 'u+rwX,g+rwX,o-rwx' +- name: Create backup logfile for error + ansible.builtin.file: + path: /var/log/opencrvs-backup.error.log + owner: '{{ ansible_user }}' + group: 'application' + state: touch + mode: 'u+rwX,g+rwX,o-rwx' + - name: Create restore logfile ansible.builtin.file: path: /var/log/opencrvs-restore.log From 8217feb5a3d6da19595ba4c29a83a7e320cfe53c Mon Sep 17 00:00:00 2001 From: "Al hel md. shahriar zaman" Date: Fri, 20 Dec 2024 17:29:51 +0600 Subject: [PATCH 5/6] modify the crontab command --- infrastructure/server-setup/tasks/backups/crontab.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/server-setup/tasks/backups/crontab.yml b/infrastructure/server-setup/tasks/backups/crontab.yml index 8abd21d67..52228dee6 100644 --- a/infrastructure/server-setup/tasks/backups/crontab.yml +++ b/infrastructure/server-setup/tasks/backups/crontab.yml @@ -20,7 +20,7 @@ name: 'backup opencrvs' minute: '0' hour: '0' - job: 'bash {{ crontab_user_home }}/backup.sh --passphrase={{ backup_encryption_passphrase }} --ssh_user={{ backup_server_user }} --ssh_host={{ backup_hostname }} --ssh_port={{ backup_port }} --remote_dir={{ backup_server_remote_target_directory }} --replicas=1 >> /var/log/opencrvs-backup.log 2>&1' + job: 'bash {{ crontab_user_home }}/backup.sh --passphrase={{ backup_encryption_passphrase }} --ssh_user={{ backup_server_user }} --ssh_host={{ backup_hostname }} --ssh_port={{ backup_port }} --remote_dir={{ backup_server_remote_target_directory }} --replicas=1 >> /var/log/opencrvs-backup.log 2>> /var/log/opencrvs-backup.error.log' state: "{{ 'present' if (backup_hostname is defined and backup_encryption_passphrase and (enable_backups | default(false))) else 'absent' }}" ## From 77fa39a6420f62807620dec6e9ab0a31d3e9b73b Mon Sep 17 00:00:00 2001 From: "Al hel md. shahriar zaman" Date: Fri, 20 Dec 2024 18:05:00 +0600 Subject: [PATCH 6/6] logrotate modified for backup error file --- infrastructure/logrotate.conf | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/infrastructure/logrotate.conf b/infrastructure/logrotate.conf index 60fe35055..8b965ffe7 100644 --- a/infrastructure/logrotate.conf +++ b/infrastructure/logrotate.conf @@ -72,6 +72,13 @@ include /etc/logrotate.d rotate 1 } +/var/log/opencrvs-backup.error.log { + missingok + monthly + create 0660 root application + rotate 1 +} + /var/log/papertrail.log { missingok monthly