Commit fe520cc9 authored by Gladys Forte's avatar Gladys Forte

notification

parent bc2be688
# chat/consumers.py
from channels.generic.websocket import AsyncWebsocketConsumer
import json
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.room_name
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# Leave room group
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# Receive message from WebSocket
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
# Receive message from room group
async def chat_message(self, event):
message = event['message']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message
}))
\ No newline at end of file
# chat/routing.py
from django.conf.urls import url
from app.applicationlayer.management.notification import consumers
websocket_urlpatterns = [
url(r'^ws/chat/(?P<room_name>[^/]+)/$', consumers.ChatConsumer),
]
\ No newline at end of file
from rest_framework import serializers
from app.entities import models
from django.conf import settings
class NotificationSerializer(serializers.ModelSerializer):
class Meta:
model = models.Notification
fields = '__all__'
read_only_fields = ['code']
\ No newline at end of file
from django.conf import settings
from websocket import create_connection
import json
REALTIMESERVER_IP = settings.REALTIMESERVER_IP
def send_broadcast_message(room_name, sender, message):
# ws = create_connection(f"ws://{REALTIMESERVER_IP}/ws/realtimeserver/{room_name}/")
ws = create_connection(f"ws://{REALTIMESERVER_IP}/ws/chat/{room_name}/")
data = {
'sender': sender,
'message': message
}
ws.send(json.dumps(data))
ws.close()
\ No newline at end of file
from django.shortcuts import render
from django.utils.safestring import mark_safe
import json
from rest_framework import viewsets as meviewsets
from app.applicationlayer.management.notification import serializers
from app.entities import models
from app.applicationlayer import paginators
from datetime import datetime
from rest_framework.response import Response
from rest_framework import status
from django.conf import settings
from app.applicationlayer.management.notification.utils_notif import (
send_broadcast_message)
from app.applicationlayer.utils import (status_message_response,
CustomPagination)
from rest_framework.exceptions import ValidationError
from django.shortcuts import render, redirect, get_object_or_404
from rest_framework.decorators import action
from rest_framework.views import APIView
class NotificationsViewset(meviewsets.ModelViewSet):
lookup_field = 'account_no'
queryset = models.Notification.objects.all()
serializer_class = serializers.NotificationSerializer
pagination_class = CustomPagination
def list(self, request, *args, **kwargs):
# try:
req = self.request
account_no = req.query_params.get('account_no')
app = req.query_params.get('app_code')
if account_no:
queryset = models.Notification.objects.filter(
account_no=account_no).order_by('-created')
queryset = self.filter_queryset(queryset)
unseen = models.Notification.objects.filter(
account_no=account_no, is_read=False).count()
if app:
queryset = models.Notification.objects.filter(
account_no=account_no, app=app).order_by('-created')
queryset = self.filter_queryset(queryset)
unseen = models.Notification.objects.filter(
account_no=account_no, app=app, is_read=False).count()
else:
queryset = models.Notification.objects.all().order_by('-created')
queryset = self.filter_queryset(queryset)
unseen = models.Notification.objects.filter(
is_read=False).count()
if not queryset:
message = status_message_response(
200, 'success', 'No records found', []
)
return Response(message)
serializer = self.get_serializer(queryset, many=True)
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
message = {
'unseen': unseen,
'code': 200,
'status': 'success',
'message': 'List of Notifications found',
'results': serializer.data
}
return self.get_paginated_response(message)
# return Response(serializer.data)
# except Exception as e:
# message = status_message_response(
# 500, 'failed',
# 'Request was not able to process' + str(e), [])
# return Response(message,
# status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@action(methods=["PATCH"], detail=True)
def seen(self, request, account_no=None, **kwargs):
try:
account_no = self.kwargs['account_no']
print(account_no)
models.Notification.objects.filter(account_no=account_no,
id__in=request.data['ids']).update(
is_read=True,
modified=datetime.now(),
modifiedby=account_no)
message = status_message_response(
200, 'success',
'Status successfully updated',
"None"
)
return Response(message)
except Exception as e:
message = status_message_response(
500, 'failed',
'Request was not able to process' + str(e), []
)
return Response(message,
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@action(methods=["PATCH"], detail=True)
def seenall(self, request, account_no=None, **kwargs):
try:
account_no = self.kwargs['account_no']
print(account_no)
models.Notification.objects.filter(account_no=account_no).update(
is_read=True,
modified=datetime.now(),
modifiedby=account_no)
message = status_message_response(
200, 'success',
'Status successfully updated',
"None"
)
return Response(message)
except Exception as e:
message = status_message_response(
500, 'failed',
'Request was not able to process' + str(e), []
)
return Response(message,
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def create(self, request, *args, **kwargs):
serializer = serializers.NotificationSerializer(data=request.data)
try:
if serializer.is_valid():
x = serializer.save()
x.created = datetime.now()
x.save()
message = {
'code': 201,
'status': 'success',
'message': 'Notification created.',
'results': serializer.data
}
ROOM = serializer.data['account_no']
SENDER = serializer.data['sender_account_no']
send_broadcast_message(
ROOM,
SENDER,
'NEW NOTIFICATIONS'
)
return Response(message, status=status.HTTP_201_CREATED)
except ValidationError as e:
message = {
'code': 400,
'status': 'failed',
'message': str(e),
}
return Response(message, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
message = {
'code': 500,
'status': 'failed',
'message': 'Request was not able to process' + str(e.__class__)
}
return Response(message,
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def index(request):
return render(request, 'chat/index.html', {})
def room(request, room_name):
return render(request, 'chat/room.html', {
'room_name_json': mark_safe(json.dumps(room_name))
})
\ No newline at end of file
......@@ -5,6 +5,8 @@ from app.applicationlayer.management.company.views import CompanyViewSet
from app.applicationlayer.management.department.views import DepartmentViewSet
from app.applicationlayer.management.module.views import ModuleViewSet
# from app.applicationlayer.management.user.views import UsersManagementViewSet
from app.applicationlayer.management.notification.views import NotificationsViewset
router = routers.DefaultRouter()
......@@ -13,6 +15,8 @@ router.register(r'companies', CompanyViewSet)
router.register(r'departments', DepartmentViewSet)
router.register(r'modules', ModuleViewSet)
# router.register(r'users', UsersManagementViewSet)
router.register(r'notifications', NotificationsViewset)
urlpatterns = (
path('', include(router.urls)),
......
......@@ -29,6 +29,7 @@ class GenerateCode(Enum):
COMPANY = 'COMPANY'
DEPARTMENT = 'DEPARTMENT'
USER = 'USER'
NOTIFICATION = 'NOTIF'
'''
......@@ -66,3 +67,14 @@ class LogEntitiesEnum(Enum):
# STOCK = "Stock"
# STOCK_ITEM = "Stock Item"
# REQUISITION = "Requisition Header"
'''
*********
NOTIFICATION ENUMS
*********
'''
class NotifTypeEnum(Enum):
REMINDER = "REMINDER"
ACTIVITY = "ACTIVITY"
TASK = "TASK"
\ No newline at end of file
# Generated by Django 2.2 on 2019-09-03 16:14
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('entities', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Notification',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('code', models.CharField(max_length=255, unique=True)),
('form_header_code', models.CharField(blank=True, max_length=255, null=True)),
('notif_type', models.CharField(choices=[('REMINDER', 'REMINDER'), ('ACTIVITY', 'ACTIVITY'), ('TASK', 'TASK')], default='TASK', max_length=20)),
('message', models.CharField(blank=True, max_length=255, null=True)),
('is_read', models.BooleanField(default=False, null=True)),
('created', models.DateTimeField(auto_now_add=True)),
('modified', models.DateTimeField(auto_now=True)),
('app_code', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='entities.Application', to_field='code')),
('receiver_account_no', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='receiver_account_no', to=settings.AUTH_USER_MODEL, to_field='code')),
('sender_account_no', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='sender_account_no', to=settings.AUTH_USER_MODEL, to_field='code')),
],
options={
'db_table': 'notifications',
},
),
]
# Generated by Django 2.2 on 2019-09-03 17:25
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('entities', '0002_notification'),
]
operations = [
migrations.RenameField(
model_name='notification',
old_name='receiver_account_no',
new_name='account_no',
),
migrations.RenameField(
model_name='notification',
old_name='app_code',
new_name='app',
),
]
......@@ -323,3 +323,40 @@ class EntityLog(AuditClass):
class Meta:
db_table = 'entity_logs'
"""
**********************
*** NOTIFICATION TABLES ***
**********************
"""
class Notification(models.Model):
code = models.CharField(unique=True, max_length=255) # primary key
form_header_code = models.CharField(max_length=255, null=True, blank=True)
# form_header_code = models.ForeignKey(ChangeRequestFormHeader, on_delete=models.DO_NOTHING,
# to_field='code')
app = models.ForeignKey(Application, on_delete=models.DO_NOTHING,
to_field='code')
notif_type = models.CharField(
choices=[(tag.value, tag.value) for tag in enums.NotifTypeEnum],
default=enums.NotifTypeEnum.TASK.value,
max_length=20
)
account_no = models.ForeignKey(User, on_delete=models.DO_NOTHING,
to_field='code',
related_name='receiver_account_no')
message = models.CharField(max_length=255, null=True, blank=True)
is_read = models.BooleanField(default=False, null=True)
sender_account_no = models.ForeignKey(User, on_delete=models.DO_NOTHING,
to_field='code',
related_name='sender_account_no')
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'notifications'
def save(self, *args, **kwargs):
super(Notification, self).save(*args, **kwargs)
code = number_generator(enums.GenerateCode.NOTIFICATION.value, self.id)
Notification.objects.filter(id=self.id).update(code=code)
\ No newline at end of file
<!-- chat/templates/chat/index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Chat Rooms</title>
</head>
<body>
What chat room would you like to enter?<br/>
<input id="room-name-input" type="text" size="100"/><br/>
<input id="room-name-submit" type="button" value="Enter"/>
<script>
document.querySelector('#room-name-input').focus();
document.querySelector('#room-name-input').onkeyup = function(e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#room-name-submit').click();
}
};
document.querySelector('#room-name-submit').onclick = function(e) {
var roomName = document.querySelector('#room-name-input').value;
window.location.pathname = '/chat/' + roomName + '/';
};
</script>
</body>
</html>
\ No newline at end of file
<!-- chat/templates/chat/room.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Chat Room</title>
</head>
<body>
<textarea id="chat-log" cols="100" rows="20"></textarea><br/>
<input id="chat-message-input" type="text" size="100"/><br/>
<input id="chat-message-submit" type="button" value="Send"/>
</body>
<script>
var roomName = {{ room_name_json }};
var chatSocket = new WebSocket(
'ws://' + window.location.host +
'/ws/chat/' + roomName + '/');
chatSocket.onmessage = function(e) {
var data = JSON.parse(e.data);
var message = data['message'];
document.querySelector('#chat-log').value += (message + '\n');
};
chatSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
};
document.querySelector('#chat-message-input').focus();
document.querySelector('#chat-message-input').onkeyup = function(e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#chat-message-submit').click();
}
};
document.querySelector('#chat-message-submit').onclick = function(e) {
var messageInputDom = document.querySelector('#chat-message-input');
var message = messageInputDom.value;
chatSocket.send(JSON.stringify({
'message': message
}));
messageInputDom.value = '';
};
</script>
</html>
\ No newline at end of file
# mysite/routing.py
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import app.applicationlayer.management.notification.routing
application = ProtocolTypeRouter({
# (http->django views is added by default)
'websocket': AuthMiddlewareStack(
URLRouter(
app.applicationlayer.management.notification.routing.websocket_urlpatterns
)
),
})
\ No newline at end of file
......@@ -44,7 +44,9 @@ INSTALLED_APPS = [
'rest_framework.authtoken',
'app.accesslayer',
'app.entities'
'app.entities',
'channels',
]
MIDDLEWARE = [
......@@ -80,6 +82,17 @@ TEMPLATES = [
WSGI_APPLICATION = 'config.wsgi.application'
ASGI_APPLICATION = "config.routing.application"
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
AUTH_USER_MODEL = 'entities.User'
# Password validation
......
......@@ -25,3 +25,5 @@ SESSION_TIMEOUT = config['LOCAL']['SESSION_TIMEOUT']
FRONT_END_URL = config['LOCAL']['FRONT_END_URL']
AUTH_ACCESSS_TOKEN_TIMEOUT = config['LOCAL']['AUTH_ACCESSS_TOKEN_TIMEOUT']
USER_DEFAULT_PASSWORD = config['LOCAL']['USER_DEFAULT_PASSWORD']
REALTIMESERVER_IP = config['NOTIFICATION']['REALTIMESERVER_IP']
\ No newline at end of file
......@@ -15,6 +15,9 @@ Including another URLconf
"""
from django.contrib import admin
from django.urls import path, include
from django.conf.urls import url
from app.applicationlayer.management.notification import views as notifview
urlpatterns = [
# path('admin/', admin.site.urls),
......@@ -22,4 +25,7 @@ urlpatterns = [
path('api/v1/auth/', include('app.accesslayer.urls')),
path('api/v1/', include('app.applicationlayer.urls')),
url(r'^chat/$', notifview.index, name='index'),
url(r'^chat/(?P<room_name>[^/]+)/$', notifview.room, name='room'),
]
......@@ -46,5 +46,8 @@ FRONT_END_URL =
AUTH_ACCESSS_TOKEN_TIMEOUT = 3600
USER_DEFAULT_PASSWORD = password
[NOTIFICATION]
REALTIMESERVER_IP = 127.0.0.1:8000
[SETTINGS]
CONFIG = config.settings.local
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment