Notificsys fehlte

This commit is contained in:
holger.trampe 2020-02-21 23:04:59 +01:00
parent 57ae275c9c
commit 361dfc4158
100 changed files with 5277 additions and 0 deletions

View File

@ -0,0 +1,22 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<div class="media-body">
<h2 class="account-heading">Bereich {{ object.name }} löschen?</h2>
<hr>
</div>
</div>
<!-- Für das Speichern der Bilder enctype -->
<form method="POST">
{% csrf_token %}
<p>Alle unter diesem Bereich erstellten Aufgaben und Standards werden gelöscht!</p>
<div class="form-group">
<button type="submit" class="btn btn-danger">Bereich löschen</button>&nbsp;
<a href="{% url 'areas-management' %}" class="btn btn-success">Abbrechen</a>
</div>
</form>
</div>
{% endblock content %}

View File

@ -0,0 +1,43 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section col-6">
<h3>Neuen Bereich anlegen</h3>
<hr>
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<div class="form-group mb-2 mb-3">
<span>Farbe</span><input type="color" id="color-picker" name="areacolor " />
</div>
<p>Nachdem Erstellen eines Bereichs können Mitarbeiter zugewiesen werden.</p>
<hr>
<button type="submit" class="btn btn-success" href="{% url 'areas-addarea' %} ">Bereich anlegen</button>&nbsp;
<a class="btn" href="{% url 'areas-management' %} ">Abbrechen</a>
</form>
</div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/themes/classic.min.css"/> <!-- 'classic' theme -->
<script src="https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/pickr.es5.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("#div_id_color").hide();
})
const pickr1 = new Pickr({
el: '#color-picker',
default: "#000000",
components: {
preview: false,
hue: true
}
});
pickr1.on('changestop', function(){
var col = pickr1.getColor().toHEXA().toString();
pickr1.setColor(col);
$("#id_color").val(col);
});
</script>
{% endblock content %}

View File

@ -0,0 +1,101 @@
{% extends "users/base.html" %}
{% block content %}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<div class="content-section col-12">
<h3>Bereichsverwaltung</h3>
<hr>
<p>
Bereiche unterteilen die Agentur in verschiedene Verantwortungsbereiche.
</p>
<div class="row">
<div class="content-section col-4">
<a class="btn btn-primary" href="{% url 'areas-addarea' %} ">Bereich anlegen</a>
</div>
</div>
<div class="row mt-3">
<div class="form-group mb-2">
<input class="form-control" id="tableSearch" size="50" type="text" placeholder="Suche in Tabelle...">
</div>
<div class="table-responsive">
<table class="table table-hover" id="areas_maintable">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Erstellt von</th>
<th scope="col">Erstellt am</th>
<th scope="col">Farbe</th>
<th scope="col">&nbsp;</th>
</tr>
</thead>
<tbody id="tableresults">
{% for item in areas_of_agency %}
<tr id="{{ item.pk }}">
<td>{{ item.name }}</td>
<td>{{ item.created_area_by.first_name }} {{ item.created_area_by.last_name }}</td>
<td>{{ item.created_area_date }}</td>
<td><div style="width: 60px; height: 20px; background-color: {{ item.color }}"></div></td>
<td>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Bereichsinfo</div>
<a class="dropdown-item" href="{% url 'areas-manage' item.pk %}">Bearbeiten</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="{% url 'areas-delete' item.pk %}" >Löschen</a>
</div>
</div>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(document).ready(function(){
/*$('#areas_maintable').DataTable();*/
$("#tableSearch").on("keyup", function() {
var value = $(this).val().toLowerCase();
$("#tableresults tr").filter(function() {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
});
});
});
/*
Update the sort-list by drag'n'drop
*/
$( "tbody" ).sortable({
update: function( event, ui ) {
datatoserver = [];
var rows = $( "tbody" ).sortable( "widget" )[0]['rows'];
for(i = 0; i < rows.length; i++){
datatoserver.push({"id" : rows[i]['id'], "neworder" : i});
}
$.ajax(
{
type: "GET",
url: "/areas/updateorder",
data:{
action: "newareaorder",
finalod : JSON.stringify(datatoserver)
},
success: function( data )
{
console.log(data);
}
});
}
});
</script>
{% endblock content %}

View File

@ -0,0 +1,172 @@
{% extends "users/base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section col-6" onmouseup="javascript:checkValue()">
<h3>Bereich aktualisieren</h3>
<hr>
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<div class="form-group mb-2 mb-3">
<span>Farbe</span><input type="color" id="color-picker" name="areacolor " />
</div>
<h6>Mitarbeiter hinzufügen</h6>
<div class="input-group mb-3">
<input class="form-control" list="usersfree" name="searchusers" id="searchusers" type="text" onkeyup="javascript:checkValue()" onchange="javascript:checkValue()" >
<div class="input-group-append">
<button type="button" id="addusertoareabtn" onclick="javascript:addUserToArea()" class="btn btn-success" disabled>Mitarbeiter hinzufügen</button>
<button type="button" onclick="javascript:clearSearchfield()" class="btn btn-secondary" ><i class="fas fa-times"></i></button>
</div>
<datalist id="usersfree">
{% for us in possible_users %}
<option id="{{us.pk}}" value="{{us.first_name}} {{us.last_name}}"></option>
{% endfor %}
</datalist>
</datalist>
</div>
<hr>
<h6>Zugewiesene Mitarbeiter</h6>
<div id="added_users_button">
{% if added_users|length > 0 %}
<p id="no_user_in_area" style="display: none">Noch kein Mitarbeiter zugewiesen.</p>
{% for us in added_users %}
<span id="span_btn_{{us.pk}}" class="badge badge-pill badge-primary mr-2 mt-2"><a class="btn btn-primary" onclick="javascript:removeUserFromArea('{{ us.pk }}')">{{ us.first_name }} {{ us.last_name }}&nbsp;&nbsp;<i class="fas fa-times"></i></a >
</span>
{% endfor %}
{% else %}
<p id="no_user_in_area">Diesem Bereich ist noch kein Mitarbeiter zugewiesen.</p>
{% endif %}
</div>
<hr>
<button type="submit" class="btn btn-success">Bereich aktualisieren</button>&nbsp;
<a class="btn" href="{% url 'areas-management' %} ">Abbrechen</a>
</form>
</div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/themes/classic.min.css"/> <!-- 'classic' theme -->
<script src="https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/pickr.es5.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("#div_id_color").hide();
})
const pickr1 = new Pickr({
el: '#color-picker',
default: "{{object.color}}",
components: {
preview: false,
hue: true
}
});
pickr1.on('changestop', function(){
var col = pickr1.getColor().toHEXA().toString();
pickr1.setColor(col);
$("#id_color").val(col);
});
var ua = window.navigator.userAgent;
var isIE = /MSIE|Trident/.test(ua);
if ( isIE ) {
//IE specific code goes here
setInterval(function()
{
checkValue();
},250);
}
var tempid = null;
var tempcounter = 0;
function addUserToArea(){
$.ajax(
{
type: "GET",
url: "/areas/areaajax",
data:{
userid: tempid,
action : 'adduser',
objectid : {{objectid}}
},
success: function( data )
{
clearSearchfield();
//Add User-Button
$("#added_users_button").append('<span id="span_btn_'+data['userid']+'" class="badge badge-pill badge-primary mr-2 mt-2"><a class="btn btn-primary" onclick="javascript:removeUserFromArea('+data['userid']+')">'+data['username_clean']+'&nbsp;&nbsp;<i class="fas fa-times"></i></a ></span>');
$("#usersfree").empty();
for (var i in data['remaining_users']) {
id = data['remaining_users'][i]['id'];
name = data['remaining_users'][i]['first_name'] + " " + data['remaining_users'][i]['last_name'];
$("#usersfree").append('<option id="'+id+'" value="'+name+'"></option>');
}
if(data['remaining_users_counter'] == 0){
$("#no_user_in_area").show();
}
else {
$("#no_user_in_area").hide();
}
}
});
}
//Remove individual User from area, appened to the datalist!
function removeUserFromArea(user_id){
$.ajax(
{
type: "GET",
url: "/areas/areaajax",
data:{
userid: user_id,
action : 'remuser',
objectid : {{objectid}}
},
success: function( data )
{
//Remove User-Button
$("#span_btn_"+data['userid']).remove();
//Rebuilding the Datalist
$("#usersfree").empty();
for (var i in data['remaining_users']) {
id = data['remaining_users'][i]['id'];
name = data['remaining_users'][i]['first_name'] + " " + data['remaining_users'][i]['last_name'];
$("#usersfree").append('<option id="'+id+'" value="'+name+'"></option>');
}
if(data['remaining_users_counter'] == 0){
$("#no_user_in_area").show();
}
else {
$("#no_user_in_area").hide();
}
}
});
}
//Clearing searchfield and set AddUser to false
function clearSearchfield(){
$("#searchusers").val("");
$("#addusertoareabtn").prop('disabled', true);
}
//Check for valid input on inputfield
function checkValue(){
var g = $('#searchusers').val();
var id = $('#usersfree').find('option[value="' + g + '"]').attr('id');
if(id != undefined && id.length > 0){
tempid = id;
$("#addusertoareabtn").prop('disabled', false);
}
else{
tempid = null;
$("#addusertoareabtn").prop("disabled", true);
}
}
</script>
{% endblock content %}

Binary file not shown.

View File

@ -0,0 +1,32 @@
# Generated by Django 3.0.2 on 2020-02-14 22:34
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('users', '0062_auto_20200213_2207'),
('cloud', '0004_data_subdir'),
]
operations = [
migrations.CreateModel(
name='DataDir',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(blank=True, default='', max_length=2000, null=True)),
('is_root', models.BooleanField(default=True)),
('date_created', models.DateTimeField(default=django.utils.timezone.now)),
('date_last_modified', models.DateTimeField(default=django.utils.timezone.now)),
('agency', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='users.Agency')),
('dirs', models.ManyToManyField(blank=True, related_name='dirs_in_dirs', to='cloud.DataDir')),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
('visibleby', models.ManyToManyField(blank=True, related_name='visible_by_user', to='users.AgencyGroup')),
],
),
]

View File

@ -0,0 +1,32 @@
# Generated by Django 3.0.2 on 2020-02-14 22:34
import cloud.models
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('users', '0062_auto_20200213_2207'),
('cloud', '0005_datadir'),
]
operations = [
migrations.CreateModel(
name='DataFiles',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(blank=True, default='', max_length=2000, null=True)),
('file', models.FileField(max_length=255, null=True, upload_to=cloud.models.user_directory_path)),
('date_created', models.DateTimeField(default=django.utils.timezone.now)),
('date_last_modified', models.DateTimeField(default=django.utils.timezone.now)),
('agency', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='users.Agency')),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
('parent', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='cloud.DataDir')),
],
),
]

View File

@ -0,0 +1,24 @@
# Generated by Django 3.0.2 on 2020-02-14 22:36
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('cloud', '0006_datafiles'),
]
operations = [
migrations.AddField(
model_name='datadir',
name='datafiles',
field=models.ManyToManyField(blank=True, related_name='files_in_dir', to='cloud.DataFiles'),
),
migrations.AlterField(
model_name='datafiles',
name='parent',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='thisfileindir', to='cloud.DataDir'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.0.2 on 2020-02-14 22:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cloud', '0007_auto_20200214_2236'),
]
operations = [
migrations.AlterField(
model_name='datadir',
name='is_root',
field=models.BooleanField(default=False),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 3.0.2 on 2020-02-14 22:38
from django.conf import settings
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('users', '0062_auto_20200213_2207'),
('cloud', '0008_auto_20200214_2237'),
]
operations = [
migrations.RenameModel(
old_name='DataFiles',
new_name='DataFile',
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 3.0.2 on 2020-02-14 22:41
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('cloud', '0009_auto_20200214_2238'),
]
operations = [
migrations.AlterField(
model_name='datadir',
name='owner',
field=models.ForeignKey(blank=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 3.0.2 on 2020-02-14 22:41
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('cloud', '0010_auto_20200214_2241'),
]
operations = [
migrations.AlterField(
model_name='datadir',
name='owner',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 3.0.2 on 2020-02-14 23:13
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0062_auto_20200213_2207'),
('cloud', '0011_auto_20200214_2241'),
]
operations = [
migrations.AddField(
model_name='datadir',
name='parent',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='dir_in_dir', to='cloud.DataDir'),
),
migrations.AlterField(
model_name='datadir',
name='agency',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.Agency'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 3.0.2 on 2020-02-15 13:47
import cloud.models
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cloud', '0012_auto_20200214_2313'),
]
operations = [
migrations.AlterField(
model_name='datafile',
name='file',
field=models.FileField(blank=True, max_length=255, null=True, upload_to=cloud.models.user_directory_path),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 3.0.2 on 2020-02-15 14:11
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('cloud', '0013_auto_20200215_1347'),
]
operations = [
migrations.AlterField(
model_name='datafile',
name='parent',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='thisfileindir', to='cloud.DataDir'),
),
]

View File

@ -0,0 +1,27 @@
# Generated by Django 3.0.2 on 2020-02-15 14:27
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('users', '0062_auto_20200213_2207'),
('cloud', '0014_auto_20200215_1411'),
]
operations = [
migrations.AlterField(
model_name='datafile',
name='agency',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='users.Agency'),
),
migrations.AlterField(
model_name='datafile',
name='owner',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 3.0.2 on 2020-02-15 15:25
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('cloud', '0015_auto_20200215_1427'),
]
operations = [
migrations.RemoveField(
model_name='datadir',
name='datafiles',
),
]

View File

@ -0,0 +1,30 @@
# Generated by Django 3.0.2 on 2020-02-15 19:10
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0062_auto_20200213_2207'),
('cloud', '0016_remove_datadir_datafiles'),
]
operations = [
migrations.AlterField(
model_name='datadir',
name='agency',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='users.Agency'),
),
migrations.AlterField(
model_name='datadir',
name='parent',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='dir_in_dir', to='cloud.DataDir'),
),
migrations.AlterField(
model_name='datafile',
name='agency',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.Agency'),
),
]

View File

@ -0,0 +1,30 @@
# Generated by Django 3.0.2 on 2020-02-15 19:11
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0062_auto_20200213_2207'),
('cloud', '0017_auto_20200215_1910'),
]
operations = [
migrations.AlterField(
model_name='datadir',
name='agency',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.Agency'),
),
migrations.AlterField(
model_name='datadir',
name='parent',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='dir_in_dir', to='cloud.DataDir'),
),
migrations.AlterField(
model_name='datafile',
name='agency',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='users.Agency'),
),
]

View File

@ -0,0 +1,7 @@
{% extends "users/base.html" %}
{% block content %}
<div class="content-section col-12">
<h3>Auf diesen Dateibereich haben Sie keinen Zugriff!</h3>
<hr>
</div>
{% endblock %}

0
dasettings/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

3
dasettings/admin.py Normal file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

5
dasettings/apps.py Normal file
View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class DASettingsConfig(AppConfig):
name = 'dasettings'

110
dasettings/forms.py Normal file
View File

@ -0,0 +1,110 @@
from django import forms
from django.db import models
from django.contrib.auth.models import User
from users.models import AgencyGroup, Agency, Profile, AgencyJob
from PIL import Image
# Change logged Users Data (Usernamen an Email) NUR HIER MÖGLICH!
class UsersSelfChangeForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['email']
# Form für die Benachrichtigungseinstellungen
class UsersNotificationForm(forms.ModelForm):
class Meta:
model = Profile
labels = {
"news_mail" : "Agentur-News",
"user_standard_public_mail" : "Veröffentlichung meiner Standards",
"agency_new_standard_mail" : "Neue Agentur-Standards",
'add_new_group_mail' : "Gruppenmitgliedschaften",
'add_task_mail' : "Tätigkeitsbereich"
}
fields = ['news_mail', 'news_push', 'user_standard_public_mail', 'user_standard_public_push', 'agency_new_standard_mail', 'agency_new_standard_push', 'add_new_group_mail', 'add_new_group_push', 'add_task_mail', 'add_task_push']
# PERMISSION GROUPS FORM
class AgencyGroupPerms(forms.Form):
'''
Permission-System
Persmissions werden im Model gesetzt, hier automatisch als Form ausgegeben.
Hat der Nutzer eine der genannten Rechte, wird die Checkbox automatisch TRUE gesetzt.
Die erstellen Felder werden entsprechend den Feldern hinzugefügt und ausgegeben.
@param: user
- User ist der aufgerufene User!
'''
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
temprof = AgencyGroup
for ele in temprof._meta.permissions:
self.fields[ele[0]] = forms.BooleanField(required=False, initial=False, help_text=(ele[1]))
# LOADING ALL MODUL-OPTIONS
class AgencyModulsForm(forms.ModelForm):
class Meta:
model = Agency
labels = {
'module_news' : "Agentur-News",
'module_quicklinks' : "Quicklinks",
'module_files' : "Dateien",
'module_organigramm' : "Organigramm",
}
fields = ['module_news','module_quicklinks','module_files','module_organigramm']
# NEW USER FORM
class UserNewUserForm(forms.ModelForm):
class Meta:
model = User
fields = ["first_name", "last_name", "email"]
# NEW USER PROFILE FORM
class UserProfileForm(forms.ModelForm):
x = forms.FloatField(widget=forms.HiddenInput())
y = forms.FloatField(widget=forms.HiddenInput())
width = forms.FloatField(widget=forms.HiddenInput())
height = forms.FloatField(widget=forms.HiddenInput())
rotation = forms.FloatField(widget=forms.HiddenInput())
class Meta:
model = Profile
labels = {
"persnumber" : "Personalnummer",
"visible" : "Im Organigramm sichtbar",
"phonemobile" : "Mobilnummer",
"phoneland" : "Festnetznummer",
"image": "Profilbild",
"func" : "Agenturfunktion",
"compfunc" : "Tätigkeit"
}
widgets = {"parent" : forms.HiddenInput()}
fields = ["parent", "func", "compfunc", "visible", "phoneland", "phonemobile", "persnumber", "image" ]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['func'].queryset = AgencyJob.objects.filter(agency__pk=self.instance.agency.pk)
def save(self):
photo = super(UserProfileForm, self).save()
try:
x = self.cleaned_data.get('x')
y = self.cleaned_data.get('y')
w = self.cleaned_data.get('width')
h = self.cleaned_data.get('height')
rotation = self.cleaned_data.get('rotation')
image = Image.open(photo.image)
rotatet_image = image.rotate(rotation, expand=True)
cropped_image = rotatet_image.crop((x, y, w+x, h+y))
resized_image = cropped_image.resize((300, 300), Image.ANTIALIAS)
resized_image.save(photo.image.path)
return photo
except:
print("no photo")

View File

3
dasettings/models.py Normal file
View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View File

@ -0,0 +1,340 @@
{% load crispy_forms_tags %}
{% load static %}
{% load mathfilters %}
{% load humanize %}
<button type="button" class="btn btn-primary" onclick="javascript:showAgencyJob()" data-toggle="tooltip" data-placement="top" title="Fügen Sie hier weitere Standard-Agenturfunktionen zu oder bearbeiten bestehende.">Agenturfunktionen verwalten</button>
<hr>
<script src="{% static 'users/js/cropper.min.js' %}"></script>
<script src="{% static 'users/js/jquery-cropper.js' %}"></script>
<div class="col-12">
<!-- Für das Speichern der Bilder enctype -->
<form method="POST" enctype="multipart/form-data">
<input type="hidden" name="form_type" value="agencyform">
<input type="hidden" name="settings_area" value="agency">
{% csrf_token %}
<fieldset class="form-group">
<!-- FORMS LADEN -->
<div class="row">
<div class="col-3">
{% for formfield in agencyform %}
{% if forloop.counter|divisibleby:5 %}
</div>
<div class="col-3">
{{formfield|as_crispy_field}}
{% else %}
{{formfield|as_crispy_field}}
{% endif %}
{% endfor %}
</div>
<div class="col-3">
<h5 class="mt-3">Abrechnung</h5>
<p>Kontostand:&nbsp;<b>{{request.user.profile.agency.balance|floatformat:0}} €</b></p>
<p>Nächste Abbuchung am&nbsp;<b>{{request.user.profile.agency.nextdebiting|date:"d.m.Y"}}</b></p>
<p>Max. Nutzungszeit:&nbsp; <b>{{request.user.profile.agency.balance|div:30|floatformat:0}} Monate</b></p>
<p>IBAN: DE4412345678912345</p>
<p><small>Laden Sie das Konto mit einem beliebigen Geldbetrag auf. Die Kosten belaufen sich auf 40 € pro Monat.</small></p>
</div>
</div>
</fieldset>
<hr>
<div class="form-group">
<button type="submit" class="btn btn-success">Agenturdaten Aktualisieren</button>&nbsp;
</div>
</form>
</div>
<!-- MODAL TO CROP THE IMAGE -->
<div class="modal fade " id="modalCrop" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Bereich bestimmen</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="clearImgField()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" id="imgmodbody">
<img src="" id="imagemod" style="max-width: 100%; max-height: 100%;">
</div>
<div class="modal-footer">
<div class="btn-group pull-left" role="group">
<button type="button" class="btn btn-default js-zoom-in">
<i class="fas fa-search-plus"></i>
</button>
<button type="button" class="btn btn-default js-zoom-out">
<i class="fas fa-search-minus"></i>
</button>
<button type="button" class="btn btn-default js-rot-left">
<i class="fas fa-undo-alt"></i>
</button>
<button type="button" class="btn btn-default js-rot-right">
<i class="fas fa-redo-alt"></i>
</button>
</div>
<button type="button" class="btn btn-default" data-dismiss="modal" onclick="clearImgField()">Abbrechen</button>
<button type="button" class="btn btn-primary js-crop-and-upload">Ausschneiden</button>
</div>
</div>
</div>
</div>
<script>
/* TEST FÜR RECHTE - GEHT, SO DANN DIE TEXTFELDER UND DEN BUTTON ENTFERNEN! */
/*
$(document).ready(function(){
$(".textinput").attr("disabled", true);
$(".emailinput").attr("disabled", true);
$(".clearablefileinput").attr("disabled", true);
})*/
/* CROPPER */
$("#id_x").val(0);
$("#id_y").val(0);
$("#id_width").val(1500);
$("#id_height").val(750);
$("#id_rotation").val(0);
function clearImgField(){
$("#id_agencypic").val("");
}
/* SCRIPT TO OPEN THE MODAL WITH THE PREVIEW */
$("#id_agencypic").change(function () {
if (this.files && this.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$("#imagemod").attr("src", e.target.result);
$("#modalCrop").modal("show");
}
reader.readAsDataURL(this.files[0]);
}
});
var cropBoxData;
var canvasData;
var $image = $("#imagemod");
$("#modalCrop").on("shown.bs.modal", function () {
$image.cropper({
viewMode: 3,
aspectRatio: 2/1,
strict: false,
cropBoxMovable: true,
cropBoxResizable: true,
minCropBoxWidth: 750,
minCropBoxHeight: 350,
ready: function () {
$image.cropper("setCanvasData", canvasData);
$image.cropper("setCropBoxData", cropBoxData);
}
});
$("#imgmodbody").css({
"maxWidth": 465
});
}).on("hidden.bs.modal", function () {
cropBoxData = $image.cropper("getCropBoxData");
canvasData = $image.cropper("getCanvasData");
$image.cropper("destroy");
});
$(".js-zoom-in").click(function () {
$image.cropper("zoom", 0.1);
});
$(".js-zoom-out").click(function () {
$image.cropper("zoom", -0.1);
});
$(".js-rot-right").click(function () {
$image.cropper("rotate", 90);
});
$(".js-rot-left").click(function () {
$image.cropper("rotate", -90);
});
/* SCRIPT TO COLLECT THE DATA AND POST TO THE SERVER */
$(".js-crop-and-upload").click(function () {
var cropData = $image.cropper("getData");
$("#id_x").val(cropData["x"]);
$("#id_y").val(cropData["y"]);
$("#id_height").val(cropData["height"]);
$("#id_width").val(cropData["width"]);
$("#id_rotation").val(cropData["rotate"]);
$("#id_agencypic").attr("src", $image);
$("#modalCrop").modal('toggle');
});
/*
AGENCY JOB FUNCTIONS
*/
function showAgencyJob(){
$("#agencyJobs").modal("toggle");
}
function addAgencyJob(){
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "add_agencyfunc"
},
success: function( data )
{
new_id = data["data"]["new_id"];
$('#allagencyjobs > tbody:last-child').append('<tr id="agencyjob_'+new_id+'"><td><input class="form-control" type="text" value="" placeholder="Neue Funktion" onkeyup="javascript:updateFunc('+new_id+', this.value)"></td><td><button type="button" class="btn btn-danger" onclick="javascript:funcDel('+new_id+')" data-toggle="tooltip" data-placement="top" title="Agenturfunktion löschen"><i class="fas fa-trash-alt"></i></button></td></tr>');
}
});
}
var todelid = 0;
function funcDel(id){
todelid = id;
$("#agencyJobs").modal("toggle");
$("#delAgencyJob").modal("toggle");
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "get_agencyfunc",
id : id
},
success: function( data )
{
$("#delFuncBody").html("Achtung! Die Funktion <b>" + data['data']['funcname'] + "</b> wird gelöscht. Alle Mitarbeiter mit dieser Funktion erhalten eine leere Funktionsbeschreibung. Fortfahren?");
}
});
}
function doDelAgencyJob(){
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "delete_agencyfunc",
id : todelid
},
success: function( data )
{
$("#agencyJobs").modal("toggle");
$("#delAgencyJob").modal("toggle");
$('#agencyjob_' + todelid).remove();
todelid = 0;
}
});
}
timeout = null;
function updateFunc(id, funcname){
var letters = /^[A-Za-zßäöüÄÖÜ_0-9 ]+$/;
if(funcname.match(letters))
{
//SAVE ONLY EVERY SECOND
$("#erroninput").hide();
$("#savebreak").show();
clearTimeout(timeout);
timeout = setTimeout(function () {
if(funcname.match(letters))
{
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "update_agencyfunc",
id : id,
newvalue : funcname
},
success: function( data )
{
if(data["success"]){
$("#savebreak").hide();
$("#funcupdate").fadeTo(2000, 500).slideUp(500, function(){
$("#funcupdate").fadeOut(500);
});
}
else{
$("#erroninput").show();
}
}
});
}
else{
$("#erroninput").show();
$("#savebreak").hide();
$("#funcupdate").hide();
}
}, 1000);
}
else{
$("#erroninput").show();
$("#savebreak").hide();
$("#funcupdate").hide();
}
}
</script>
<!-- MODAL FOR AGENCYJOBS -->
<!-- Modal -->
<div class="modal fade" id="agencyJobs" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="agencyFunction" aria-hidden="true">
<div class="modal-dialog " role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Agenturfunktionen bearbeiten</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Schließen">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<table class="table table-hover" id="allagencyjobs">
<tbody>
{% for ele in agencyjobs %}
<tr id="agencyjob_{{ele.pk}}">
<td>
<input class="form-control" type="text" value="{{ele.name}}" onkeyup="javascript:updateFunc({{ele.pk}}, this.value)">
</td>
<td>
<button type="button" class="btn btn-danger" onclick="javascript:funcDel({{ele.pk}})" data-toggle="tooltip" data-placement="top" title="Agenturfunktion löschen"><i class="fas fa-trash-alt"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div id="erroninput" class="alert alert-danger" style="display: none">Falsche Eingabe! Es wird nichts gespeichert.</div>
<div id="savebreak" class="alert alert-success" style="display: none">Speichern pausiert...</div>
<div id="funcupdate" class="alert alert-success" style="display: none">Agenturfunktionen aktualisiert.</div>
<button type="button" class="btn btn-primary" title="Neue Funktion hinzufügen" onclick="javascript:addAgencyJob()" data-toggle="tooltip" data-placement="top" title="Dialog für eine neue Agenturfunktion öffnen"><i class="fas fa-plus"></i>&nbsp;Funktion</button>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
<!-- CONFIRMA DELETE DIALOG -->
<div class="modal fade" id="delAgencyJob" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="agencyDelFunction" aria-hidden="true">
<div class="modal-dialog " role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Agenturfunktion löschen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Schließen">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" id="delFuncBody">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal" onclick="javascript:doDelAgencyJob()">Agenturfunktion löschen</button>&nbsp;&nbsp;
<button type="button" class="btn btn-success" data-dismiss="modal" onclick="javascript:$('#agencyJobs').modal('toggle')">Abbrechen</button>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,476 @@
{% load counter_tag %}
<div class="col-9">
<button type="button" class="btn btn-primary" onclick="javascript:addGroup()" data-toggle="tooltip" data-placement="top" title="Neue Gruppe erstellen, Namen und Rechte vergeben und anschließend Mitglieder hinzufügen."><i class="fas fa-plus"></i>&nbsp;Gruppe</button>
<!-- GROUPS -->
<!-- COUNTER USER IN GROUPS -->
<div id="allGroups">
<div id="groupAccordion" class="mt-3">
{% for aggroup in agencygroups %}
{% setvar 0 %}
{% for user in usersofagency %}
{% for group in user.groups.all %}
{% if group.name == aggroup.group.name %}
{% incvar %}
{% endif %}
{% endfor %}
{% endfor %}
{% getvar as varcounter %}
<div class="card mb-2">
<div class="card-header" id="agroup_{{aggroup.pk}}" style="float: left">
<h5 class="mb-0">
<button class="btn btn-link" data-toggle="collapse" data-target="#agroup_{{aggroup.pk}}_card" aria-expanded="false" aria-controls="agroup_{{aggroup.pk}}_card"><small><i class="fas fa-chevron-down"></i></small></button>&nbsp;&nbsp;&nbsp;
<button class="btn btn-link" data-toggle="collapse" data-target="#agroup_{{aggroup.pk}}_card" aria-expanded="false" aria-controls="agroup_{{aggroup.pk}}_card">
<span id="groupname_{{aggroup.pk}}" >Gruppe <b>{{aggroup.agencygroupname}}&nbsp;</b></span><small>(<span id="groupcounter_{{aggroup.pk}}">{{varcounter}}</span>)</small>
</button>
<button type="button" style="float: right" class="btn btn-primary btn-sm" onclick="javascript:changeGroupName({{aggroup.pk}})" data-toggle="tooltip" data-placement="top" title="Gruppennamen andern"><small><i class="fas fa-pen"></i></small></button>
{% if not aggroup.savefordel %}
<button style="float: right" type="button" class="btn btn-danger btn-sm mr-1" onclick="javascript:delGroup({{aggroup.pk}})" data-toggle="tooltip" data-placement="top" title="Gruppe löschen. Nur möglich, bei selbst erstellten Gruppen."><i class="fas fa-trash-alt"></i></button>
{% endif %}
{% if aggroup.savefordel %}
<button style="float: right" type="button" class="btn btn-danger btn-sm mr-1" onclick="javascript:delGroup({{aggroup.pk}})" data-toggle="tooltip" data-placement="top" title="Gruppe löschen. Nur möglich, bei selbst erstellten Gruppen." disabled><i class="fas fa-trash-alt" ></i></button>
{% endif %}
</h5>
</div>
<div id="agroup_{{aggroup.pk}}_card" class="collapse" aria-labelledby="agroup_{{aggroup.pk}}" data-parent="#groupAccordion">
<div class="card-body">
<h5>Gruppenrechte&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Gruppenrechte beeinflussen die Möglichkeiten der Mitarbeiter in einer Gruppe, z.B. dürfen nur Mitarbeiter in einer Gruppe mit dem Recht News entsprechend News erstellen, veröffentlichen und bearbeiten." class="far fa-question-circle"></i></small></h5>
<div class="row">
<div class="col-4">
{% for perm in perms %}
{% if forloop.counter|divisibleby:7 %}
</div>
<div class="col-4">
<div class="custom-control custom-checkbox mb-2 {{perm.name}}">
<input type="checkbox" class="custom-control-input" name="{{aggroup.pk}}_{{perm.name}}" id="{{aggroup.pk}}_{{perm.name}}" onchange="javascript:changePerm(this.id)" {% if aggroup.is_admin %} disabled="true" {% endif %}>
<label class="custom-control-label" for="{{aggroup.pk}}_{{perm.name}}" >{{perm.help_text}}</label>
</div>
{% else %}
<div class="custom-control custom-checkbox mb-2 {{perm.name}}" >
<input type="checkbox" class="custom-control-input" name="{{aggroup.pk}}_{{perm.name}}" id="{{aggroup.pk}}_{{perm.name}}" onchange="javascript:changePerm(this.id)" {% if aggroup.is_admin %} disabled="true" {% endif %}>
<label class="custom-control-label" for="{{aggroup.pk}}_{{perm.name}}" >{{perm.help_text}}</label>
</div>
{% endif %}
{% endfor %}
</div>
</div><!-- END ROW RIGHT -->
<hr>
<div col="10">
<h6>Mitarbeiter zur Gruppe <b>{{aggroup.agencygroupname}}</b> hinzufügen</h6>
<div class="input-group mb-3 col-5">
<input class="form-control searchuserfields" list="usersfree_{{aggroup.pk}}" id="searchusers_{{aggroup.pk}}" type="text" onkeyup="javascript:checkSearchUser({{aggroup.pk}})">
<div class="input-group-append">
<button type="button" onclick="javascript:clearSearchfield({{aggroup.pk}})" class="btn btn-secondary" ><i class="fas fa-times"></i></button>
</div>
<datalist id="usersfree_{{aggroup.pk}}">
{% for user in usersofagency %}
{% if not user|has_group:aggroup.group.name %}
<option id="{{user.pk}}_{{aggroup.pk}}" value="{{user.first_name}} {{user.last_name}}">
{% endif %}
{% endfor %}
</datalist>
</datalist>
</div>
<hr>
<h6>Gruppenmitglieder in <b>{{aggroup.agencygroupname}}</b></h6>
{% if varcounter > 0 %}
<span id="nogroupmember_{{aggroup.pk}}" style="display: none">Diese Gruppe hat noch keine Mitglieder.</span>
{% else %}
<span id="nogroupmember_{{aggroup.pk}}">Diese Gruppe hat noch keine Mitglieder.</span>
{% endif %}
<div id="added_users_button_{{aggroup.pk}}">
{% for user in usersofagency %}
{% for group in user.groups.all %}
{% if group.name == aggroup.group.name %}
{% if request.user == user and aggroup.is_admin %}
<span class="badge badge-pill badge-primary mr-2 mt-2"><button class="btn btn-primary" disabled="true">{{ user.first_name }} {{ user.last_name }}</button></span>
{% else %}
<span id="span_btn_{{user.pk}}_{{aggroup.pk}}" class="badge badge-pill badge-primary mr-2 mt-2"><a class="btn btn-primary" onclick="javascript:removeUserFromGroup({{ user.pk }}, {{aggroup.pk}})">{{ user.first_name }} {{ user.last_name }}&nbsp;&nbsp;<i class="fas fa-times"></i></a >
</span>
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- ADDING GROUP PERMS -->
{% for aggroup in agencygroups %}
{% for p in aggroup.group.permissions.all %}
{% for perm in perms %}
{% if p.codename == perm.name %}
<script>$("#{{aggroup.pk}}_{{perm.name}}").prop('checked', true);</script>
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
<script>
/* CHECK FOR ACTIVATED MODULS */
module_news = '{{request.user.profile.agency.module_news}}'
module_quicklinks = '{{request.user.profile.agency.module_quicklinks}}'
//module_files = '{{request.user.profile.agency.module_files}}'
//module_organigramm = '{{request.user.profile.agency.module_organigramm}}'
if(module_quicklinks == "False"){
$(".modulequicklinks").remove();
}
if(module_news == "False"){
$(".modulenews").remove();
}
var ua = window.navigator.userAgent;
var isIE = /MSIE|Trident/.test(ua);
if ( isIE ) {
//IE specific code goes here
setInterval(function()
{
alluserfields = $(".searchuserfields").each(function(key, value){
specific_userfield_id = value['id'].split("_")[1];
checkSearchUser(specific_userfield_id);
});
},400);
}
//returns the params of url GET
function getUrlVars() {
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
vars[key] = value;
});
return vars;
}
//Show Save-Toast while reload side by new group
$(document).ready(function(){
if( getUrlVars()["showtoast"]){
$('#notchange_done').toast('show');
}
if(getUrlVars()["groupdel"]){
$("#toast_savecontent").html("Gruppe erfolgreich gelöscht!");
}
})
/*
MANAGE GROUP FUNCTIONS
*/
groupaction = 0;
groupupdate_id = false;
tempid_useraddgroup = 0;
function clearSearchfield(groupid){
$("#searchusers_" + groupid).val("");
}
function checkSearchUser(groupid){
var g = $('#searchusers_' + groupid).val();
var id = $('#usersfree_' + groupid).find('option[value="' + g + '"]').attr('id');
if(id != undefined && id.length > 0){
tempid_useraddgroup = id.split("_")[0];
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "add_user_to_group",
groupid : groupid,
userid: tempid_useraddgroup,
},
success: function( data )
{
if(data['success']){
groupid = data['data']['groupid'];
userid = data['data']['userid'];
user_fname = data['data']['user_fname'];
user_lname = data['data']['user_lname'];
$('#notchange_done').toast('show');
$("#" + userid + "_" + groupid).remove();
$("#toast_savecontent").html("Mitarbeiter erfolgreich hinzugefügt!");
$("#added_users_button_" + groupid).append('<span id="span_btn_'+userid+'_'+groupid+'" class="badge badge-pill badge-primary mr-2 mt-2"><a class="btn btn-primary" onclick="javascript:removeUserFromGroup('+userid+', '+groupid+')">'+user_fname+' '+user_lname+'&nbsp;&nbsp;<i class="fas fa-times"></i></a >');
clearSearchfield(groupid);
newgroupcounter = parseInt($("#groupcounter_" + groupid).html())+1;
$("#groupcounter_" + groupid).html(newgroupcounter);
if(newgroupcounter > 0){
$("#nogroupmember_" + groupid).hide();
}
}
else{
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Mitarbeiter konnte nicht hinzugefügt werden!");
}
}
});
}
}
function removeUserFromGroup(userid, groupid){
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "remove_user_from_group",
groupid : groupid,
userid: userid
},
success: function( data )
{
if(data['success']){
groupid = data['data']['groupid'];
userid = data['data']['userid'];
user_fname = data['data']['user_fname'];
user_lname = data['data']['user_lname'];
$('#notchange_done').toast('show');
$("#toast_savecontent").html("Mitarbeiter erfolgreich entfernt!");
$("#span_btn_" + userid + "_" + groupid).remove();
newgroupcounter = parseInt($("#groupcounter_" + groupid).html())-1;
$("#groupcounter_" + groupid).html(newgroupcounter);
if(newgroupcounter == 0){
$("#nogroupmember_" + groupid).show();
}
$("#usersfree_" + groupid).append('<option id="'+userid+'_'+groupid+'" value="'+ user_fname +' '+ user_lname +'">');
}
else{
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Mitarbeiter konnte nicht entfernt werden!");
}
}
});
}
function changePerm(tosplitid){
var splitted = tosplitid.split("_");
perm_groupid = splitted[0];
perm_name = splitted[1];
perm_value = $("#"+tosplitid).is(":checked");
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "change_perm_group",
id : perm_groupid,
perm: perm_name,
val : perm_value
},
success: function( data )
{
if(data['success']){
$('#notchange_done').toast('show');
$("#toast_savecontent").html("Gruppenrechte gespeichert!");
}
else{
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Gruppenrechte nicht gespeichert!");
}
}
});
}
function delGroup(groupid){
groupupdate_id = groupid;
$("#delAgencyGroup").modal("toggle");
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "get_groupname",
id : groupid
},
success: function( data )
{
$("#delGroupBody").html("Soll Gruppe <b>" + data["data"]["groupname"] + "</b> glöscht werden? Mitarbeiter in dieser Gruppe <u>werden nicht gelöscht</u>.")
}
});
}
function doDelGroup(){
$("#delAgencyGroup").modal("toggle");
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "delete_group",
id : groupupdate_id
},
success: function( data )
{
if(data['success']){
window.location.href = window.location.href + "?showtoast=true&groupdel=true";
}
else{
$("#newGroup").modal("toggle");
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Gruppe konnte nicht gelöscht werden!");
}
}
});
}
function changeGroupName(groupid){
addGroup();
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "get_groupname",
id : groupid
},
success: function( data )
{
$("#newgroupname").val(data['data']['groupname']);
$("#modTitle").html("Gruppenname ändern");
$("#saveNewGroup").prop("disabled", false);
groupupdate_id = groupid;
groupaction = 1;
}
});
}
//SHOW ADD GROUP MODAL
function addGroup(){
groupaction = 0;
$("#newGroup").modal("toggle");
$("#newgroupname").val("");
$("#groupnameerr").hide();
$("#saveNewGroup").prop("disabled", true);
$("#modTitle").html("Gruppe erstellen");
}
//CREATE NEW GROUP
function updateGroupName(){
namevalue = $("#newgroupname").val();
//ADD GROUP
if(groupaction == 0){
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "add_group",
newvalue : namevalue
},
success: function( data )
{
if(data['success']){
window.location.href = window.location.href + "?showtoast=true";
}
else{
$("#newGroup").modal("toggle");
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Der Gruppenname ist in der Agentur bereits vorhanden!");
}
}
});
}
//CHANGE GROUP
else if(groupaction == 1){
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "update_groupname",
id : groupupdate_id,
newvalue : namevalue
},
success: function( data )
{
if(data['success']){
$("#newGroup").modal("toggle");
$('#notchange_done').toast('show');
$("#groupname_" + groupupdate_id).html("Gruppe <b>"+data['data']['newvalue']+"&nbsp;</b>");
}
else{
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Der Gruppenname ist in der Agentur bereits vorhanden!");
}
}
});
}
}
//VALIDATE FOR CORRECT INPUT IN GROUP
function validateGroupName(groupname){
var letters = /^[A-Za-zßäöüÄÖÜ_\-0-9 ]+$/;
if(groupname.length > 0){
if(!groupname.match(letters))
{
$("#groupnameerr").show();
$("#saveNewGroup").prop("disabled", true);
}
else{
$("#groupnameerr").hide();
$("#saveNewGroup").prop("disabled", false);
}
}
else{
$("#groupnameerr").hide();
$("#saveNewGroup").prop("disabled", true);
}
}
</script>
<!-- MODEAL NEW GROUP -->
<div class="modal fade" id="newGroup" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="" aria-hidden="true">
<div class="modal-dialog " role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modTitle"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Schließen">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<input class="form-control" id="newgroupname" type="text" value="" placeholder="Gruppenname" onkeyup="javascript:validateGroupName(this.value)">
<div id="groupnameerr" class="alert alert-danger mt-3" style="display: none">Falsche Eingabe! Keine Sonderzeichen!</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">Abrechen</button>&nbsp;
<button id="saveNewGroup" type="button" class="btn btn-success" data-dismiss="modal" onclick="javascript:updateGroupName()" disabled="true">Speichern</button>
</div>
</div>
</div>
</div>
<!-- CONFIRMA DELETE GROUP -->
<div class="modal fade" id="delAgencyGroup" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="groupDelFunction" aria-hidden="true">
<div class="modal-dialog " role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Gruppe löschen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Schließen">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" id="delGroupBody">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal" onclick="javascript:doDelGroup()">Gruppe löschen</button>&nbsp;&nbsp;
<button type="button" class="btn btn-success" data-dismiss="modal">Abbrechen</button>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,28 @@
{% load crispy_forms_tags %}
<div class="col-6 mt-3">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Modul</th>
<th scope="col">Aktiviert</th>
<th scope="col">Einstellungen</th>
</tr>
</thead>
<tbody id="module_checkboxes">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="form_type" value="agencymodform">
<input type="hidden" name="settings_area" value="moduls">
{% for formfield in modulform %}
<tr>
<td>{{formfield.label_tag}}</td>
<td>{{formfield}}</td>
<td><button type="button" class="btn btn-sm btn-primary" disabled="true"><i class="fas fa-cog"></i></button></td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit" class="btn btn-success" data-toggle="tooltip" data-placement="top" title="Mit dem Speichern wird die Seite neu geladen, damit alle Einstellungen aktualisiert werden. Werden Module deaktiviert, gehen die Einstellungen und zugewiesenen Rechte nicht verloren.">Moduleinstellungen aktualisieren</button>
</form>
</div>

View File

@ -0,0 +1,64 @@
{% load crispy_forms_tags %}
<div class="col-6 mt-3">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Benachrichtigung</th>
<th scope="col">E-Mail</th>
<th scope="col">Push</th>
</tr>
</thead>
<tbody id="checkboxes">
{% for formfield in notificationform %}
{% if forloop.counter|divisibleby:2 %}
<td>{{formfield}}</td>
</tr>
{% else %}
<tr>
<td>{{formfield.label_tag}}</td>
<td>{{formfield}}</td>
{% endif %}
{% endfor %}
</tbody>
</table>
<!-- Flexbox container for aligning the toasts -->
</div>
<script>
$('input:checkbox').change(
function(){
ele = $(this).prop("name");
if(!ele.includes("module")){
new_stat = 0;
if($(this).prop("checked")){
new_stat = 1;
}
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "update_notifications",
fieldname : ele,
new_stat : new_stat
},
success: function( data )
{
if(data['success']){
$('#notchange_done').toast('show');
}
else{
$('#notchange_err').toast('show');
}
}
});
}
});
$(document).ready(function(){
$(".toast").toast({
autohide: true,
delay : 3000
});
})
</script>

View File

@ -0,0 +1,114 @@
{% load crispy_forms_tags %}
<div class="media">
<img class="img-profile " width="17%" src="{{ user.profile.get_photo_url }}">
<div class="media-body col-5">
<h2 class="account-heading">Profil von {{ user.first_name }} {{ user.last_name }}</h2>
<hr>
<div class="row">
<div class="col-6">
<h6><b>Name</b></h6>
<p>
{{ user.first_name }} {{ user.last_name }}
</p>
<h6><b>E-Mail</b></h6>
<p>
{{ user.email }}
</p>
<h6><b>Agenturfunktion</b></h6>
<p>
{{ user.profile.func }}
</p>
</div>
<div class="col-6">
<h6><b>Tätigkeit</b></h6>
<p>
{{ user.profile.compfunc }}
</p>
<h6><b>Festnetz</b></h6>
<p>
{{ user.profile.phoneland }}
</p>
<h6><b>Mobil</b></h6>
<p>
{{ user.profile.phonemobile }}
</p>
</div>
</div>
</div>
</div>
<!-- Für das Speichern der Bilder enctype -->
<div class="col-8">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="form_type" value="userform">
<input type="hidden" name="settings_area" value="profil">
<fieldset class="form-group mb-2">
<legend class="border-bottom mb-4">
Profil bearbeiten
</legend>
{% if request.user.profile.showtooltips %}
<div class="custom-control custom-checkbox mb-2" >
<input type="checkbox" class="custom-control-input" name="showtooltips" id="showtooltips" checked>
<label class="custom-control-label" for="showtooltips" >Tooltips anzeigen</label>
</div>
{% else %}
<div class="custom-control custom-checkbox mb-2">
<input type="checkbox" class="custom-control-input" name="showtooltips" id="showtooltips">
<label class="custom-control-label" for="showtooltips">Tooltips anzeigen</label>
</div>
{% endif %}
<!-- FORMS LADEN -->
{{ userform|crispy }}
</fieldset>
<small>Agenturrelevante Daten (Bild, Telefonnummer etc.) werden in der Benutzerverwaltung verändert.</small>
<div class="form-group mt-3">
<button type="submit" class="btn btn-success">E-Mailadresse aktualisieren</button>&nbsp;
</div>
</form>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="form_type" value="passwordform">
<input type="hidden" name="settings_area" value="profil">
<fieldset class="form-group mb-2">
<!-- FORMS LADEN -->
{{ passwordform|crispy}}
</fieldset>
<div class="form-group mt-3">
<button type="submit" class="btn btn-success">Passwort ändern</button>&nbsp;
</div>
</form>
</div>
<script>
$("#showtooltips").change(function(){
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "change_showtooltips"
},
success: function( data )
{
if(data['success'])
{
$('#notchange_done').toast('show');
$("#toast_savecontent").html("Tooltipseinstellung erfolgreich gespeichert!");
if(data['data']['newttvalue']){
$('*').tooltip("enable");
}
else{
$('*').tooltip("disable");
}
}
else{
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Tooltips konnten nicht gespeichert werden!");
}
}
});
})
</script>

View File

@ -0,0 +1,184 @@
{% extends "users/base.html" %}
{% load counter_tag %}
{% block content %}
<div aria-live="polite" aria-atomic="true" class="d-flex justify-content-center align-items-center" style="min-height: 200px; max-width: 250px; position: fixed; margin-top: -3%; margin-left: 70.5%; z-index: 10">
<!-- Then put toasts within -->
<div id="notchange_done" class="toast alert-success" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="mr-auto">Gespeichert</strong>
<!--<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>-->
</div>
<div class="toast-body">
<div id="toast_savecontent">Änderungen wurden gespeichert.</div>
</div>
</div>
</div>
<div aria-live="polite" aria-atomic="true" class="d-flex justify-content-center align-items-center" style="min-height: 200px; max-width: 250px; position: fixed; margin-top: -3%; margin-left: 70.5%; z-index: 10">
<!-- Then put toasts within -->
<div id="notchange_err" class="toast alert-danger" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="mr-auto">Fehler aufgetreten</strong>
<!--
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
-->
</div>
<div class="toast-body">
<div id="toast_errcontent">Bitte kontaktieren Sie den Support.</div>
</div>
</div>
</div>
<div class="content-section col-12">
<h3>Einstellungen</i></b>&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Hier können Agenturweite Einstellungen (Mitarbeiter, Gruppen, Agenturinfos, Bereiche und Tätigkeiten, Abrechnung, Module usw.) verwaltet werden." class="far fa-question-circle"></i></small></h3>
<hr>
<ul class="nav nav-tabs" id="settingsTabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="profil-tab" data-toggle="tab" href="#profil" role="tab" aria-controls="profil" aria-selected="false" >Profil</a>
</li>
<li class="nav-item">
<a class="nav-link" id="notifications-tab" data-toggle="tab" href="#notifications" role="tab" aria-controls="notifications-tab" aria-selected="false">Benachrichtigungen</a>
</li>
{% if user|usergperm:"agencyinfo" %}
<li class="nav-item">
<a class="nav-link" id="agency-tab" data-toggle="tab" href="#agency" role="tab" aria-controls="agency" aria-selected="false">Agentur</a>
</li>
{% endif %}
{% if user|usergperm:"structuremanager" %}
<li class="nav-item">
<a class="nav-link" id="structure-tab" data-toggle="tab" href="#structure" role="tab" aria-controls="structure" aria-selected="false">Struktur</a>
</li>
{% endif %}
{% if user|usergperm:"usermanager" %}
<li class="nav-item">
<a class="nav-link" id="user-tab" data-toggle="tab" href="#user" role="tab" aria-controls="user" aria-selected="false">Mitarbeiter</a>
</li>
{% endif %}
{% if user|usergperm:"groupmanager" %}
<li class="nav-item">
<a class="nav-link" id="groups-tab" data-toggle="tab" href="#groups" role="tab" aria-controls="groups" aria-selected="false">Gruppen</a>
</li>
{% endif %}
{% if user|usergperm:"modulesconfig" %}
<li class="nav-item">
<a class="nav-link" id="moduls-tab" data-toggle="tab" href="#moduls" role="tab" aria-controls="moduls" aria-selected="false">Module</a>
</li>
{% endif %}
</ul>
<div class="tab-content" id="settingsTabsContent">
<div class="tab-pane fade show" id="profil" role="tabpanel" aria-labelledby="profil-tab">
<h5 class="mt-3">Profileinstellungen&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Hier können Sie Einstellungen an ihrem Profil vornehmen (E-Mail, Passwort und, ob die Tooltips angezeigt werden sollen). Alle anderen Einstellungen werden von Mitarbeitern mit entsprechenden Gruppenrechten verwaltet." class="far fa-question-circle"></i></small></h5>
<hr>
{% block profil_content %}
{% include "dasettings/profil_content.html" %}
{% endblock %}
</div>
<div class="tab-pane fade" id="notifications" role="tabpanel" aria-labelledby="notifications-tab">
<h5 class="mt-3">Benachrichtigungen&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Stellen Sie hier ein, welche Art der Benachrichtigung (E-Mail oder Push) Sie für welches Ereignis (Gruppenzuweisungen, Veröffentlichung eines Standards, neue Agenturnews usw.) erhalten möchten." class="far fa-question-circle"></i></small></h5>
{% block notifications_content %}
{% include "dasettings/notifications_content.html" %}
{% endblock %}
</div>
{% if user|usergperm:"agencyinfo" %}
<div class="tab-pane fade" id="agency" role="tabpanel" aria-labelledby="agency-tab">
<h5 class="mt-3">Agenturinformationen&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Verwalten Sie hier die Informationen Ihrer Agentur, z.B. Adresse, E-Mailadresse und Telefon." class="far fa-question-circle"></i></small></h5>
<hr>
{% block agency_content %}
{% include "dasettings/agency_content.html" %}
{% endblock %}
</div>
{% endif %}
{% if user|usergperm:"structuremanager" %}
<div class="tab-pane fade" id="structure" role="tabpanel" aria-labelledby="structure-tab">
<h5 class="mt-3">Struktur&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Richten Sie hier Bereiche und Tätigkeiten ein, um diese in Standards und Organigramm als Agenturstruktur zu nutzen." class="far fa-question-circle"></i></small></h5>
<hr>
{% block structure_content %}
{% include "dasettings/structure_content.html" %}
{% endblock %}
</div>
{% endif %}
{% if user|usergperm:"usermanager" %}
<div class="tab-pane fade" id="user" role="tabpanel" aria-labelledby="user-tab">
<h5 class="mt-3">Mtarbeiter&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Legen Sie hier neue Mtarbeiter an, weisen ihnen Gruppen zu und ändern Sie Stammdaten wie Foto, Namen und Agenturfunktion." class="far fa-question-circle"></i></small></h5>
<hr>
{% block user_content %}
{% include "dasettings/user_content.html" %}
{% endblock %}
</div>
{% endif %}
{% if user|usergperm:"groupmanager" %}
<div class="tab-pane fade" id="groups" role="tabpanel" aria-labelledby="groups-tab">
<h5 class="mt-3">Gruppen&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Hier werden Gruppen erstellt und bearbeitet sowie Mitglieder der Gruppen hinzugefügt und entfernt. Zudem können Rechte der Gruppen vergeben werden." class="far fa-question-circle"></i></small></h5>
<hr>
{% block groups_content %}
{% include "dasettings/groups_content.html" %}
{% endblock %}
</div>
{% endif %}
{% if user|usergperm:"modulesconfig" %}
<div class="tab-pane fade" id="moduls" role="tabpanel" aria-labelledby="moduls-tab">
<h5 class="mt-3">Module&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Hier werden Module aktiviert oder deaktiviert sowie individuelle Einstellungen der Module gemacht. Wird ein Modul deaktiviert, gehen Einstellungen und Dateien nicht verloren." class="far fa-question-circle"></i></small></h5>
{% block moduls_content %}
{% include "dasettings/moduls_content.html" %}
{% endblock %}
</div>
{% endif %}
</div>
</div>
<script type="text/javascript">
var defaultsettingsview = "profil";
/* COOKIE FOR SAVING OPEN TAB */
$(document).ready(function(){
$(".toast").toast({
autohide: true,
delay : 3000
});
//Check prev Side
var check_for_settings = document.referrer;
//If prev side was not settings, reload cookie
if(check_for_settings.indexOf("settings") == -1){
$('#' + defaultsettingsview).tab('show');
document.cookie = "lastview=" + defaultsettingsview;
}
// Load active Tab with CSS class, if last Side was part of Settings
if(getCookie('lastview').length > 0){
$('#' + getCookie('lastview')).tab('show');
$(".nav-link").removeClass("active");
$("#" + getCookie('lastview') + "-tab").addClass("active");
}
});
//Change Cookie-Settings when changing Tab
$('#settingsTabs a').on('click', function (e) {
e.preventDefault();
$(this).tab('show');
lastview_name = $(this)[0]['hash'].substring(1);
document.cookie = "lastview="+lastview_name;
});
//Get Cookie by Name from document.cookie. Returns a String!
function getCookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for(var i = 0; i <ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
</script>
{% endblock content %}

View File

@ -0,0 +1,747 @@
{% load static %}
{% load counter_tag %}
<script src="{% static 'users/js/jquery-cropper.js' %}"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="{% static 'users/js/colorPick.js' %}"></script>
<link rel="stylesheet" href="{% static 'users/css/colorPick.css' %}">
<style>
.colorPickSelector {
border-radius: 5px;
width: 36px;
height: 36px;
cursor: pointer;
-webkit-transition: all linear .2s;
-moz-transition: all linear .2s;
-ms-transition: all linear .2s;
-o-transition: all linear .2s;
transition: all linear .2s;
}
.colorPickSelector:hover { transform: scale(1.1); }
</style>
<div class="col-6">
<button type="button" class="btn btn-primary" onclick="javascript:addArea(false)" data-toggle="tooltip" data-placement="top" title="Neuen Bereich erstellen."><i class="fas fa-plus"></i>&nbsp;Bereich</button>
</div>
<div id="allAreas" class="mt-3 col-8">
<div class="areaCollapseContent" id="sortableAreas" class="mt-3">
{%for area in agencyareas%}
<div class="card mb-2" id="maincard_{{area.pk}}">
<div class="card-header" id="area_{{area.pk}}" style="background-color: {{area.color}};opacity:0.8;">
<h5 class="mb-0" style="opacity:1.0;">
<small><i class="fas fa-sort"></i>&nbsp;&nbsp;&nbsp;&nbsp;</small>
<button class="btn btn-link " data-toggle="collapse" data-target="#area_content_{{area.pk}}" aria-expanded="false" aria-controls="area_content_{{area.pk}}"><small><i class="fas fa-chevron-down"></i></small></button>
<button class="btn btn-link" data-toggle="collapse" data-target="#area_content_{{area.pk}}" aria-expanded="false" aria-controls="area_content_{{area.pk}}">
<span id="areaname_{{area.pk}}" style="color: #ffffff">Bereich <b>{{area.name}}&nbsp;</b></span>
</button>
<button type="button" style="float: right" class="btn btn-primary btn-sm" onclick="javascript:addArea({{area.pk}})" data-toggle="tooltip" data-placement="top" title="Bereichsnamen und -farbe ändern"><small><i class="fas fa-pen"></i></small></button>
<button style="float: right" type="button" class="btn btn-danger btn-sm mr-1" onclick="javascript:delArea({{area.pk}})" data-toggle="tooltip" data-placement="top" title="Bereich löschen"><i class="fas fa-trash-alt"></i></button>
</h5>
</div>
<div id="area_content_{{area.pk}}" class="collapse" data-labelledby="area_{{area.pk}}" data-parent="#sortableAreas">
<div class="card-body">
<button class="btn btn-primary" onclick="javascript:addTask({{area.pk}})" data-toggle="tooltip" data-placement="top" title="Neue Tätigkeit hinzufügen."><i class="fas fa-plus"></i>&nbsp;Tätigkeit</button>
<table class="table table-hover mt-2" id="areatask_{{area.pk}}_table">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Bereich</th>
<th scope="col">Erstellt von</th>
<th scope="col">Erstellt am</th>
<th scope="col">&nbsp;</th>
</tr>
</thead>
<tbody id="areatask_{{area.pk}}">
{% for task in alltasks %}
{% if task.area.pk == area.pk %}
<tr id="task_{{task.id}}" name="{{task.name}}">
<td><a href="{% url 'standard-task' task.pk %}" id="taskname_td_area_{{task.pk}}">{{task.name }}</a></td>
<td>{{ task.area.name }}</td>
<td>{{ task.created_area_by.first_name }} {{ task.created_area_by.last_name }}</td>
<td>{{ task.created_area_date }}</td>
<td>
<button style="float: right" class="btn btn-primary btn-sm" onclick="javascript:updateTaskComplete({{task.pk}})" data-toggle="tooltip" data-placement="top" title="Tätigkeit bearbeiten"><small><i class="fas fa-pen"></i></small></button>
<button style="float: right" type="button" class="btn btn-danger btn-sm mr-1" onclick="javascript:delTask({{task.pk}})" data-toggle="tooltip" data-placement="top" title="Tätigkeit löschen"><i class="fas fa-trash-alt"></i></button>
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<!-- MODEAL NEW CHANGE AREA -->
<div class="modal fade" id="mainmodalArea" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="" aria-hidden="true">
<div class="modal-dialog " role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="mainmodalArea_title"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Schließen">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="exampleInputPassword1">Bereichsname:</label>
<input class="form-control" id="newareaname" type="text" value="" placeholder="Bereichsname" onkeyup="javascript:validateAreaName(this.value)">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Bereichsfarbe:</label>
<div id="areacolor" class="colorPickSelector"></div>
</div>
<div id="newareaname_err" class="alert alert-danger mt-3" style="display: none">Falsche Eingabe! Keine Sonderzeichen!</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">Abrechen</button>&nbsp;
<button id="doActionAreaModal" type="button" class="btn btn-success" data-dismiss="modal" onclick="javascript:mainmodalAreaSave()" disabled="true">Speichern</button>
</div>
</div>
</div>
</div>
<!-- CONFIRMA DELETE Area -->
<div class="modal fade" id="delArea" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="agencyDelFunction" aria-hidden="true">
<div class="modal-dialog " role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Bereich löschen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Schließen">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
Möchten Sie den Bereich <b><span id="areaName"></span></b> wirklich löschen? Alle darin enthaltenen Tätigkeiten <u>und Standards</u> werden ebenfalls entfernt!
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal" onclick="javascript:doDelArea()">Bereich löschen</button>&nbsp;&nbsp;
<button type="button" class="btn btn-success" data-dismiss="modal" onclick="javascript:$('#delArea').modal('toggle')">Abbrechen</button>
</div>
</div>
</div>
</div>
<!-- MODEAL ADD TASK -->
<div class="modal fade" id="mainmodalTasks" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="" aria-hidden="true">
<div class="modal-dialog " role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="mainmodalArea_title">Neue Tätigkeit</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Schließen">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="exampleInputPassword1">Tätigkeitsname:</label>
<input class="form-control" id="newtaskname" type="text" value="" placeholder="Bereichsname" onkeyup="javascript:validateTaskName(this.value, 0)">
</div>
Nach dem Erstellen der Tätigkeit können Mitarbeiter zugewiesen werden.
<div id="newtaskname_err" class="alert alert-danger mt-3" style="display: none">Falsche Eingabe! Keine Sonderzeichen!</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">Abrechen</button>&nbsp;
<button id="doActionTaskModal" type="button" class="btn btn-success" data-dismiss="modal" onclick="javascript:mainmodalTaskSave()" disabled="true">Speichern</button>
</div>
</div>
</div>
</div>
<!-- UPDATE TASK MODAL -->
<div class="modal fade" id="updateTask" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="agencyDelFunction" aria-hidden="true">
<div class="modal-dialog " role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Tätigkeit <b><span id="tasknametoupdate"></span></b> bearbeiten</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Schließen">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="exampleInputPassword1">Tätigkeitsname:</label>
<input class="form-control" id="updateTaskName" type="text" value="" placeholder="Bereichsname" onkeyup="javascript:validateTaskName(this.value, 1)">
</div>
<h6>Bereich:&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Wird der Bereich verändert, werden auch alle Standards in den neuen Bereich verschoben." class="far fa-question-circle"></i></small></h6>
<div class="input-group mb-3">
<select class="custom-select" id="taskAreaSelected">
{%for area in agencyareas%}
<option value="{{area.pk}}">{{area.name}}</option>
{% endfor %}
</select>
</div>
<div id="updateTaskName_err" class="alert alert-danger mt-3" style="display: none">Falsche Eingabe! Keine Sonderzeichen!</div>
<div class="custom-control custom-checkbox mb-2 mt-2">
<input type="checkbox" class="custom-control-input" id="visibleTask" onchange="javascript:changeVisibleTask()">
<label class="custom-control-label" for="visibleTask" >Im Organigramm sichtbar</label>
</div>
<h6>Mitarbeiter hinzufügen:</h6>
<div class="input-group mb-3">
<input class="form-control searchuserfieldstask" list="possusers" id="searchusertotask" type="text" onkeyup="javascript:checkUserToTask()" >
<div class="input-group-append">
<button type="button" onclick="javascript:clearSearchfieldAddToTask()" class="btn btn-secondary" ><i class="fas fa-times"></i></button>
</div>
<datalist id="possusers"></datalist>
</div>
<h6>Zugewiesene Mitarbeiter:</h6>
<div id="added_users_button"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal" onclick="javascript:updateTask()" id="doActionUpdateTask">Tätigkeit aktualisieren</button>&nbsp;&nbsp;
<button type="button" class="btn btn-success" data-dismiss="modal" onclick="javascript:$('#updateTask').modal('toggle')">Schließen</button>
</div>
</div>
</div>
</div>
<!-- CONFIRMA STRUCTURE CHANGE RELOAD -->
<div class="modal fade" id="structureChangeReload" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="agencyDelFunction" aria-hidden="true">
<div class="modal-dialog " role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Struktur verändert</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Schließen">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
Achtung! Die grundlegende Struktur der Tätigkeiten wurde verändert. Die Seite wird einmal neu geladen, sobald Sie dieses Fenster schließen.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal" onclick="javascript:window.location=window.location">Schließen</button>
</div>
</div>
</div>
</div>
<!-- CONFIRMA DELETE Task -->
<div class="modal fade" id="delTask" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="agencyDelFunction" aria-hidden="true">
<div class="modal-dialog " role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Tätigkeit löschen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Schließen">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
Möchten Sie den Bereich <b><span id="taskName"></span></b> wirklich löschen? Alle darin enthaltenen <u>Standards</u> werden ebenfalls entfernt!
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal" onclick="javascript:doDelTask()">Tätigkeit löschen</button>&nbsp;&nbsp;
<button type="button" class="btn btn-success" data-dismiss="modal" onclick="javascript:$('#delTask').modal('toggle')">Abbrechen</button>
</div>
</div>
</div>
</div>
<script>
var ua = window.navigator.userAgent;
var isIE = /MSIE|Trident/.test(ua);
if ( isIE ) {
//IE specific code goes here
setInterval(function()
{
alluserfields = $(".searchuserfieldstask").each(function(key, value){
specific_userfield_id = value['id'].split("_")[1];
checkUserToTask();
});
},400);
}
function checkUserToTask(){
var g = $('#searchusertotask').val();
var id = $('#possusers').find('option[value="' + g + '"]').attr('id');
if(id != undefined && id.length > 0){
tempid_useraddtask = id.split("_")[0];
$.ajax(
{
type: "GET",
url: "/tasks/areaajax",
data:{
userid: tempid_useraddtask,
action : 'adduser',
objectid : workingTaskId
},
success: function( data )
{
clearSearchfieldAddToTask();
//Add User-Button
$("#added_users_button").append('<span id="span_btn_'+data['userid']+'" class="badge badge-pill badge-primary mr-2 mt-2"><a class="btn btn-primary" onclick="javascript:removeUserFromTask('+data['userid']+')">'+data['username_clean']+'&nbsp;&nbsp;<i class="fas fa-times"></i></a ></span>');
$("#possusers").empty();
for (var i in data['remaining_users']) {
id = data['remaining_users'][i]['id'];
name = data['remaining_users'][i]['first_name'] + " " + data['remaining_users'][i]['last_name'];
$("#possusers").append('<option id="'+id+'" value="'+name+'"></option>');
}
}
});
}
}
//Initial function for draggable areas
$( function() {
$( "#sortableAreas" ).sortable
({
axis:"y",
update: function( event, ui )
{
datatoserver = [];
var rows = $( "#sortableAreas" ).sortable( "widget" )[0]['children'];
for(i = 0; i < rows.length; i++){
tempid = rows[i]['id'].split("_")[1];
datatoserver.push({"id" : tempid, "neworder" : i});
}
$.ajax(
{
type: "GET",
url: "/areas/updateorder",
data:{
action: "newareaorder",
finalod : JSON.stringify(datatoserver)
},
success: function( data )
{
$('#notchange_done').toast('show');
}
});
}
});
});
$( "#sortableAreas" ).disableSelection();
taskaddtoarea = false;
function clearSearchfieldAddToTask(){
$("#searchusertotask").val("");
}
function addTask(areaid){
taskaddtoarea = areaid;
$("#mainmodalTasks").modal("toggle");
$("#newtaskname").val("");
$("#doActionTaskModal").prop("disabled", true);
$("#newtaskname_err").hide();
}
function mainmodalTaskSave(){
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "add_task",
newvalue : $("#newtaskname").val(),
areaid : taskaddtoarea
},
success: function( data )
{
if(data['success']){
newtaskid = data['data']['newtaskid'];
newtaskname = data['data']['name'];
newtaskareaname = data['data']['areaname'];
taskcreatedby = data['data']['taskcreator_fullname'];
taskcreateddate = data['data']['createdate'];
$("#areatask_" + taskaddtoarea).prepend('<tr id="task_'+newtaskid+'"><td><a href="/standards/standard/'+newtaskid+'/task" id="taskname_td_area_'+newtaskid+'">'+newtaskname+'</a></td><td>'+newtaskareaname+'</td><td>'+taskcreatedby+'</td><td>'+taskcreateddate+'</td><td><button style="float: right" class="btn btn-primary btn-sm" onclick="javascript:updateTaskComplete('+newtaskid+')" data-toggle="tooltip" data-placement="top" title="Tätigkeit bearbeiten"><small><i class="fas fa-pen"></i></small></button><button style="float: right" type="button" class="btn btn-danger btn-sm mr-1" onclick="javascript:delTask('+newtaskid+')" data-toggle="tooltip" data-placement="top" title="Tätigkeit löschen"><i class="fas fa-trash-alt"></i></button></td> ></tr>');
}
else{
$("#mainmodalArea").modal('toggle');
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Fehler beim Erstellen des Bereichs!");
}
}
});
}
function updateTask(){
namevalue = $("#updateTaskName").val();
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "change_taskname",
newvalue : namevalue,
newareaid : $("#taskAreaSelected").val(),
id : workingTaskId
},
success: function( data )
{
$("a#taskname_td_area_" + workingTaskId).text(data["data"]["newvalue"]);
$("#updateTask").modal("toggle");
$('#updateTask').on('hidden.bs.modal', function (e) {
console.log(data)
if(data["data"]["smoved"]){
$("#structureChangeReload").modal("toggle");
}
});
}
});
}
function removeUserFromTask(userid){
$.ajax(
{
type: "GET",
url: "/tasks/areaajax",
data:{
userid: userid,
action : 'remuser',
objectid : workingTaskId
},
success: function( data )
{
//Remove User-Button
$("#span_btn_"+data['userid']).remove();
$("#possusers").empty();
for (var i in data['remaining_users']) {
id = data['remaining_users'][i]['id'];
name = data['remaining_users'][i]['first_name'] + " " + data['remaining_users'][i]['last_name'];
$("#possusers").append('<option id="'+id+'" value="'+name+'" class="addusertotask_remclass"></option>');
}
}
});
}
function updateTaskComplete(id){
workingTaskId = id;
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "get_taskname",
id : workingTaskId
},
success: function( data )
{
$("#added_users_button").html("");
$("#possusers").empty();
$("#taskAreaSelected").val(data["data"]["taskarea"]);
$("#updateTask").modal("toggle");
$("#updateTaskName").val(data['data']['taskname']);
$("#tasknametoupdate").html(data['data']['taskname']);
if(data['data']['visible'] == true){
$("#visibleTask").prop("checked", true);
}
else{
$("#visibleTask").prop("checked", false);
}
//ADDED USERS
for(i = 0; i < data["data"]["addedl"]; i++){
$("#added_users_button").append('<span id="span_btn_'+data["data"]["added_users"][i]['userid']+'" class="badge badge-pill badge-primary mr-2 mt-2"><a class="btn btn-primary" onclick="javascript:removeUserFromTask('+data["data"]["added_users"][i]['userid']+')">'+data["data"]["added_users"][i]['fullname']+'&nbsp;&nbsp;<i class="fas fa-times"></i></a ></span>')
}
//POSSIBLE USERS
for(i = 0; i < data["data"]["possl"]; i++){
$("#possusers").append('<option id="'+data["data"]["possible_users"][i]['userid']+'" value="'+ data["data"]["possible_users"][i]['fullname']+'" class="addusertotask_remclass">');
}
}
});
}
function changeVisibleTask(){
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "update_visible_taskname",
id : workingTaskId
},
success: function( data )
{}
});
}
//Validate new Area-Name
function validateTaskName(newtaskname, updateornew){
// NEW TASK
var letters = /^[A-Za-zßäöüÄÖÜ_\-0-9 ]+$/;
if(updateornew == 0)
{
if(newtaskname.length > 0){
if(!newtaskname.match(letters))
{
$("#newtaskname_err").show();
$("#doActionTaskModal").prop("disabled", true);
}
else{
$("#newtaskname_err").hide();
$("#doActionTaskModal").prop("disabled", false);
}
}
else{
$("#newtaskname_err").hide();
$("#doActionTaskModal").prop("disabled", true);
}
}
//UPDATE TASK
else{
if(newtaskname.length > 0){
if(!newtaskname.match(letters))
{
$("#updateTaskName_err").show();
$("#doActionUpdateTask").prop("disabled", true);
}
else{
$("#updateTaskName_err").hide();
$("#doActionUpdateTask").prop("disabled", false);
}
}
else{
$("#updateTaskName_err").hide();
$("#doActionUpdateTask").prop("disabled", true);
}
}
}
workingTaskId = false;
function delTask(taskid){
workingTaskId = taskid;
$("#delTask").modal("toggle");
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "get_taskname",
id : workingTaskId
},
success: function( data )
{
$("#taskName").html(data['data']['taskname']);
}
});
}
function doDelTask(){
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "remove_task",
id : workingTaskId
},
success: function( data )
{
if(data['success']){
$('#notchange_done').toast('show');
$("#task_"+workingTaskId).remove();
}
else{
$("#delArea").modal('toggle');
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Fehler beim Erstellen des Bereichs!");
}
}
});
}
function doDelArea(){
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "remove_area",
id : workingAreaId
},
success: function( data )
{
if(data['success']){
window.location.href = window.location.href + "?showtoast=true";
}
else{
$("#delArea").modal('toggle');
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Fehler beim Erstellen des Bereichs!");
}
}
});
}
function delArea(areaid){
workingAreaId = areaid;
$("#delArea").modal("toggle");
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "get_areaname",
id : areaid
},
success: function( data )
{
$("#areaName").html(data['data']['areaname']);
}
});
}
/*
0 = DEFAULT
1 = NEW AREA
2 = CHANGE AREA
*/
modalarea_action = 0;
areaupdateid = false;
default_colorpickerinit = "#3498db";
newareacolor= "#ffffff";
//Prepare addArea-Modal and show
function addArea(workingAreaId)
{
if(workingAreaId == false)
{
$("#mainmodalArea_title").html("Neuen Bereich anlegen");
$("#mainmodalArea").modal('toggle');
$("#newareaname").val("");
default_colorpickerinit = "#3498db";
modalarea_action = 1;
}
else {
areaupdateid = workingAreaId;
modalarea_action = 2;
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "get_areaname",
id : workingAreaId
},
success: function( data )
{
$("#mainmodalArea_title").html("Bereich bearbeiten");
$("#mainmodalArea").modal('toggle');
$("#newareaname").val(data['data']['areaname']);
$("#doActionAreaModal").prop("disabled", false);
default_colorpickerinit = data['data']['areacolor'];
}
});
}
}
$('#mainmodalArea').on('shown.bs.modal', function() {
$(".colorPickSelector").colorPick(
{
'initialColor': default_colorpickerinit,
'allowRecent': true,
'recentMax': 5,
'allowCustomColor': false,
'palette': ["#1abc9c", "#16a085", "#2ecc71", "#27ae60", "#3498db", "#2980b9", "#9b59b6", "#8e44ad", "#34495e", "#2c3e50", "#f1c40f", "#f39c12", "#e67e22", "#d35400", "#e74c3c", "#c0392b", "#ecf0f1", "#bdc3c7", "#95a5a6", "#7f8c8d"],
'onColorSelected': function() {
this.element.css({'backgroundColor': this.color, 'color': this.color});
newareacolor = this.color;
}
});
});
//Validate new Area-Name
function validateAreaName(newareaname){
var letters = /^[A-Za-zßäöüÄÖÜ_\-0-9 ]+$/;
if(newareaname.length > 0){
if(!newareaname.match(letters))
{
$("#newareaname_err").show();
$("#doActionAreaModal").prop("disabled", true);
}
else{
$("#newareaname_err").hide();
$("#doActionAreaModal").prop("disabled", false);
}
}
else{
$("#newareaname_err").hide();
$("#doActionAreaModal").prop("disabled", true);
}
}
//Final save-Area
function mainmodalAreaSave(){
namevalue = $("#newareaname").val();
//ADD AREA
if(modalarea_action == 1){
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "add_area",
newvalue : namevalue,
color : newareacolor
},
success: function( data )
{
if(data['success']){
window.location.href = window.location.href + "?showtoast=true";
}
else{
$("#mainmodalArea").modal('toggle');
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Fehler beim Erstellen des Bereichs!");
}
}
});
}
//CHANGE AREA
else if(modalarea_action == 2){
console.log(newareacolor);
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "update_areaname",
id : areaupdateid,
newvalue : namevalue,
color : newareacolor
},
success: function( data )
{
if(data['success']){
$("#mainmodalArea").modal('toggle');
$('#notchange_done').toast('show');
$("#areaname_" + areaupdateid).html("Bereich <b>"+data['data']['newvalue']+"&nbsp;</b>");
$("#area_" + areaupdateid).css("background-color", data['data']['color']);
}
else{
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Fehler beim Erstellen des Bereichs!");
}
}
});
}
}
</script>

View File

@ -0,0 +1,16 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section col-5">
<h3>Stammdaten von {{user_fullname}} ändern</h3>
<hr>
<form method="POST">
{% csrf_token %}
{{ userform|crispy }}
<hr>
<a class="btn" href="{% url 'dasettings' %} ">Abbrechen</a>
<button type="submit" class="btn btn-primary" style="float: right">Stammdaten speichern</button>
</form>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,51 @@
{% load counter_tag %}
<a href="{% url 'newuserfirst' %}"class="btn btn-primary active" data-toggle="tooltip" data-placement="top" title="Fügen Sie hier einen weiteren Mitarbeiter Ihrer Agentur hinzu.">+ Mitarbeiter</a>
<hr>
<div class="row">
<div class="form-group mb-2">
<input class="form-control" id="tableSearch" size="50" type="text" placeholder="Suche in Tabelle...">
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">E-Mail</th>
<th scope="col">Agenturfunktion</th>
<th scope="col">Tätigkeit</th>
<th scope="col">Telefon</th>
<th scope="col">Mobil</th>
<th scope="col">&nbsp;</th>
</tr>
</thead>
<tbody id="tableresults">
{% for item in usersofagency %}
<tr>
<td><a href="{% url 'user_updateprofile' item.pk 0 %}">{{item.first_name }} {{ item.last_name }}</a></td>
<td>{{ item.email }}</td>
<td>{% if item.profile.func == None %}-{%else%}{{ item.profile.func }}{%endif%}</td>
<td>{{ item.profile.compfunc }}</td>
<td>{{ item.profile.phoneland }}</td>
<td>{{ item.profile.phonemobile }}</td>
<td>
{% if item != request.user %}
<a class="dropdown-item text-danger" href="{% url 'users-delete' item.pk %}" ><i class="fas fa-trash-alt"></i></a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<script>
$(document).ready(function(){
$("#tableSearch").on("keyup", function() {
var value = $(this).val().toLowerCase();
$("#tableresults tr").filter(function() {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
});
});
});
</script>

View File

@ -0,0 +1,30 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section col-5">
<h3>Neuer Benutzer&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Legen Sie zuerst die Stammdaten fest. Anschließend können Agenturfunktion, Gruppen und Profilbild eingetragen werden." class="far fa-question-circle"></i></small></h3>
<hr>
<div class="progress mb-3" style="max-height: 15px;">
<div class="progress-bar" role="progressbar" style="width: 30%; " aria-valuenow="30" aria-valuemin="0" aria-valuemax="100">Schritt 1: Stammdaten</div>
</div>
<small>Legen Sie hier die Stammdaten des neuen Mitarbeiters fest.</small>
<form method="POST">
{% csrf_token %}
{{ newuserform|crispy }}
<div class="form-check">
<input class="form-check-input" type="checkbox" value="true" id="sendmailnewuser" name="sendmailnewuser">
<label class="form-check-label" for="sendmailnewuser" name="sendmailnewuser">
E-Mailbenachrichtigung schicken
</label>
</div>
<small>*: Der Benutzer erhält direkt eine E-Mail mit einem Link zur Passworterstellung, wenn der Haken bei <i>E-Mailbenachrichtung schicken</i> gesetzt ist. Dies kann später auch wiederholt werden.</small>
<hr>
<a class="btn" href="{% url 'dasettings' %} ">Abbrechen</a>
<button type="submit" class="btn btn-primary" style="float: right">Weiter zu Schritt 2</button>
</form>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,325 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% load counter_tag %}
{% load static %}
{% block content %}
<script src="{% static 'users/js/cropper.min.js' %}"></script>
<script src="{% static 'users/js/jquery-cropper.js' %}"></script>
<div aria-live="polite" aria-atomic="true" class="d-flex justify-content-center align-items-center" style="min-height: 200px; max-width: 250px; position: fixed; margin-top: -3%; margin-left: 70.5%; z-index: 10">
<!-- Then put toasts within -->
<div id="notchange_done" class="toast alert-success" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="mr-auto">Gespeichert</strong>
<!--<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>-->
</div>
<div class="toast-body">
<div id="toast_savecontent">Änderungen wurden gespeichert.</div>
</div>
</div>
</div>
<div aria-live="polite" aria-atomic="true" class="d-flex justify-content-center align-items-center" style="min-height: 200px; max-width: 250px; position: fixed; margin-top: -3%; margin-left: 70.5%; z-index: 10">
<!-- Then put toasts within -->
<div id="notchange_err" class="toast alert-danger" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="mr-auto">Fehler aufgetreten</strong>
<!--
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
-->
</div>
<div class="toast-body">
<div id="toast_errcontent">Bitte kontaktieren Sie den Support.</div>
</div>
</div>
</div>
<div class="content-section col-10">
<h3>Profil von {{user_fullname}} bearbeiten&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Geben Sie hier die Profildaten für den Mitarbeiter ein." class="far fa-question-circle"></i></small></h3>
<hr>
{% if newuser == 1 %}
<div class="progress mb-3" style="max-height: 15px;">
<div class="progress-bar" role="progressbar" style="width: 80%; " aria-valuenow="80" aria-valuemin="0" aria-valuemax="100">Schritt 2: Profildaten festlegen</div>
</div>
{% endif %}
<div class="media mb-4">
<img class="img-profile" style="width: 15%;" src="{{ imagelink }}">
<div class="media-body col-6">
<div class="row">
<div class="col-6">
<h6><b>Name</b></h6>
<p>
{{ user_fullname }}
</p>
<h6><b>E-Mail</b></h6>
<p>
{{ mail }}
</p>
<a type="button" class="btn-primary btn-sm active" href="{% url 'changeusermaindata' vieweduser %}">Stammdaten ändern</a>
</div>
</div>
</div>
</div>
<hr>
<form method="POST" enctype="multipart/form-data">
<input type="hidden" name="userprof_formtype" value="profileform">
<div class="mt-2">
<p>Gruppen&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Legen Sie fest, in welchen Gruppen der neue Mitarbeiter sein soll. Standardmäßig sind alle Mitarbeiter in der Gruppe Mitarbeiter (wenn diese nicht umbenannt worden ist)." class="far fa-question-circle"></i></small></p>
<div class="row">
<div class="col-4">
{% for g in agencygroups %}
{% if forloop.counter|divisibleby:6 %}
</div><div class="col-4">
<div class="custom-control custom-checkbox mb-2">
{% if vieweduser|useringroupbyid:g.group.name %}
<input type="checkbox" class="custom-control-input" name="group_{{g.pk}}" id="group_{{g.pk}}" onchange="javascript:updateUser({{vieweduser}}, {{g.pk}}, this.checked)" checked="true">
{% else %}
<input type="checkbox" class="custom-control-input" name="group_{{g.pk}}" id="group_{{g.pk}}" onchange="javascript:updateUser({{vieweduser}}, {{g.pk}}, this.checked)">
{% endif %}
<label class="custom-control-label" for="group_{{g.pk}}" >{{g.agencygroupname}}</label>
</div>
{% else %}
<div class="custom-control custom-checkbox mb-2">
{% if vieweduser|useringroupbyid:g.group.name %}
<input type="checkbox" class="custom-control-input" name="group_{{g.pk}}" id="group_{{g.pk}}" onchange="javascript:updateUser({{vieweduser}}, {{g.pk}}, this.checked)" checked="true">
{% else %}
<input type="checkbox" class="custom-control-input" name="group_{{g.pk}}" id="group_{{g.pk}}" onchange="javascript:updateUser({{vieweduser}}, {{g.pk}}, this.checked)">
{% endif %}
<label class="custom-control-label" for="group_{{g.pk}}" >{{g.agencygroupname}}</label>
</div>
{% endif %}
{% endfor %}
</div></div>
</div>
<hr>
<div class="mt-2">
<p>Übergeordneter Mitarbeiter&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Legen Sie fest, welche Mitarbeiter über diesen im Organigramm steht. Ist die Einstellung leer, wir" class="far fa-question-circle"></i></small></p>
<select name="usertoparent" id="usertoparent" class="select form-control col-4">
<option value="">---------</option>
{% for singleparent in usertoparent %}
{% if parentuser == singleparent.pk %}
<option value="{{singleparent.pk}}" selected>{{singleparent.first_name}} {{singleparent.last_name}} </option>
{% else %}
<option value="{{singleparent.pk}}">{{singleparent.first_name}} {{singleparent.last_name}} </option>
{% endif %}
{% endfor %}
</select>
</div>
<hr>
<p>Persönliches Profil</p>
{% csrf_token %}
<div class="row">
<div class="col-6">
{% for field in profileform %}
{% if forloop.counter|divisibleby:6 %}
</div>
<div class="col-6">
{{field|as_crispy_field}}
{% else %}
{{field|as_crispy_field}}
{% endif %}
{% endfor %}
</div>
</div>
<hr>
{% if newuser == 1 %}
<button type="submit" class="btn btn-primary" style="float: right">Profilerstellung abschließen</button>
{% else %}
<button type="submit" name="submitprof" class="btn btn-primary" style="float: right">Profil Aktualisieren</button>
{% endif %}
<a class="btn" href="{% url 'dasettings' %} ">Profilbearbeitung abbrechen</a>
</form>
</div>
</div>
<!-- MODAL TO CROP THE IMAGE --><div class="modal fade " id="modalCrop" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Bereich bestimmen</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="clearImgField()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" id="imgmodbody">
<img src="" id="imagemod" style="max-width: 100%; max-height: 100%;">
</div>
<div class="modal-footer">
<div class="btn-group pull-left" role="group">
<button type="button" class="btn btn-default js-zoom-in">
<i class="fas fa-search-plus"></i>
</button>
<button type="button" class="btn btn-default js-zoom-out">
<i class="fas fa-search-minus"></i>
</button>
<button type="button" class="btn btn-default js-rot-left">
<i class="fas fa-undo-alt"></i>
</button>
<button type="button" class="btn btn-default js-rot-right">
<i class="fas fa-redo-alt"></i>
</button>
</div>
<button type="button" class="btn btn-default" data-dismiss="modal" onclick="clearImgField()">Abbrechen</button>
<button type="button" class="btn btn-primary js-crop-and-upload">Ausschneiden</button>
</div>
</div>
</div>
</div>
<script>
function showMainUserForm(){
$("#changeMainUserData").modal("toggle");
}
$(document).ready(function(){
$(".toast").toast({
autohide: true,
delay : 3000
});
});
function updateUser(userid, groupid, newvalue){
if(newvalue){
addUserToGroup(userid, groupid);
}
else{
removeUserFromGroup(userid, groupid);
}
}
function removeUserFromGroup(userid, groupid){
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "remove_user_from_group",
groupid : groupid,
userid: userid
},
success: function( data )
{
if(data['success']){
$('#notchange_done').toast('show');
$("#toast_savecontent").html("Mitarbeiter erfolgreich aus der Gruppe entfernt!");
}
else{
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Mitarbeiter konnte nicht entfernt werden!");
}
}
});
}
function addUserToGroup(userid, groupid){
$.ajax(
{
type: "GET",
url: "/dasettings/ajax",
data:{
action : "add_user_to_group",
groupid : groupid,
userid: userid,
},
success: function( data )
{
if(data['success']){
$('#notchange_done').toast('show');
$("#toast_savecontent").html("Mitarbeiter erfolgreich der Gruppe hinzugefügt!");
}
else{
$('#notchange_err').toast('show');
$("#toast_errcontent").html("Mitarbeiter konnte nicht hinzugefügt werden!");
}
}
});
}
/* CROPPER */
$("#id_x").val(0);
$("#id_y").val(0);
$("#id_width").val(300);
$("#id_height").val(300);
$("#id_rotation").val(0);
function clearImgField(){
$("#id_image").val("");
}
/* SCRIPT TO OPEN THE MODAL WITH THE PREVIEW */
$("#id_image").change(function () {
if (this.files && this.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$("#imagemod").attr("src", e.target.result);
$("#modalCrop").modal("show");
}
reader.readAsDataURL(this.files[0]);
}
});
var cropBoxData;
var canvasData;
var $image = $("#imagemod");
$("#modalCrop").on("shown.bs.modal", function () {
$image.cropper({
viewMode: 3,
aspectRatio: 1/1,
strict: false,
cropBoxMovable: true,
cropBoxResizable: true,
minCropBoxWidth: 200,
minCropBoxHeight: 200,
ready: function () {
$image.cropper("setCanvasData", canvasData);
$image.cropper("setCropBoxData", cropBoxData);
}
});
$("#imgmodbody").css({
"maxWidth": 465
});
}).on("hidden.bs.modal", function () {
cropBoxData = $image.cropper("getCropBoxData");
canvasData = $image.cropper("getCanvasData");
$image.cropper("destroy");
});
$(".js-zoom-in").click(function () {
$image.cropper("zoom", 0.1);
});
$(".js-zoom-out").click(function () {
$image.cropper("zoom", -0.1);
});
$(".js-rot-right").click(function () {
$image.cropper("rotate", 90);
});
$(".js-rot-left").click(function () {
$image.cropper("rotate", -90);
});
/* SCRIPT TO COLLECT THE DATA AND POST TO THE SERVER */
$(".js-crop-and-upload").click(function () {
var cropData = $image.cropper("getData");
$("#id_x").val(cropData["x"]);
$("#id_y").val(cropData["y"]);
$("#id_height").val(cropData["height"]);
$("#id_width").val(cropData["width"]);
$("#id_rotation").val(cropData["rotate"]);
$("#id_image").attr("src", $image);
$("#modalCrop").modal('toggle');
});
</script>
{% endblock content %}

3
dasettings/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

16
dasettings/urls.py Normal file
View File

@ -0,0 +1,16 @@
from django.urls import path
from django.contrib.auth import views as auth_views
from django.contrib.auth.decorators import login_required, permission_required
from . import views
from .views import NewUserFirstStep, UserProfileUpdate, UserChangeMain
'''
Permissions definiert in models.py bei USERS und dann hier vor die View geschrieben!
'''
urlpatterns = [
path('main/', views.DASettings, name='dasettings'),
path('newuser/s1', permission_required('users.usermanager')(views.NewUserFirstStep), name='newuserfirst'),
path('changeus/<int:pk>/', permission_required('users.usermanager')(views.UserChangeMain), name='changeusermaindata'),
path('ajax/', views.SettingsAjaxRouter, name="dasettings-ajax"),
path('usprof/<int:pk>/<int:newuser>', permission_required('users.usermanager')(views.UserProfileUpdate), name="user_updateprofile")
]

557
dasettings/views.py Normal file
View File

@ -0,0 +1,557 @@
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect,HttpResponse, JsonResponse
from .forms import UsersSelfChangeForm, UsersNotificationForm, AgencyGroupPerms, AgencyModulsForm, UserNewUserForm, UserProfileForm
from django.contrib import messages
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.forms import PasswordChangeForm
from users.usersforms import AgencyUpdateForm
from users.models import AgencyJob, AgencyGroup
from django.contrib.auth.models import User, Group, Permission
import random
import string
from users.usersforms import UsersPermForm
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import CreateView
from users.models import Profile
from areas.models import Areas
from tasks.models import Tasks
import webcolors
from datetime import datetime
from standards.models import Standards
def randomString(stringLength=10):
"""Generate a random string of fixed length """
letters = string.ascii_lowercase
return ''.join(random.choice(letters) for i in range(stringLength))
@login_required
def checkForGroupName(request, newgroupname):
stat = True
groupsagency = AgencyGroup.objects.filter(agency__pk=request.user.profile.agency.pk)
for group in groupsagency:
if group.agencygroupname.upper() == newgroupname.upper():
stat = False
return stat
@login_required
def getAllForms(request, context):
# USERFORMS
userform = UsersSelfChangeForm(instance=request.user)
passwordform = PasswordChangeForm(request.user)
context.update({'userform' : userform})
context.update({'passwordform' : passwordform})
# NOTIFICTAION FORMS
notificationform = UsersNotificationForm(instance=request.user.profile)
context.update({'notificationform' : notificationform})
# AGENCY UPDATE FORMS
agencyform = AgencyUpdateForm(instance=request.user.profile.agency)
context.update({'agencyform' : agencyform})
#PERMS
perms = AgencyGroupPerms()
context.update({'perms' : perms})
#MODULFORMS
modulform = AgencyModulsForm(instance=request.user.profile.agency)
context.update({'modulform' : modulform})
# USER FOR USERTABLE
users = User.objects.filter(profile__agency__pk=request.user.profile.agency.pk)
return context
'''
Lädt die Formulare für die einzelnen Einstellungen vollständig
'''
@login_required
def DASettings(request):
context = {
'active_link' : 'dasettings'
}
context = getAllForms(request, context)
# USERS FOR MEMBERS AND GROUPCOUNTERS
usersofagency = User.objects.filter(profile__agency__pk=request.user.profile.agency.pk).order_by("last_name")
context.update({"usersofagency" : usersofagency})
# LOAD AGENCYJOBS
context.update({"agencyjobs" : AgencyJob.objects.filter(agency__pk=request.user.profile.agency.pk).order_by("name")})
# LOAD GROUPS
agencygroups = AgencyGroup.objects.filter(agency__pk=request.user.profile.agency.pk).order_by("agencygroupname")
context.update({"agencygroups" : agencygroups})
# LOAD AREAS
agencyareas = Areas.objects.filter(agency__pk=request.user.profile.agency.pk).order_by('areaorder')
context.update({"agencyareas" : agencyareas})
# LOAD TASKS
alltasks = Tasks.objects.filter(agency__pk=request.user.profile.agency.pk).order_by('name')
context.update({"alltasks" : alltasks})
if request.method == 'POST' and request.POST.get("settings_area") == "profil":
return SettingsProfilManagement(request, context)
elif request.method == 'POST' and request.POST.get("settings_area") == "agency":
return SettingsAgency(request, context)
elif request.method == 'POST' and request.POST.get("settings_area") == "moduls":
return SettingsAgencyModuls(request, context)
# Returning the data from database for normal-loading Settings
else:
# DEFAULT DATA FORM-INFOS
# Hier müssen alle Standard-Formulare rein, damit die Seite Settings
# generell geladen werden kann.
# PROFILE FORMS
userform = UsersSelfChangeForm(instance=request.user)
passwordform = PasswordChangeForm(request.user)
context.update({'userform' : userform})
context.update({'passwordform' : passwordform})
# NOTIFICTAION FORMS
notificationform = UsersNotificationForm(instance=request.user.profile)
context.update({'notificationform' : notificationform})
# AGENCY UPDATE FORMS
agencyform = AgencyUpdateForm(instance=request.user.profile.agency)
context.update({'agencyform' : agencyform})
return render(request, 'dasettings/settings.html', context)
'''
AGENCY
Hier werden die Agenturinfos ink. Agenturcropper für das Agenturbild angepasst.
'''
@login_required
def SettingsAgency(request, context):
if request.POST.get("form_type") == "agencyform":
agencyform = AgencyUpdateForm(request.POST, instance=request.user.profile.agency)
if agencyform.is_valid():
if 'agencypic' in request.FILES:
request.user.profile.agency.agencypic = request.FILES['agencypic']
agencyform.save()
context['agencyform'] = AgencyUpdateForm(instance=request.user.profile.agency)
messages.success(request, f'Agenturdaten aktualisiert!')
return render(request, 'dasettings/settings.html', context)
else:
messages.success(request, f'Daten falsch eingegeben!')
context['agencyform'] = AgencyUpdateForm(instance=request.user.profile.agency)
return render(request, 'dasettings/settings.html', context)
@login_required
def SettingsAgencyModuls(request, context):
if request.POST.get("form_type") == "agencymodform":
agencymoduleform = AgencyModulsForm(request.POST, instance=request.user.profile.agency)
if agencymoduleform.is_valid():
agencymoduleform.save()
context['modulform'] = AgencyModulsForm(instance=request.user.profile.agency)
messages.success(request, f'Moduleinstellungen aktualisiert!')
return render(request, 'dasettings/settings.html', context)
else:
context['modulform'] = AgencyModulsForm(instance=request.user.profile.agency)
messages.success(request, f'Fehler beim aktualisieren! Bitte wenden Sie sich an den Support.')
return render(request, 'dasettings/settings.html', context)
'''
Hier werden die Profilinfos des User zurückgesetzt; Parameter kommen von Settings()
- Email
- Passwort aktualisieren
'''
@login_required
def SettingsProfilManagement(request, context):
# Check, which form
# USERFORM
if request.POST.get("form_type") == "userform":
userform = UsersSelfChangeForm(request.POST, instance=request.user)
if userform.is_valid():
userform.save()
messages.success(request, f'E-Mailadresse aktualisiert!')
passwordform = PasswordChangeForm(request.user)
context['userform'] = userform
context['passwordform'] = passwordform
return render(request, 'dasettings/settings.html', context)
else:
messages.success(request, f'Keine E-Mailadresse eingegeben oder E-Mail bereits vorhanden!')
passwordform = PasswordChangeForm(request.user)
userform = UsersSelfChangeForm(instance=request.user)
context['userform'] = userform
context['passwordform'] = passwordform
return render(request, 'dasettings/settings.html', context)
# PASSWORDFORM
elif request.POST.get("form_type") == "passwordform":
passwordform = PasswordChangeForm(request.user, request.POST)
if passwordform.is_valid():
passwordform.save()
update_session_auth_hash(request, request.user)
userform = UsersSelfChangeForm(instance=request.user)
context['userform'] = userform
context['passwordform'] = passwordform
messages.success(request, f'Passwort aktualisiert!')
return render(request, 'dasettings/settings.html', context)
else:
messages.success(request, f'Passwort falsch eingegeben!')
passwordform = PasswordChangeForm(request.user)
userform = UsersSelfChangeForm(instance=request.user)
context['userform'] = userform
context['passwordform'] = passwordform
return render(request, 'dasettings/settings.html', context)
@login_required
def SettingsAjaxRouter(request):
success = False
data = {}
# UPDATE NOTIFICATIONS BY FIELDNAME AND NEW VALUE
if request.method == 'GET' and request.GET['action'] == "update_notifications" :
success = False
new_stat = request.GET['new_stat']
field_to_change = getattr(request.user.profile, request.GET['fieldname'])
if(field_to_change or not field_to_change):
if(new_stat == "1"):
setattr(request.user.profile, request.GET['fieldname'], True)
else:
setattr(request.user.profile, request.GET['fieldname'], False)
request.user.profile.save()
success = True
# UPDATE TOOLTUP
elif request.method == 'GET' and request.GET['action'] == "change_showtooltips" :
newtooltipvalue = False
user = User.objects.get(pk=request.user.pk, profile__agency=request.user.profile.agency)
if user.profile.showtooltips:
user.profile.showtooltips = False
else:
user.profile.showtooltips = True
newtooltipvalue = True
user.save()
success = True
data = {'newttvalue' : newtooltipvalue}
# UPDATE AGENCYJOB
elif request.method == 'GET' and request.GET['action'] == "update_agencyfunc" :
job_id = request.GET['id']
job_value = request.GET['newvalue']
tempjob = AgencyJob.objects.get(pk=job_id, agency=request.user.profile.agency)
tempjob.name = job_value
tempjob.save()
success = True
# DELETE AGENVY JOB FUNC - RETURN ONLY NAME FOR CONFIRM
elif request.method == 'GET' and request.GET['action'] == "get_agencyfunc" :
job_id = request.GET['id']
tempjob = AgencyJob.objects.get(pk=job_id, agency=request.user.profile.agency)
data = {"funcname" : tempjob.name}
success = True
# DELETE FINAL AGECY JOB
elif request.method == 'GET' and request.GET['action'] == "delete_agencyfunc" :
job_id = request.GET['id']
tempjob = AgencyJob.objects.get(pk=job_id, agency=request.user.profile.agency)
tempjob.delete()
success = True
elif request.method == 'GET' and request.GET['action'] == "add_agencyfunc" :
tempjob = AgencyJob(name="", agency=request.user.profile.agency)
tempjob.save()
data = {"new_id" : tempjob.pk}
success = True
# GRUPPENAMEN AKTUALISIEREN
elif request.method == 'GET' and request.GET['action'] == "update_groupname" :
group = AgencyGroup.objects.get(pk=request.GET['id'], agency=request.user.profile.agency)
if(checkForGroupName(request, request.GET['newvalue'])):
group.agencygroupname = request.GET['newvalue']
group.save()
data = {"newvalue" : group.agencygroupname}
success = True
else:
success = False
# GRUPPENNAMEN HOLEN
elif request.method == 'GET' and request.GET['action'] == "get_groupname" :
group = AgencyGroup.objects.get(pk=request.GET['id'], agency=request.user.profile.agency)
data = {"groupname" : group.agencygroupname}
success = True
elif request.method == 'GET' and request.GET['action'] == "add_group" :
if(checkForGroupName(request, request.GET['newvalue'])):
tempgroup = Group(name=str(request.user.profile.agency.pk) + "_" + randomString(8))
tempgroup.save()
tempgroup_ag = AgencyGroup(savefordel=False, group=tempgroup, agency=request.user.profile.agency, agencygroupname=request.GET['newvalue'])
tempgroup_ag.save()
success = True
data = {"group_id" : tempgroup_ag.pk, "group_name" : tempgroup_ag.agencygroupname}
else:
success = False
elif request.method == 'GET' and request.GET['action'] == "delete_group" :
groupag = AgencyGroup.objects.get(pk=request.GET['id'], agency=request.user.profile.agency)
group_to_del = groupag.group
group_to_del.delete()
success = True
# PERMISSIONS ON GROUP!
elif request.method == 'GET' and request.GET['action'] == "change_perm_group" :
success = True
group_id = request.GET['id']
perm_name = request.GET['perm']
val = request.GET['val']
aggroup = AgencyGroup.objects.get(pk=group_id, agency=request.user.profile.agency)
# CHECK IF REQUESTED USER IS IN THIS AGENCY
if(request.user.profile.agency.pk == aggroup.agency.pk):
if(val == "true"):
tempperm = Permission.objects.get(codename=perm_name)
aggroup.group.permissions.add(tempperm)
else:
tempperm = Permission.objects.get(codename=perm_name)
aggroup.group.permissions.remove(tempperm)
else:
success = False
# REMOVE USER FROM GROUP
elif request.method == 'GET' and request.GET['action'] == "remove_user_from_group" :
success = True
groupid = request.GET['groupid']
userid = request.GET['userid']
aggroup = AgencyGroup.objects.get(pk=groupid, agency=request.user.profile.agency)
usertoremove = User.objects.get(pk=userid, profile__agency=request.user.profile.agency)
# CHECK IF REQUESTED USER IS IN THIS AGENCY
if(request.user.profile.agency.pk == aggroup.agency.pk):
if aggroup.group in usertoremove.groups.all():
aggroup.group.user_set.remove(usertoremove)
data = {"userid" : usertoremove.pk, "groupid" : aggroup.pk, "user_fname" : usertoremove.first_name, "user_lname" : usertoremove.last_name}
else:
success = False
# ADD USER TO GROUP
elif request.method == 'GET' and request.GET['action'] == "add_user_to_group" :
success = True
groupid = request.GET['groupid']
userid = request.GET['userid']
aggroup = AgencyGroup.objects.get(pk=groupid, agency=request.user.profile.agency)
usertoadd = User.objects.get(pk=userid, profile__agency=request.user.profile.agency)
# CHECK IF REQUESTED USER IS IN THIS AGENCY
if(request.user.profile.agency.pk == aggroup.agency.pk):
aggroup.group.user_set.add(usertoadd)
data = {"userid" : usertoadd.pk, "groupid" : aggroup.pk, "user_fname" : usertoadd.first_name, "user_lname" : usertoadd.last_name}
else:
success = False
# AREA
# AREANAMEN HOLEN
elif request.method == 'GET' and request.GET['action'] == "get_areaname" :
area = Areas.objects.get(pk=request.GET['id'], agency=request.user.profile.agency)
data = {"areaname" : area.name, "areacolor" : area.color}
success = True
# ARENAMEN UPDATE
elif request.method == 'GET' and request.GET['action'] == "update_areaname" :
area = Areas.objects.get(pk=request.GET['id'], agency=request.user.profile.agency)
area.name = request.GET['newvalue']
area.color = request.GET['color']
area.save()
data = {"newvalue" : area.name, "color" : area.color}
success = True
# ADD AREA
elif request.method == 'GET' and request.GET['action'] == "add_area" :
area = Areas(created_area_by=request.user, agency=request.user.profile.agency, name=request.GET["newvalue"], color=request.GET['color'])
area.save()
success = True
# REMOVE AREA
elif request.method == 'GET' and request.GET['action'] == "remove_area" :
Areas(pk=request.GET['id']).delete()
success = True
# ADD TASK
elif request.method == 'GET' and request.GET['action'] == "add_task" :
task = Tasks(created_area_by=request.user, area=Areas.objects.get(pk=request.GET['areaid']), agency=request.user.profile.agency, name=request.GET["newvalue"])
task.save()
taskcreator_fullname = task.created_area_by.first_name + " " + task.created_area_by.last_name
data = {"name" : task.name, "newtaskid" : task.pk, "areaname" : task.area.name, "taskcreator_fullname" : taskcreator_fullname, "createdate" : task.created_area_date.strftime("%d. %B %Y")}
success = True
# TASKNAME VISIBLE UND USERS HOLEN
elif request.method == 'GET' and request.GET['action'] == "get_taskname" :
task = Tasks.objects.get(pk=request.GET['id'], agency=request.user.profile.agency)
# User still in Area
# Get all Users from same Agency which are NOT in context_added_users
added_users = task.usersfield.all()
addus = {}
posus = {}
i = 0
# GET ADDED USERS
for us in added_users:
addus.update({ i : {"fullname" : us.first_name + " " + us.last_name, "userid" : us.pk}})
i += 1
# GET POSSIBLE TO ADD USERS
k = 0
possible_users = User.objects.filter(profile__agency__pk=request.user.profile.agency.pk).exclude(pk__in=added_users)
print(possible_users)
for us in possible_users:
posus.update({ k : {"fullname" : us.first_name + " " + us.last_name, "userid" : us.pk}})
k += 1
print(posus)
data = {"taskname" : task.name, "visible" : task.visible, "added_users" : addus, "addedl" : i, "possl" : k, "possible_users" : posus, "taskarea" : task.area.pk}
success = True
# REMOVE Task
elif request.method == 'GET' and request.GET['action'] == "remove_task" :
Tasks.objects.get(pk=request.GET['id'], agency=request.user.profile.agency).delete()
success = True
# UPDATE TASK VISIBLE
elif request.method == 'GET' and request.GET['action'] == "update_visible_taskname" :
task = Tasks.objects.get(pk=request.GET['id'], agency=request.user.profile.agency)
if(task.visible):
task.visible = False;
else:
task.visible = True;
task.save()
success = True
# UPDATE TASKNAME
elif request.method == 'GET' and request.GET['action'] == "change_taskname" :
task = Tasks.objects.get(pk=request.GET['id'])
task.name = request.GET["newvalue"]
data = {"newvalue" : task.name}
newareaid = request.GET["newareaid"]
standardsmoved = False
if int(task.area.pk) != int(newareaid):
standardsmoved = True
newareaobj = Areas.objects.get(pk=newareaid, agency=request.user.profile.agency)
Standards.objects.filter(agency=request.user.profile.agency, area=task.area).update(area=newareaobj)
task.area = newareaobj
task.save()
data = {"newvalue" : task.name, "smoved" : standardsmoved}
success = True
else:
success = False
return JsonResponse({"success" : success, "data" : data})
'''
UserProfileUpdate
unterscheidet zwischen newuser=0 --> PROFIL AKTUALISIEREN
und newuser=1 --> PROFIL Neu speichern
'''
@login_required
def UserProfileUpdate(request, pk, newuser=0):
usertochange = User.objects.get(pk=pk)
user_fullname = usertochange.first_name + " " + usertochange.last_name
parentuser = ""
if(usertochange.profile.parent != None):
parentuser = usertochange.profile.parent.pk
if request.method == 'POST':
if 'image' in request.FILES:
usertochange.profile.image = request.FILES['image']
formtosave = False
formtosave = UserProfileForm(request.POST, instance=usertochange.profile)
if formtosave.is_valid():
try:
usertochange.profile.parent = User.objects.get(pk=request.POST['usertoparent'], profile__agency=request.user.profile.agency)
usertochange.save()
except Exception as e:
usertochange.profile.parent = None
usertochange.save()
formtosave.save()
messages.success(request, f'Profil gespeichert!')
return redirect('dasettings')
else:
messages.success(request, f'Fehlerhafte Eingabe!')
context = {
'active_link' : 'dasettings',
'user_fullname' : user_fullname,
'newuser' : newuser,
'vieweduser' : usertochange.pk,
'parentuser' : parentuser,
'mail' : usertochange.email,
'imagelink' : usertochange.profile.get_photo_url,
'profileform' : UserProfileForm(instance=usertochange.profile),
'usertoparent' : User.objects.filter(profile__agency__pk=usertochange.profile.agency.pk, profile__visible=True)
}
return render(request, 'dasettings/user_usprof.html', context)
else:
context = {
'active_link' : 'dasettings',
'user_fullname' : user_fullname,
'newuser' : newuser,
'mail' : usertochange.email,
'vieweduser' : usertochange.pk,
'imagelink' : usertochange.profile.get_photo_url,
'profileform' : UserProfileForm(instance=usertochange.profile),
'parentuser' : parentuser,
'usertoparent' : User.objects.filter(profile__agency__pk=usertochange.profile.agency.pk, profile__visible=True),
'agencygroups' : AgencyGroup.objects.filter(agency__pk=usertochange.profile.agency.pk).order_by("agencygroupname")
}
return render(request, 'dasettings/user_usprof.html', context)
# View zur Veränderung der Stammdaten des Benutzers
@login_required
def UserChangeMain(request, pk):
usertochange = User.objects.get(pk=pk, profile__agency=request.user.profile.agency)
user_fullname = usertochange.first_name + " " + usertochange.last_name
if request.method == 'POST':
formtosave = UserNewUserForm(request.POST, instance=usertochange)
if formtosave.is_valid():
formtosave.save()
formtosave.save()
messages.success(request, f'Stammdaten aktualisiert!')
return redirect('dasettings')
else:
messages.success(request, f'Fehlerhafte Eingabe! Mailadresse bereits vorhanden!')
context = {
'active_link' : 'dasettings',
'user_fullname' : user_fullname,
'userform' : UserNewUserForm(request.POST, instance=usertochange),
}
return render(request, 'dasettings/user_changemaindata.html', context)
else:
context = {
'active_link' : 'dasettings',
'user_fullname' : user_fullname,
'userform' : UserNewUserForm(instance=usertochange),
}
return render(request, 'dasettings/user_changemaindata.html', context)
# Method for first User-Creation-Step
@login_required
def NewUserFirstStep(request):
context = {
'active_link' : 'dasettings'
}
if request.method == 'POST':
newuserform = UserNewUserForm(request.POST)
if newuserform.is_valid():
if(request.POST.get("sendmailnewuser")):
send_mail(
request.user.profile.agency.name + ' Account',
'Hallo ' + newuserform.cleaned_data.get('first_name') + ' ' + newuserform.cleaned_data.get('last_name') + '! Bitte setzen sie sich auf https://digitale-agentur.com/password-reset/ ein Passwort.',
'support@digitale-agentur.com',
[newuserform.cleaned_data.get('email')],
html_message=msg_html,
fail_silently=False,
)
newuser = newuserform.save(commit=False)
newuser.username = newuser.email
newprofile = Profile(agency=request.user.profile.agency, parent=None)
newprofile.save()
newuser.profile = newprofile
newuser.save()
newuser_id = newuser.id
messages.success(request, f'Benutzer angelegt!')
getadmingroup = AgencyGroup.objects.filter(savefordel=True, is_admin=False, agency=request.user.profile.agency)
for g in getadmingroup:
g.group.user_set.add(newuser)
return redirect('/dasettings/usprof/'+str(newuser_id)+'/1')
else:
messages.success(request, f'Daten falsch eingegeben!')
context['newuserform'] = UserNewUserForm(request.POST)
return render(request, 'dasettings/user_newuser_step1.html', context)
# Returning the data from database for normal-loading Settings
else:
newuserform = UserNewUserForm()
context.update({'newuserform' : newuserform})
return render(request, 'dasettings/user_newuser_step1.html', context)

0
notificsys/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

3
notificsys/admin.py Normal file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

5
notificsys/apps.py Normal file
View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class NotificsysConfig(AppConfig):
name = 'notificsys'

View File

@ -0,0 +1,31 @@
# Generated by Django 3.0.2 on 2020-02-09 15:35
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='UserNotification',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('notificationtype', models.CharField(blank=True, max_length=60)),
('wassend', models.BooleanField(default=False)),
('wasviewed', models.BooleanField(default=False)),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('notificationtext', models.CharField(blank=True, max_length=200)),
('fromuser', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='fromuser', to=settings.AUTH_USER_MODEL)),
('touser', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='touser', to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 3.0.2 on 2020-02-09 16:06
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('notificsys', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='usernotification',
name='fromuser',
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 3.0.2 on 2020-02-09 16:20
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('notificsys', '0002_remove_usernotification_fromuser'),
]
operations = [
migrations.AlterField(
model_name='usernotification',
name='touser',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.0.2 on 2020-02-09 21:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('notificsys', '0003_auto_20200209_1620'),
]
operations = [
migrations.AddField(
model_name='usernotification',
name='elementid',
field=models.IntegerField(blank=True, default=None, null=True),
),
]

View File

27
notificsys/models.py Normal file
View File

@ -0,0 +1,27 @@
from django.db import models
from django.utils import timezone
from datetime import datetime, timedelta
from django.contrib.auth.models import User
# Create your models here.
'''
class UserNotification
Model für Benachrichtigungen
'''
class UserNotification(models.Model):
# Wenn der User gelöscht wird, wird auch die Notification entfernt
touser = models.ForeignKey(User, on_delete=models.CASCADE)
notificationtype = models.CharField(max_length=60, blank=True)
# Notifcaton was send or not (for sound-update at the client)
wassend = models.BooleanField(default=False)
# Wurde gesehen
wasviewed = models.BooleanField(default=False)
created = models.DateTimeField(default=timezone.now)
elementid = models.IntegerField(default=None, null=True, blank=True)
# Eventuell automatisches Lösch-Datum
#willdeleted = models.DateTimeField(default=timezone.now()+timedelta(days=30))
# Textcontent
notificationtext = models.CharField(max_length=200, blank=True)

View File

@ -0,0 +1,87 @@
{% extends "users/base.html" %}
{% block content %}
<div class="content-section col-5">
<h3>Alle Benachrichtigungen</h3>
<hr>
<button href="#" class="btn btn-danger mb-2" data-toggle="tooltip" data-placement="top" title="Alle Benachrichtigung löschen" onclick="javascript:delNotify(false)">Alle Benachrichtigungen löschen</button>
{% for notification in usernotifications %}
<div class="card mb-2 notifydelclass" id="notify_{{notification.pk}}">
<div class="card-body">
<button href="#" class="btn btn-danger" style="float: right;" onclick="javascript:delNotify({{notification.pk}})"><i class="fas fa-trash-alt"></i></button>
<p class="card-text">
{% if notification.notificationtype == "agencynews" %}
<a href="/news/news/{{notification.elementid}}/single" class="" style="text-decoration: none; color: #000000">
{{notification.notificationtext}}
</a><br />
{% else %}
{{notification.notificationtext}}<br />
{% endif %}
<small>Am {{notification.created}}</small>
</div>
</div>
{% endfor %}
</div>
<!-- CONFIRMA DELETE ALL NOTIFICATIONS -->
<div class="modal fade" id="delAllNotifictaions" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="agencyDelFunction" aria-hidden="true">
<div class="modal-dialog " role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Alle Benachrichtigungen löschen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Schließen">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
Möchten Sie alle Benachrichtigungen löschen?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal" onclick="javascript:doDelAllNotifications()">Alle Benachrichtigungen löschen</button>&nbsp;&nbsp;
<button type="button" class="btn btn-success" data-dismiss="modal">Abbrechen</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var todelnotifyid = false;
function delNotify(notifydelid){
todelnotifyid = notifydelid;
if(!notifydelid){
$("#delAllNotifictaions").modal("toggle");
}
else{
$.ajax(
{
type: "GET",
url: "/notifications/delsingle",
data : {
action : "delsingle",
todelid : notifydelid
},
success: function( data )
{
$("#notify_" + todelnotifyid).remove();
}
});
}
}
function doDelAllNotifications(){
$.ajax(
{
type: "GET",
url: "/notifications/delall",
data : {
action : "delall"
},
success: function( data )
{
$(".notifydelclass").remove();
}
});
}
</script>
{% endblock content %}

View File

@ -0,0 +1,172 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<title> </title>
<!--[if !mso]><!-- -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--<![endif]-->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
#outlook a {
padding: 0;
}
body {
margin: 0;
padding: 0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table,
td {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
p {
display: block;
margin: 13px 0;
}
</style>
<!--[if mso]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<![endif]-->
<!--[if lte mso 11]>
<style type="text/css">
.mj-outlook-group-fix { width:100% !important; }
</style>
<![endif]-->
<!--[if !mso]><!-->
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet" type="text/css">
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Roboto:300,400,500,700);
</style>
<!--<![endif]-->
<style type="text/css">
@media only screen and (min-width:480px) {
.mj-column-per-100 {
width: 100% !important;
max-width: 100%;
}
}
</style>
<style type="text/css">
</style>
</head>
<body>
<div style="">
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td style="font-size:0px;padding:10px 25px;word-break:break-word;">
<p style="border-top:solid 4px #5a5c69;font-size:1;margin:0px auto;width:100%;"> </p>
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" style="border-top:solid 4px #5a5c69;font-size:1;margin:0px auto;width:550px;" role="presentation" width="550px"
>
<tr>
<td style="height:0;line-height:0;">
&nbsp;
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Roboto;font-size:20px;line-height:1;text-align:left;color:#000000;">
<h2>Digitale Agentur | Benachrichtigung</h2>
</div>
</td>
</tr>
<tr>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Roboto;font-size:18px;line-height:1;text-align:left;color:#000000;">
<p>Hallo {{username}},</p>
<p>{{notificationtext}}</p>
<p>Weitere Informationen erhalten Sie von Ihrem Agenturleiter. Vielen Dank, dass Sie die Plattform <b>Digitale Agentur</b> nutzen!</p>
<p>Mit freundlichen Grüßen</p>
<p>Ihr Team von Digitale Agentur</p>
</div>
</td>
</tr>
<tr>
<td style="font-size:0px;padding:10px 25px;word-break:break-word;">
<p style="border-top:solid 4px #5a5c69;font-size:1;margin:0px auto;width:100%;"> </p>
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" style="border-top:solid 4px #5a5c69;font-size:1;margin:0px auto;width:550px;" role="presentation" width="550px"
>
<tr>
<td style="height:0;line-height:0;">
&nbsp;
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</div>
</body>
</html>

3
notificsys/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

11
notificsys/urls.py Normal file
View File

@ -0,0 +1,11 @@
from django.urls import path
from .views import CheckNotifications, GetBasicNotifications, ShowAllNotifications, ChangeNotificationsToViewed, delAllNotification, delSingleNotification
urlpatterns = [
path('checknotifications/', CheckNotifications, name='checknotifications'),
path('getnotifications/', GetBasicNotifications, name='getnotifications'),
path('showallnotificaions/', ShowAllNotifications, name='showallnotificaions'),
path('newnotificationsviewed/', ChangeNotificationsToViewed, name='newnotificationsviewed'),
path('delsingle/', delSingleNotification, name='delsinglenotification'),
path('delall/', delAllNotification, name='delall'),
]

108
notificsys/views.py Normal file
View File

@ -0,0 +1,108 @@
from django.shortcuts import render
from django.http import HttpResponseRedirect,HttpResponse, JsonResponse
from .models import UserNotification
from django.views import generic
from django.contrib.auth.decorators import login_required
# Create your views here.
@login_required
def CheckNotifications(request):
if request.method == 'GET':
if request.GET['action'] == 'checknotifications':
#print("HERE WE ARE")
unknownnotification = UserNotification.objects.filter(touser__pk=request.user.pk, wassend=False).order_by('-created')[:5]
data = {};
i = 0
for notify in unknownnotification:
elelink = "notifications/showallnotificaions/"
if notify.notificationtype == "agencynews":
elelink = "news/news/" + str(notify.elementid) + "/single"
formatedDate = notify.created.strftime("%d.%m.20%y um %H:%M")
data.update({ i : {
"not_id" : notify.pk,
"type": notify.notificationtype,
"date" : formatedDate,
"text" : notify.notificationtext,
"elelink" : elelink
}})
i += 1
notify.save()
return JsonResponse({"unknownnotification" : data})
# Create your views here.
@login_required
def GetBasicNotifications(request):
if request.method == 'GET':
if request.GET['action'] == 'oldnotifications':
#print("HERE WE ARE")
oldnotifications = UserNotification.objects.filter(touser__pk=request.user.pk, wassend=True, wasviewed=False).order_by('-created')[:5]
data = {};
i = 0
for notify in oldnotifications:
elelink = "notifications/showallnotificaions/"
if notify.notificationtype == "agencynews":
elelink = "news/news/" + str(notify.elementid) + "/single"
formatedDate = notify.created.strftime("%d.%m.20%y um %H:%M")
data.update({ i : {
"not_id" : notify.pk,
"type": notify.notificationtype,
"date" : formatedDate,
"text" : notify.notificationtext,
"elelink" : elelink
}})
i += 1
notify.save()
return JsonResponse({"oldnotifications" : data})
@login_required
def ShowAllNotifications(request):
context ={}
context["usernotifications"] = UserNotification.objects.filter(touser__pk=request.user.pk).order_by('-created')
return render(request, "notificsys/allnotifications.html", context)
@login_required
def ChangeNotificationsToViewed(request):
if request.method == 'GET':
if request.GET['action'] == 'newnotificationsviewed':
oldnotifications = UserNotification.objects.filter(touser__pk=request.user.pk, wassend=False, wasviewed=False).order_by('-created')[:5]
data = {};
i = 0
for notify in oldnotifications:
formatedDate = notify.created.strftime("%d.%m.20%y um %H:%M")
data.update({ i : {
"not_id" : notify.pk,
"type": notify.notificationtype,
"date" : formatedDate,
"text" : notify.notificationtext
}})
i += 1
notify.wassend = True
notify.save()
return JsonResponse({})
@login_required
def delSingleNotification(request):
if request.method == 'GET':
if request.GET['action'] == 'delsingle':
todelnotification = UserNotification.objects.get(pk=request.GET['todelid'])
todelnotification.delete()
return JsonResponse({})
@login_required
def delAllNotification(request):
if request.method == 'GET':
if request.GET['action'] == 'delall':
todelnotification = UserNotification.objects.filter(touser__pk=request.user.pk).delete()
return JsonResponse({})

25
re.txt Normal file
View File

@ -0,0 +1,25 @@
Django==3.0.2
django-appconf==1.0.3
django-bootstrap-datepicker-plus==3.0.5
django-cleanup==4.0.0
django-colorful==1.3
django-crispy-forms==1.8.1
django-image-cropping==1.3.0
django-js-asset==1.2.2
django-jsonfield==1.3.1
django-mathfilters==0.4.0
django-mptt==0.11.0
django-polymorphic==2.0.3
django-redis==4.11.0
django-staticfiles==1.2.1
django-summernote==0.8.11.6
django-templatetags==1.1
django-user-agents==0.4.0
djangorestframework==3.11.0
easy-thumbnails==2.7
mysqlclient==1.4.6
Pillow==6.2.1
requests==2.22.0
requests-oauthlib==1.3.0
user-agents==2.1
webcolors==1.10

View File

@ -0,0 +1,7 @@
{% extends "users/base.html" %}
{% block content %}
<div class="content-section col-12">
<h3>Auf diesen Standard haben Sie keinen Zugriff!</h3>
<hr>
</div>
{% endblock %}

View File

@ -0,0 +1,88 @@
/*!
*
* ColorPick jQuery plugin
* https://github.com/philzet/ColorPick.js
*
* Copyright (c) 2017-2019 Phil Zet (a.k.a. Phil Zakharchenko)
* Licensed under the MIT License
*
*/
@font-face {
font-family: "Open Sans";
font-style: normal;
font-weight: 400;
src: local("Open Sans"), local("OpenSans"),
url(https://fonts.gstatic.com/s/opensans/v13/cJZKeOuBrn4kERxqtaUH3bO3LdcAZYWl9Si6vvxL-qU.woff)
format("woff");
}
@font-face {
font-family: "Open Sans";
font-style: normal;
font-weight: 700;
src: local("Open Sans Bold"), local("OpenSans-Bold"),
url(https://fonts.gstatic.com/s/opensans/v13/k3k702ZOKiLJc3WVjuplzKRDOzjiPcYnFooOUGCOsRk.woff)
format("woff");
}
#colorPick * {
-webkit-transition: all linear 0.2s;
-moz-transition: all linear 0.2s;
-ms-transition: all linear 0.2s;
-o-transition: all linear 0.2s;
transition: all linear 0.2s;
}
#colorPick {
background: rgba(255, 255, 255, 0.85);
-webkit-backdrop-filter: blur(15px);
position: absolute;
border-radius: 5px;
box-shadow: 0px 3px 8px rgba(0, 0, 0, 0.2);
padding: 15px;
font-family: "Open Sans", sans-serif;
width: 140px;
}
#colorPick span {
font-size: 9pt;
text-transform: uppercase;
font-weight: bold;
color: #bbb;
margin-bottom: 5px;
display: block;
clear: both;
}
.customColorHash {
border-radius: 5px;
height: 23px;
width: 122px;
margin: 1px 4px;
padding: 0 4px;
border: 1px solid #babbba;
outline: none;
}
.customColorHash.error {
border-color: #ff424c;
color: #ff424c;
}
.colorPickButton {
border-radius: 5px;
width: 20px;
height: 20px;
margin: 0px 3px;
cursor: pointer;
display: inline-block;
border: thin solid #eee;
}
.colorPickButton:hover {
transform: scale(1.1);
}
.colorPickDummy {
background: #fff;
border: 1px dashed #bbb;
}

View File

@ -0,0 +1,24 @@
*, *:before, *:after {box-sizing: border-box;}
ul, ol {margin: 0; padding: 0;}
li {list-style: none; line-height: 1.6rem;}
/* List styling */
.jslists{
font-size: 1.3rem;
font-family: Arial, Helvetica, sans-serif;
}
.jslist-ul, .jslist-ol, .jslist-li {margin-left: 12px;} /* Unordered lists */
.jsl-collapsed {display: none;}
.jsl-list-closed {
float: left;
clear: both;
margin: 2px 4px 2px 0px;
width: 18px;
height: 18px;
cursor: pointer;
background-image: url('data:image/svg+xml;utf8,<svg aria-hidden="true" data-prefix="far" data-icon="plus-square" class="svg-inline--fa fa-plus-square fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M352 240v32c0 6.6-5.4 12-12 12h-88v88c0 6.6-5.4 12-12 12h-32c-6.6 0-12-5.4-12-12v-88h-88c-6.6 0-12-5.4-12-12v-32c0-6.6 5.4-12 12-12h88v-88c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v88h88c6.6 0 12 5.4 12 12zm96-160v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"></path></svg>');
background-repeat: no-repeat;
background-position: center;
}
.jsl-open {display: block;}
.jsl-list-open {background-image: url('data:image/svg+xml;utf8,<svg aria-hidden="true" data-prefix="far" data-icon="minus-square" class="svg-inline--fa fa-minus-square fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M108 284c-6.6 0-12-5.4-12-12v-32c0-6.6 5.4-12 12-12h232c6.6 0 12 5.4 12 12v32c0 6.6-5.4 12-12 12H108zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"></path></svg>');}

View File

@ -0,0 +1,163 @@
/*!
*
* ColorPick jQuery plugin
* https://github.com/philzet/ColorPick.js
*
* Copyright (c) 2017-2019 Phil Zet (a.k.a. Phil Zakharchenko)
* Licensed under the MIT License
*
*/
(function( $ ) {
$.fn.colorPick = function(config) {
return this.each(function() {
new $.colorPick(this, config || {});
});
};
$.colorPick = function (element, options) {
options = options || {};
this.options = $.extend({}, $.fn.colorPick.defaults, options);
if(options.str) {
this.options.str = $.extend({}, $.fn.colorPick.defaults.str, options.str);
}
$.fn.colorPick.defaults = this.options;
this.color = this.options.initialColor.toUpperCase();
this.element = $(element);
var dataInitialColor = this.element.data('initialcolor');
if (dataInitialColor) {
this.color = dataInitialColor;
this.appendToStorage(this.color);
}
var uniquePalette = [];
$.each($.fn.colorPick.defaults.palette.map(function(x){ return x.toUpperCase() }), function(i, el){
if($.inArray(el, uniquePalette) === -1) uniquePalette.push(el);
});
this.palette = uniquePalette;
return this.element.hasClass(this.options.pickrclass) ? this : this.init();
};
$.fn.colorPick.defaults = {
'initialColor': '#3498db',
'paletteLabel': 'Farbauswahl',
'allowRecent': true,
'recentMax': 5,
'allowCustomColor': false,
'palette': ["#1abc9c", "#16a085", "#2ecc71", "#27ae60", "#3498db", "#2980b9", "#9b59b6", "#8e44ad", "#34495e", "#2c3e50", "#f1c40f", "#f39c12", "#e67e22", "#d35400", "#e74c3c", "#c0392b", "#ecf0f1", "#bdc3c7", "#95a5a6", "#7f8c8d"],
'onColorSelected': function() {
this.element.css({'backgroundColor': this.color, 'color': this.color});
}
};
$.colorPick.prototype = {
init : function(){
var self = this;
var o = this.options;
$.proxy($.fn.colorPick.defaults.onColorSelected, this)();
this.element.click(function(event) {
event.preventDefault();
self.show(event.pageX, event.pageY);
$('.customColorHash').val(self.color);
$('.colorPickButton').click(function(event) {
self.color = $(event.target).attr('hexValue');
self.appendToStorage($(event.target).attr('hexValue'));
self.hide();
$.proxy(self.options.onColorSelected, self)();
return false;
});
$('.customColorHash').click(function(event) {
return false;
}).keyup(function (event) {
var hash = $(this).val();
if (hash.indexOf('#') !== 0) {
hash = "#"+hash;
}
if (/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hash)) {
self.color = hash;
self.appendToStorage(hash);
$.proxy(self.options.onColorSelected, self)();
$(this).removeClass('error');
} else {
$(this).addClass('error');
}
});
return false;
}).blur(function() {
self.element.val(self.color);
$.proxy(self.options.onColorSelected, self)();
self.hide();
return false;
});
$(document).on('click', function(event) {
self.hide();
return true;
});
return this;
},
appendToStorage: function(color) {
if ($.fn.colorPick.defaults.allowRecent === true) {
var storedColors = JSON.parse(localStorage.getItem("colorPickRecentItems"));
if (storedColors == null) {
storedColors = [];
}
if ($.inArray(color, storedColors) == -1) {
storedColors.unshift(color);
storedColors = storedColors.slice(0, $.fn.colorPick.defaults.recentMax)
localStorage.setItem("colorPickRecentItems", JSON.stringify(storedColors));
}
}
},
show: function(left, top) {
$("#colorPick").remove();
$("#mainmodalArea").append('<div id="colorPick" style="display:none;top:' + top + 'px;left:' + left + 'px"><span>'+$.fn.colorPick.defaults.paletteLabel+'</span></div>');
jQuery.each(this.palette, function (index, item) {
$("#colorPick").append('<div class="colorPickButton" hexValue="' + item + '" style="background:' + item + '"></div>');
});
if ($.fn.colorPick.defaults.allowCustomColor === true) {
$("#colorPick").append('<input type="text" style="margin-top:5px" class="customColorHash" />');
}
if ($.fn.colorPick.defaults.allowRecent === true) {
$("#colorPick").append('<span style="margin-top:5px">Kürzlich</span>');
if (JSON.parse(localStorage.getItem("colorPickRecentItems")) == null || JSON.parse(localStorage.getItem("colorPickRecentItems")) == []) {
$("#colorPick").append('<div class="colorPickButton colorPickDummy"></div>');
} else {
jQuery.each(JSON.parse(localStorage.getItem("colorPickRecentItems")), function (index, item) {
$("#colorPick").append('<div class="colorPickButton" hexValue="' + item + '" style="background:' + item + '"></div>');
if (index == $.fn.colorPick.defaults.recentMax-1) {
return false;
}
});
}
}
$("#colorPick").fadeIn(200);
},
hide: function() {
$( "#colorPick" ).fadeOut(200, function() {
$("#colorPick").remove();
return this;
});
},
};
}( jQuery ));

View File

@ -0,0 +1,181 @@
/*
* JSLists v0.4.5
* © 2016 George Duff
*
* Release date: 01/06/2016
* The MIT License (MIT)
* Copyright (c) 2016 George Duff
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// TO DO LIST - Will get round to most of them at some point!
// Add folder & file icons dynamically from param
// Collapse All & Open All are ropey at best!
// Add a search function
// Make the margins user definable
// Add support for UL & OL
var blackCircle = '&#9679; ';
var openCircle = '&#9678; ';
(function() {
"use strict";
function define_JSLists() {
var JSLists = {};
var JSLists_Error = function(error, alertType) {
console.log(error);
}
var getUl = function(){
return document.getElementsByTagName("UL");
};
var getOl = function(){
return document.getElementsByTagName("OL");
};
var getAllLists = function(){
var olLists = Array.prototype.slice.call(document.getElementsByTagName("UL")),
ulLists = Array.prototype.slice.call(document.getElementsByTagName("OL"))
var gLists = olLists.concat(ulLists);
return gLists;
}
JSLists.searchList = function(listId, searchTerm) {
var i, j, lilNodes, liItems = document.getElementsByTagName("LI");
for(i=0; i<liItems.length; i++) {
if(liItems[i].hasChildNodes()) {
for(j=0; j<liItems[i].childNodes.length; j++) {
if(liItems[i].childNodes[j].innerHTML == searchTerm) {
//?????
}
}
}
}
}
JSLists.collapseAll = function(listId) {
var i, ulLists = document.getElementsByTagName("UL");
for(i=0; i<ulLists.length; i++) {
if(ulLists[i].className == "jsl-collapsed") {
console.log(ulLists[i].className + '\n' + '@');
}
};
};
JSLists.openAll = function(listId){
var i, olLists = Array.prototype.slice.call(document.getElementsByTagName("UL")),
ulLists = Array.prototype.slice.call(document.getElementsByTagName("OL"))
var gLists = olLists.concat(ulLists);
for(i=1; i<gLists.length; i++) {
gLists[i].setAttribute('class', 'jsl-open');
};
};
JSLists.padUnorderedLists = function(listId) {
var i, listItems = document.getElementById(listId).getElementsByTagName("UL");
for(i=0; i<listItems.length; i++) {
listItems[i].classList.add('jslist-ul');
}
};
JSLists.padOrderedLists = function(listId) {
var i, listItems = document.getElementById(listId).getElementsByTagName("UL");
for(i=0; i<listItems.length; i++) {
listItems[i].classList.add('jslist-ol');
}
};
JSLists.padLists = function(listId) {
var i, listItems = document.getElementById(listId).getElementsByTagName("LI");
for(i=0; i<listItems.length; i++) {
if(listItems[i].childNodes[0].className != "jsl-collapsed-arrow") {
listItems[i].classList.add('jslist-li');
}
}
for(i=1; i<listItems.length; i++) {
// console.log(listItems[i].childNodes.length);
if(listItems[i].classList = "jslist-li" && listItems[i].childNodes.length < 2) {
listItems[i].innerHTML = blackCircle + listItems[i].innerHTML
}
}
this.padUnorderedLists(listId);
this.padOrderedLists(listId);
};
JSLists.createTree = function(listId, bulletPoint) {
document.getElementById(listId).style.display = "none;"
var i, j, curElem, ulCount, olCount, listItems = document.getElementById(listId).getElementsByTagName('LI'); //this should be the main parent
for(i=0; i<listItems.length; i++) {
if(listItems[i].id.length > 0) {
curElem = document.getElementById(listItems[i].id);
ulCount = document.getElementById(listItems[i].id).getElementsByTagName("UL");
if(ulCount.length > 0){
for(j=0; j<ulCount.length; j++) {
if(ulCount[j].nodeName == "UL") {
break;
}
}
ulCount[j].setAttribute('class', 'jsl-collapsed');
var tglDiv = document.createElement("div");
tglDiv.setAttribute('class', 'jsl-list-closed');
tglDiv.setAttribute("id", listItems[i].id + i +'_tgl');
curElem.insertBefore(tglDiv, curElem.childNodes[0]);
document.getElementById(listItems[i].id + i +'_tgl').addEventListener('click', function(e) {
document.getElementById(e.target.id).classList.toggle('jsl-list-open');
document.getElementById(e.target.id).parentElement.lastElementChild.classList.toggle('jsl-open');
e.stopPropagation();
},true);
}
} else {
listItems[i].setAttribute("id", listId+"tmp"+i);
curElem = document.getElementById(listId+"tmp"+i);
ulCount = document.getElementById(listItems[i].id).getElementsByTagName("UL");
if(ulCount.length > 0) { //There is a nested UL in this LI element, now find the position of the UL
for(j=0; j<ulCount.length; j++) {
if(ulCount[j].nodeName == "UL") {
break; //Multiple UL's? //Set class collapseAll here
}
}
ulCount[j].setAttribute('class', 'jsl-collapsed');
var tglDiv = document.createElement("div");
tglDiv.setAttribute('class', 'jsl-list-closed');
tglDiv.setAttribute("id", listItems[i].id + i +'_tgl');
curElem.insertBefore(tglDiv, curElem.childNodes[0]);
document.getElementById(listItems[i].id + i +'_tgl').addEventListener('click', function(e){
document.getElementById(e.target.id).classList.toggle('jsl-list-open');
document.getElementById(e.target.id).parentElement.lastElementChild.classList.toggle('jsl-open');
e.stopPropagation();
},true);
}
listItems[i].removeAttribute("id");
}
}
setTimeout(function() {
document.getElementById(listId).style.display = "block;"
}, 50); // stops FOUC!
this.padLists(listId);
};
// JSLists.applyToList = function(listId, listType, applyIcons, applyTheme, themeNumber){
//Check the params here
// does the id exist?
JSLists.applyToList = function(listId, bulletPoint) {
this.createTree(listId, "UL");
};
return JSLists;
}
//define the JSLists library in the global namespace if it doesn't already exist
if(typeof(JSLists) === 'undefined') {
window.JSLists = define_JSLists();
}else{
console.log("JSLists already defined.");
}
})();

View File

@ -0,0 +1,31 @@
{% extends "users/base.html" %}
{% block content %}
<div class="content-section col-12">
<h3>Agentur <b>{{ request.user.profile.agency.name }}</b></h3>
<hr>
<div class="col-md-6">
<h6><b>Inhaber</b></h6>
<p>
{{ request.user.profile.agency.inhaber }}
</p>
<h6><b>Adresse</b></h6>
<p>
{{ request.user.profile.agency.street }}
</p>
<p>
{{ request.user.profile.agency.plz }} {{ request.user.profile.agency.city }}
</p>
<h6><b>Kontaktdaten</b></h6>
<p>
{{ request.user.profile.agency.agency_email }}
</p>
<p>
{{ request.user.profile.agency.phone }}
</p>
<h6><b>Agenturbild</b></h6>
<p>
<img class="img-profile" width="75%" src="{{ request.user.profile.agency.get_photo_url }}">
</p>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,23 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<!-- Für das Speichern der Bilder enctype -->
<div class="col-7">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">
Agenturinformationen bearbeiten
</legend>
<!-- FORMS LADEN -->
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button type="submit" class="btn btn-success">Speichern</button>&nbsp;
<a href="{% url 'agencyinfo' %}" class="btn">Abbrechen</a>
</div>
</form>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,62 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="img-profile " width="17%" src="{{ user.profile.get_photo_url }}">
<div class="media-body col-5">
<h2 class="account-heading">Profil von {{ user.first_name }} {{ user.last_name }}</h2>
<hr>
<div class="row">
<div class="col-6">
<h6><b>Name</b></h6>
<p>
{{ user.first_name }} {{ user.last_name }}
</p>
<h6><b>E-Mail</b></h6>
<p>
{{ user.email }}
</p>
<h6><b>Agenturfunktion</b></h6>
<p>
{{ user.profile.get_func_display }}
</p>
</div>
<div class="col-6">
<h6><b>Tätigkeit</b></h6>
<p>
{{ user.profile.compfunc }}
</p>
<h6><b>Festnetz</b></h6>
<p>
{{ user.profile.phoneland }}
</p>
<h6><b>Mobil</b></h6>
<p>
{{ user.profile.phonemobile }}
</p>
</div>
</div>
</div>
</div>
<!-- Für das Speichern der Bilder enctype -->
<div class="col-7 mt-5">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group mb-2">
<legend class="border-bottom mb-4">
Profil bearbeiten
</legend>
<!-- FORMS LADEN -->
{{ u_form|crispy }}
</fieldset>
<small>Agenturrelevante Daten werden in der Benutzerverwaltung verändert.</small>
<div class="form-group mt-3">
<button type="submit" class="btn btn-success">Speichern</button>&nbsp;
<a href="{% url 'users-management' %}" class="btn">Abbrechen</a>
</div>
</form>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,262 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% load static %}
{% block content %}
<script src="{% static 'users/js/cropper.min.js' %}"></script>
<script src="{% static 'users/js/jquery-cropper.js' %}"></script>
<div class="content-section">
<div class="media">
<img class="img-profile " id="profpic" width="17%" src="{{ prof_user.profile.get_photo_url }}">
<div class="media-body col-5">
<h2 class="account-heading">Profil von {{ prof_user.first_name }} {{ prof_user.last_name }}</h2>
<hr>
<div class="row mt-2">
<div class="col-md-6">
<h6><b>Name</b></h6>
<p>
{{ prof_user.first_name}} {{ prof_user.last_name }}
</p>
<h6><b>E-Mail</b></h6>
<p>
{{ prof_user.email }}
</p>
<h6><b>Agenturfunktion</b></h6>
<p>
{{ prof_user.profile.get_func_display }}
</p>
</div>
<div class="col-md-6">
<h6><b>Tätigkeit</b></h6>
<p>
{{ prof_user.profile.compfunc }}
</p>
<h6><b>Festnetz</b></h6>
<p>
{{ prof_user.profile.phoneland }}
</p>
<h6><b>Mobil</b></h6>
<p>
{{ prof_user.profile.phonemobile }}
</p>
</div>
</div>
</div>
</div>
<!-- Für das Speichern der Bilder enctype -->
<div class="col-7 mt-5">
<form method="POST" id="newprofiledata" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">
Profil bearbeiten
</legend>
<!-- FORMS LADEN -->
{{ profileform_form|crispy }}
<button type="button" id="" onclick="javascript:sendPassMail({{prof_user.pk}})" class="btn btn-success">E-Mail mit Link zur Passworterstellung senden</button>&nbsp;&nbsp;<span class="alert alert-success" id="mailsend" role="alert" style="display: none;">&nbsp;E-Mail gesendet!</span>
</fieldset>
Übergeordneter Mitarbeiter: <span id="ps_act">{{prof_user.profile.parent.first_name}} {{prof_user.profile.parent.last_name}}</span>
<div class="input-group mb-3">
<input class="form-control" name="puser" id="puser" list="parentuser" type="text" onkeyup="javascript:checkValueAddParent()">
<div class="input-group-append">
<button type="button" id="addusertouserp" onclick="javascript:addUserParentUser()" class="btn btn-success" disabled>Festlegen</button>
<button type="button" onclick="javascript:clearSearchfield()" class="btn btn-secondary" ><i class="fas fa-times"></i></button>
</div>
<datalist id="parentuser" nmae="parentuser">
{% for us in possible_users %}
<option id="{{us.pk}}" value="{{us.first_name}} {{us.last_name}}"></option>
{% endfor %}
</datalist>
</div>
<hr>
<div class="form-group">
<button type="submit" class="btn btn-success">Speichern</button>&nbsp;
<a href="{% url 'users-management' %}" class="btn">Abbrechen</a>
</div>
</form>
</div>
</div>
<!-- MODAL TO CROP THE IMAGE -->
<!-- MODAL TO CROP THE IMAGE -->
<div class="modal fade " id="modalCrop" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Bereich bestimmen</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="clearImgField()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" id="imgmodbody">
<img src="" id="imagemod" style="max-width: 100%; max-height: 100%;">
</div>
<div class="modal-footer">
<div class="btn-group pull-left" role="group">
<button type="button" class="btn btn-default js-zoom-in">
<span class="glyphicon glyphicon-zoom-in"></span>
</button>
<button type="button" class="btn btn-default js-zoom-out">
<span class="glyphicon glyphicon-zoom-out"></span>
</button>
</div>
<button type="button" class="btn btn-default" data-dismiss="modal" onclick="clearImgField()">Abbrechen</button>
<button type="button" class="btn btn-primary js-crop-and-upload">Ausschneiden</button>
</div>
</div>
</div>
</div>
{% block javascript %}
<script>
$("#id_x").val(0);
$("#id_y").val(0);
$("#id_width").val($("#profpic")[0]['naturalWidth']);
$("#id_height").val($("#profpic")[0]['naturalHeight']);
function clearImgField(){
$("#id_image").val("");
}
/* SCRIPT TO OPEN THE MODAL WITH THE PREVIEW */
$("#id_image").change(function () {
if (this.files && this.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$("#imagemod").attr("src", e.target.result);
$("#modalCrop").modal("show");
}
reader.readAsDataURL(this.files[0]);
}
});
var cropBoxData;
var canvasData;
var $image = $("#imagemod");
$("#modalCrop").on("shown.bs.modal", function () {
$image.cropper({
viewMode: 3,
aspectRatio: 1/1,
strict: false,
cropBoxMovable: true,
cropBoxResizable: true,
minCropBoxWidth: 200,
minCropBoxHeight: 200,
ready: function () {
$image.cropper("setCanvasData", canvasData);
$image.cropper("setCropBoxData", cropBoxData);
}
});
$("#imgmodbody").css({
"maxWidth": 465
});
}).on("hidden.bs.modal", function () {
cropBoxData = $image.cropper("getCropBoxData");
canvasData = $image.cropper("getCanvasData");
$image.cropper("destroy");
});
$(".js-zoom-in").click(function () {
$image.cropper("zoom", 0.1);
});
$(".js-zoom-out").click(function () {
$image.cropper("zoom", -0.1);
});
/* SCRIPT TO COLLECT THE DATA AND POST TO THE SERVER */
$(".js-crop-and-upload").click(function () {
var cropData = $image.cropper("getData");
$("#id_x").val(cropData["x"]);
$("#id_y").val(cropData["y"]);
$("#id_height").val(cropData["height"]);
$("#id_width").val(cropData["width"]);
$("#id_image").attr("src", $image);
$("#modalCrop").modal('toggle');
});
</script>
{% endblock %}
<script type="text/javascript">
var ua = window.navigator.userAgent;
var isIE = /MSIE|Trident/.test(ua);
if ( isIE ) {
//IE specific code goes here
setInterval(function()
{
checkValueAddParent();
},250);
}
//Call Function in view to send e-mail with pass-reset-data
function sendPassMail(id){
$.ajax(
{
type: "GET",
url: "/dashboard/sendpassmail",
data:{
userid : {{prof_user.pk}}
},
success: function( data )
{
if(data["message"] == 0){
$("#mailsend").fadeIn().delay(4000).fadeOut();
}
}
});
}
tempid = null;
function clearSearchfield(){
$("#puser").val("");
$("#addusertouserp").prop('disabled', true);
}
function addUserParentUser(){
$.ajax(
{
type: "GET",
url: "/dashboard/setuserparent",
data:{
userid: tempid,
action : 'adduserp',
objectid : {{prof_user.pk}}
},
success: function( data )
{
console.log(data);
clearSearchfield();
//Add User-Button
$("#ps_act").html(data['username_clean']);
$("#parentuser").empty();
for (var i in data['remaining_users']) {
id = data['remaining_users'][i]['id'];
name = data['remaining_users'][i]['first_name'] + " " + data['remaining_users'][i]['last_name'];
$("#parentuser").append('<option id="'+id+'" value="'+name+'"></option>');
}
}
});
}
function checkValueAddParent()
{
var g = $('#puser').val();
var id = $('#parentuser').find('option[value="' + g + '"]').attr('id');
if(id != undefined && id.length > 0){
tempid = id;
$("#addusertouserp").prop('disabled', false);
}
else{
tempid = null;
$("#addusertouserp").prop('disabled', true);
}
}
</script>
{% endblock content %}

View File

@ -0,0 +1,24 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section col-6">
<h3>Neuer Benutzer</h3>
<hr>
<!-- FORMS LADEN users/userforms.py und users/views.py -->
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<div class="form-check">
<input class="form-check-input" type="checkbox" value="true" id="sendmailnewuser" name="sendmailnewuser">
<label class="form-check-label" for="sendmailnewuser" name="sendmailnewuser">
E-Mailbenachrichtigung schicken
</label>
</div>
<small>*: Der Benutzer erhält direkt eine E-Mail mit einem Link zur Passworterstellung, wenn der Haken bei <i>E-Mailbenachrichtung schicken</i> gesetzt ist. Dies kann später auch wiederholt werden.</small>
<hr>
<button type="submit" class="btn btn-success" href="{% url 'users-adduser' %} ">Benutzer anlegen</button>&nbsp;
<a class="btn" href="{% url 'users-management' %} ">Abbrechen</a>
</form>
</div>
{% endblock content %}

View File

@ -0,0 +1,81 @@
{% extends "users/base.html" %}
{% block content %}
<div class="content-section col-12">
<h3>Benutzerverwaltung</h3>
<hr>
<p>
Erstellen Sie weitere Mitarbeiter ihrer Agentur. Die neuen Benutzer erhalten eine E-Mail mit einem entsprechenden Link, um ihr Passwort zu generieren.
</p>
<div class="row mb-3">
<div class="content-section col-4">
<a class="btn btn-primary" href="{% url 'users-adduser' %} ">Benutzer anlegen</a>
</div>
</div>
<div class="row">
<div class="form-group mb-2">
<input class="form-control" id="tableSearch" size="50" type="text" placeholder="Suche in Tabelle...">
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Benutzername</th>
<th scope="col">E-Mail</th>
<th scope="col">Agenturfunktion</th>
<th scope="col">Tätigkeit</th>
<th scope="col">Telefon</th>
<th scope="col">Mobil</th>
<th scope="col">&nbsp;</th>
</tr>
</thead>
<tbody id="tableresults">
{% for item in users_of_agency %}
<tr>
<td><a href="{% url 'orga-single' item.pk %}">{{item.first_name }} {{ item.last_name }}</a></td>
<td>{{ item.username }}</td>
<td>{{ item.email }}</td>
<td>{{ item.profile.get_func_display }}</td>
<td>{{ item.profile.compfunc }}</td>
<td>{{ item.profile.phoneland }}</td>
<td>{{ item.profile.phonemobile }}</td>
<td>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Benutzerdaten</div>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="{% url 'users-perm-update' item.profile.pk %}">Rechte</a>
<!--<div class="dropdown-header"></div>-->
<a class="dropdown-item" href="{% url 'users-areataskupdate' item.pk %}">Zuständigkeiten</a>
{% if item != request.user %}
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="{% url 'users-delete' item.pk %}" >Löschen</a>
{% endif %}
</div>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$("#tableSearch").on("keyup", function() {
var value = $(this).val().toLowerCase();
$("#tableresults tr").filter(function() {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
});
});
});
</script>
{% endblock content %}

View File

@ -0,0 +1,51 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<h3>Reihenfolge im Organigramm von {{ user_first_name }} {{ user_last_name }}</h3>
<small>Elemente mit einer größeren Zahl werden im Organigramm weiter oben angezeigt. Die Änderungen werden sofort gespeichert.</small>
<hr>
<div class="col-12">
{% for area in areas %}
<h4>Bereich {{ area.name }}</h4>
{% for prio in prios %}
{% if prio.task.area == area %}
<div class="form-group row">
<label for="{{forloop.counter}}" class="col-sm-2 col-form-label"><h5>{{ prio.task.name }}</h5></label>
<div class="col-sm-1" style="float:right" >
<input type="number" min="0" class="form-control" id="{{forloop.counter}}" value="{{ prio.prio}}" onkeyup="javascript:updatePrio({{prio.pk}}, {{prio.task.pk}}, this.value)" onchange="javascript:updatePrio({{prio.pk}}, {{prio.task.pk}}, this.value)"></div><span class="badge badge-success mt-1 mb-3" id="save_{{prio.pk}}" style="display: none; font-size: 0.8em;">Gespeichert</span>
</div>
{% endif %}
{% endfor%}
<hr>
{% endfor %}
</div>
<a href="{% url 'users-dashboard' %}" class="btn btn-success">Zum Dashboard</a>
</div>
<script type="text/javascript">
function updatePrio(prio, task, value)
{
console.log({{userprio.pk}} + " " + prio + " " + task + " VAL: " + value);
$.ajax(
{
type: "GET",
url: "/dashboard/prioupdate",
data:{
userid: {{user_id}},
prioid : 'adduser',
taskid : task,
value : value
},
success: function( data )
{
$('#save_'+prio).show();
setTimeout(function() {
$('#save_'+prio).fadeOut();
}, 1000 );
}
});
}
</script>
{% endblock content %}