diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 2dd8f7c1..00000000 --- a/.coveragerc +++ /dev/null @@ -1,10 +0,0 @@ -[run] -omit = - /*/test* - /tests - /*/__init__.py - /setup.py - /*/migrations/* -source = openwisp_notifications -parallel = true -concurrency = multiprocessing diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..19e1875c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,30 @@ +--- +name: Bug report +about: Open a bug report +title: "[bug] " +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of the bug or unexpected behavior. + +**Steps To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**System Informatioon:** + - OS: [e.g. Ubuntu 24.04 LTS] + - Python Version: [e.g. Python 3.11.2] + - Django Version: [e.g. Django 4.2.5] + - Browser and Browser Version (if applicable): [e.g. Chromium v126.0.6478.126] diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..523386b9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[feature] " +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 00000000..34a8295a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,12 @@ +--- +name: Question +about: Please use the Discussion Forum to ask questions +title: "[question] " +labels: question +assignees: '' + +--- + +Please use the [Discussion Forum](https://github.com/orgs/openwisp/discussions) to ask questions. + +We will take care of moving the discussion to a more relevant repository if needed. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..c893f4a8 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,19 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "pip" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "monthly" + commit-message: + prefix: "[deps] " + - package-ecosystem: "github-actions" # Check for GitHub Actions updates + directory: "/" # The root directory where the Ansible role is located + schedule: + interval: "monthly" # Check for updates weekly + commit-message: + prefix: "[ci] " diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..a7d72cee --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,20 @@ +## Checklist + +- [ ] I have read the [OpenWISP Contributing Guidelines](http://openwisp.io/docs/developer/contributing.html). +- [ ] I have manually tested the changes proposed in this pull request. +- [ ] I have written new test cases for new code and/or updated existing tests for changes to existing code. +- [ ] I have updated the documentation. + +## Reference to Existing Issue + +Closes #. + +Please [open a new issue](https://github.com/openwisp/openwisp-notifications/issues/new/choose) if there isn't an existing issue yet. + +## Description of Changes + +Please describe these changes. + +## Screenshot + +Please include any relevant screenshots. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f34ed149..fcf028c9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: OpenWISP CI Build +name: OpenWISP Notifications CI Build on: push: @@ -16,7 +16,7 @@ jobs: build: name: Python==${{ matrix.python-version }} | ${{ matrix.django-version }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 services: redis: @@ -37,63 +37,54 @@ jobs: - django~=4.2.0 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - name: Install system packages + - name: Install Dependencies + id: deps run: | sudo apt update sudo apt-get -qq -y install sqlite3 gdal-bin - - - name: Upgrade python system packages - run: pip install -U pip wheel setuptools - - - name: Install test dependencies - run: | + pip install -U pip wheel setuptools pip install -U -r requirements-test.txt - - - name: Install openwisp-notifications - run: | pip install -U -e . pip install ${{ matrix.django-version }} - - - name: Install npm dependencies - run: sudo npm install -g jshint stylelint + sudo npm install -g jshint stylelint - name: QA checks run: | ./run-qa-checks - name: Tests + if: ${{ !cancelled() && steps.deps.conclusion == 'success' }} run: | - SAMPLE_APP=1 ./runtests.py + SAMPLE_APP=1 coverage run ./runtests.py --parallel coverage run runtests.py --parallel coverage combine + coverage xml env: SELENIUM_HEADLESS: 1 - name: Upload Coverage - run: coveralls --service=github - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COVERALLS_FLAG_NAME: python-${{ matrix.python-version }}-${{ matrix.django-version }} - COVERALLS_PARALLEL: true + if: ${{ success() }} + uses: coverallsapp/github-action@v2 + with: + parallel: true + format: cobertura + flag-name: python-${{ matrix.env.env }} + github-token: ${{ secrets.GITHUB_TOKEN }} coveralls: - name: Finish Coveralls needs: build runs-on: ubuntu-latest - container: python:3-slim steps: - - name: Finished - run: | - pip3 install --upgrade coveralls - coveralls --finish - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Coveralls Finished + uses: coverallsapp/github-action@v2 + with: + parallel-finished: true diff --git a/CHANGES.rst b/CHANGES.rst index b4aacbda..6dc69835 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -12,11 +12,11 @@ Version 1.0.3 [2022-08-03] Bugfixes ~~~~~~~~ -- Flagged tests that should not be run on a production environment: - These tests depend on the static storage backend of the project. - In a production environment, the filenames could get changed due to - static minification and cache invalidation. Hence, these tests - should not be run on the production environment because they'll fail. +- Flagged tests that should not be run on a production environment: These + tests depend on the static storage backend of the project. In a + production environment, the filenames could get changed due to static + minification and cache invalidation. Hence, these tests should not be + run on the production environment because they'll fail. Version 1.0.2 [2022-07-01] -------------------------- @@ -25,11 +25,11 @@ Bugfixes ~~~~~~~~ - Fixed `hardcoded static image URLs - `_. - These create issues when static files are served using an - external service (e.g. S3 storage buckets). -- Fixed `"Organization.DoesNotExist" error on creating - a new organization `_. + `_. These + create issues when static files are served using an external service + (e.g. S3 storage buckets). +- Fixed `"Organization.DoesNotExist" error on creating a new organization + `_. Version 1.0.1 [2022-06-09] -------------------------- @@ -38,10 +38,10 @@ Bugfixes ~~~~~~~~ - Fixed `handling of the "OPENWISP_NOTIFICATIONS_SOUND" setting - `_. - The code was not passing the sound file path to the utilities - of ``django.contrib.staticfiles`` and hence the sound file was - not loaded properly when using different static storage backend. + `_. The + code was not passing the sound file path to the utilities of + ``django.contrib.staticfiles`` and hence the sound file was not loaded + properly when using different static storage backend. Version 1.0.0 [2022-04-28] -------------------------- @@ -56,15 +56,16 @@ Changes ~~~~~~~ Backward incompatible changes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++++++++++++++++++++++++++++++ -- Removed notification widget and toast template tags: - the template tags "notification_widget" and "notification_toast" have been - removed and their HTML is added directly to the admin/base_site.html template -- Changed the API URL prefix to make it consistent with other OpenWISP modules +- Removed notification widget and toast template tags: the template tags + "notification_widget" and "notification_toast" have been removed and + their HTML is added directly to the admin/base_site.html template +- Changed the API URL prefix to make it consistent with other OpenWISP + modules Dependencies -^^^^^^^^^^^^ +++++++++++++ - Dropped support for Python 3.6 - Added support for Python 3.8 and 3.9 @@ -75,9 +76,10 @@ Dependencies - Upgraded openwisp-utils to 1.0.x Other changes -^^^^^^^^^^^^^ ++++++++++++++ -- Restyled widget to new OpenWISP theme plus various UI fixes and improvements +- Restyled widget to new OpenWISP theme plus various UI fixes and + improvements - Restyled notification email template - When clicking on the mark as read button, the notification widget now instantaneously marks notification as read instead of waiting for the @@ -89,27 +91,27 @@ Other changes (which may take a long time to finish in big installations) - Changed wording of "unsubscribe" button, which has been renamed to "Silence notifications" -- Added dedicated channel layer group for each user to avoid - generating warnings like - ``63 of 67 channels over capacity in group ow_notification`` +- Added dedicated channel layer group for each user to avoid generating + warnings like ``63 of 67 channels over capacity in group + ow_notification`` Bugfixes ~~~~~~~~ - Fixed a bug which caused to lose notification preferences of users -- Fixed extensibility of openwisp-users: - removed openwisp-users as a direct dependency from migrations file - because it was creating issues when extending openwisp-users +- Fixed extensibility of openwisp-users: removed openwisp-users as a + direct dependency from migrations file because it was creating issues + when extending openwisp-users - Fixed multiple jquery inclusions in ``base_site.html`` - Fixed WSS connection error when running on http - Fixed creation of notification settings for superuser - Fixed unregistered notification type breaking API - Fixed closing notification toast on slow connections -- Fixed notification storms: when many notifications are created - due to severe network outages, the UI is not flooded anymore +- Fixed notification storms: when many notifications are created due to + severe network outages, the UI is not flooded anymore - Fixed browsable API view for NotificationReadAllView -- Added error handling for sending emails when notification settings - for a specific user are not present +- Added error handling for sending emails when notification settings for a + specific user are not present - Fixed unsubscribe / silence notifications button alignment - Fixed Swagger API doc issues - Fixed ``create_notification`` command to honor organization notification @@ -153,13 +155,14 @@ Features - Added support for Django 3.1 - Added possibility of `silencing notifications for specific objects \ - temporarily or permanently `_ + temporarily or permanently + `_ Bugfixes ~~~~~~~~ -- Resolved accessibility issues with the notification widget: - all clickable items are now browsable with the keyboard as well +- Resolved accessibility issues with the notification widget: all + clickable items are now browsable with the keyboard as well Version 0.1.0 [2020-09-02] -------------------------- diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index f401b583..f4b2721d 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1 +1,2 @@ -Please refer to the `Contribution Guidelines `_. +Please refer to the `Contribution Guidelines +`_. diff --git a/openwisp_notifications/CONTRIBUTING.rst b/openwisp_notifications/CONTRIBUTING.rst new file mode 100644 index 00000000..9602293b --- /dev/null +++ b/openwisp_notifications/CONTRIBUTING.rst @@ -0,0 +1,2 @@ +Please refer to the `OpenWISP Contributing Guidelines +`_. diff --git a/openwisp_notifications/base/models.py b/openwisp_notifications/base/models.py index 75b5ea4b..f4e2fd55 100644 --- a/openwisp_notifications/base/models.py +++ b/openwisp_notifications/base/models.py @@ -204,7 +204,7 @@ def _related_object(self, field): cache.set( cache_key, obj, - timeout=app_settings.OPENWISP_NOTIFICATIONS_CACHE_TIMEOUT, + timeout=app_settings.CACHE_TIMEOUT, ) return obj diff --git a/openwisp_notifications/checks.py b/openwisp_notifications/checks.py index d4d3ea57..bbfe9c87 100644 --- a/openwisp_notifications/checks.py +++ b/openwisp_notifications/checks.py @@ -9,7 +9,7 @@ @checks.register def check_cors_configuration(app_configs, **kwargs): errors = [] - if not app_settings.OPENWISP_NOTIFICATIONS_HOST: + if not app_settings.HOST: return errors if not ( diff --git a/openwisp_notifications/context_processors.py b/openwisp_notifications/context_processors.py index 23f219cf..6ccd70eb 100644 --- a/openwisp_notifications/context_processors.py +++ b/openwisp_notifications/context_processors.py @@ -5,8 +5,6 @@ def notification_api_settings(request): return { - 'OPENWISP_NOTIFICATIONS_HOST': app_settings.OPENWISP_NOTIFICATIONS_HOST, - 'OPENWISP_NOTIFICATIONS_SOUND': static( - app_settings.OPENWISP_NOTIFICATIONS_SOUND - ), + 'OPENWISP_NOTIFICATIONS_HOST': app_settings.HOST, + 'OPENWISP_NOTIFICATIONS_SOUND': static(app_settings.SOUND), } diff --git a/openwisp_notifications/migrations/0001_initial.py b/openwisp_notifications/migrations/0001_initial.py index ec35a4d5..155bc180 100644 --- a/openwisp_notifications/migrations/0001_initial.py +++ b/openwisp_notifications/migrations/0001_initial.py @@ -11,7 +11,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/openwisp_notifications/migrations/0003_notification_notification_type.py b/openwisp_notifications/migrations/0003_notification_notification_type.py index 87bc0569..745bad3f 100644 --- a/openwisp_notifications/migrations/0003_notification_notification_type.py +++ b/openwisp_notifications/migrations/0003_notification_notification_type.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ('openwisp_notifications', '0002_default_permissions'), ] diff --git a/openwisp_notifications/migrations/0004_notificationsetting.py b/openwisp_notifications/migrations/0004_notificationsetting.py index ddb044f7..0ddf2967 100644 --- a/openwisp_notifications/migrations/0004_notificationsetting.py +++ b/openwisp_notifications/migrations/0004_notificationsetting.py @@ -67,7 +67,6 @@ def reverse_notification_setting_groups_permissions(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), swapper.dependency('openwisp_users', 'Organization'), diff --git a/openwisp_notifications/migrations/0005_delete_notificationuser.py b/openwisp_notifications/migrations/0005_delete_notificationuser.py index 0b35d96c..58d3958b 100644 --- a/openwisp_notifications/migrations/0005_delete_notificationuser.py +++ b/openwisp_notifications/migrations/0005_delete_notificationuser.py @@ -21,7 +21,6 @@ def populate_notification_user_permissions(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('openwisp_notifications', '0004_notificationsetting'), ] diff --git a/openwisp_notifications/migrations/0006_objectnotification.py b/openwisp_notifications/migrations/0006_objectnotification.py index e704fb03..a380a46f 100644 --- a/openwisp_notifications/migrations/0006_objectnotification.py +++ b/openwisp_notifications/migrations/0006_objectnotification.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ ('contenttypes', '0002_remove_content_type_name'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), diff --git a/openwisp_notifications/migrations/0007_notificationsetting_deleted.py b/openwisp_notifications/migrations/0007_notificationsetting_deleted.py index 9dd35252..de69bb65 100644 --- a/openwisp_notifications/migrations/0007_notificationsetting_deleted.py +++ b/openwisp_notifications/migrations/0007_notificationsetting_deleted.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ('openwisp_notifications', '0006_objectnotification'), ] diff --git a/openwisp_notifications/settings.py b/openwisp_notifications/settings.py index 9498c4d9..46eacb06 100644 --- a/openwisp_notifications/settings.py +++ b/openwisp_notifications/settings.py @@ -5,9 +5,9 @@ CONFIG_DEFAULTS.update({'USE_JSONFIELD': True}) -OPENWISP_NOTIFICATIONS_HOST = getattr(settings, 'OPENWISP_NOTIFICATIONS_HOST', None) +HOST = getattr(settings, 'OPENWISP_NOTIFICATIONS_HOST', None) -OPENWISP_NOTIFICATIONS_CACHE_TIMEOUT = getattr( +CACHE_TIMEOUT = getattr( settings, 'OPENWISP_NOTIFICATIONS_CACHE_TIMEOUT', 2 * 24 * 60 * 60 ) @@ -31,7 +31,7 @@ }, ) -OPENWISP_NOTIFICATIONS_SOUND = getattr( +SOUND = getattr( settings, 'OPENWISP_NOTIFICATIONS_SOUND', 'openwisp-notifications/audio/notification_bell.mp3', @@ -48,7 +48,7 @@ # Remove the leading "/static/" here as it will # conflict with the "static()" call in context_processors.py. # This is done for backward compatibility. -OPENWISP_NOTIFICATIONS_SOUND = re.sub('^/static/', '', OPENWISP_NOTIFICATIONS_SOUND) +SOUND = re.sub('^/static/', '', SOUND) def get_config(): diff --git a/openwisp_notifications/tests/test_admin.py b/openwisp_notifications/tests/test_admin.py index 2042054d..7dcd6843 100644 --- a/openwisp_notifications/tests/test_admin.py +++ b/openwisp_notifications/tests/test_admin.py @@ -129,7 +129,7 @@ def test_default_notification_setting(self): # For more info, look at TestAdmin.test_default_notification_setting @patch.object( app_settings, - 'OPENWISP_NOTIFICATIONS_SOUND', + 'SOUND', '/static/notification.mp3', ) def test_notification_sound_setting(self): @@ -141,7 +141,7 @@ def test_notification_sound_setting(self): @patch.object( app_settings, - 'OPENWISP_NOTIFICATIONS_HOST', + 'HOST', 'https://example.com', ) def test_notification_host_setting(self): diff --git a/openwisp_notifications/tests/test_notifications.py b/openwisp_notifications/tests/test_notifications.py index 67752ddf..555eb060 100644 --- a/openwisp_notifications/tests/test_notifications.py +++ b/openwisp_notifications/tests/test_notifications.py @@ -644,7 +644,7 @@ def test_related_objects_database_query(self): self.assertEqual(n.action_object, operator) self.assertEqual(n.target, operator) - @patch.object(app_settings, 'OPENWISP_NOTIFICATIONS_CACHE_TIMEOUT', 0) + @patch.object(app_settings, 'CACHE_TIMEOUT', 0) def test_notification_cache_timeout(self): # Timeout=0 means value is not cached operator = self._get_operator() diff --git a/openwisp_notifications/tests/test_utils.py b/openwisp_notifications/tests/test_utils.py index 807d7d7b..29156165 100644 --- a/openwisp_notifications/tests/test_utils.py +++ b/openwisp_notifications/tests/test_utils.py @@ -49,7 +49,7 @@ def test_populate_notification_preferences_command(self, mocked_task): class TestChecks(TestCase, TestOrganizationMixin): @patch.object( app_settings, - 'OPENWISP_NOTIFICATIONS_HOST', + 'HOST', 'https://example.com', ) def test_cors_not_configured(self): diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..88a860d0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,22 @@ +[tool.coverage.run] +source = ["openwisp_notifications"] +parallel = true +concurrency = ["multiprocessing"] +omit = [ + "openwisp_notifications/__init__.py", + "*/tests/*", + "*/migrations/*", +] + +[tool.docstrfmt] +extend_exclude = ["**/*.py", "README.rst"] + +[tool.isort] +known_third_party = ["django", "django_x509"] +known_first_party = ["openwisp_users", "openwisp_utils", "openwisp_notifications"] +default_section = "THIRDPARTY" +line_length = 88 +multi_line_output = 3 +use_parentheses = true +include_trailing_comma = true +force_grid_wrap = 0 diff --git a/requirements-test.txt b/requirements-test.txt index 57b38551..7c267db4 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,7 +1,7 @@ openwisp-utils[qa,selenium] @ https://github.com/openwisp/openwisp-utils/tarball/master -django-cors-headers~=4.0.0 -django-redis~=5.2.0 -channels_redis~=4.1.0 -pytest-asyncio~=0.21.0 -pytest-django~=4.5.0 -freezegun~=1.2.2 +django-cors-headers~=4.4.0 +django-redis~=5.4.0 +channels_redis~=4.2.0 +pytest-asyncio~=0.23.8 +pytest-django~=4.8.0 +freezegun~=1.5.1 diff --git a/requirements.txt b/requirements.txt index 0f28bd10..8e29af7f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -django-notifications-hq~=1.8.2 +django-notifications-hq~=1.8.3 channels~=3.0.2 openwisp-users @ https://github.com/openwisp/openwisp-users/tarball/master openwisp-utils[rest,celery] @ https://github.com/openwisp/openwisp-utils/tarball/master -markdown~=3.4.3 +markdown~=3.6.0 diff --git a/setup.cfg b/setup.cfg index 6c64acd3..5a0e0235 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,16 +12,6 @@ max-line-length = 110 # W605: invalid escape sequence ignore = W605, W503, W504 -[isort] -known_third_party = django -known_first_party = openwisp_users, openwisp_utils -line_length=88 -default_section = THIRDPARTY -multi_line_output=3 -use_parentheses=True -include_trailing_comma=True -force_grid_wrap=0 - [tool:pytest] DJANGO_SETTINGS_MODULE = openwisp2.settings python_files = test_websokcets.py diff --git a/setup.py b/setup.py index 7a7f1259..8a62d419 100755 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ def get_install_requires(): name='openwisp-notifications', version=get_version(), license='GPL3', - author='Gagan Deep', + author='OpenWISP', author_email='support@openwisp.io', description='Notifications module of OpenWISP', long_description=open('README.rst').read(), @@ -56,7 +56,7 @@ def get_install_requires(): zip_safe=False, install_requires=get_install_requires(), classifiers=[ - 'Development Status :: 3 - Alpha', + 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Topic :: Internet :: WWW/HTTP', 'Topic :: System :: Networking', diff --git a/tests/openwisp2/sample_notifications/migrations/0001_initial.py b/tests/openwisp2/sample_notifications/migrations/0001_initial.py index 27759336..d6f83ac6 100644 --- a/tests/openwisp2/sample_notifications/migrations/0001_initial.py +++ b/tests/openwisp2/sample_notifications/migrations/0001_initial.py @@ -13,7 +13,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/tests/openwisp2/sample_notifications/migrations/0002_testapp.py b/tests/openwisp2/sample_notifications/migrations/0002_testapp.py index a92ac136..c1bdf765 100644 --- a/tests/openwisp2/sample_notifications/migrations/0002_testapp.py +++ b/tests/openwisp2/sample_notifications/migrations/0002_testapp.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ ('openwisp_users', '0007_unique_email'), ('sample_notifications', '0001_initial'),