2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-08-12 14:50:54 +00:00

Merge branch 'master' of https://github.com/inventree/InvenTree into plugin-2037

This commit is contained in:
Matthias
2021-11-04 10:10:58 +01:00
50 changed files with 1380 additions and 495 deletions

View File

@@ -5,7 +5,7 @@ from django.contrib import admin
from import_export.admin import ImportExportModelAdmin
from .models import InvenTreeSetting, InvenTreeUserSetting, WebhookEndpoint, WebhookMessage
import common.models
class SettingsAdmin(ImportExportModelAdmin):
@@ -23,7 +23,15 @@ class WebhookAdmin(ImportExportModelAdmin):
list_display = ('endpoint_id', 'name', 'active', 'user')
admin.site.register(InvenTreeSetting, SettingsAdmin)
admin.site.register(InvenTreeUserSetting, UserSettingsAdmin)
admin.site.register(WebhookEndpoint, WebhookAdmin)
admin.site.register(WebhookMessage, ImportExportModelAdmin)
admin.site.register(common.models.InvenTreeSetting, SettingsAdmin)
admin.site.register(common.models.InvenTreeUserSetting, UserSettingsAdmin)
admin.site.register(common.models.WebhookEndpoint, WebhookAdmin)
admin.site.register(common.models.WebhookMessage, ImportExportModelAdmin)
class NotificationEntryAdmin(admin.ModelAdmin):
list_display = ('key', 'uid', 'updated', )
admin.site.register(common.models.InvenTreeSetting, SettingsAdmin)
admin.site.register(common.models.InvenTreeUserSetting, UserSettingsAdmin)
admin.site.register(common.models.NotificationEntry, NotificationEntryAdmin)

View File

@@ -0,0 +1,25 @@
# Generated by Django 3.2.5 on 2021-11-03 13:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('common', '0011_auto_20210722_2114'),
]
operations = [
migrations.CreateModel(
name='NotificationEntry',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('key', models.CharField(max_length=250)),
('uid', models.IntegerField()),
('updated', models.DateTimeField(auto_now=True)),
],
options={
'unique_together': {('key', 'uid')},
},
),
]

View File

@@ -15,6 +15,7 @@ import json
import hashlib
import base64
from secrets import compare_digest
from datetime import datetime, timedelta
from django.db import models, transaction
from django.contrib.auth.models import User, Group
@@ -921,8 +922,14 @@ class InvenTreeUserSetting(BaseInvenTreeSetting):
GLOBAL_SETTINGS = {
'HOMEPAGE_PART_STARRED': {
'name': _('Show starred parts'),
'description': _('Show starred parts on the homepage'),
'name': _('Show subscribed parts'),
'description': _('Show subscribed parts on the homepage'),
'default': True,
'validator': bool,
},
'HOMEPAGE_CATEGORY_STARRED': {
'name': _('Show subscribed categories'),
'description': _('Show subscribed part categories on the homepage'),
'default': True,
'validator': bool,
},
@@ -1445,3 +1452,63 @@ class WebhookMessage(models.Model):
verbose_name=_('Worked on'),
help_text=_('Was the work on this message finished?'),
)
class NotificationEntry(models.Model):
"""
A NotificationEntry records the last time a particular notifaction was sent out.
It is recorded to ensure that notifications are not sent out "too often" to users.
Attributes:
- key: A text entry describing the notification e.g. 'part.notify_low_stock'
- uid: An (optional) numerical ID for a particular instance
- date: The last time this notification was sent
"""
class Meta:
unique_together = [
('key', 'uid'),
]
key = models.CharField(
max_length=250,
blank=False,
)
uid = models.IntegerField(
)
updated = models.DateTimeField(
auto_now=True,
null=False,
)
@classmethod
def check_recent(cls, key: str, uid: int, delta: timedelta):
"""
Test if a particular notification has been sent in the specified time period
"""
since = datetime.now().date() - delta
entries = cls.objects.filter(
key=key,
uid=uid,
updated__gte=since
)
return entries.exists()
@classmethod
def notify(cls, key: str, uid: int):
"""
Notify the database that a particular notification has been sent out
"""
entry, created = cls.objects.get_or_create(
key=key,
uid=uid
)
entry.save()

29
InvenTree/common/tasks.py Normal file
View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import logging
from datetime import timedelta, datetime
from django.core.exceptions import AppRegistryNotReady
logger = logging.getLogger('inventree')
def delete_old_notifications():
"""
Remove old notifications from the database.
Anything older than ~3 months is removed
"""
try:
from common.models import NotificationEntry
except AppRegistryNotReady:
logger.info("Could not perform 'delete_old_notifications' - App registry not ready")
return
before = datetime.now() - timedelta(days=90)
# Delete notification records before the specified date
NotificationEntry.objects.filter(updated__lte=before).delete()

View File

@@ -2,11 +2,12 @@
from __future__ import unicode_literals
from http import HTTPStatus
import json
from datetime import timedelta
from django.test import TestCase, Client
from django.contrib.auth import get_user_model
from .models import InvenTreeSetting, WebhookEndpoint, WebhookMessage
from .models import InvenTreeSetting, WebhookEndpoint, WebhookMessage, NotificationEntry
from .api import WebhookView
@@ -200,3 +201,23 @@ class WebhookMessageTests(TestCase):
assert str(response.content, 'utf-8') == WebhookView.model_class.MESSAGE_OK
message = WebhookMessage.objects.get()
assert message.body == {"this": "is a message"}
class NotificationTest(TestCase):
def test_check_notification_entries(self):
# Create some notification entries
self.assertEqual(NotificationEntry.objects.count(), 0)
NotificationEntry.notify('test.notification', 1)
self.assertEqual(NotificationEntry.objects.count(), 1)
delta = timedelta(days=1)
self.assertFalse(NotificationEntry.check_recent('test.notification', 2, delta))
self.assertFalse(NotificationEntry.check_recent('test.notification2', 1, delta))
self.assertTrue(NotificationEntry.check_recent('test.notification', 1, delta))