Skip to content

Commit

Permalink
Merge pull request #489 from elixir-luxembourg/implement-notification…
Browse files Browse the repository at this point in the history
…-views-react

Implement notification views
  • Loading branch information
Fancien authored Nov 10, 2023
2 parents e7c2cb7 + 338b306 commit 2b8e497
Show file tree
Hide file tree
Showing 44 changed files with 12,953 additions and 5,426 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ fabric.properties
elixir_daisy/settings_local.py
static/css/*
web/static/vendor/node_modules/*

web/static/js/*.bundle.js
web/static/js/*.bundle.js.LICENSE.txt


/log/*.log
Expand Down
10 changes: 10 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,13 @@ repos:
hooks:
- id: black
language_version: python3
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.15.0
hooks:
- id: eslint
files: web/static/vendor/(components|tests)/.*\.[jt]sx?$
types: [file]
additional_dependencies:
- eslint@8.15.0
- eslint-plugin-react@7.29.4
- eslint-plugin-react-hooks@4.6.0
7 changes: 5 additions & 2 deletions DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ sudo /usr/local/bin/pip3.9 install gunicorn
## NPM and Node.js

```bash
curl -sL https://rpm.nodesource.com/setup_16.x | sudo bash -
sudo yum install nodejs
apt-get update && apt-get install -y ca-certificates curl gnupg
mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_18.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
apt-get update && apt-get install -y nodejs
```

Then you need to compile the static files.
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ You are encouraged to try Daisy for yourself using our [DEMO deployment](https:/
1. Compile and deploy static files

```bash
cd web/static/vendor
npm run build
cd ../../../
docker-compose exec web python manage.py collectstatic
```
1. Create initial data in the database
Expand Down Expand Up @@ -224,7 +227,7 @@ cd web/static/vendor/
npm ci
```

### Compile daisy.scss
### Compile daisy.scss and React
```bash
cd web/static/vendor
npm run-script build
Expand Down
6 changes: 3 additions & 3 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ services:
# database
db:
image: postgres:10.1
restart: always
restart: on-failure
environment:
POSTGRES_PASSWORD: daisy
POSTGRES_USER: daisy
Expand All @@ -34,7 +34,7 @@ services:
# web werver frontend
nginx:
build: ./docker/nginx
restart: always
restart: on-failure
volumes:
- statics:/public/static:ro
ports:
Expand All @@ -52,7 +52,7 @@ services:
# rabbit mq
mq:
image: rabbitmq:3.9-management-alpine
restart: "always"
restart: on-failure
ports:
- "15672:15672"
- "5672:5672"
Expand Down
3 changes: 2 additions & 1 deletion elixir_daisy/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
"django.contrib.messages.context_processors.messages",
"web.views.context_processors.daisy_version",
"web.views.context_processors.instance_branding",
"notification.views.context_processors.daisy_notifications_enabled",
],
},
},
Expand Down Expand Up @@ -309,7 +310,7 @@
}

# by default, notifications by email are disabled
NOTIFICATIONS_DISABLED = True
NOTIFICATIONS_DISABLED = False

LOGIN_USERNAME_PLACEHOLDER = ""
LOGIN_PASSWORD_PLACEHOLDER = ""
Expand Down
2 changes: 2 additions & 0 deletions elixir_daisy/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

from core.forms.user import UserAuthForm
from web.urls import web_urls
from notification.urls import notif_urls

urlpatterns = [
url(
Expand All @@ -31,6 +32,7 @@
),
url(r"^logout/$", auth_views.LogoutView.as_view(), name="logout"),
url(r"^admin/", admin.site.urls),
url(r"^notifications/", include(notif_urls)),
url(r"", include(web_urls)),
]

Expand Down
85 changes: 85 additions & 0 deletions notification/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import logging

from django.views.decorators.http import require_http_methods
from django.core.exceptions import PermissionDenied
from django.db.models import QuerySet
from django.http import JsonResponse

from notification.models import Notification


logger = logging.getLogger(__name__)


def jsonify(data):
if isinstance(data, QuerySet) or isinstance(data, list):
data = [o.to_json() for o in data]
else:
data = data.to_json()

return JsonResponse({"data": data}, status=200)


@require_http_methods(["PATCH"])
def api_dismiss_notification(request, pk):
notification = Notification.objects.get(pk=pk)
if request.user != notification.recipient:
raise PermissionDenied(
"You cannot dismiss a notification you are not the recipient of"
)
logger.debug(f"Dismissing user {request.user.pk} notification {notification.pk}")
notification.dismissed = True
notification.save()

notification_list = Notification.objects.filter(
recipient=request.user,
content_type=notification.content_type,
dispatch_in_app=True,
)
return jsonify(notification_list)


@require_http_methods(["PATCH"])
def api_dismiss_all_notifications(request, object_type):
logger.debug(f"Dismissing notifications for object_type {object_type}")
notification_list = Notification.objects.filter(
recipient=request.user,
content_type__model=object_type,
dispatch_in_app=True,
)
for notif in notification_list:
notif.dismissed = True
notif.save()

logger.debug(
f"Successfully dismissed {len(notification_list)} notifications for user {request.user.pk}"
)
return jsonify(notification_list)


@require_http_methods(["GET"])
def api_get_notifications(request):
notifications_list = Notification.objects.filter(
dispatch_in_app=True,
)
if request.GET.get("show_dismissed") != "true":
notifications_list = notifications_list.filter(dismissed=False)
if request.GET.get("as_admin") != "true":
notifications_list = notifications_list.filter(recipient__pk=request.user.pk)
elif request.GET.get("recipient", ""):
notifications_list = notifications_list.filter(
recipient__pk=request.GET.get("recipient")
)

return jsonify(notifications_list.all())


@require_http_methods(["GET"])
def api_get_notifications_number(request):
number = Notification.objects.filter(
recipient=request.user,
dismissed=False,
dispatch_in_app=True,
).count()

return JsonResponse({"success": True, "data": number}, status=200)
31 changes: 30 additions & 1 deletion notification/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
Notification class does not have any target at the moment.
"""
from datetime import datetime

from django.db import models
from django.urls import reverse
from django.apps import apps
Expand Down Expand Up @@ -102,7 +104,8 @@ def get_absolute_url(self):
return reverse("contract", args=[str(self.object_id)])
elif self.content_type.model_class() == apps.get_model("core.Project"):
return reverse("project", args=[str(self.object_id)])
raise Exception("No url defined for this content type")
else:
return None

def get_full_url(self):
"""
Expand All @@ -114,5 +117,31 @@ def get_full_url(self):
self.get_absolute_url(),
)

@property
def event_time(self):
return datetime.now()

def to_json(self):
user_json = (
self.recipient.to_json()
if hasattr(self.recipient, "to_json")
else {"id": self.recipient.id, "name": self.recipient.get_full_name()}
)
return {
"id": self.id,
"recipient": user_json,
"verb": self.verb.value,
"on": self.on,
"time": self.time,
"sentInApp": self.dispatch_in_app,
"sentByEmail": self.dispatch_by_email,
"dismissed": self.dismissed,
"message": self.message,
"objectType": self.content_type.model,
"objectDisplayName": self.content_type.name,
"objectName": self.content_object.__str__(),
"objectUrl": self.get_absolute_url() or "",
}

def __str__(self):
return f"N: {self.recipient} {self.verb} {self.object_id} {self.time}"
62 changes: 62 additions & 0 deletions notification/static/notification/css/datatables.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dataTables_filter,
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_processing,
.dataTables_wrapper .dataTables_paginate {
display: flex;
color: #333333;
}

.dataTables_wrapper .dataTables_paginate span {
display: flex;
}

.dataTables_wrapper .dataTables_paginate .paginate_button {
min-width: 2.6em;
margin-right: 0.5em;
text-align: center;
border-radius: 4em;
position: relative;
display: block;
padding: 0.5rem 0.75rem;
margin-left: 0;
line-height: 1.25;
color: #023452 !important;
background: transparent !important;
border: 0 solid #dee2e6 !important;
}

.dataTables_wrapper .dataTables_paginate .paginate_button:hover {
z-index: 2;
text-decoration: none;
color: #000507 !important;
background-color: #e9ecef !important;
border-color: #dee2e6 !important;
}

.dataTables_wrapper .dataTables_paginate .paginate_button:active,
.dataTables_wrapper .dataTables_paginate .paginate_button:not(:disabled):not(.disabled).active,
.dataTables_wrapper .dataTables_paginate .paginate_button:not(:disabled):not(.disabled).active:hover,
.dataTables_wrapper .dataTables_paginate .paginate_button:not(:disabled):not(.disabled).current,
.dataTables_wrapper .dataTables_paginate .paginate_button:not(:disabled):not(.disabled).current:hover {
z-index: 1;
color: #fff !important;
background-color: #023452 !important;
border-color: #023452 !important;
}

.dataTables_wrapper .dataTables_paginate .paginate_button:focus {
z-index: 2;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(2, 52, 82, 0.25);
}

.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,
.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,
.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {
cursor: default;
color: #666 !important;
border: 0 solid transparent !important;
background: transparent !important;
box-shadow: none !important;
}
5 changes: 5 additions & 0 deletions notification/static/notification/css/notification.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.card-badge {
position: absolute;
right: 25px;
bottom: 35%;
}
Loading

0 comments on commit 2b8e497

Please sign in to comment.