Skip to content

Communication class and admin for email texts#1658

Merged
susanodd merged 22 commits intomasterfrom
1657-installation-specific-emails
Jan 26, 2026
Merged

Communication class and admin for email texts#1658
susanodd merged 22 commits intomasterfrom
1657-installation-specific-emails

Conversation

@susanodd
Copy link
Copy Markdown
Collaborator

@susanodd susanodd commented Nov 13, 2025

Of the existing kinds of email subject and body text files, the various places that they are sent by the code, it looks like the case where a user has request change permission for a dataset does not send any email if this has been granted.

  • Mail to dataset owner

    • new user granted view access (sent to inform the owner if the dataset is public, includes users motivation)
    • user has requested access (sent if the dataset is not public, this includes a link for the owner to go to the manage page to grant access for this user, includes motivation from the user
  • Mail to user

    • welcome email to new users
    • access granted to public dataset (default dataset, plus other public datasets requested view access for)
    • access granted to dataset (mail on behalf of dataset owner, if the dataset is not public and the manager has approved)

Context variables:

signbank_name
url
user.firstname
user.lastname
user.email
user.username
new_user_firstname
new_user_lastname
new_user_email
dataset
motivation
site.name
https://{{site}}/datasets/manager/

@susanodd susanodd linked an issue Nov 13, 2025 that may be closed by this pull request
@susanodd susanodd marked this pull request as draft November 13, 2025 13:42
@susanodd susanodd added the DRAFT label Nov 13, 2025
@susanodd susanodd marked this pull request as ready for review December 11, 2025 13:45
uses template and context to generate in branch if found in database
@susanodd
Copy link
Copy Markdown
Collaborator Author

susanodd commented Dec 12, 2025

SUMMARY

Some help text for editing of the email subject and message fields in the database has been added.
The fields are actually templates since they may have variables in them, surrounded by {{ }}

I added a kind of template render preview to the admin edit page for communication. This is by way of an extra non-editable field that shows the rendering of the text the user has entered

  • displays the available context variables for use in the emails templates as an non-editable "instructions" field for add communication
  • the communication choices are in a predefined choice-list. The newest such object matching the type is retrieved

@susanodd susanodd changed the title Initial communication class and admin for email texts Communication class and admin for email texts Dec 16, 2025
susanodd and others added 2 commits December 16, 2025 12:59
@susanodd

This comment was marked as outdated.

@susanodd susanodd removed the DRAFT label Dec 18, 2025
@Woseseltops Woseseltops self-requested a review December 18, 2025 12:58
Copy link
Copy Markdown
Collaborator

@Woseseltops Woseseltops left a comment

Choose a reason for hiding this comment

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

In addition to my one comment in the code, a place other than attachments for this whole thing is probably better, as discussed in another issue.

Comment on lines +3973 to +3981
access_email = Communication.objects.filter(label='dataset_to_owner_existing_user_given_access').first()

if access_email:
subject_template = template.Template(access_email.subject)
subject = subject_template.render(mail_template_context)
else:
subject = render_to_string('registration/dataset_to_owner_existing_user_given_access_subject.txt',
context={'dataset': dataset_object.name,
'site': current_site})
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I see this pattern repeated several times... perhaps a function?

Copy link
Copy Markdown
Collaborator Author

@susanodd susanodd Jan 12, 2026

Choose a reason for hiding this comment

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

This was originally much cooler in one expression statement. Unfortunately the branches handle different types.

I'll try to recreate the original one and hide the branches. DONE

@susanodd
Copy link
Copy Markdown
Collaborator Author

susanodd commented Jan 12, 2026

In addition to my one comment in the code, a place other than attachments for this whole thing is probably better, as discussed in another issue.

  • I made a separate "app" folder for "communication"
  • removing the "attachments" needs to be in multiple steps rather than just removing the files:
  • the model was removed and a migration made to removes the table from the database.
  • (Later) After that has been done, then the files can be removed and the "app" removed from the "base" applications.

@susanodd
Copy link
Copy Markdown
Collaborator Author

susanodd commented Jan 13, 2026

I finished the requested revisions.

  • generate communication function retrieves from the database if available, otherwise uses the appropriate files. The file names are determined by f-strings

  • revised the other duplicated function that generates the context variables mockup.

  • added an "instructions" (non-editable) field to the add communication template.
    This shows the available context variables and briefly says how to use them.

  • the retrieval of the communication now retrieves that last one, so if the user creates multiple objects with the same label, the most recent is retrieved

@susanodd
Copy link
Copy Markdown
Collaborator Author

susanodd commented Jan 15, 2026

Here is what the "instructions help text" in the admin looks like:

Details add_communication_json_context_instructions

This includes all of the possible context variables that are used in all the template files for the various places where an email is sent.

Each of the places in the code creates a context for the email.

Since we don't know whether the fixtures initial content will be imported, there is no "starting block" for the various emails if the user wants to construct these from scratch.

Since the content of the context depends on the file and the place in the code, it would be best to make the data structure shown above have an additional set of keys above that is the label, then show the context variables dynamically based on what the user has chosen.

Here is a modification to display the instructions in a separate panel.
An additional json structure has been made to show the context variables per usage in the code (the json is not used yet)

Details communication-add-admin-with-fieldset-instructions-display

extra json per type of email label
@Woseseltops
Copy link
Copy Markdown
Collaborator

Woseseltops commented Jan 15, 2026

For the help text, I suggest this:

You indicate variables with double curly brackets. You can use {{site_name}}, {{signbank_name}}, {{url}}, {{user.firstname}}, {{user.lastname}}, {{user.email}}, {{user.username}}, {{new_user_firstname}}, {{new_user_lastname}}, {{new_user_email}}, {{dataset}}, {{movitation}} and {{site.name}}. Use the 'Save and continue editing' button to preview them with actual values.

Why not use help_text for this?

class MyModel(models.Model):
    description = models.TextField(
        help_text=(
            "Explain how to use this field. "
            "You can write multiple sentences here. "
            "Formatting like paragraphs is fine."
        )
    )

@susanodd
Copy link
Copy Markdown
Collaborator Author

susanodd commented Jan 15, 2026

For the help text, I suggest this:

You indicate variables with double curly brackets. You can use {{site_name}}, {{signbank_name}}, {{url}}, {{user.firstname}}, {{user.lastname}}, {{user.email}}, {{user.username}}, {{new_user_firstname}}, {{new_user_lastname}}, {{new_user_email}}, {{dataset}}, {{movitation}} and {{site.name}}. Use the 'Save and continue editing' button to preview them with actual values.

Why not use help_text for this?

class MyModel(models.Model):
    description = models.TextField(
        help_text=(
            "Explain how to use this field. "
            "You can write multiple sentences here. "
            "Formatting like paragraphs is fine."
        )
    )

Yes, it was originally a help text. Except the stupid context variables are "context sensitive" based on where in the code the emails are generated. (That's what I was trying to do with the "new" json expression, to make it context sensitive what the variables may be.)

I guess I could add something to "check" what is entered and see whether all the context variables are available for that kind of email. (Kip of Ei)

Another question about the context variables, Unify them? (Like the ones that use {{new_user_email}} versus {{user.email}}) This would need to be modified in the file templates as well as the places in the code where the context is created.

@susanodd
Copy link
Copy Markdown
Collaborator Author

susanodd commented Jan 16, 2026

@Woseseltops I figured out how to make use of the context per label dictionary! This can be used in the "render" preview.

Although some additional comments are needed to point out that the variable used isn't available for the type label.

I normalised the context variables.

See #1672 (comment)

One of the context variables is wrong in registration

@susanodd
Copy link
Copy Markdown
Collaborator Author

@Woseseltops check it out! I got it working, to validate the context variables the user has in their text

Details validation-of-context-variables

susanodd and others added 3 commits January 18, 2026 13:14
variables per email type; form validation of context variables depending on type of communication chosed, to match code where the emails are sent
@Woseseltops Woseseltops requested a review from Copilot January 22, 2026 10:56
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new Communication class to centralize email text management and removes the unused Attachment model. It replaces inline template rendering with a database-backed system for managing email subjects and bodies.

Changes:

  • Added a Communication model and admin interface for managing email templates
  • Refactored email sending code to use the new generate_communication function
  • Removed the Attachment model, views, URLs, and related functionality

Reviewed changes

Copilot reviewed 21 out of 24 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
signbank/communication/models.py New Communication model with validation for email templates and a generate_communication function to render emails
signbank/communication/admin.py Admin interface for Communication model with context variable instructions and preview rendering
signbank/communication/fixtures/communication.json Initial fixture data with default email templates
signbank/communication/migrations/0001_initial.py Database migration creating the Communication table
signbank/registration/views.py Updated to use generate_communication instead of inline template rendering
signbank/registration/models.py Updated to use generate_communication for activation emails
signbank/dictionary/adminviews.py Updated to use generate_communication for dataset access emails
signbank/registration/templates/registration/*.txt Fixed template variable references (e.g., {{site}} to {{site.domain}}, {{new_user_*}} to {{user.*}})
signbank/settings/base.py Added 'signbank.communication' to INSTALLED_APPS and removed ATTACHMENT_LOCATION setting
signbank/urls.py Removed attachments URL configuration
signbank/attachments/* Removed Attachment model, views, URLs, admin, and management commands

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,47 @@
[
{
"model": "attachments.communication",
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

The model reference is incorrect. It should be 'communication.communication' instead of 'attachments.communication' since the Communication model is in the communication app, not the attachments app.

Copilot uses AI. Check for mistakes.
}
},
{
"model": "attachments.communication",
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

The model reference is incorrect. It should be 'communication.communication' instead of 'attachments.communication' since the Communication model is in the communication app, not the attachments app.

Copilot uses AI. Check for mistakes.
}
},
{
"model": "attachments.communication",
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

The model reference is incorrect. It should be 'communication.communication' instead of 'attachments.communication' since the Communication model is in the communication app, not the attachments app.

Copilot uses AI. Check for mistakes.
}
},
{
"model": "attachments.communication",
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

The model reference is incorrect. It should be 'communication.communication' instead of 'attachments.communication' since the Communication model is in the communication app, not the attachments app.

Copilot uses AI. Check for mistakes.
}
},
{
"model": "attachments.communication",
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

The model reference is incorrect. It should be 'communication.communication' instead of 'attachments.communication' since the Communication model is in the communication app, not the attachments app.

Copilot uses AI. Check for mistakes.
A new user has signed up at {{site.name}}.

{{new_user_firstname}} {{new_user_lastname}} (user {{new_user_username}}, email address {{new_user_email}})
{{user.firstname}} {{user.lastname}} (user {{user.username}}, email address {{user.email}})
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

The template variable {{user.firstname}} should be {{user.first_name}} to match Django's User model field name. Similarly, {{user.lastname}} should be {{user.last_name}}.

Suggested change
{{user.firstname}} {{user.lastname}} (user {{user.username}}, email address {{user.email}})
{{user.first_name}} {{user.last_name}} (user {{user.username}}, email address {{user.email}})

Copilot uses AI. Check for mistakes.
Comment on lines +26 to +27
'dataset_to_owner_existing_user_given_access': {'user': {'firstname': 'FIRST NAME',
'lastname': 'LAST NAME',
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

The context keys 'firstname' and 'lastname' should be 'first_name' and 'last_name' to match Django's User model field names.

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +37
'user': {'firstname': 'FIRST NAME',
'lastname': 'LAST NAME',
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

The context keys 'firstname' and 'lastname' should be 'first_name' and 'last_name' to match Django's User model field names.

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +46
'user': {'firstname': 'FIRST NAME',
'lastname': 'LAST NAME',
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

The context keys 'firstname' and 'lastname' should be 'first_name' and 'last_name' to match Django's User model field names.

Copilot uses AI. Check for mistakes.
Comment on lines +74 to +75
'user': {'firstname': 'FIRST NAME',
'lastname': 'LAST NAME',
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

The context keys 'firstname' and 'lastname' should be 'first_name' and 'last_name' to match Django's User model field names.

Copilot uses AI. Check for mistakes.
@susanodd
Copy link
Copy Markdown
Collaborator Author

CoPilot changes (i.e., bugs) fixed!

Copy link
Copy Markdown
Collaborator

@Woseseltops Woseseltops left a comment

Choose a reason for hiding this comment

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

I love the screenshot @susanodd :)

@susanodd susanodd merged commit 09ccee1 into master Jan 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Installation specific emails

3 participants