Skip to content

First version of moderation emails #9587

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Conversation

marcospri
Copy link
Member

@marcospri marcospri commented May 26, 2025

Send emails on moderation status changes

  • Templates for moderation emails
  • Emit a ModerationEvent on the set_status view
  • Preview moderation emails on the admin pages

Docs

Follow up tasks (in the project board)

  • Link KB article on these emails about moderation.
  • Tune the subject for better threading.
  • Also send these in non pre-moderated groups.
  • Add a dropdown to be able to preview all status emails in the admin pages

Testing

  • Check the email template render in http://localhost:5000/admin/email

  • In a pre moderated group, create an annotation (or grab the ID of an existing one), with curl we can test the email sending:

curl  -i 'http://localhost:5000/api/annotations/ANNOTATION_ID/moderation' -X PATCH \
  -H 'Content-Type: application/json' \
  -H 'Accept: */*' \
  -H 'x-csrf-token: TOKEN' \
  -b 'auth=AUTH' \
  --data '{"annotation_updated":"2025-05-15T13:40:41.997487+00:00", "moderation_status": "DENIED"}'

In the console you'll see traces of the email being "sent":

worker (stderr)      | [2025-05-27 16:19:51,075: INFO/MainProcess] Task h.tasks.email.send[56486ba7-6cb5-45ba-b0af-f77ed591ac4f] received
worker (stderr)      | [2025-05-27 16:19:51,077: INFO/ForkPoolWorker-16] h.tasks.email.send[56486ba7-6cb5-45ba-b0af-f77ed591ac4f]: emailing in debug mode: check the `mail/` directory
worker (stderr)      | [2025-05-27 16:19:51,079: INFO/ForkPoolWorker-16] h.tasks.email.send[56486ba7-6cb5-45ba-b0af-f77ed591ac4f]: Sent email: tag='moderated_notification', sender_id=3, recipient_ids=[3], annotation_id='MeEgsjGSEfCvzqNvsMlrIg'
worker (stderr)      | [2025-05-27 16:19:51,083: INFO/ForkPoolWorker-16] h.tasks.email.send[56486ba7-6cb5-45ba-b0af-f77ed591ac4f] Task h.tasks.email.send[56486ba7-6cb5-45ba-b0af-f77ed591ac4f] succeeded in 0.003097740998782683s: None

@marcospri marcospri force-pushed the moderation-emails-simple branch 4 times, most recently from ede5484 to 7141ba1 Compare May 27, 2025 14:01
@marcospri marcospri changed the title [WIP] Moderation emails simple First version of moderation emails May 27, 2025
@marcospri marcospri force-pushed the moderation-emails-simple branch from 7141ba1 to d67bafa Compare May 27, 2025 14:13
@@ -58,6 +58,10 @@ def includeme(config): # noqa: PLR0915
"admin.email.preview.mention_notification",
"/admin/email/preview/mention-notification",
)
config.add_route(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New route to preview the email.

@@ -26,23 +46,27 @@ def set_status(
annotation: Annotation,
status: ModerationStatus | None,
user: User | None = None,
) -> None:
) -> ModerationLog | None:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor this method to return the resulting log entry.

report_exception(err)

@staticmethod
def email_subject(group_name: str, new_status: ModerationStatus) -> str:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using regular python (instead of template logic) for these.

Easier to test them IMO.

@@ -0,0 +1,722 @@
<!doctype html>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could consider using a base template for these like in LMS.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's looking the same as for mention emails, yes, I think we should extract a common layout at some point.

from .base import ModelFactory


class ModerationLog(ModelFactory):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing factory for this model.

return f"Your comment in {group_name} is pending approval"

msg = f"Unexpected moderation status change to {new_status}" # pragma: no cover
raise ValueError(msg)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be possible because we check the states for which we send emails but just in case we make a mistake we don't want to send an email with an empty subject or description.

return {
"user_display_name": "Jane Doe",
"status_change_description": AnnotationModerationService.email_status_change_description(
"GROUP NAME", ModerationStatus.APPROVED
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These would be nicer if we had a simple dropdown to be able to preview different statuses.

Added a card to the board to track that.

@@ -20,6 +20,7 @@ class EmailTag(StrEnum):
RESET_PASSWORD = "reset_password" # noqa: S105
MENTION_NOTIFICATION = "mention_notification"
TEST = "test"
MODERATED = "moderated_notification"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New email tag.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of the entries seem to be nouns. Maybe this one should be MODERATION instead of MODERATED?

user_id=author.userid, type_=Subscriptions.Type.MODERATED
),
),
"preferences_url": request.route_url("account_notifications"),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This URL still doesn't list this type of email, added a card to the board about it.

@marcospri marcospri marked this pull request as ready for review May 27, 2025 14:26
@marcospri marcospri requested a review from acelaya May 27, 2025 14:26
Copy link
Contributor

@acelaya acelaya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good in general, but I suggested we use nouns as in "moderation" or "annotation moderation" instead of "moderated" or "moderated annotation" in various places.

It sounds more natural and is more consistent with other types of events and notifications.

@@ -20,6 +20,7 @@ class EmailTag(StrEnum):
RESET_PASSWORD = "reset_password" # noqa: S105
MENTION_NOTIFICATION = "mention_notification"
TEST = "test"
MODERATED = "moderated_notification"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of the entries seem to be nouns. Maybe this one should be MODERATION instead of MODERATED?

Comment on lines +186 to +193
return f"Your comment in {group_name} has been declined"

if new_status == ModerationStatus.APPROVED:
return f"Your comment in {group_name} has been approved"

if new_status == ModerationStatus.PENDING:
return f"Your comment in {group_name} is pending approval"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we say "comment" or "annotation"?

I know we use the "comment" terminology in other places, but maybe it's worth discussing with the wider group. It should not block merging this PR though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I didn't address this in a comment.

TLDR (IMO): we can merge this version, and I’ll link to this comment from the board. I already have a vague "Send moderation emails in non-pre-moderated groups" card there, but I reckon most of the work there will be this issue.

The "comment" wording is what bioRxiv wants, so we’ll start with that. This PR only sends emails for pre-moderated groups, which are only offered to bioRxiv, so this will work for them.

Of course, we’ll want to send these in all cases eventually, so we have a few options:

  • Use the "comment" wording everywhere.
    I don't like this. It would be odd if this were the only place where annotations become comments.

  • Convince bioRxiv to use “annotation” instead.
    I don't think this is likely.

  • Use the "comment" wording everywhere, but just for "page notes".
    Not ideal to use both page note and comment for the same thing, but this would be easy to implement.

  • Use different templates or a conditional to show comment for bioRxiv and annotation for others.
    While this seems like the obvious solution, I’m not sure how we’d determine this—by authority? Organization? The group the annotation is in?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following my previous comments, maybe this file should be named annotation_moderation_notification.html.jinja2

@@ -0,0 +1,722 @@
<!doctype html>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's looking the same as for mention emails, yes, I think we should extract a common layout at some point.

@marcospri marcospri force-pushed the moderation-emails-simple branch from 1c8384b to e9e353c Compare May 28, 2025 11:29
- Templates for moderation emails
- Emit a ModerationEvent on the set_status view
- Preview moderation emails on the admin pages
@marcospri marcospri force-pushed the moderation-emails-simple branch from e9e353c to 95971a3 Compare May 28, 2025 11:53
Copy link
Contributor

@acelaya acelaya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏼

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants