feat: repeat license expiration reminders daily
This commit is contained in:
@@ -29,6 +29,7 @@
|
|||||||
* Make the license type field optional
|
* Make the license type field optional
|
||||||
* Show the plugin under Licences in the main menu
|
* Show the plugin under Licences in the main menu
|
||||||
* Restrict SMTP notification activation to administrators and explicitly authorized users
|
* Restrict SMTP notification activation to administrators and explicitly authorized users
|
||||||
|
* Repeat NetBox and optional email reminders on every daily job run from the first due interval through expiration
|
||||||
|
|
||||||
## [1.9.0](https://github.com/ICTU/netbox_slm/releases/tag/1.9.0) - 2026-06-25
|
## [1.9.0](https://github.com/ICTU/netbox_slm/releases/tag/1.9.0) - 2026-06-25
|
||||||
|
|
||||||
|
|||||||
@@ -86,9 +86,10 @@ Die Aktivierung des E-Mail-Versands darf nur durch Administratoren oder Benutzer
|
|||||||
`netbox_slm.manage_softwarelicense_email_notifications` geändert werden. Die eigentlichen SMTP-Zugangsdaten werden
|
`netbox_slm.manage_softwarelicense_email_notifications` geändert werden. Die eigentlichen SMTP-Zugangsdaten werden
|
||||||
ausschließlich in der NetBox-Serverkonfiguration gepflegt und sind im Plugin nicht einsehbar.
|
ausschließlich in der NetBox-Serverkonfiguration gepflegt und sind im Plugin nicht einsehbar.
|
||||||
|
|
||||||
Die Prüfung läuft einmal täglich als NetBox-Systemjob. Der NetBox-RQ-Worker muss daher mit Scheduler-Unterstützung
|
Die Prüfung läuft einmal täglich als NetBox-Systemjob. Sobald der erste konfigurierte Erinnerungstermin erreicht ist,
|
||||||
laufen; dies ist bei der regulären NetBox-Installation mit `rqworker` standardmäßig der Fall. Das interne
|
werden die Abonnenten bei jedem Joblauf erneut informiert: immer über NetBox und bei aktivierter E-Mail-Option
|
||||||
Versandprotokoll verhindert doppelte Nachrichten.
|
zusätzlich per SMTP. Dies wird bis einschließlich des Ablaufdatums wiederholt. Der NetBox-RQ-Worker muss dafür mit
|
||||||
|
Scheduler-Unterstützung laufen; dies ist bei der regulären NetBox-Installation mit `rqworker` standardmäßig der Fall.
|
||||||
|
|
||||||
### 3. Plugin in NetBox aktivieren
|
### 3. Plugin in NetBox aktivieren
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ limitations under the License.
|
|||||||
from netbox.plugins import PluginConfig
|
from netbox.plugins import PluginConfig
|
||||||
from django.utils.translation import gettext, gettext_lazy as _
|
from django.utils.translation import gettext, gettext_lazy as _
|
||||||
|
|
||||||
__version__ = "1.12.4"
|
__version__ = "1.13.0"
|
||||||
|
|
||||||
|
|
||||||
class SLMConfig(PluginConfig):
|
class SLMConfig(PluginConfig):
|
||||||
|
|||||||
+16
-16
@@ -47,23 +47,23 @@ class LicenseExpirationNotificationJob(JobRunner):
|
|||||||
)[0]
|
)[0]
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
|
|
||||||
if log.netbox_sent_at is None:
|
object_type = ContentType.objects.get_for_model(license)
|
||||||
object_type = ContentType.objects.get_for_model(license)
|
Notification.objects.update_or_create(
|
||||||
Notification.objects.update_or_create(
|
object_type=object_type,
|
||||||
object_type=object_type,
|
object_id=license.pk,
|
||||||
object_id=license.pk,
|
user=user,
|
||||||
user=user,
|
defaults={
|
||||||
defaults={
|
"created": now,
|
||||||
"object_repr": Notification.get_object_repr(license),
|
"object_repr": Notification.get_object_repr(license),
|
||||||
"event_type": LICENSE_EXPIRING,
|
"event_type": LICENSE_EXPIRING,
|
||||||
"read": None,
|
"read": None,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
log.netbox_sent_at = now
|
log.netbox_sent_at = now
|
||||||
log.save(update_fields=("netbox_sent_at",))
|
log.save(update_fields=("netbox_sent_at",))
|
||||||
self.logger.info(f"Created NetBox expiration notification for license {license.pk} and user {user}")
|
self.logger.info(f"Created NetBox expiration notification for license {license.pk} and user {user}")
|
||||||
|
|
||||||
if license.email_notifications and user.email and log.email_sent_at is None:
|
if license.email_notifications and user.email:
|
||||||
subject = _("License %(license)s expires on %(date)s") % {
|
subject = _("License %(license)s expires on %(date)s") % {
|
||||||
"license": license,
|
"license": license,
|
||||||
"date": license.expiration_date,
|
"date": license.expiration_date,
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ class ModelTestCase(SlmBaseTestCase):
|
|||||||
|
|
||||||
@override_settings(SERVER_EMAIL="netbox@example.com", EMAIL_HOST_USER="smtp-user")
|
@override_settings(SERVER_EMAIL="netbox@example.com", EMAIL_HOST_USER="smtp-user")
|
||||||
@patch("netbox_slm.jobs.send_mail")
|
@patch("netbox_slm.jobs.send_mail")
|
||||||
def test_expiration_job_notifies_subscribers_once(self, send_mail):
|
def test_expiration_job_notifies_subscribers_on_every_run(self, send_mail):
|
||||||
user = get_user_model().objects.create_user(
|
user = get_user_model().objects.create_user(
|
||||||
username="license-recipient",
|
username="license-recipient",
|
||||||
email="recipient@example.com",
|
email="recipient@example.com",
|
||||||
@@ -192,7 +192,7 @@ class ModelTestCase(SlmBaseTestCase):
|
|||||||
notification = Notification.objects.get(user=user, object_id=license.pk)
|
notification = Notification.objects.get(user=user, object_id=license.pk)
|
||||||
self.assertIsInstance(str(notification.event), str)
|
self.assertIsInstance(str(notification.event), str)
|
||||||
self.assertEqual(1, SoftwareLicenseNotificationLog.objects.filter(user=user, license=license).count())
|
self.assertEqual(1, SoftwareLicenseNotificationLog.objects.filter(user=user, license=license).count())
|
||||||
send_mail.assert_called_once()
|
self.assertEqual(2, send_mail.call_count)
|
||||||
self.assertEqual("netbox@example.com", send_mail.call_args.args[2])
|
self.assertEqual("netbox@example.com", send_mail.call_args.args[2])
|
||||||
|
|
||||||
def test_german_translation(self):
|
def test_german_translation(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user