fpdcc / document-search

Search and management interface for spatial documents at the Forest Preserves of Cook County.
2 stars 0 forks source link

Send license expiration notification emails #107

Closed xmedr closed 1 year ago

xmedr commented 1 year ago

Overview

This creates a management command send_expiration_email that puts details for all licenses expiring within a year of the command's start date into an email, which will be sent to users in the NotificationSubscription model. The intention is that this will be run once a year with a cron job.

There is a fix here for an error with validators that would not allow for migrations to be made. The fix adds @wraps decorators to certain validator functions.

This also adds an .env.example file intended to store the mandrill credentials and adds more context to local_settings.example.py for email sending.

Closes #106 Connects #63

Notes

For testing, my local db didn't have any licenses that were expiring this year, so I brought the app up and made one.

Also, this does not include work done to make a cron job. To my understanding, it seems like that's done on the deployment instance.

Testing Instructions

xmedr commented 1 year ago

I've realized that I can get the commands for the cronjob into the Dockerfile, so I'll be adding that shortly!

xmedr commented 1 year ago

@smcalilly Cool, I've got the command wrapped in a transaction and did some refactoring! I tried to encapsulate as much as I could in helper functions.

Transactions seem super useful, how often do you find yourself using them? I had read that they're a bit taxing to run so I don't imagine they're used everywhere all the time.

smcalilly commented 1 year ago

@xmedr yeah you need to be careful with it because it locks up the database. In this case, if the mgmt command was running at the same time somebody was trying to change the date in the admin, then they wouldn't be able to change the date until the transaction is committed. I'm sure there are other ways that make transactions resource intensive but I'm at the edge of my knowledge.

I don't use them a ton. I use them whenever there's any logic that has a higher likelihood to fail, like sending an email or requesting a third-party API. Or, if there's a critical operation where data integrity is the most important thing — a classic example is withdrawing money from a bank account. These are only some of the examples I'm most familiar with, I'm sure there are more use cases.

Based on your implementation in this PR (where you were asking about how to handle this in case the email sending fails), it seems like you have the right instinct for when to use it or not.