-
-
Notifications
You must be signed in to change notification settings - Fork 825
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
dev/core#1590: Don't send reminders on deleted events #17641
Conversation
(Standard links)
|
@@ -138,15 +138,15 @@ public function __construct($now, $actionSchedule, $mapping) { | |||
public function build() { | |||
$this->buildRelFirstPass(); | |||
|
|||
if ($this->prepareAddlFilter('c.id') && $this->notTemplate()) { | |||
if ($this->prepareAddlFilter('c.id') && $this->mapping->sendToAdditional($this->actionSchedule->entity_value)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I started by reading 16311 and then this PR. I like how this one has a (REF) to delegate the check from the RecipientBuilder
to each ActionMapping
.
In either revision, there's a couple things which feel odd/fishy. Just thinking out loud.
- If a
civicrm_event
is generally not actionable because ofis_template=1
, and if you can make the short-circuit decision here (which I'm not 100% certain of; but that seems to be implied), then shouldn't it short-circuit all four passes(buildRelFirstPass()
,buildAddlFirstPass()
,buildRelRepeatPass()
,buildAddlRepeatPass()
)? It seems the value ofis_template
would be equally germane to all of them? - In the underlying createQuery(), it has a filter on
is_template
andis_active
. My expectation was that the filter would protect all four passes. (createQuery()
is supposed to be a common building-block by way ofRecipientBuilder::build{Rel,Addl}{First,Repeat}}Pass()
=>RecipientBuilder::prepareQuery()
=>ActionMapping::createQuery()
). But evidently not... - I suppose there's a question about whether reminders should be sent for an inactive event. I would generally think not, and the
createQuery()
says no (r.is_active = 1
)... so if we have to reproduce these guards, perhapssendToAdditional()
should also reproduce theis_active
guard?
Anyway, these comments aren't meant as hard blocks. As a (REF) and a bugfix, the new code seems better than the old code. I'm just commenting because something about the context feels fishy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The heart of the issue here is that createQuery()
isn't called when sending to additional recipients. Which is why these passes are necessary to begin with - createQuery()
's docblock reads: Generate a query to locate recipients who match the given schedule.
Additional recipients are by definition arbitrary and outside the normal query parameters.
I hope that addresses your points 1 and 2! I agree re: point 3, and I'll fix that when I clean up these failing tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The heart of the issue here is that createQuery() isn't called when sending to additional recipients.
Yeah, I had that intuition -- that maybe createQuery()
isn't called because AddlFirst/AddlRepeat can use a static contact-list. But then I tried to check the intuition:
-
At least in skimming the PHP, there is a code-path from
buildAddl{First,Repeat}Pass()
toprepareQuery()
tocreateQuery()
to$query->where('r.is_template = 0');
. As near I can see, the path doesn't have any obstructions/short-circuits. It could just be my bad reading though. I guess a debugger would reveal the truth. Or maybe there's something in the structure of the query (like anOR
orIN
orUNION
) which makes the filter inoperative. -
AddlFirst/AddlRepeat do need some information from the
ActionMapping
- i.e. to identify the subject-matter for the reminder (the entity and the date; egcivicrm_event
,123
,start_date
,2020-06-02
). I suppose that some mapping-types (EVENT_TPL_MAPPING_ID
,EVENT_NAME_MAPPING_ID
) do convey part of the subject-matter (entity ID) in their$schedule->entity_value
record. But$schedule->entity_value
is not necessarily entity IDs. It could equally be an array of even-type-ids or activity-type-ids (dependent on the mapping type...).
(IMHO, entity_value
is a misnomer... it's more like "the primary filter supplied by the user" or primary_query_value
.)
Tangentially... there may be a crossed wire in using $schedule->entity_value
to set sendToAdditional(int $entityId)
. Since $schedule->entity_value
can have different things packed into it, it takes some work to unpack. Notice the extra work that createQuery()
does here and here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @totten . How about simply passing the entityValue (which may be event ID(s) or event_type ID(s) based on EVENT_TPL_MAPPING_ID
) and extending the SQL here a bit
diff --git a/CRM/Event/ActionMapping.php b/CRM/Event/ActionMapping.php
index 77fa8d77ed..9a91b69e07 100644
--- a/CRM/Event/ActionMapping.php
+++ b/CRM/Event/ActionMapping.php
@@ -186,4 +186,24 @@ class CRM_Event_ActionMapping extends \Civi\ActionSchedule\Mapping {
+ /**
+ * Determine whether a schedule based on this mapping should
+ * send to additional contacts.
+ * @param int|array $entityValue
+ */
+ public function sendToAdditional($entityValue): bool {
+ $selectedValues = (array) \CRM_Utils_Array::explodePadded($entityValue);
+ $valueField = ($this->id == \CRM_Event_ActionMapping::EVENT_TYPE_MAPPING_ID) ? 'event_type_id' : 'id';
+ // Don't send to additional recipients if this event is deleted or a template.
+ $query = new \CRM_Utils_SQL_Select('civicrm_event e');
+ $sql = $query
+ ->select('e.id')
+ ->where("e.{$valueField} IN (@selectedValues)")
+ ->where("is_template = 0")
+ ->where("is_active = 1")
+ ->param('selectedValues', $selectedValues)
+ ->toSQL();
+ $dao = \CRM_Core_DAO::executeQuery($sql);
+ return (bool) $dao->N;
+ }
+
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went to implement this, then realized that the code Tim mentions doesn't account for "event template" scheduled reminders - just "event type" and "event name" scheduled reminders. I implemented similar code, but it's a bit larger to support all three cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@monishdeb can you review again the updated PR?
Hi Tim - you're right, I'll look into the |
test this please |
I have a lot of feelings about this PR. On the one hand, it's better in than out. OTOH, "additional recipients" scheduled reminder functionality is so utterly broken that I'm inclined to think that it should be disabled altogether, or at least limited to certain entities. Because the scheduled reminder is based on
This is, I believe, my third PR targeting "send to additional contacts" bugs, but the truth is that even with this merged, it's still quite broken. |
Test this please |
Jenkins test this please |
test this please |
4b99c9f
to
77d0894
Compare
test this please |
1 similar comment
test this please |
@MegaphoneJon Error in the test run (had to look at the console log for it tho)
|
@MegaphoneJon I think it would be appropriate to rename the parameter to $entityValue from $entityID and update the param type to mixed - string|int |
test this please |
PHP Fatal error: Declaration of CRM_Event_ActionMapping::sendToAdditional($entityId): bool must be compatible with Civi\ActionSchedule\Mapping::sendToAdditional(int $entityId): bool in /home/jenkins/bknix-dfl/build/core-17641-7utem/web/sites/all/modules/civicrm/CRM/Event/ActionMapping.php on line 235 |
CRM/Activity/ActionMapping.php
Outdated
* Determine whether a schedule based on this mapping should | ||
* send to additional contacts. | ||
*/ | ||
public function sendToAdditional(int $entityId): bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you either need to add int to the parent or remove here
…ve/template events support reminders with event types/templates and multiple event/type/template IDs fix
77d0894
to
3741f35
Compare
test this please |
(fail was unrelated but let's get the green tick) |
Overview
If you have a scheduled reminder for an event that's deleted, it will still send (repeatedly!) reminders to anyone listed under "Additional Recipients".
Details for replication and a technical discussion are in core#1590.
Technical Details
This is an improvement on the approach used in #16311. When I wrote that patch, I thought the only exception to "send to additional recipients" was if the event was a template. I can now see that each ActionMapping class needs its own criteria to determine if additional recipients should be reminded. E.g. contacts need to check for
is_deleted
, contributions/memberships need to actually check if the record was deleted, events must do the latter AND ensure it's not a template.So instead of simply modifying the logic of the
notTemplate()
method, I've created a new methodCivi/ActionSchedule/MappingInterface::sendToAdditional()
, and moved thenotTemplate()
logic intoCRM_Event_ActionMapping
.Comments
This passes the test in #16311, and adds another test for deleted events.
I've set all the other
sendToAdditional()
methods to returnTRUE
to preserve current behavior on all other scheduled reminder types. I don't doubt there are some undesired behaviors in there, but that's beyond the scope of this PR (though this PR should make those fixes trivial).