QS Nach Deck

This commit is contained in:
Holger Trampe 2020-09-16 16:48:03 +02:00
parent 557b3fb0a4
commit 298ca23a5b
23 changed files with 584 additions and 391 deletions

View File

@ -24,7 +24,7 @@ class Areas(models.Model):
color = RGBColorField(colors=['#FFB900', '#E74856', '#0078D7', '#0099BC', '#7A7574'], default='#0099BC', blank=True)
desc = models.TextField(max_length=3000, blank=True)
usersfield = models.ManyToManyField(User, blank=True, related_name='users_in_area')
created_area_by = models.ForeignKey(User, on_delete=models.PROTECT)
created_area_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
created_area_date = models.DateField(default=datetime.date.today, blank=True)
visible = models.BooleanField(default=True)
areaorder = models.IntegerField(default=0)

View File

@ -6,14 +6,14 @@
width: 100%;
}
.icon-container {
width: 50px;
height: 50px;
width: 25px;
height: 25px;
position: relative;
}
.status-circle {
width: 15px;
height: 15px;
width: 5px;
height: 5px;
border-radius: 50%;
bottom: 0;
right: 0;
@ -22,19 +22,12 @@
</style>
<div class="card" style="position: fixed; right: 35px; bottom: 75px;">
<div class="card-body">
<h4>Chat öffnen
<!--<h5>Chat öffnen
<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>
<div class="row" style="float: right">
<div class="col">
</h5>
<hr>-->
{% for user in usersofagency %}
{% if forloop.counter|divisibleby:6 %}
</div>
<div class="col">
{% endif %}
<span style="padding: 20px;">
<button class="btn btn-sm btn-light mb-2" style="float: right; min-width: 100%; text-align: left;" onclick="javascript:openChat({{user.pk}})">
<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 %}
@ -51,12 +44,9 @@
</div>
</div>
{{user.first_name}} {{user.last_name}}
<button class="btn btn-sm btn-secondary" style="float: right;" onclick="javascript:openChat({{user.pk}})"><small><i class="far fa-comment"></i></small></button>
</span>
</button>
<br />
{% endfor %}
</div>
</div>
</div>
<script type="text/javascript">
function openChat(userid){

View File

@ -0,0 +1,86 @@
<style type="text/css">
.roundimg {
border-radius: 50%;
z-index: 999;
height: 100%;
width: 100%;
}
.icon-container {
width: 25px;
height: 25px;
position: relative;
}
.status-circle {
width: 5px;
height: 5px;
border-radius: 50%;
bottom: 0;
right: 0;
position: absolute;
}
</style>
<div class="card" style="position: fixed; right: 35px; bottom: 75px;">
<div class="card-body">
<h5>Chat öffnen
<button class="btn btn-sm btn-secondary" style="float: right;" onclick="javascript:$('#chat_alluserscontent').fadeOut()"><small><i class="fas fa-times"></i></small></button>
</h5>
<hr>
<div class="row" style="float: right">
<div class="col">
{% for user in usersofagency %}
{% if forloop.counter|divisibleby:6 %}
</div>
<div class="col">
{% endif %}
<span style="padding: 20px;">
<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 %}
{% if user.profile.onlinestatus == 0 %}
green
{% elif user.profile.onlinestatus == 1 %}
red
{% elif user.profile.onlinestatus == 2 %}
orange
{% elif user.profile.onlinestatus == 3 %}
grey
{% endif %}
{% else %} grey {% endif %};">
</div>
</div>
{{user.first_name}} {{user.last_name}}
<button class="btn btn-sm btn-secondary" style="float: right;" onclick="javascript:openChat({{user.pk}})"><small><i class="far fa-comment"></i></small></button>
</span>
<br />
{% endfor %}
</div>
</div>
</div>
<script type="text/javascript">
function openChat(userid){
$("#chat_alluserscontent").hide();
$.ajax(
{
type: "GET",
url: "{% url 'chat:chat-ajax' %}",
data : {
action : "startnewchat_user_user",
new_chat_userid : userid,
is_basechat : 1
},
success: function( data )
{
$("#dynamicchatwindow_content").html(data);
$("#dynamicchatwindow").show();
localStorage.setItem("basechatid", userid);
}
});
}
</script>

View File

@ -56,18 +56,19 @@
</style>
<div class="content-section col-12">
<h3>Chat&nbsp;<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. Alle Nachrichten werden verschlüsselt übertragen und in der Datenbank ebenfalls verschlüsselt gespeichert." class="far fa-question-circle"></i></small>
<button class="btn btn-primary btn-sm" style="float: right; " data-toggle="tooltip" data-placement="top" title="Erstellen Sie einen Gruppenchat." onclick="window.location.href='{% url 'chat:chat-addgroup' %}'"><i class="fas fa-plus"></i>&nbsp;Chatraum</button>
</h3>
<hr>
</div>
<div class="row col">
<div class="row">
<div class="col-3">
<!--
<h5>Mitarbeiter</h5>
<hr>
<div class="col-3" style="margin-top: -25px; margin-left: -8px;">
<div class="card-body">
{% for user in usersofagency %}
<div class="card mb-2 hoverchatcard" id="userchat_{{user.pk}}">
<div class="card hoverchatcard" id="userchat_{{user.pk}}">
<div class="card-body" style="margin: -15px !important;" >
<div style="float: left;" class="col-12 ">
<div class='icon-container mr-2'>
@ -90,14 +91,10 @@
</div>
</div>
{% endfor %}
<hr>
<h5>Chaträume
<button class="btn btn-primary btn-sm" style="float: right; margin-top: -6px !important;" data-toggle="tooltip" data-placement="top" title="Erstellen Sie einen Gruppenchat." onclick="window.location.href='{% url 'chat:chat-addgroup' %}'"><i class="fas fa-plus"></i></button>
</h5>
<hr>
{% for chatroom in chatrooms %}
{% if user in chatroom.chatmembers.all or user in chatroom.chatmembers_admin.all or user == chatroom.creator and chatroom.chatroomtype == 1 %}
<div class="card mb-2 hoverchatcard" id="groupchat_{{chatroom.pk}}">
<div class="card hoverchatcard" id="groupchat_{{chatroom.pk}}">
<div class="card-body" style="margin: -15px !important;">
<div style="float: left;" class="col-12 ">
<h5 class="mt-3">{{chatroom.roomname}}
@ -111,86 +108,13 @@
</div>
{% endif %}
{% endfor %}
-->
<div id="accordion">
<div class="card">
<div class="card-header" id="users">
<h5 class="mb-0">
<button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
Mitarbeiter
</button>
</h5>
</div>
<div id="collapseOne" class="collapse show" aria-labelledby="users" data-parent="#accordion">
<div class="card-body">
{% for user in usersofagency %}
<div class="card mb-2 hoverchatcard" id="userchat_{{user.pk}}">
<div class="card-body" style="margin: -15px !important;" >
<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 %}
{% if user.profile.onlinestatus == 0 %}
green
{% elif user.profile.onlinestatus == 1 %}
red
{% elif user.profile.onlinestatus == 2 %}
orange
{% elif user.profile.onlinestatus == 3 %}
grey
{% endif %}
{% else %} grey {% endif %};">
</div>
</div>
<h5 class="mt-3">{{user.first_name}} {{user.last_name}}</h5>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<div class="card">
<div class="card-header" id="chatrooms">
<h5 class="mb-0">
<button class="btn btn-link" data-toggle="collapse" data-target="#rooms" aria-expanded="true" aria-controls="rooms">
Chaträume
</button>
<button class="btn btn-primary btn-sm" style="float: right; " data-toggle="tooltip" data-placement="top" title="Erstellen Sie einen Gruppenchat." onclick="window.location.href='{% url 'chat:chat-addgroup' %}'"><i class="fas fa-plus"></i></button>
</h5>
</div>
<div id="rooms" class="collapse" aria-labelledby="chatrooms" data-parent="#accordion">
<div class="card-body">
{% for chatroom in chatrooms %}
{% if user in chatroom.chatmembers.all or user in chatroom.chatmembers_admin.all or user == chatroom.creator and chatroom.chatroomtype == 1 %}
<div class="card mb-2 hoverchatcard" id="groupchat_{{chatroom.pk}}">
<div class="card-body" style="margin: -15px !important;">
<div style="float: left;" class="col-12 ">
<h5 class="mt-3">{{chatroom.roomname}}
</h5>
<small style="font-size: 10pt;">{% for member in chatroom.chatmembers.all %}
{{member.first_name}} {{member.last_name}}{% if forloop.counter < chatroom.chatmembers.all|length %}, {% endif %}
{% endfor %}
</small>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</div>
</div>
</div>
</div>
</div></div>
<div class="col-9" style="float: left; position: relative; margin-left: -30px" id="mainchatcontent"></div><!-- END CHATAREA -->
</div>
<div class="col-9" style="" id="mainchatcontent"></div><!-- END CHATAREA -->
</div>
<!-- LOADER OVERLAY -->
<div id="overlay" style="display: none;">
<div class="loader"></div>

View File

@ -0,0 +1,340 @@
{% 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_breaker
{
float: right;
}
.chatmessageele_me
{
padding: 5px;
border-radius: 15px;
background-color: #cfe6f4;
float: right;
text-align: right;
}
.chatmessageele_other
{
padding: 5px;
border-radius: 15px;
background-color: #f8f9fc;
float: left;
text-align: left;
color: #000000;
}
.scroll {
max-height: 600px;
min-height: 600px;
overflow-y: auto;
}
</style>
<div class="content-section col-12">
<h3>Chat&nbsp;<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. Alle Nachrichten werden verschlüsselt übertragen und in der Datenbank ebenfalls verschlüsselt gespeichert." class="far fa-question-circle"></i></small>
</h3>
<hr>
</div>
<div class="row col">
<div class="col-3">
<!--
<h5>Mitarbeiter</h5>
<hr>
{% for user in usersofagency %}
<div class="card mb-2 hoverchatcard" id="userchat_{{user.pk}}">
<div class="card-body" style="margin: -15px !important;" >
<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 %}
{% if user.profile.onlinestatus == 0 %}
green
{% elif user.profile.onlinestatus == 1 %}
red
{% elif user.profile.onlinestatus == 2 %}
orange
{% elif user.profile.onlinestatus == 3 %}
grey
{% endif %}
{% else %} grey {% endif %};">
</div>
</div>
<h5 class="mt-3">{{user.first_name}} {{user.last_name}}</h5>
</div>
</div>
</div>
{% endfor %}
<hr>
<h5>Chaträume
<button class="btn btn-primary btn-sm" style="float: right; margin-top: -6px !important;" data-toggle="tooltip" data-placement="top" title="Erstellen Sie einen Gruppenchat." onclick="window.location.href='{% url 'chat:chat-addgroup' %}'"><i class="fas fa-plus"></i></button>
</h5>
<hr>
{% for chatroom in chatrooms %}
{% if user in chatroom.chatmembers.all or user in chatroom.chatmembers_admin.all or user == chatroom.creator and chatroom.chatroomtype == 1 %}
<div class="card mb-2 hoverchatcard" id="groupchat_{{chatroom.pk}}">
<div class="card-body" style="margin: -15px !important;">
<div style="float: left;" class="col-12 ">
<h5 class="mt-3">{{chatroom.roomname}}
</h5>
<small style="font-size: 10pt;">{% for member in chatroom.chatmembers.all %}
{{member.first_name}} {{member.last_name}}{% if forloop.counter < chatroom.chatmembers.all|length %}, {% endif %}
{% endfor %}
</small>
</div>
</div>
</div>
{% endif %}
{% endfor %}
-->
<div id="accordion">
<div class="card">
<div class="card-header" id="users">
<h5 class="mb-0">
<button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
Mitarbeiter
</button>
</h5>
</div>
<div id="collapseOne" class="collapse show" aria-labelledby="users" data-parent="#accordion">
<div class="card-body">
{% for user in usersofagency %}
<div class="card mb-2 hoverchatcard" id="userchat_{{user.pk}}">
<div class="card-body" style="margin: -15px !important;" >
<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 %}
{% if user.profile.onlinestatus == 0 %}
green
{% elif user.profile.onlinestatus == 1 %}
red
{% elif user.profile.onlinestatus == 2 %}
orange
{% elif user.profile.onlinestatus == 3 %}
grey
{% endif %}
{% else %} grey {% endif %};">
</div>
</div>
<h5 class="mt-3">{{user.first_name}} {{user.last_name}}</h5>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<div class="card">
<div class="card-header" id="chatrooms">
<h5 class="mb-0">
<button class="btn btn-link" data-toggle="collapse" data-target="#rooms" aria-expanded="true" aria-controls="rooms">
Chaträume
</button>
<button class="btn btn-primary btn-sm" style="float: right; " data-toggle="tooltip" data-placement="top" title="Erstellen Sie einen Gruppenchat." onclick="window.location.href='{% url 'chat:chat-addgroup' %}'"><i class="fas fa-plus"></i></button>
</h5>
</div>
<div id="rooms" class="collapse" aria-labelledby="chatrooms" data-parent="#accordion">
<div class="card-body">
{% for chatroom in chatrooms %}
{% if user in chatroom.chatmembers.all or user in chatroom.chatmembers_admin.all or user == chatroom.creator and chatroom.chatroomtype == 1 %}
<div class="card mb-2 hoverchatcard" id="groupchat_{{chatroom.pk}}">
<div class="card-body" style="margin: -15px !important;">
<div style="float: left;" class="col-12 ">
<h5 class="mt-3">{{chatroom.roomname}}
</h5>
<small style="font-size: 10pt;">{% for member in chatroom.chatmembers.all %}
{{member.first_name}} {{member.last_name}}{% if forloop.counter < chatroom.chatmembers.all|length %}, {% endif %}
{% endfor %}
</small>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</div>
</div>
</div>
</div>
</div>
<div class="col-9" style="" id="mainchatcontent"></div><!-- END CHATAREA -->
</div>
<!-- LOADER OVERLAY -->
<div id="overlay" style="display: none;">
<div class="loader"></div>
</div>
<style>
.loader {
position: relative;
border: 7px solid #d3d3d3;
border-radius: 50%;
border-top: 7px solid red;
width: 70px;
height: 70px;
left:50%;
top:35%;
-webkit-animation: spin 1s linear infinite; /* Safari */
animation: spin 1s linear infinite;
}
#overlay{
position: absolute;
top:0px;
left:0px;
width: 100%;
height: 100%;
background: black;
opacity: .4;
}
.container{
position:relative;
height: 300px;
width: 200px;
border:1px solid red;
}
/* Safari */
@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
<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(){
clickedroomtype = $(this)[0]["id"].split("_")[0];
clickedroomid = $(this)[0]["id"].split("_")[1];
if (clickedroomtype == "userchat"){
$.ajax(
{
type: "GET",
url: "{% url 'chat:chat-ajax' %}",
data : {
action : "startnewchat_user_user",
new_chat_userid : $(this)[0]["id"].split("_")[1],
is_basechat : 0
},
beforeSend: function(request) {
$("#overlay").fadeIn();
},
success: function( data )
{
$("#overlay").fadeOut();
if(creator_id != false && chatmember_id != false){
chatwebsocket.close();
}
$("#mainchatcontent").html(data);
}
});
}
//Open Groupchat
else{
$.ajax(
{
type: "GET",
url: "{% url 'chat:chat-ajax' %}",
data : {
action : "startnewchat_groupchat",
groupchatid : clickedroomid,
is_basechat : 0
},
beforeSend: function(request) {
$("#overlay").fadeIn();
},
success: function( data )
{
$("#overlay").fadeOut();
if(creator_id != false && chatmember_id != false){
chatwebsocket.close();
}
$("#mainchatcontent").html(data);
}
});
}
});
function updatePresenceLive() {
$.ajax(
{
type: "GET",
url: "{% url 'chat:chtaajax-getloggedusers-data' %}",
data : {
action : "getloggedusers"
},
success: function( data )
{
counter = 0;
$( ".status-circle" ).each(function( index ) {
if(data["user_online_final"].indexOf($(this)[0]["id"].split("_")[2]) !== -1){
$("#" + $(this)[0]["id"]).css("background-color", "green");
}
else if(data["user_besch_final"].indexOf($(this)[0]["id"].split("_")[2]) !== -1){
$("#" + $(this)[0]["id"]).css("background-color", "red");
}
else if(data["user_abw_final"].indexOf($(this)[0]["id"].split("_")[2]) !== -1){
$("#" + $(this)[0]["id"]).css("background-color", "orange");
}
else{
$("#" + $(this)[0]["id"]).css("background-color", "grey");
}
});
}
});
};
</script>
{% else %}
<h3>Das Module Chat wurde in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -17,7 +17,7 @@ class Data(models.Model):
file = models.FileField(null=True, max_length=255, upload_to=user_directory_path)
date_created = models.DateTimeField(default = timezone.now)
date_last_modified = models.DateTimeField(default = timezone.now)
owner = models.ForeignKey(User, on_delete=models.PROTECT)
owner = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
agency = models.ForeignKey(Agency, on_delete=models.CASCADE, default=None)
def __str__(self):
@ -34,7 +34,7 @@ class DataDir(models.Model):
visibleby = models.ManyToManyField(AgencyGroup, blank=True, related_name='visible_by_user')
date_created = models.DateTimeField(default = timezone.now)
date_last_modified = models.DateTimeField(default = timezone.now)
owner = models.ForeignKey(User, on_delete=models.PROTECT, blank=True, null=True)
owner = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True)
agency = models.ForeignKey(Agency, on_delete=models.CASCADE)
parent = models.ForeignKey('DataDir', on_delete=models.CASCADE, blank=True, null=True, related_name='dir_in_dir')
@ -48,7 +48,7 @@ class DataFile(models.Model):
file = models.FileField(null=True, max_length=255, upload_to=user_directory_path, blank=True)
date_created = models.DateTimeField(default = timezone.now)
date_last_modified = models.DateTimeField(default = timezone.now)
owner = models.ForeignKey(User, on_delete=models.PROTECT, default=None, blank=True, null=True)
owner = models.ForeignKey(User, on_delete=models.SET_NULL, default=None, blank=True, null=True)
agency = models.ForeignKey(Agency, on_delete=models.CASCADE, default=None, blank=True, null=True)
parent = models.ForeignKey(DataDir, on_delete=models.PROTECT, related_name='thisfileindir', blank=True, null=True)

View File

@ -19,7 +19,7 @@ class News(models.Model):
go_online_on = models.DateTimeField(default=timezone.now, blank=True)
# Default date plus two weeks
go_offline_on = models.DateTimeField(default=timezone.now()+timedelta(days=14), blank=True, null=True)
go_offline_on = models.DateTimeField(default=timezone.now, blank=True, null=True)
last_modified_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='news_mod_by', default=None)
last_modified_on = models.DateTimeField(default=timezone.now, blank=True)

View File

@ -23,6 +23,12 @@ $(document).ready(function() {
lang: "de-DE",
disableDragAndDrop: true
});
//Set offline-Datei plus 2 weeks
today = new Date();
today = new Date(today.setDate(today.getDate() + 14));
$("#id_go_offline_on").data("DateTimePicker").date(today);
});
</script>
{% else %}

View File

@ -18,7 +18,6 @@ users speichert alle primary-Keys der User, welche diesem Bereich zugeordnet sin
'''
class QuickLinks(models.Model):
# Wenn die Area gelöscht wird, wird NICHT die Agency gelöscht
agency = models.ForeignKey(Agency, on_delete=models.PROTECT)
name = models.CharField(max_length=200, blank=False)
link = models.CharField(max_length=200, blank=False)

View File

@ -133,7 +133,7 @@ class StandardUpdateStandard(forms.ModelForm):
self.fields['task'].queryset = Tasks.objects.filter(area__id=areaid).order_by('name')
except (ValueError, TypeError):
pass
elif loggeduser.pk and standard.area != None:
elif loggeduser != None and standard.area != None:
self.fields['task'].queryset = Tasks.objects.filter(area__pk=standard.area.pk)
self.fields['area'].required = True

View File

@ -12,7 +12,7 @@ from django.utils import timezone
class StandardCommentRate(models.Model):
#standard = models.ForeignKey("Standards", on_delete=models.CASCADE)
rated_by = models.ForeignKey(User, on_delete=models.PROTECT)
rated_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
rate_stats = models.IntegerField(default=0)
oncomment = models.ForeignKey("StandardComments", on_delete=models.CASCADE)
@ -30,13 +30,13 @@ class Standards(models.Model):
name = models.CharField(max_length=200, blank=False, default="")
content = models.TextField(blank=True, verbose_name='Inhalt', default="")
created_standard_by = models.ForeignKey(User, on_delete=models.PROTECT)
created_standard_by = models.ForeignKey(User, default=None, null=True, on_delete=models.SET_NULL)
created_standard_date = models.DateTimeField(default=timezone.now, blank=True)
published_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name='user_published_standard', default=None)
published_by = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='user_published_standard', default=None, null=True)
published_on = models.DateTimeField(default=timezone.now, blank=True)
last_modified_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name='user_modified_standard', default=None)
last_modified_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='user_modified_standard', default=None)
last_modified_on = models.DateTimeField(default=timezone.now, blank=True)
public = models.BooleanField(default=False)

View File

@ -14,7 +14,7 @@
<h2>{{standard.name}}
<span style="float: right">
{% if standard.created_standard_by == user or perms.users.standardmanager %}
{% if standard.created_standard_by != null and standard.created_standard_by == user or perms.users.standardmanager %}
<a style="float: right" class="btn btn-secondary btn-sm ml-2" href="{% url 'standard-delete' standard.pk %}"><small><i class="fas fa-trash"></i></small></a>
<a style="float: right" class="btn btn-secondary btn-sm " href="{% url 'standard-add' standard.pk %}"><small><i class="fas fa-pen"></i></small></a>
{% endif %}
@ -193,8 +193,9 @@
</div>
<div class="mt-2">
<small>
Erstellt durch <a href="{% url 'orga-single' standard.created_standard_by.pk %}">{{standard.created_standard_by.first_name}} {{standard.created_standard_by.last_name}}</a> am {{standard.created_standard_date}} | Zuletzt bearbeitet von <a href="{% url 'orga-single' standard.last_modified_by.pk %}">{{ standard.last_modified_by.first_name}} {{ standard.last_modified_by.last_name}}</a> am {{ standard.last_modified_on}}
{% if not standard.created_standard_by %} Erstellt von gelöschtem Mitarbeiter {% else %} Erstellt durch <a href="{% url 'orga-single' standard.created_standard_by.pk %}">{{standard.created_standard_by.first_name}} {{standard.created_standard_by.last_name}}</a> {% endif %} am {{standard.created_standard_date}} | {% if not standard.last_modified_by %} Zuletzt bearbeitet von gelöschtem Benutzer {% else %} Zuletzt bearbeitet von <a href="{% url 'orga-single' standard.last_modified_by.pk %}">{{ standard.last_modified_by.first_name}} {{ standard.last_modified_by.last_name}}</a>{% endif %} am {{ standard.last_modified_on}}
</small>
</div>
</div>

View File

@ -125,8 +125,7 @@
{% getcommentsup comment.pk as cup %}
{% if cup > 0 %}{{cup}}{% endif %}
{% if comment.comment_by == request.user or standard.created_standard_by == request.user or standard.last_modified_by == request.user %}
{% if comment.comment_by == request.user or (standard.created_standard_by != none and standard.created_standard_by == request.user) or standard.last_modified_by == request.user %}
<span style="float: right;">
<button type="button" class="btn btn-sm btn-secondary" onclick="javascript:delComment({{comment.pk}})" ><i class="fa fa-trash"></i></button>
</span>

View File

@ -557,6 +557,19 @@ def gettimeoveralldiff(workday, user):
Es werden nur Tage berücksichtigt, die in der Vergangenheit liegen!
'''
def format_timedelta(td):
hours, remainder = divmod(td.total_seconds(), 3600)
minutes, seconds = divmod(remainder, 60)
hours, minutes, seconds = int(hours), int(minutes), int(seconds)
if hours < 10:
hours = '0%s' % int(hours)
if minutes < 10:
minutes = '0%s' % minutes
if seconds < 10:
seconds = '0%s' % seconds
return '%s:%s:%s' % (hours, minutes, seconds)
@register.simple_tag
def loadaccounttime(user):
status = 0
@ -591,14 +604,13 @@ def loadaccounttime(user):
# Wenn GLeitzeit NEGATIV ist
if(finalaccounttimesum.total_seconds() < 0):
status = 1
final_info_data = str(datetime.timedelta(seconds=finalaccounttimesum.total_seconds()*(-1))).split(":")
final_info_data = format_timedelta(datetime.timedelta(seconds=finalaccounttimesum.total_seconds()*(-1)))
else:
status = 0
final_info_data = str(datetime.timedelta(seconds=finalaccounttimesum.total_seconds())).split(":")
final_info_data = format_timedelta(datetime.timedelta(seconds=finalaccounttimesum.total_seconds()))
final_info = str(final_info_data[0]) + ":" + str(final_info_data[1])
return [final_info, status]
#final_info = str(final_info_data[0]) + ":" + str(final_info_data[1])
return [final_info_data, status]
'''

View File

@ -607,6 +607,7 @@ def StandardSingle(request, pk):
'active_link':'standards',
'standard' : standard
}
return render(request, 'standards/standards_single.html', context)
else:
context = {

View File

@ -18,7 +18,7 @@ class Tasks(models.Model):
name = models.CharField(max_length=200, blank=False, default="")
desc = models.TextField(max_length=3000, blank=True)
usersfield = models.ManyToManyField(User, blank=True, related_name='users_in_task')
created_area_by = models.ForeignKey(User, on_delete=models.PROTECT)
created_area_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
created_area_date = models.DateField(default=datetime.date.today, blank=True)
visible = models.BooleanField(default=True)

View File

@ -428,15 +428,14 @@ function recalculateChoosenDays(userid=false){
$("#id_start").data("DateTimePicker").date(date_start);
$("#id_end").data("DateTimePicker").date(date_end);
console.log(userid);
localStorage.setItem("ab_userid", userid);
$.ajax({
type: "GET",
url: "{% url 'tm-ajax' %}",
data:{
action : "getrestholidays",
userid : userid,
userid : localStorage.getItem("ab_userid"),
startdate : date_start.getFullYear() + "__" + (date_start.getMonth()+1) + "__" + date_start.getDate(),
enddate : date_end.getFullYear() + "__" + (date_end.getMonth()+1) + "__" + date_end.getDate(),
//start_half : $("#id_start_ishalf").prop("checked"),
@ -462,8 +461,6 @@ function recalculateChoosenDays(userid=false){
$("#ownholidays").hide();
}
$("#startAbsenceProgress").modal("show");
@ -504,8 +501,6 @@ function recalculateChoosenDays(userid=false){
}
function recalculateChoosenDaysAfterInit(){
console.log("CHANGE!")
console.log(userid);
new_start = $("#id_start").datepicker().val();
new_end = $("#id_end").datepicker().val();
@ -515,10 +510,10 @@ function recalculateChoosenDaysAfterInit(){
behindcheck_start = new Date(new_start[2], (parseInt(new_start[1])-1), new_start[0]);
behindcheck_end = new Date(new_end[2], (parseInt(new_end[1])-1), new_end[0]);
if(sameday){
behindcheck_end = behindcheck_start;
new_end = new_start;
}
//if(sameday){
// behindcheck_end = behindcheck_start;
// new_end = new_start;
//}
$.ajax({
@ -526,7 +521,7 @@ function recalculateChoosenDaysAfterInit(){
url: "{% url 'tm-ajax' %}",
data:{
action : "getrestholidays",
userid : userid,
userid : localStorage.getItem("ab_userid"),
startdate : new_start[2] + "__" + new_start[1] + "__" + new_start[0],
enddate : new_end[2] + "__" + new_end[1] + "__" + new_end[0],
//start_half : $("#id_start_ishalf").prop("checked"),

View File

@ -1,229 +0,0 @@
'''
@receiver(post_save, sender=DataDir)
def save_dir(sender, instance, **kwargs):
usersofagency = User.objects.filter(profile__agency__pk=instance.agency.pk)
# CREATED
if(kwargs["created"]):
for user in usersofagency:
if(user.usernotifications.filedir_created_mail):
notificationtext = " es gibt neue Ordner: " + instance.name
sendMailNoti(notificationtext, user)
if(user.usernotifications.filedir_created_push):
newnotification = UserNotification(touser=user, notificationtext="Neuer Ordner: " + instance.name, notificationtype="", elementid=instance.pk)
newnotification.save()
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Ordner | Neuer Ordner: " + instance.name})
# UPDATED
else:
for user in usersofagency:
if(user.usernotifications.filedir_update_mail):
notificationtext = " Ordner wurden aktualisiert: " + instance.name
sendMailNoti(notificationtext, user)
if(user.usernotifications.filedir_update_push):
newnotification = UserNotification(touser=user, notificationtext="Aktualisierter Ordner: " + instance.name, notificationtype="", elementid=instance.pk)
newnotification.save()
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Ordner | Aktualisierter Ordner: " + instance.name})
'''
'''
@receiver(pre_delete, sender=DataDir)
def del_dir(sender, instance, **kwargs):
usersofagency = User.objects.filter(profile__agency__pk=instance.agency.pk)
for user in usersofagency:
if(user.usernotifications.filedir_delete_mail):
notificationtext = " ein Ordner wurde gelöscht: " + instance.name
sendMailNoti(notificationtext, user)
if(user.usernotifications.filedir_delete_push):
newnotification = UserNotification(touser=user, notificationtext="Ordner gelöscht: " + instance.name, notificationtype="", elementid=instance.pk)
newnotification.save()
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Ordner | Ordner gelöscht: " + instance.name})
'''
@receiver(pre_delete, sender=DataFile)
def del_file(sender, instance, **kwargs):
usersofagency = User.objects.filter(profile__agency__pk=instance.agency.pk)
for user in usersofagency:
if(user.usernotifications.filedir_delete_mail):
notificationtext = " eine Datei wurde gelöscht: " + instance.name
sendMailNoti(notificationtext, user)
if(user.usernotifications.filedir_delete_push):
newnotification = UserNotification(touser=user, notificationtext="Datei gelöscht: " + instance.name, notificationtype="", elementid=instance.pk)
newnotification.save()
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Dateiein | Datei gelöscht: " + instance.name})
# Signals for FILES
@receiver(post_save, sender=DataFile)
def save_file(sender, instance, **kwargs):
if(kwargs["created"] and len(instance.name) > 0):
newNotifiyPush(0, instance, " es gibt eine neue Datei: ", "Neue Datei: ", "Dateien | ", "", "")
elif(len(instance.name) > 0):
newNotifiyPush(1, instance, " Datei wurde aktualisiert: ", "Aktualisierter Datei: ", "Dateien | ", "", "")
usersofagency = User.objects.filter(profile__agency__pk=instance.agency.pk)
# CREATED
if(kwargs["created"]):
for user in usersofagency:
if(user.usernotifications.filedir_created_mail):
notificationtext = " es gibt eine neue Datei: " + instance.name
sendMailNoti(notificationtext, user)
if(user.usernotifications.filedir_created_push):
newnotification = UserNotification(touser=user, notificationtext="Neue Datei: " + instance.name, notificationtype="", elementid=instance.pk)
newnotification.save()
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Dateien | Neue Datei: " + instance.name})
# UPDATED
else:
for user in usersofagency:
if(user.usernotifications.filedir_update_mail):
notificationtext = " Datei wurden aktualisiert: " + instance.name
sendMailNoti(notificationtext, user)
if(user.usernotifications.filedir_update_push):
newnotification = UserNotification(touser=user, notificationtext="Aktualisierte Datei: " + instance.name, notificationtype="", elementid=instance.pk)
newnotification.save()
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Dateien | Aktualisierte Datei: " + instance.name})
@receiver(post_save, sender=QuickLinks)
def save_ql(sender, instance, **kwargs):
usersofagency = User.objects.filter(profile__agency__pk=instance.agency.pk)
# CREATED
if(kwargs["created"]):
for user in usersofagency:
if(user.usernotifications.ql_created_mail):
notificationtext = " es gibt einen neuen Quicklink: " + instance.name
sendMailNoti(notificationtext, user)
if(user.usernotifications.ql_created_push):
newnotification = UserNotification(touser=user, notificationtext="Neuer Quicklink: " + instance.name, notificationtype="", elementid=instance.pk)
newnotification.save()
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Organizer | Neuer Quicklink: " + instance.name})
# UPDATED
else:
for user in usersofagency:
if(user.usernotifications.ql_update_mail):
notificationtext = " Quicklink wurde aktualisiert: " + instance.name
sendMailNoti(notificationtext, user)
if(user.usernotifications.ql_update_push):
newnotification = UserNotification(touser=user, notificationtext="Quicklink aktualisiert: " + instance.name, notificationtype="", elementid=instance.pk)
newnotification.save()
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Organizer | Aktualisierter Quicklink: " + instance.name})
@receiver(pre_delete, sender=QuickLinks)
def del_ql(sender, instance, **kwargs):
usersofagency = User.objects.filter(profile__agency__pk=instance.agency.pk)
for user in usersofagency:
if(user.usernotifications.ql_delete_mail):
notificationtext = " ein Quicklink wurde gelöscht: " + instance.name
sendMailNoti(notificationtext, user)
if(user.usernotifications.ql_delete_push):
newnotification = UserNotification(touser=user, notificationtext="Quicklink gelöscht: " + instance.name, notificationtype="", elementid=instance.pk)
newnotification.save()
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Organizer | Quicklink gelöscht: " + instance.name})
@receiver(post_save, sender=Standards)
def save_standard(sender, instance, **kwargs):
usersofagency = User.objects.filter(profile__agency__pk=instance.agency.pk)
targeturl = settings.BASE_URL + "standards/standard/" + str(instance.pk) + "/single"
# NEW STANDARD
if(kwargs["created"]):
if(instance.public):
for user in usersofagency:
if(user.usernotifications.standard_created_mail):
notificationtext = " es wurde ein neuer Agenturstandard erstellt: " + instance.name
sendMailNoti(notificationtext, user)
if(user.usernotifications.standard_created_push):
newnotification = UserNotification(touser=user, notificationtext="Neuer Agenturstandard: " + instance.name, notificationtype="newstandard", elementid=instance.pk)
newnotification.save()
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Standards | Neuer Agenturstandard: " + instance.name})
else:
for user in usersofagency:
if(user.has_perm("users.standardmanager") and user.usernotifications.standard_created_unpub_push):
newnotification = UserNotification(touser=user, notificationtext="Neuer unveröffentlichter Agenturstandard: " + instance.name, notificationtype="newstandard", elementid=instance.pk)
newnotification.save()
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Standards | Neuer unveröffentlichter Agenturstandard: " + instance.name})
if(user.has_perm("users.standardmanager") and user.usernotifications.standard_created_unpub_mail):
notificationtext = " es wurde ein neuer unveröffentlichter Agenturstandard erstellt: " + instance.name
sendMailNoti(notificationtext, user)
# Standard wurde aktualisiert
else:
for user in usersofagency:
if(user.usernotifications.standard_update_mail):
notificationtext = " es wurde ein neuer Agenturstandard aktualisiert: " + instance.name
sendMailNoti(notificationtext, user)
if(user.usernotifications.standard_update_push):
newnotification = UserNotification(touser=user, notificationtext="Agenturstandard aktualisiert: " + instance.name, notificationtype="newstandard", elementid=instance.pk)
newnotification.save()
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Standards | Agenturstandard aktualisiert: " + instance.name})
# DELETE
@receiver(pre_delete, sender=Standards)
def delete_standard(sender, instance, **kwargs):
usersofagency = User.objects.filter(profile__agency__pk=instance.agency.pk)
for user in usersofagency:
if(user.usernotifications.standard_delete_mail):
notificationtext = " es wurde ein neuer Agenturstandard gelöscht: " + instance.name
sendMailNoti(notificationtext, user)
if(user.usernotifications.standard_delete_push):
newnotification = UserNotification(touser=user, notificationtext="Agenturstandard gelöscht: " + instance.name, notificationtype="", elementid=instance.pk)
newnotification.save()
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Standards | Agenturstandard gelöscht: " + instance.name})

View File

@ -23,9 +23,9 @@
</style>
<div class="card col-2" style="position: fixed; right: 35px; bottom: 75px;">
<div class="card-body">
<h4>Chat starten
<h5>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>
</h5>
<hr>
{% for user in usersofagency %}
<span>

View File

@ -10,13 +10,22 @@
</div>
</div>
<!-- Für das Speichern der Bilder enctype -->
<!-- TASK: Hinzufügen von Zeiterfassung und Urlaub! -->
<form method="POST">
{% csrf_token %}
<p>Alle vom Benutzer erstellen Standards werden dem aktuellen Benutzer zugewiesen.<br /><small>(Aktuller Benutzer: {{request.user.pre_name}} {{request.user.last_name}})</small></p>
<p>Alle vom Benutzer erstellen Informationen (Standards, Dateien usw.) bleiben bestehen, jedoch werden die Verweise auf einen Nutzer entfernt. Alle Chat-Nachrichten werden unwiederruflich gelöscht! Soeben wurden alle Vertragsdaten (Abwesenheit und Zeiterfassung), wenn vorhanden, als CSV heruntergeladen. Diese können Sie archivieren und entsprechend Ihrer agenturinternen Gegebenheiten bzgl. Datenspeicherung aufbewahren.<br /></p>
<a href="{% url 'users-delete-getdata' user.pk %}" id="downloadFileAction" download>Daten erneut herunterladen</a>
<hr>
<div class="form-group">
<button type="submit" class="btn btn-primary">Benutzer löschen</button>&nbsp;
<a href="{% url 'dasettings' %}" class="btn">Abbrechen</a>
</div>
</form>
</div>
<script type="text/javascript">
//Auto-Download the file
$(document).ready(function(){
location.href = "{% url 'users-delete-getdata' user.pk %}"
})
</script>
{% endblock content %}

View File

@ -23,6 +23,7 @@ urlpatterns = [
#path('usersman/<int:pk>/', permission_required('users.usermanager')(ProfileUpdateView.as_view()), name='users-update'),
path('usersman/<int:pk>/perms', permission_required('users.usermanager')(UsersPermUpdateView.as_view()), name='users-perm-update'),
path('usersman/<int:pk>/delete', permission_required('users.usermanager')(ProfileDeleteView.as_view()), name='users-delete'),
path('usersman/gd/<int:pk>', views.getDataFromToDelUser, name="users-delete-getdata"),
#path('agencyinfo/', views.agency, name='agencyinfo'),
#path('agencyinfo/<int:pk>/', permission_required('users.agency_change')(AgencyUpdateView.as_view()), name='agency-manage'),
path('usersman/<int:pk>/prio', views.UsersPrio, name='users-prio'),
@ -37,7 +38,8 @@ urlpatterns = [
path('sendpassmail/', views.sendpassmail, name="users-sendpassmail"),
path('changeonlinestat/', views.changeonlinestat, name="users-updateonlinestat"),
path('dacron/<slug:code>', views.cronactions, name="cronmain"),
path('dacrondaily/<slug:code>', views.cronactionsdaily, name="cronmaindaily")
path('dacrondaily/<slug:code>', views.cronactionsdaily, name="cronmaindaily"),
]

View File

@ -41,7 +41,7 @@ from channels_presence.models import Room
from channels_presence.models import Presence
import channels.layers
from datetime import date, timedelta
from timemanagement.models import Workday, Absence
from timemanagement.models import Workday, Absence, Breaks
import base64
import filetype
from django.db.models.signals import m2m_changed
@ -507,15 +507,73 @@ def changeonlinestat(request):
zugeschrieben, welcher eingeloggt ist. Das passiert VOR dem löschen!
'''
import csv
@login_required
def getDataFromToDelUser(request, pk):
if(request.method == "GET"):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="newfile.csv"'
writer = csv.writer(response)
# LOAD ABSENCE OBJECTES
user = User.objects.get(pk=pk)
# TASK: Hier besprechen, ob das Recht als Benutzermanager ausreicht!
if(request.user.has_perm("users.usermanager") and user.profile.agency == request.user.profile.agency):
user_absences = Absence.objects.filter(agency=request.user.profile.agency, user=user).order_by("-start")
for ab in user_absences:
status = "OK"
if(ab.confirm_status == 1 or ab.confirm_status == 2):
status = "Abgelehnt"
writer.writerow(['Abwesenheit', str(ab.start), str(ab.end), 'Grund: '+ab.reason.name, 'Status: '+status])
user_workdays = Workday.objects.filter(agency=request.user.profile.agency, user=user).order_by("-start")
for wd in user_workdays:
breaks = Breaks.objects.filter(agency=request.user.profile.agency, user=user, workday=wd)
breaks_string = ""
for b in breaks:
breaks_string += str(b.start) + " bis " + str(b.end) + ", "
writer.writerow(['Arbeitstag', str(wd.start), str(wd.end), 'Pausen: ' + breaks_string])
return response
else:
pass
class ProfileDeleteView(LoginRequiredMixin, DeleteView):
model = User
success_url = '/dasettings/main'
template_name = 'users/user_confirm_delete.html'
# Adding active_link
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Hier Daten zusammenstellen, damit alle Daten bzgl Vertrag nicht verloren gehen (Zeiterfassung, Urlaub und Abwesenheiten)
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="file.csv"'
writer = csv.writer(response)
writer.writerow(['1001', 'John', 'Domil', 'CA'])
writer.writerow(['1002', 'Amit', 'Mukharji', 'LA', '"Testing"'])
context.update({"response" : response})
print(response)
return context
def delete(self, request, *args, **kwargs):
user = User.objects.get(pk=kwargs['pk'])
logged_user = request.user
''' ALTER LÖSCHBEREICH - User wird einfach entfernt '''
'''
areas_fs = Areas.objects.filter(created_area_by=user)
for a in areas_fs:
a.created_area_by = logged_user
@ -542,6 +600,7 @@ class ProfileDeleteView(LoginRequiredMixin, DeleteView):
for a in standards_fs:
a.published_by = logged_user
a.save()
'''
response = super(ProfileDeleteView, self).delete(request, *args, **kwargs)
name = user.first_name + " " + user.last_name
@ -615,7 +674,6 @@ def UsersPrioUpdate(request):
else:
return HttpResponse("Request method is not a GET")
import re