Richtig geiler shit
This commit is contained in:
parent
1c26681068
commit
233206e77e
|
|
@ -37,6 +37,10 @@ cloud/migrations/*
|
||||||
!cloud/migrations/__init__.py
|
!cloud/migrations/__init__.py
|
||||||
cloud/__pycache__/*
|
cloud/__pycache__/*
|
||||||
|
|
||||||
|
chat/migrations/*
|
||||||
|
!chat/migrations/__init__.py
|
||||||
|
chat/__pycache__/*
|
||||||
|
|
||||||
notificsys/migrations/*
|
notificsys/migrations/*
|
||||||
!notificsys/migrations/__init__.py
|
!notificsys/migrations/__init__.py
|
||||||
notificsys/__pycache__/*
|
notificsys/__pycache__/*
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ from rest_framework import serializers
|
||||||
from .serializers import StandardsSerializer
|
from .serializers import StandardsSerializer
|
||||||
from rest_framework.decorators import api_view, permission_classes
|
from rest_framework.decorators import api_view, permission_classes
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication
|
||||||
|
from rest_framework.decorators import authentication_classes
|
||||||
|
|
||||||
class HelloView(APIView):
|
class HelloView(APIView):
|
||||||
permission_classes = (IsAuthenticated,) # <-- And here
|
permission_classes = (IsAuthenticated,) # <-- And here
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class ChatConfig(AppConfig):
|
||||||
|
name = 'chat'
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
from django.db import models
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from users.models import Agency
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
MODEL ChatMessage
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
class ChatMessage(models.Model):
|
||||||
|
author = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
|
content = models.CharField(max_length=5000, blank=False, default="")
|
||||||
|
sendtime = models.DateTimeField(default=timezone.now, blank=True)
|
||||||
|
room = models.ForeignKey("ChatRoom", on_delete=models.CASCADE)
|
||||||
|
'''
|
||||||
|
|
||||||
|
Model ChatRoom
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
class ChatRoom(models.Model):
|
||||||
|
|
||||||
|
creator = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
'''
|
||||||
|
chatroomtype
|
||||||
|
|
||||||
|
0 - User-User-Chat
|
||||||
|
1 - Group-Chat
|
||||||
|
|
||||||
|
'''
|
||||||
|
chatroomtype = models.IntegerField(default=0)
|
||||||
|
roomname = models.CharField(max_length=200, blank=False, default="")
|
||||||
|
# This field is for random-String Django Channels
|
||||||
|
roomname_channel = models.CharField(max_length=200, blank=False)
|
||||||
|
chatmembers = models.ManyToManyField(User, blank=True, related_name='users_in_chatroom')
|
||||||
|
chatroom_createddate = models.DateTimeField(blank=True)
|
||||||
|
chatmember_single = models.ForeignKey(User, related_name='singleuserchat', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
'''
|
||||||
|
VIEWSTATUS
|
||||||
|
|
||||||
|
0 - Hide and Close
|
||||||
|
1 - Hide, but visible in base.html
|
||||||
|
2 - Full visible
|
||||||
|
|
||||||
|
'''
|
||||||
|
viewstatus = models.IntegerField(default=True)
|
||||||
|
messages = models.ManyToManyField("ChatMessage", blank=True, related_name='all_chatmessages')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.roomname}'
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
<style type="text/css">
|
||||||
|
.roundimg {
|
||||||
|
border-radius: 50%;
|
||||||
|
z-index: 999;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.icon-container {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-circle {
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="card col-2" style="position: fixed; right: 35px; bottom: 75px;">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4>Chat starten
|
||||||
|
<button class="btn btn-sm btn-secondary" style="float: right;" onclick="javascript:$('#chat_alluserscontent').fadeOut()"><small><i class="fas fa-times"></i></small></button>
|
||||||
|
</h4>
|
||||||
|
<hr>
|
||||||
|
{% for user in usersofagency %}
|
||||||
|
<span>
|
||||||
|
|
||||||
|
<div class='icon-container'>
|
||||||
|
<img class="img-profile roundimg" src="{{ user.profile.get_photo_url }}">
|
||||||
|
<div class='status-circle' style="background-color: {% if user in onlineusers %} green {% else %} grey {% endif %};">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{user.first_name}} {{user.last_name}}
|
||||||
|
<button class="btn btn-sm btn-secondary" style="float: right;"><small><i class="far fa-comment"></i></small></button>
|
||||||
|
</span>
|
||||||
|
<br />
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="chat-popup">
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,215 @@
|
||||||
|
{% if roomdata.creator == user %}
|
||||||
|
<h4 id="chattitle">Gespräch mit {{roomdata.chatmember_single.first_name}} {{roomdata.chatmember_single.last_name}}</h4>
|
||||||
|
{% else %}
|
||||||
|
<h4 id="chattitle">Gespräch mit {{roomdata.creator.first_name}} {{roomdata.creator.last_name}}</h4>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<div class="card" >
|
||||||
|
<div class="card-body scroll" id="chatcontentcomplete">
|
||||||
|
|
||||||
|
<div id="roomstart" style="min-width: 100%; text-align: center;">
|
||||||
|
|
||||||
|
<small>Unterhaltung gestartet am {{roomdata.chatroom_createddate}}</small>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div id="chatmessages">
|
||||||
|
|
||||||
|
{% for message in roomdata.messages.all %}
|
||||||
|
{% if message.author == request.user %}
|
||||||
|
<div style="" class="chatmessageele_me col-7 mb-3 ">
|
||||||
|
<div class='icon-container ml-2 mt-1 ' style="float: right;">
|
||||||
|
<img class="img-profile roundimg" src="{{ message.author.profile.get_photo_url }}">
|
||||||
|
</div>
|
||||||
|
<h6 class="mt-3"><small>{{message.author.first_name}} {{message.author.last_name}}, {{message.sendtime}}</small></h6>
|
||||||
|
<div style="text-align: left;" class="mt-1">
|
||||||
|
<span style="float: right !important; font-size: 1.0em;">
|
||||||
|
{{message.content}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div style="" class="chatmessageele_other col-7 mb-3">
|
||||||
|
<div class='icon-container mr-2 mt-1 ' style="float: left;">
|
||||||
|
<img class="img-profile roundimg" src="{{ message.author.profile.get_photo_url }}">
|
||||||
|
</div>
|
||||||
|
<h6 class="mt-3"><small>{{message.author.first_name}} {{message.author.last_name}}, {{message.sendtime}}</small></h6>
|
||||||
|
<div style="text-align: left;" class="mt-1">
|
||||||
|
<span style="float: left !important; font-size: 1.0em;">
|
||||||
|
{{message.content}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<!-- SINGLE MESSAGE -->
|
||||||
|
<!--
|
||||||
|
<div style="" class="chatmessageele_me col-7 mb-3 ">
|
||||||
|
<div class='icon-container ml-2 mt-1 ' style="float: right;">
|
||||||
|
<img class="img-profile roundimg" src="{{ user.profile.get_photo_url }}">
|
||||||
|
</div>
|
||||||
|
<h6 class="mt-3"><small>{{user.first_name}} {{user.last_name}}, 13:45 18.05.2020</small></h6>
|
||||||
|
<div style="text-align: left;" class="mt-1">
|
||||||
|
<span style="float: right !important; font-size: 1.0em;">
|
||||||
|
Ich finde schon, dass wir hier langsam mal mit den Daten arbeiten sollten...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="" class="chatmessageele_other col-7 mb-3 ">
|
||||||
|
<div class='icon-container mr-2 mt-1 ' style="float: left;">
|
||||||
|
<img class="img-profile roundimg" src="{{ user.profile.get_photo_url }}">
|
||||||
|
</div>
|
||||||
|
<h6 class="mt-3"><small>{{user.first_name}} {{user.last_name}}, 13:45 18.05.2020</small></h6>
|
||||||
|
<div style="text-align: left;" class="mt-1">
|
||||||
|
<span style="float: left !important; font-size: 1.0em;">
|
||||||
|
Ich finde schon, dass wir hier langsam mal mit den Daten arbeiten sollten...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
|
||||||
|
</div><!-- END CHAT MESSAGES -->
|
||||||
|
<span id="scrolltarget"> </span>
|
||||||
|
</div><!-- END CARD BODY-->
|
||||||
|
|
||||||
|
<div id="is_typing" class="ml-2">
|
||||||
|
<div class="spinner-grow spinner-border-sm" id="typingspinner" role="status" style="display: none;">
|
||||||
|
<span class="sr-only">Jemand tippt...</span>
|
||||||
|
</div>
|
||||||
|
<small id="is_typing_name" class="">
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="card-footer bg-transparent border-success">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control" placeholder="Neue Nachricht" id="message" aria-describedby="">
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button class="btn btn-primary" id="sendNewMessgeButton" onclick="javascript:sendNewMessage()" type="button"><i class="fas fa-location-arrow"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function scrollDown(){
|
||||||
|
//$('#chatmessages').animate({scrollTop: $('#chatmessages').prop("scrollHeight")}, 500);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
$('#chatcontentcomplete').scrollTop( $('#chatcontentcomplete').height()*200 )
|
||||||
|
});
|
||||||
|
|
||||||
|
userownid = "{{user.pk}}";
|
||||||
|
|
||||||
|
creator_id = {{roomdata.creator.pk}};
|
||||||
|
chatmember_id = {{roomdata.chatmember_single.pk}};
|
||||||
|
|
||||||
|
ws_string = 'wss://'
|
||||||
|
if (location.protocol !== 'https:') {
|
||||||
|
ws_string = 'ws://'
|
||||||
|
}
|
||||||
|
if(typeof chatwebsocket != "undefined"){
|
||||||
|
chatwebsocket = new WebSocket(ws_string+window.location.host+"/chat/{{roomdata.creator.pk}}/{{roomdata.chatmember_single.pk}}/")
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
chatwebsocket = new WebSocket(ws_string+window.location.host+"/chat/{{roomdata.creator.pk}}/{{roomdata.chatmember_single.pk}}/")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
chatwebsocket.onmessage = function(e) {
|
||||||
|
datainfo = e["data"].split("__");
|
||||||
|
if(datainfo[0] == "starttyping")
|
||||||
|
{
|
||||||
|
typingname = (datainfo[1].split("_"))[1];
|
||||||
|
typingid = (datainfo[1].split("_"))[0];
|
||||||
|
if(typingid != userownid){
|
||||||
|
$("#is_typing_name").html("" + typingname);
|
||||||
|
$("#typingspinner").show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(datainfo[0] == "stoptyping")
|
||||||
|
{
|
||||||
|
$("#is_typing_name").html(" ");
|
||||||
|
$("#typingspinner").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(datainfo[0] == "reloadmessages")
|
||||||
|
{
|
||||||
|
$.ajax(
|
||||||
|
{
|
||||||
|
type: "GET",
|
||||||
|
url: "{% url 'chat:chat-ajax' %}",
|
||||||
|
data : {
|
||||||
|
action : "loadnewestmessage",
|
||||||
|
room : {{roomdata.pk}}
|
||||||
|
},
|
||||||
|
success: function( data )
|
||||||
|
{
|
||||||
|
$("#chatmessages").append(data);
|
||||||
|
$('#chatcontentcomplete').scrollTop( $('#chatcontentcomplete').height()*200 );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
chatwebsocket.onclose = function(e) {
|
||||||
|
console.error('Chat socket closed unexpectedly');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
$("#message").keyup(function(){
|
||||||
|
if($("#message").val().length > 0){
|
||||||
|
chatwebsocket.send("starttyping__{{user.pk}}__privatechat_{{roomdata.creator.pk}}_{{roomdata.chatmember_single.pk}}");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
chatwebsocket.send("stoptyping__{{user.pk}}__privatechat_{{roomdata.creator.pk}}_{{roomdata.chatmember_single.pk}}");
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
function sendNewMessage(){
|
||||||
|
$.ajax(
|
||||||
|
{
|
||||||
|
type: "GET",
|
||||||
|
url: "{% url 'chat:chat-ajax' %}",
|
||||||
|
data : {
|
||||||
|
action : "addnewmessage",
|
||||||
|
new_chat_userid : userownid,
|
||||||
|
message : $("#message").val(),
|
||||||
|
room : {{roomdata.pk}}
|
||||||
|
},
|
||||||
|
success: function( data )
|
||||||
|
{
|
||||||
|
$("#message").val("");
|
||||||
|
chatwebsocket.send("load__{{user.pk}}__privatechat_{{roomdata.creator.pk}}_{{roomdata.chatmember_single.pk}}");
|
||||||
|
chatwebsocket.send("stoptyping__{{user.pk}}__privatechat_{{roomdata.creator.pk}}_{{roomdata.chatmember_single.pk}}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$(document).on('keypress',function(e) {
|
||||||
|
if(e.which == 13) {
|
||||||
|
if($("#message").val().length > 0){
|
||||||
|
sendNewMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<div style="" class="chatmessageele_other col-7 mb-3 ">
|
||||||
|
<div class='icon-container mr-2 mt-1 ' style="float: left;">
|
||||||
|
<img class="img-profile roundimg" src="{{ newmessage.author.profile.get_photo_url }}">
|
||||||
|
</div>
|
||||||
|
<h6 class="mt-3"><small>{{newmessage.author.first_name}} {{newmessage.author.last_name}}, {{newmessage.sendtime}}</small></h6>
|
||||||
|
<div style="text-align: left;" class="mt-1">
|
||||||
|
<span style="float: left !important; font-size: 1.0em;">
|
||||||
|
{{newmessage.content}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<div style="" class="chatmessageele_me col-7 mb-3 ">
|
||||||
|
<div class='icon-container ml-2 mt-1 ' style="float: right;">
|
||||||
|
<img class="img-profile roundimg" src="{{ newmessage.author.profile.get_photo_url }}">
|
||||||
|
</div>
|
||||||
|
<h6 class="mt-3"><small>{{newmessage.author.first_name}} {{newmessage.author.last_name}}, {{newmessage.sendtime}}</small></h6>
|
||||||
|
<div style="text-align: left;" class="mt-1">
|
||||||
|
<span style="float: right !important; font-size: 1.0em;">
|
||||||
|
{{newmessage.content}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,152 @@
|
||||||
|
{% extends "users/base.html" %}
|
||||||
|
{% block content %}
|
||||||
|
{% if request.user.profile.agency.module_chat %}
|
||||||
|
<style type="text/css">
|
||||||
|
.roundimg {
|
||||||
|
border-radius: 50%;
|
||||||
|
z-index: 999;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.icon-container {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-circle {
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatmessageele_me
|
||||||
|
{
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 15px;
|
||||||
|
background-color: #f8f9fc;
|
||||||
|
float: right;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatmessageele_other
|
||||||
|
{
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 15px;
|
||||||
|
background-color: #858796;
|
||||||
|
float: left;
|
||||||
|
text-align: left;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll {
|
||||||
|
max-height: 600px;
|
||||||
|
min-height: 600px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="content-section col-12">
|
||||||
|
<h3>Chat <small><i data-toggle="tooltip" data-placement="top" title="Verwalten Sie hier Ihre Chatverläufe und starten Sie neue Unterhaltungen mit Mitarbeitern und anderen Agenturen." class="far fa-question-circle"></i></small>
|
||||||
|
</h3>
|
||||||
|
<hr>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row col">
|
||||||
|
<div class="col-3">
|
||||||
|
<h4>Mitarbeiter und Räume</h4>
|
||||||
|
<hr>
|
||||||
|
{% for user in usersofagency %}
|
||||||
|
<div class="card mb-2 hoverchatcard" id="userchat_{{user.pk}}">
|
||||||
|
<div class="card-body">
|
||||||
|
<div style="float: left;" class="col-12 ">
|
||||||
|
<div class='icon-container mr-2'>
|
||||||
|
<img class="img-profile roundimg" src="{{ user.profile.get_photo_url }}">
|
||||||
|
<div class='status-circle' id="userstatus_circle_{{user.pk}}" style="background-color: {% if user in onlineusers %} green {% else %} grey {% endif %};">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h5 class="mt-3">{{user.first_name}} {{user.last_name}}</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="col-9" style="" id="mainchatcontent">
|
||||||
|
|
||||||
|
</div><!-- END CHATAREA -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
creator_id = false;
|
||||||
|
chatmember_id = false;
|
||||||
|
|
||||||
|
$(".hoverchatcard").hover(function(){
|
||||||
|
var $this = $(this);
|
||||||
|
$this.data('bgcolor', $this.css('background-color')).css('background-color', '#f8f9fc');
|
||||||
|
}, function(){
|
||||||
|
var $this = $(this);
|
||||||
|
$this.data('bgcolor', $this.css('background-color')).css('background-color', '#FFFFFF');
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
$(".hoverchatcard").click(function(){
|
||||||
|
|
||||||
|
$.ajax(
|
||||||
|
{
|
||||||
|
type: "GET",
|
||||||
|
url: "{% url 'chat:chat-ajax' %}",
|
||||||
|
data : {
|
||||||
|
action : "startnewchat_user_user",
|
||||||
|
new_chat_userid : $(this)[0]["id"].split("_")[1]
|
||||||
|
},
|
||||||
|
success: function( data )
|
||||||
|
{
|
||||||
|
if(creator_id != false && chatmember_id != false){
|
||||||
|
chatwebsocket.close();
|
||||||
|
}
|
||||||
|
$("#mainchatcontent").html(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function updatePresenceLive(e) {
|
||||||
|
$.ajax(
|
||||||
|
{
|
||||||
|
type: "GET",
|
||||||
|
url: "{% url 'chat:chtaajax-getloggedusers-data' %}",
|
||||||
|
data : {
|
||||||
|
action : "getloggedusers"
|
||||||
|
},
|
||||||
|
success: function( data )
|
||||||
|
{
|
||||||
|
console.log(data);
|
||||||
|
$( ".status-circle" ).each(function( index ) {
|
||||||
|
if(data["onlineusers"].indexOf($(this)[0]["id"].split("_")[2]) !== -1){
|
||||||
|
$("#" + $(this)[0]["id"]).css("background-color", "green");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$("#" + $(this)[0]["id"]).css("background-color", "grey");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<h3>Das Module Chat wurde in ihrer Agentur deaktiviert.</h3>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock content %}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
app_name = 'chat'
|
||||||
|
urlpatterns = [
|
||||||
|
path('managemenet/', views.chatmanagement, name='chat-management'),
|
||||||
|
path('ajaxchat', views.chatajaxmain, name="chat-ajax"),
|
||||||
|
path('ajaxchat/getloggedusers', views.getloggedusers, name="chtaajax-getloggedusers"),
|
||||||
|
path('ajaxchat/getloggedusersdata', views.getloggedusersdata, name="chtaajax-getloggedusers-data")
|
||||||
|
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
from django.shortcuts import render
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from channels_presence.models import Presence
|
||||||
|
from django.http import HttpResponseRedirect,HttpResponse, JsonResponse
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from channels_presence.models import Room
|
||||||
|
from channels_presence.models import Presence
|
||||||
|
import channels.layers
|
||||||
|
from django.utils import timezone
|
||||||
|
from .models import ChatRoom, ChatMessage
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
|
@login_required
|
||||||
|
def chatmanagement(request):
|
||||||
|
|
||||||
|
users_online = Room.objects.get(channel_name="agency_" + str(request.user.profile.agency.pk))
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'active_link' : 'chat',
|
||||||
|
"usersofagency" : User.objects.filter(profile__agency=request.user.profile.agency).exclude(pk=request.user.pk).order_by("last_name"),
|
||||||
|
"onlineusers" : users_online.get_users()
|
||||||
|
|
||||||
|
}
|
||||||
|
return render(request, 'chat/chatmanagement.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def getloggedusers(request):
|
||||||
|
if request.method == "GET":
|
||||||
|
|
||||||
|
users_online = Room.objects.get(channel_name="agency_" + str(request.user.profile.agency.pk))
|
||||||
|
|
||||||
|
context = {
|
||||||
|
"usersofagency" : User.objects.filter(profile__agency=request.user.profile.agency).exclude(pk=request.user.pk).oder_by("last_name"),
|
||||||
|
"onlineusers" : users_online.get_users()
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(request, "chat/chat_allusers.html", context)
|
||||||
|
else:
|
||||||
|
return JsonResponse({})
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def getloggedusersdata(request):
|
||||||
|
if request.method == "GET":
|
||||||
|
|
||||||
|
users_online = Room.objects.get(channel_name="agency_" + str(request.user.profile.agency.pk)).get_users()
|
||||||
|
users_agency = User.objects.filter(profile__agency=request.user.profile.agency).exclude(pk=request.user.pk)
|
||||||
|
|
||||||
|
user_online_final = []
|
||||||
|
for u in users_agency:
|
||||||
|
if(u in users_online):
|
||||||
|
user_online_final.append("" + str(u.pk))
|
||||||
|
|
||||||
|
return JsonResponse({"onlineusers" : user_online_final})
|
||||||
|
else:
|
||||||
|
return JsonResponse({})
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def chatajaxmain(request):
|
||||||
|
if request.method == "GET":
|
||||||
|
|
||||||
|
context = {}
|
||||||
|
choosenroom = ""
|
||||||
|
if request.GET["action"] == "startnewchat_user_user":
|
||||||
|
singleuserid = request.GET["new_chat_userid"]
|
||||||
|
getroom = ChatRoom.objects.filter(chatmember_single__pk=singleuserid, creator=request.user) | ChatRoom.objects.filter(creator__pk=singleuserid, chatmember_single=request.user)
|
||||||
|
singleuser = User.objects.get(pk=singleuserid)
|
||||||
|
# NO PRIVATE CHAT THERE, CREATE ONE!
|
||||||
|
if(len(getroom) == 0):
|
||||||
|
newchatroom = ChatRoom(creator=request.user, chatroomtype=0, roomname="Gespräch mit " + singleuser.first_name + " " + singleuser.last_name, roomname_channel="privatechat_" + str(request.user.pk) + "_" + singleuserid, chatmember_single=singleuser, chatroom_createddate=timezone.now(), viewstatus=0)
|
||||||
|
newchatroom.save()
|
||||||
|
context = {
|
||||||
|
"roomdata" : newchatroom
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
context = {
|
||||||
|
"roomdata" : list(getroom)[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(request, "chat/chat_content.html", context)
|
||||||
|
elif request.GET["action"] == "addnewmessage":
|
||||||
|
room = ChatRoom.objects.get(pk=request.GET["room"])
|
||||||
|
if(request.user == room.creator or request.user == room.chatmember_single):
|
||||||
|
|
||||||
|
newmessage = ChatMessage(room=room, author=request.user, content=request.GET["message"])
|
||||||
|
newmessage.save()
|
||||||
|
room.messages.add(newmessage)
|
||||||
|
room.save()
|
||||||
|
return render(request, "chat/chat_ownmessage.html", {"newmessage" : newmessage})
|
||||||
|
else:
|
||||||
|
JsonResponse({"status" : "Error on CHATAJAXMAIN"})
|
||||||
|
elif request.GET["action"] == "loadnewestmessage":
|
||||||
|
room = ChatRoom.objects.get(pk=request.GET["room"])
|
||||||
|
last_message = list(room.messages.order_by('-sendtime'))[0]
|
||||||
|
|
||||||
|
if(last_message.author == request.user):
|
||||||
|
return render(request, "chat/chat_ownmessage.html", {"newmessage" : last_message})
|
||||||
|
else:
|
||||||
|
return render(request, "chat/chat_othermessage.html", {"newmessage" : last_message})
|
||||||
|
|
||||||
|
else:
|
||||||
|
return JsonResponse({"status" : "Error on CHATAJAXMAIN"})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
author = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
|
content = models.CharField(max_length=5000, blank=False, default="")
|
||||||
|
sendtime = models.DateField(default=timezone.now, blank=True)
|
||||||
|
room = models.ForeignKey("ChatRoom", on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -10,7 +10,7 @@ For the full list of settings and their values, see
|
||||||
https://docs.djangoproject.com/en/2.2/ref/settings/
|
https://docs.djangoproject.com/en/2.2/ref/settings/
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
from datetime import datetime, timedelta
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
@ -49,6 +49,8 @@ REDIS_URL = ("localhost", 6379)
|
||||||
# Nach zehn Stunden läuft der Cookie ab!
|
# Nach zehn Stunden läuft der Cookie ab!
|
||||||
SESSION_COOKIE_AGE = 8*60*60
|
SESSION_COOKIE_AGE = 8*60*60
|
||||||
|
|
||||||
|
CHANNELS_PRESENCE_MAX_AGE = 30
|
||||||
|
|
||||||
# FOR SUMMERNOTE ORIGIN
|
# FOR SUMMERNOTE ORIGIN
|
||||||
X_FRAME_OPTIONS = 'SAMEORIGIN'
|
X_FRAME_OPTIONS = 'SAMEORIGIN'
|
||||||
|
|
||||||
|
|
@ -67,6 +69,7 @@ INSTALLED_APPS = [
|
||||||
'dasettings.apps.DASettingsConfig',
|
'dasettings.apps.DASettingsConfig',
|
||||||
'areas.apps.AreasConfig',
|
'areas.apps.AreasConfig',
|
||||||
'orga.apps.OrgaConfig',
|
'orga.apps.OrgaConfig',
|
||||||
|
'chat.apps.ChatConfig',
|
||||||
'message.apps.MessageConfig',
|
'message.apps.MessageConfig',
|
||||||
'cloud.apps.CloudConfig',
|
'cloud.apps.CloudConfig',
|
||||||
'tasks.apps.TasksConfig',
|
'tasks.apps.TasksConfig',
|
||||||
|
|
@ -90,7 +93,8 @@ INSTALLED_APPS = [
|
||||||
'django_user_agents',
|
'django_user_agents',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'rest_framework.authtoken',
|
'rest_framework.authtoken',
|
||||||
'channels'
|
'channels',
|
||||||
|
'channels_presence',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
|
@ -125,7 +129,6 @@ TEMPLATES = [
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||||
'rest_framework.authentication.TokenAuthentication',
|
'rest_framework.authentication.TokenAuthentication',
|
||||||
'rest_framework.authentication.SessionAuthentication',
|
|
||||||
),
|
),
|
||||||
'DEFAULT_PERMISSION_CLASSES': [
|
'DEFAULT_PERMISSION_CLASSES': [
|
||||||
'rest_framework.permissions.IsAuthenticated',
|
'rest_framework.permissions.IsAuthenticated',
|
||||||
|
|
|
||||||
|
|
@ -7,21 +7,7 @@ from users.views import AgencyCreateView, registerNewAgency
|
||||||
from . import views
|
from . import views
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from rest_framework.authtoken.views import obtain_auth_token
|
from rest_framework.authtoken.views import obtain_auth_token
|
||||||
'''
|
|
||||||
|
|
||||||
Main URLS
|
|
||||||
|
|
||||||
Apps:
|
|
||||||
areas
|
|
||||||
tasks
|
|
||||||
standards
|
|
||||||
orga
|
|
||||||
news
|
|
||||||
quicklinkgs
|
|
||||||
|
|
||||||
-> Rest ist von Django
|
|
||||||
|
|
||||||
'''
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name='login'),
|
path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name='login'),
|
||||||
path('', include('users.urls'), name="dashboard-first"),
|
path('', include('users.urls'), name="dashboard-first"),
|
||||||
|
|
@ -46,6 +32,7 @@ urlpatterns = [
|
||||||
path('notifications/', include('notificsys.urls'), name="notifications"),
|
path('notifications/', include('notificsys.urls'), name="notifications"),
|
||||||
path('tm/', include('timemanagement.urls'), name="timemanagement"),
|
path('tm/', include('timemanagement.urls'), name="timemanagement"),
|
||||||
path('api/', include('api.urls', namespace='api')),
|
path('api/', include('api.urls', namespace='api')),
|
||||||
|
path('chat/', include('chat.urls'), name='chat'),
|
||||||
path('api-token-auth/', obtain_auth_token, name='api-token-auth'),
|
path('api-token-auth/', obtain_auth_token, name='api-token-auth'),
|
||||||
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import json
|
import json
|
||||||
from channels.generic.websocket import WebsocketConsumer
|
from channels.generic.websocket import WebsocketConsumer
|
||||||
from asgiref.sync import async_to_sync
|
from asgiref.sync import async_to_sync
|
||||||
|
from channels_presence.models import Room
|
||||||
|
from channels_presence.decorators import touch_presence, remove_presence
|
||||||
|
from channels_presence.models import Presence
|
||||||
|
import channels
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
class UsersConsumer(WebsocketConsumer):
|
class UsersConsumer(WebsocketConsumer):
|
||||||
|
|
||||||
|
|
@ -14,15 +19,15 @@ class UsersConsumer(WebsocketConsumer):
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
|
super().connect()
|
||||||
loggeduser = self.scope["user"]
|
loggeduser = self.scope["user"]
|
||||||
async_to_sync(self.channel_layer.group_add)(
|
Presence.objects.touch(self.channel_name)
|
||||||
"agency_" + str(loggeduser.profile.agency.pk),
|
Room.objects.add("agency_" + str(loggeduser.profile.agency.pk), self.channel_name, self.scope["user"])
|
||||||
self.channel_name
|
|
||||||
)
|
|
||||||
self.accept()
|
|
||||||
|
|
||||||
def disconnect(self, close_code):
|
def disconnect(self, close_code):
|
||||||
pass
|
loggeduser = self.scope["user"]
|
||||||
|
Room.objects.remove("agency_" + str(loggeduser.profile.agency.pk), self.channel_name)
|
||||||
|
Presence.objects.touch(self.channel_name)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
def receive(self, text_data):
|
def receive(self, text_data):
|
||||||
|
|
@ -36,6 +41,9 @@ class UsersConsumer(WebsocketConsumer):
|
||||||
)
|
)
|
||||||
'''
|
'''
|
||||||
# WEBSOCKET-DATA-CONTENT
|
# WEBSOCKET-DATA-CONTENT
|
||||||
|
def receive(self, text_data=None, bytes_data=None):
|
||||||
|
if text_data == '"heartbeat"':
|
||||||
|
Presence.objects.touch(self.channel_name)
|
||||||
|
|
||||||
# UPDATET STANDARD
|
# UPDATET STANDARD
|
||||||
def update_standard(self, event):
|
def update_standard(self, event):
|
||||||
|
|
@ -43,5 +51,54 @@ class UsersConsumer(WebsocketConsumer):
|
||||||
|
|
||||||
# NEW AGENCY NEWS
|
# NEW AGENCY NEWS
|
||||||
def agency_newnews(self, event):
|
def agency_newnews(self, event):
|
||||||
print(event)
|
self.send("Neue Agenturnews!")
|
||||||
self.send("agency_newnews")
|
|
||||||
|
# SOMETHING IN PRESENCE CHANGED
|
||||||
|
def update_presence_live(self, event):
|
||||||
|
self.send("presence_update")
|
||||||
|
|
||||||
|
|
||||||
|
class UsersChat(UsersConsumer):
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
CONNECT A WEBSOCKET
|
||||||
|
|
||||||
|
Die Clients werden in Channel-Layer pro Agentur gepackt, damit gesendete Websocket-Nachrichten
|
||||||
|
auch nur Clients innerhalb der Agentur treffen!
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
super().connect()
|
||||||
|
loggeduser = self.scope["user"]
|
||||||
|
roomname = "privatechat_" + str(self.scope["url_route"]["kwargs"]["creator"]) + "_" + str(self.scope["url_route"]["kwargs"]["single"])
|
||||||
|
Room.objects.add(roomname, self.channel_name, self.scope["user"])
|
||||||
|
|
||||||
|
def disconnect(self, close_code):
|
||||||
|
Room.objects.remove("", self.channel_name)
|
||||||
|
|
||||||
|
# WEBSOCKET-DATA-CONTENT
|
||||||
|
def receive(self, text_data=None, bytes_data=None):
|
||||||
|
datainfo = text_data.split("__")
|
||||||
|
typinguserid = datainfo[1]
|
||||||
|
if datainfo[0] == 'starttyping':
|
||||||
|
channel_layer = channels.layers.get_channel_layer()
|
||||||
|
async_to_sync(channel_layer.group_send)(datainfo[2], {'type' : 'start_typing', 'typingname' : typinguserid})
|
||||||
|
elif datainfo[0] == 'stoptyping':
|
||||||
|
channel_layer = channels.layers.get_channel_layer()
|
||||||
|
async_to_sync(channel_layer.group_send)(datainfo[2], {'type' : 'stop_typing'})
|
||||||
|
elif datainfo[0] == 'load':
|
||||||
|
channel_layer = channels.layers.get_channel_layer()
|
||||||
|
async_to_sync(channel_layer.group_send)(datainfo[2], {'type' : 'reloadmessages'})
|
||||||
|
|
||||||
|
|
||||||
|
def start_typing(self, event):
|
||||||
|
useristyping = User.objects.get(pk=event["typingname"])
|
||||||
|
self.send("starttyping__" + str(useristyping.pk) + "_" + useristyping.first_name + " " + useristyping.last_name + " tippt...")
|
||||||
|
|
||||||
|
def stop_typing(self, event):
|
||||||
|
self.send("stoptyping")
|
||||||
|
|
||||||
|
def reloadmessages(self, event):
|
||||||
|
self.send("reloadmessages")
|
||||||
|
|
@ -102,6 +102,9 @@ class Agency(models.Model):
|
||||||
|
|
||||||
module_messages = models.BooleanField(default=True)
|
module_messages = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
module_chat = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
|
||||||
# KOSTENPFLICHTIGE MODULE
|
# KOSTENPFLICHTIGE MODULE
|
||||||
|
|
||||||
# Abwesenheits- und Zeiterfassung
|
# Abwesenheits- und Zeiterfassung
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,6 @@ from django.urls import re_path
|
||||||
from . import mainwebsocket
|
from . import mainwebsocket
|
||||||
|
|
||||||
websocket_urlpatterns = [
|
websocket_urlpatterns = [
|
||||||
re_path(r'', mainwebsocket.UsersConsumer),
|
re_path(r'chat/(?P<creator>\w+)/(?P<single>\w+)/$', mainwebsocket.UsersChat),
|
||||||
|
re_path('main/', mainwebsocket.UsersConsumer),
|
||||||
]
|
]
|
||||||
|
|
@ -22,6 +22,8 @@ import requests, csv, os
|
||||||
from django.templatetags.static import static
|
from django.templatetags.static import static
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
import channels.layers
|
||||||
|
from asgiref.sync import async_to_sync
|
||||||
|
|
||||||
def loadingFreeDays(plz):
|
def loadingFreeDays(plz):
|
||||||
# Getting land
|
# Getting land
|
||||||
|
|
@ -192,14 +194,9 @@ def adjust_group_notifications(instance, action, reverse, model, pk_set, using,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
import channels.layers
|
|
||||||
from asgiref.sync import async_to_sync
|
|
||||||
|
|
||||||
|
|
||||||
# SIGNAL FOR STANDARDS POST SAVE
|
# SIGNAL FOR STANDARDS POST SAVE
|
||||||
@receiver(post_save, sender=Standards)
|
@receiver(post_save, sender=Standards)
|
||||||
def save_standard(sender, instance, **kwargs):
|
def save_standard(sender, instance, **kwargs):
|
||||||
print(kwargs)
|
|
||||||
GLOBALSENDMAILS = True
|
GLOBALSENDMAILS = True
|
||||||
# NEW STANDARD AND DIRECT PUBLIC
|
# NEW STANDARD AND DIRECT PUBLIC
|
||||||
if(kwargs["created"]):
|
if(kwargs["created"]):
|
||||||
|
|
@ -283,6 +280,9 @@ def save_news(sender, instance, **kwargs):
|
||||||
else:
|
else:
|
||||||
instance.agnotify = False
|
instance.agnotify = False
|
||||||
instance.save()
|
instance.save()
|
||||||
|
else:
|
||||||
|
channel_layer = channels.layers.get_channel_layer()
|
||||||
|
async_to_sync(channel_layer.group_send)("agency_" + str(instance.agency.pk), {'type' : 'agency_newnews'})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -345,3 +345,22 @@ def adjust_group_notifications_task(instance, action, reverse, model, pk_set, us
|
||||||
def save_agjoin_prep(sender, instance, **kwargs):
|
def save_agjoin_prep(sender, instance, **kwargs):
|
||||||
newnotification = UserNotification(touser=instance.target_network.creator, notificationtext="Eine Agentur möchte Ihrem Verbund beitreten.", notificationtype="wantedag", elementid=instance.pk)
|
newnotification = UserNotification(touser=instance.target_network.creator, notificationtext="Eine Agentur möchte Ihrem Verbund beitreten.", notificationtype="wantedag", elementid=instance.pk)
|
||||||
newnotification.save()
|
newnotification.save()
|
||||||
|
|
||||||
|
|
||||||
|
from django.core.signals import request_started
|
||||||
|
from channels_presence.models import Room
|
||||||
|
from channels_presence.models import Presence
|
||||||
|
from channels_presence.signals import presence_changed
|
||||||
|
# REQUEST MAIN STUFF
|
||||||
|
@receiver(signal=request_started)
|
||||||
|
def receiver_function(sender, **kwargs):
|
||||||
|
# DELETES ALL PRESENCE-OBJETS LOWER THAN 15 MINUTES
|
||||||
|
now_minus = datetime.datetime.now() - datetime.timedelta(minutes=2)
|
||||||
|
Presence.objects.filter(last_seen__lt=now_minus).delete()
|
||||||
|
|
||||||
|
|
||||||
|
# PREENCE CHANGED
|
||||||
|
@receiver(signal=presence_changed)
|
||||||
|
def update_presence_live(sender, **kwargs):
|
||||||
|
channel_layer = channels.layers.get_channel_layer()
|
||||||
|
async_to_sync(channel_layer.group_send)(str(kwargs["room"]), {'type' : 'update_presence_live'})
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<!-- Page Wrapper -->
|
<!-- Page Wrapper -->
|
||||||
<div id="wrapper">
|
<div id="wrapper">
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
|
|
@ -72,7 +73,6 @@
|
||||||
<i class="fas fa-laptop"></i>
|
<i class="fas fa-laptop"></i>
|
||||||
<div class="sidebar-brand-text mx-2" style="">Digitale Agentur</div>
|
<div class="sidebar-brand-text mx-2" style="">Digitale Agentur</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Divider -->
|
<!-- Divider -->
|
||||||
<hr class="sidebar-divider my-0">
|
<hr class="sidebar-divider my-0">
|
||||||
|
|
||||||
|
|
@ -161,6 +161,20 @@
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if request.user.profile.agency.module_chat %}
|
||||||
|
{% if active_link == 'chat' %}
|
||||||
|
<li class="nav-item active">
|
||||||
|
{% else%}
|
||||||
|
<li class="nav-item">
|
||||||
|
{%endif%}
|
||||||
|
|
||||||
|
<a class="nav-link " href="{% url 'chat:chat-management' %}" aria-expanded="true">
|
||||||
|
<i class="fas fa-comments"></i>
|
||||||
|
<span>Chat</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if request.user.profile.agency.module_timemanagement %}
|
{% if request.user.profile.agency.module_timemanagement %}
|
||||||
{% if active_link == 'abscence' %}
|
{% if active_link == 'abscence' %}
|
||||||
<li class="nav-item active">
|
<li class="nav-item active">
|
||||||
|
|
@ -379,8 +393,17 @@
|
||||||
<div style="height: 300px"> </div>
|
<div style="height: 300px"> </div>
|
||||||
</div> <!-- End of Main Content CONTAINER FLUID-->
|
</div> <!-- End of Main Content CONTAINER FLUID-->
|
||||||
<!-- End of Content Wrapper -->
|
<!-- End of Content Wrapper -->
|
||||||
|
{% if active_link != 'chat' %}
|
||||||
|
<div id="chat_alluserscontent" style="position: fixed; bottom: 75px; right: 36px; z-index: 999;"></div>
|
||||||
|
<button id="chatButton" class="btn btn-primary" style="position: fixed; right: 36px; bottom: 30px;"><i class="far fa-comments"></i></button>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- CHAT BUTTON -->
|
||||||
|
|
||||||
|
|
||||||
<!-- End of Page Wrapper -->
|
<!-- End of Page Wrapper -->
|
||||||
<!--
|
<!--
|
||||||
<footer class="sticky-footer bg-white" style="width: 86.2%;position: absolute;
|
<footer class="sticky-footer bg-white" style="width: 86.2%;position: absolute;
|
||||||
|
|
@ -619,17 +642,15 @@ function removeNotification(notifyid){
|
||||||
//$("#allnotificationsarea").show();
|
//$("#allnotificationsarea").show();
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function(){
|
|
||||||
|
|
||||||
$("#notification_items").html("");
|
|
||||||
loadUnsendNotifications();
|
|
||||||
loadUnviewnNotifications();
|
|
||||||
});
|
|
||||||
|
|
||||||
$(window).click(function() {
|
$(document).on('click', function (e) {
|
||||||
$("#notification_items").html("");
|
|
||||||
loadUnsendNotifications();
|
if(e.target["id"] != 'chatButton'){
|
||||||
loadUnviewnNotifications();
|
if ($(e.target).closest("#chat_alluserscontent").length === 0) {
|
||||||
|
$("#chat_alluserscontent").fadeOut();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -637,16 +658,95 @@ $(window).click(function() {
|
||||||
<!-- WEBSOCKETS -->
|
<!-- WEBSOCKETS -->
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
const mainwebsocket = new WebSocket('wss://'+window.location.host)
|
|
||||||
|
$("#chat_alluserscontent").hide();
|
||||||
|
|
||||||
|
ws_string = 'wss://'
|
||||||
|
if (location.protocol !== 'https:') {
|
||||||
|
ws_string = 'ws://'
|
||||||
|
}
|
||||||
|
|
||||||
|
const mainwebsocket = new WebSocket(ws_string+window.location.host+"/main/")
|
||||||
|
|
||||||
mainwebsocket.onmessage = function(e) {
|
mainwebsocket.onmessage = function(e) {
|
||||||
console.log(e);
|
if(e["data"] != "presence_update")
|
||||||
|
{
|
||||||
|
var notify = new Notification('Digitale Agentur', {
|
||||||
|
body: e["data"]
|
||||||
|
});
|
||||||
|
loadUnsendNotifications();
|
||||||
|
loadUnviewnNotifications();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
|
||||||
|
{% if active_link == "chat" %}
|
||||||
|
updatePresenceLive(e);
|
||||||
|
{% endif %}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mainwebsocket.onclose = function(e) {
|
mainwebsocket.onclose = function(e) {
|
||||||
console.error('Chat socket closed unexpectedly');
|
console.error('Chat socket closed unexpectedly');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//HEARTBEAT every minute
|
||||||
|
setInterval(function()
|
||||||
|
{
|
||||||
|
mainwebsocket.send(JSON.stringify("heartbeat"));
|
||||||
|
console.log("heartbeat is alive...");
|
||||||
|
},60000);
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.onerror = function (msg, url, line) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window.Notification) {
|
||||||
|
console.log('Browser does not support notifications.');
|
||||||
|
} else {
|
||||||
|
// check if permission is already granted
|
||||||
|
if (Notification.permission === 'granted') {
|
||||||
|
// show notification here
|
||||||
|
} else {
|
||||||
|
// request permission from user
|
||||||
|
Notification.requestPermission().then(function(p) {
|
||||||
|
if(p === 'granted') {
|
||||||
|
// show notification here
|
||||||
|
console.log("OK!")
|
||||||
|
} else {
|
||||||
|
console.log('User blocked notifications.');
|
||||||
|
}
|
||||||
|
}).catch(function(err) {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$("#chatButton").click(function(){
|
||||||
|
$.ajax(
|
||||||
|
{
|
||||||
|
type: "GET",
|
||||||
|
url: "{% url 'chat:chtaajax-getloggedusers' %}",
|
||||||
|
data : {
|
||||||
|
action : "getloggedusers"
|
||||||
|
},
|
||||||
|
success: function( data )
|
||||||
|
{
|
||||||
|
$("#chat_alluserscontent").fadeToggle();
|
||||||
|
$("#chat_alluserscontent").html(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
<style type="text/css">
|
||||||
|
.roundimg {
|
||||||
|
border-radius: 50%;
|
||||||
|
z-index: 999;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.icon-container {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-circle {
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="card col-2" style="position: fixed; right: 35px; bottom: 75px;">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4>Chat starten
|
||||||
|
<button class="btn btn-sm btn-secondary" style="float: right;" onclick="javascript:$('#chat_alluserscontent').fadeOut()"><small><i class="fas fa-times"></i></small></button>
|
||||||
|
</h4>
|
||||||
|
<hr>
|
||||||
|
{% for user in usersofagency %}
|
||||||
|
<span>
|
||||||
|
|
||||||
|
<div class='icon-container'>
|
||||||
|
<img class="img-profile roundimg" src="{{ user.profile.get_photo_url }}">
|
||||||
|
<div class='status-circle' style="background-color: {% if user in onlineusers %} green {% else %} grey {% endif %};">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{user.first_name}} {{user.last_name}}
|
||||||
|
<button class="btn btn-sm btn-secondary" style="float: right;"><small><i class="far fa-comment"></i></small></button>
|
||||||
|
</span>
|
||||||
|
<br />
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="chat-popup">
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -35,9 +35,11 @@ from cloud.models import DataDir
|
||||||
from message.models import Message
|
from message.models import Message
|
||||||
from notificsys.models import UserNotification
|
from notificsys.models import UserNotification
|
||||||
from organizer.models import AGContacts, AGPassword
|
from organizer.models import AGContacts, AGPassword
|
||||||
import socket
|
|
||||||
import sys, os
|
import sys, os
|
||||||
|
from asgiref.sync import async_to_sync
|
||||||
|
from channels_presence.models import Room
|
||||||
|
from channels_presence.models import Presence
|
||||||
|
import channels.layers
|
||||||
|
|
||||||
def randomString(stringLength=10):
|
def randomString(stringLength=10):
|
||||||
"""Generate a random string of fixed length """
|
"""Generate a random string of fixed length """
|
||||||
|
|
@ -853,6 +855,3 @@ def cronactions(request, code):
|
||||||
print("API CODE FAILED")
|
print("API CODE FAILED")
|
||||||
data.update({"status" : "failed"})
|
data.update({"status" : "failed"})
|
||||||
return JsonResponse(data)
|
return JsonResponse(data)
|
||||||
|
|
||||||
def index(request):
|
|
||||||
return render(request, 'users/websocket.html', {})
|
|
||||||
Loading…
Reference in New Issue