- Sicherheitslücke beim ändern von Priorisierungen geschlossen, die angeforderte ID wird nun mit der Agency des eingeloggten USers verglichen

- Suche implementiert: Jetzt kann aus jeder Ansicht heraus sofort gesucht werden, man kann von den Ergebnissen des Standards direkt zum Standard gehen; Es wurd gesucht im Namen, COntext und Hersteller. Sollte die Suiche gelöscht werden sieht man die aktuelle Ansicht wieder
This commit is contained in:
holger.trampe 2019-12-06 18:04:58 +01:00
parent d1bebf51d4
commit 4b51d757e3
69 changed files with 211 additions and 57 deletions

View File

@ -7,6 +7,7 @@ from users.views import AgencyCreateView
from . import views from . import views
from ckeditor_uploader.views import upload from ckeditor_uploader.views import upload
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
''' '''
ADMINPAGE - Verwaltung der Super-User ADMINPAGE - Verwaltung der Super-User
- LOGIN-Page - LOGIN-Page

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Binary file not shown.

View File

@ -8,7 +8,10 @@
<tbody> <tbody>
<tr> <tr>
<td colspan="3" class="text-center"> <td colspan="3" class="text-center">
{% if leader != None %}
<a href="{% url 'orga-single' leader.pk %}"> <a href="{% url 'orga-single' leader.pk %}">
{% endif %}
<div> <div>
<img class="img-profile mb-2 " width="12%" src="{{ leader.profile.image.url }}"> <img class="img-profile mb-2 " width="12%" src="{{ leader.profile.image.url }}">
</div> </div>

View File

@ -4,11 +4,11 @@
<h3>Bereiche und Aufgaben von {{user_first_name}} {{user_last_name}}</h3> <h3>Bereiche und Aufgaben von {{user_first_name}} {{user_last_name}}</h3>
<hr> <hr>
<div class="media"> <div class="media">
<img class="img-profile" width="12%" src="{{ imageurl }}"> <img class="img-profile" width="12%" src="{{ imageurl }}" >
<div class="media-body col-7"> <div class="media-body">
<div class="row ml-2">
<div class="col-8"> <div class="col-3">
<h6><b>Name</b></h6> <h6><b>Name</b></h6>
<p> <p>
{{ user_first_name }} {{ user_last_name }} {{ user_first_name }} {{ user_last_name }}
@ -22,37 +22,56 @@
{{ mail }} {{ mail }}
</p> </p>
</div> </div>
<div class="col-md-3">
<h6><b>Tätigkeit</b></h6>
<p>
{{ compfunc }}
</p>
<h6><b>Festznetz</b></h6>
<p>
{{ phoneland }}
</p>
<h6><b>Mobil</b></h6>
<p>
{{ phonemobile }}
</p>
</div>
</div>
</div> </div>
</div> </div>
<hr>
<table class="table borderless mt-3"> <table class="table" id="orgasingle">
<tbody> <thead>
<tr > <tr >
{% for area in areas %} {% for area in areas %}
<td class="text-center" style="background-color: rgba({{area.color.0}},{{area.color.1}},{{area.color.2}}, 0.3); color: #ffffff"><h4 style="color: rgba(0,0,0, 1);"><b>{{area.name}}</b></h4></td> <td class="text-center" style="background-color: rgba({{area.color.0}},{{area.color.1}},{{area.color.2}}, 0.3); color: #ffffff"><h4 style="color: rgba(0,0,0, 1);"><b>{{area.name}}</b></h4></td>
<td>&nbsp;</td>
{% endfor %} {% endfor %}
</tr> </tr>
<tr style="background-color: {{area.hex}}"> </thead>
<tbody>
<tr>
{% for area in areas %} {% for area in areas %}
<td class="text-center"> <td class="text-center" style="background-color: rgba({{area.color.0}},{{area.color.1}},{{area.color.2}}, 0.3)">
{%for prio in prios %} {%for prio in prios %}
{% if prio.task.area.pk == area.pk %} {% if prio.task.area.pk == area.pk and prio.task.visible %}
<div style="background-color: rgba({{area.color.0}},{{area.color.1}},{{area.color.2}}, 1)" class="mb-2 p-2"> <div style="background-color: rgba({{area.color.0}},{{area.color.1}},{{area.color.2}}, 1)" class="mb-2 pt-3 pb-1">
<span style=" color: #FFFFFF;"><h5>{{prio.task.name}}</h5></span> <span style=" color: #FFFFFF;"><h6>{{prio.task.name}}</h6></span>
</div> </div>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</td><td>&nbsp;</td> </td>
{% endfor %} {% endfor %}
</tr> </tr>
</tbody> </tbody>
</table> </table>
<style>
#orgasingle {
border-collapse: separate;
border-spacing: 25px 0px;
}
</style>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -9,7 +9,11 @@ import webcolors
@login_required @login_required
def mainorga(request): def mainorga(request):
leader = list(User.objects.filter(profile__agency__pk=request.user.profile.agency.pk).filter(profile__func='lead'))[0] leader = list(User.objects.filter(profile__agency__pk=request.user.profile.agency.pk).filter(profile__func='lead'))
if len(leader) > 0:
leader = leader[0]
else:
leader = None
indoor = list(User.objects.filter(profile__agency__pk=request.user.profile.agency.pk).filter(profile__func='indoor')) indoor = list(User.objects.filter(profile__agency__pk=request.user.profile.agency.pk).filter(profile__func='indoor'))
external = list(User.objects.filter(profile__agency__pk=request.user.profile.agency.pk).filter(profile__func='external')) external = list(User.objects.filter(profile__agency__pk=request.user.profile.agency.pk).filter(profile__func='external'))
trainee = list(User.objects.filter(profile__agency__pk=request.user.profile.agency.pk).filter(profile__func='trainee')) trainee = list(User.objects.filter(profile__agency__pk=request.user.profile.agency.pk).filter(profile__func='trainee'))
@ -31,7 +35,11 @@ def mainorga(request):
@login_required @login_required
def singleorga(request, pk): def singleorga(request, pk):
user = User.objects.get(pk=pk) user = User.objects.get(pk=pk)
'''
VON GROß NACH KLEIN - SINNLOS
prios = Prio.objects.filter(user__pk=pk).order_by('-prio')[::-1] prios = Prio.objects.filter(user__pk=pk).order_by('-prio')[::-1]
'''
prios = Prio.objects.filter(user__pk=pk).order_by('-prio')
areas = list(Areas.objects.filter(agency__pk=request.user.profile.agency.pk)) areas = list(Areas.objects.filter(agency__pk=request.user.profile.agency.pk))
i = 0 i = 0
for area in areas: for area in areas:
@ -52,7 +60,10 @@ def singleorga(request, pk):
'prios' : prios, 'prios' : prios,
'mail' : user.email, 'mail' : user.email,
'userfunc' : user.profile.get_func_display, 'userfunc' : user.profile.get_func_display,
'imageurl' : user.profile.image.url 'imageurl' : user.profile.image.url,
'compfunc' : user.profile.compfunc,
'phoneland' : user.profile.phoneland,
'phonemobile' : user.profile.phonemobile
} }
return render(request, 'orga/orga_single.html', context) return render(request, 'orga/orga_single.html', context)

View File

@ -8,10 +8,10 @@ from django.contrib import messages
from django.http import HttpResponse, JsonResponse from django.http import HttpResponse, JsonResponse
from users.priomodel import Prio from users.priomodel import Prio
# Create your views here. # Create your views here.
class TasksManagement(LoginRequiredMixin, ListView): class TasksManagement(LoginRequiredMixin, ListView):
model = Tasks model = Tasks
# Adding active_link # Adding active_link
# Loading only user same agency # Loading only user same agency
# Change context and return for template-data # Change context and return for template-data

View File

@ -101,7 +101,7 @@
<hr class="sidebar-divider"> <hr class="sidebar-divider">
<!-- Heading --> <!-- Heading -->
<div class="sidebar-heading"> <div class="sidebar-heading">
Agenturverwaltung Agenturorga
</div> </div>
{%endif%} {%endif%}
@ -173,12 +173,14 @@
<!-- Topbar Search --> <!-- Topbar Search -->
<form class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search"> <form class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<div class="input-group"> <div class="input-group">
<input type="text" class="form-control bg-light border-0 small" placeholder="Suche..." aria-label="Suche" aria-describedby="basic-addon2"> <input type="text" onkeyup="javascript:startSearch(this.value)" class="form-control bg-light border-0 small" placeholder="Suche..." aria-label="Suche" aria-describedby="basic-addon2" id="searchfield">
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-primary" type="button"> <button class="btn btn-primary" type="button" onclick="javascript:clearSF()">
<i class="fas fa-search fa-sm"></i> <i class="fas fa-times fa-sm"></i>
</button> </button>
</div> </div>
</div> </div>
</form> </form>
@ -219,6 +221,8 @@
<!-- Begin Page Content --> <!-- Begin Page Content -->
<div class="container-fluid"> <div class="container-fluid">
<!-- RESULTS -->
<div id="searchresults_div"></div>
<!-- MESSAGES --> <!-- MESSAGES -->
{% if messages %} {% if messages %}
@ -239,9 +243,11 @@
</script> </script>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
<div id="maincontent_for_search">
{% block content %}
{% endblock %}
</div>
{% block content %}
{% endblock %}
</div> </div>
<!-- End of Main Content --> <!-- End of Main Content -->
@ -288,3 +294,67 @@
</body> </body>
</html> </html>
<script type="text/javascript">
function clearSF(){
$("#searchfield").val("");
$("#searchresults_div").empty();
$("#searchresults_div").hide();
$("#maincontent_for_search").show();
}
function startSearch(searchstring){
if(searchstring.length > 2){
$("#maincontent_for_search").hide();
$("#searchresults_div").show();
$.ajax(
{
type: "GET",
url: "/dashboard/globalsearch",
data:{
searchstring: searchstring
},
success: function( data )
{
$("#searchresults_div").empty();
if(data['res'].length > 1){
$("#searchresults_div").append('<h4>' + data['res'].length + ' Sucherergebnisse</h4><hr>');
}
else if(data['res'].length == 1){
$("#searchresults_div").append('<h4>' + data['res'].length + ' Sucherergebnis</h4><hr>');
}
else {
$("#searchresults_div").append('<h4>Keine Sucherergebnis</h4><hr>');
}
for (var i = 0; i < data['res'].length; i++)
{
$("#searchresults_div").append('<div class="mb-4"><div class="card"><div class="card-header py-3 d-flex flex-row align-items-center justify-content-between"><a href="/standards/standard/'+data['res'][i]['id']+'/single"><h5><u>'+data['res'][i]['name']+'</u></h5></a><div class="dropdown no-arrow"></div></div><div class="card-body"><h6 class="card-title">Von '+data['res'][i]['first_name']+' '+data['res'][i]['last_name']+' | <small>Zuletzt bearbeitet von '+data['res'][i]['first_name_mod']+' '+data['res'][i]['last_name_mod']+' am '+data['res'][i]['last_modified_on']+'</small></h6><p class="card-text">'+data['res'][i]['content']+'</p></div></div></div>');
}
}
});
}
else {
$("#searchresults_div").empty();
$("#searchresults_div").hide();
$("#maincontent_for_search").show();
}
}
function goToStandard(id){
$.ajax(
{
type: "GET",
url: "/dashboard/standardrout",
data:{
's_id': id
},
success (data){
console.log(data);
}
});
}
</script>

View File

@ -28,12 +28,11 @@
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" aria-labelledby="dropdownMenuLink"> <div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Benutzerdaten</div> <div class="dropdown-header">Benutzerdaten</div>
<a class="dropdown-item" href="{% url 'users-update' item.profile.pk %}">Bearbeiten</a> <a class="dropdown-item" href="{% url 'users-update' item.profile.pk %}">Bearbeiten</a>
<a class="dropdown-item" href="{% url 'users-perm-update' item.profile.pk %}">Rechte</a>
<a class="dropdown-item" href="{% url 'users-prio' item.pk %}">Priorisierung</a> <a class="dropdown-item" href="{% url 'users-prio' item.pk %}">Priorisierung</a>
<hr class="sidebar-divider"> <div class="dropdown-divider"></div>
<a class="dropdown-item" href="{% url 'users-perm-update' item.profile.pk %}">Rechte</a>
<!--<div class="dropdown-header"></div>--> <!--<div class="dropdown-header"></div>-->
<a class="dropdown-item" href="#">Bereiche</a> <a class="dropdown-item" href="#">Zuständigkeitenn</a>
<a class="dropdown-item" href="#">Aufgaben</a>
{% if item != request.user %} {% if item != request.user %}
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="{% url 'users-delete' item.pk %}" >Löschen</a> <a class="dropdown-item text-danger" href="{% url 'users-delete' item.pk %}" >Löschen</a>

View File

@ -3,7 +3,7 @@
{% block content %} {% block content %}
<div class="content-section"> <div class="content-section">
<h3>Priorisierung von {{ user_first_name }} {{ user_last_name }} verändern</h3> <h3>Priorisierung von {{ user_first_name }} {{ user_last_name }} verändern</h3>
<small>Elemente mit einer kleineren Zahl werden im Organigramm weiter oben angezeigt. Die Änderungen werden sofort gespeichert.</small> <small>Elemente mit einer größeren Zahl werden im Organigramm weiter oben angezeigt. Die Änderungen werden sofort gespeichert.</small>
<hr> <hr>
<div class="col-12"> <div class="col-12">
{% for area in areas %} {% for area in areas %}

View File

@ -24,7 +24,9 @@ urlpatterns = [
path('agencyinfo/', views.agency, name='agencyinfo'), path('agencyinfo/', views.agency, name='agencyinfo'),
path('agencyinfo/<int:pk>/', permission_required('users.agency_change')(AgencyUpdateView.as_view()), name='agency-manage'), path('agencyinfo/<int:pk>/', permission_required('users.agency_change')(AgencyUpdateView.as_view()), name='agency-manage'),
path('usersman/<int:pk>/prio', views.UsersPrio, name='users-prio'), path('usersman/<int:pk>/prio', views.UsersPrio, name='users-prio'),
path('prioupdate/', views.UsersPrioUpdate, name="users-prioupdate") path('prioupdate/', views.UsersPrioUpdate, name="users-prioupdate"),
path('globalsearch/', views.GlobalSearch, name="globalsearch"),
path('standardrout/', views.searchStandardRouter, name="standardrouter")
] ]

View File

@ -1,4 +1,4 @@
from django.shortcuts import render, redirect from django.shortcuts import render, redirect, reverse
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.conf import settings from django.conf import settings
@ -10,10 +10,13 @@ from django.db import models
from .models import Profile, Agency from .models import Profile, Agency
from django.core.mail import send_mail from django.core.mail import send_mail
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.http import HttpResponseRedirect,HttpResponse from django.http import HttpResponseRedirect,HttpResponse, JsonResponse
from areas.models import Areas from areas.models import Areas
from tasks.models import Tasks from tasks.models import Tasks
from .priomodel import Prio from .priomodel import Prio
from standards.models import Standards
from datetime import datetime
from django.utils import formats
''' '''
DASHBOARD-View DASHBOARD-View
@ -234,24 +237,31 @@ class AgencyUpdateView(LoginRequiredMixin, UpdateView):
''' '''
def UsersPrio(request, pk): def UsersPrio(request, pk):
user = User.objects.get(pk=pk) user = User.objects.get(pk=pk)
prios = Prio.objects.filter(user__pk=pk)
areas = Areas.objects.filter(agency__pk=request.user.profile.agency.pk) if(user.profile.agency.pk != request.user.profile.agency.pk):
user_first_name = user.first_name return HttpResponseRedirect('users-dashboard')
user_last_name = user.last_name else:
user_id = user.pk prios = Prio.objects.filter(user__pk=pk)
context = { areas = Areas.objects.filter(agency__pk=request.user.profile.agency.pk)
'active_link' : '', user_first_name = user.first_name
'areas' : areas, user_last_name = user.last_name
'user_first_name' : user_first_name, user_id = user.pk
'user_last_name' : user_last_name, context = {
'user_id' : user_id, 'active_link' : '',
'prios' : prios 'areas' : areas,
} 'user_first_name' : user_first_name,
return render(request, 'users/users_prio.html', context) 'user_last_name' : user_last_name,
'user_id' : user_id,
'prios' : prios
}
return render(request, 'users/users_prio.html', context)
def UsersPrioUpdate(request): def UsersPrioUpdate(request):
if request.method == 'GET': tempuser = User.objects.get(pk=request.GET['userid'])
if request.method == 'GET' and tempuser.profile.agency.pk == request.user.profile.agency.pk:
prio = Prio.objects.filter(user__pk=request.GET['userid']).filter(task__pk=request.GET['taskid']) prio = Prio.objects.filter(user__pk=request.GET['userid']).filter(task__pk=request.GET['taskid'])
prio = list(prio)[0] prio = list(prio)[0]
prio.prio = request.GET['value'] prio.prio = request.GET['value']
@ -260,3 +270,42 @@ def UsersPrioUpdate(request):
else: else:
return HttpResponse("Request method is not a GET") return HttpResponse("Request method is not a GET")
# Searxh for Standards by name, content, creator - standards needs to be public!
def GlobalSearch(request):
if request.method == 'GET':
searchfor = request.GET['searchstring']
results = {}
ag = request.user.profile.agency.pk
results = Standards.objects.filter(agency__pk=ag, public=True).filter(name__icontains=searchfor) | Standards.objects.filter(agency__pk=ag, public=True).filter(content__contains=searchfor) | Standards.objects.filter(agency__pk=ag, public=True).filter(area__name__icontains=searchfor) | Standards.objects.filter(agency__pk=ag, public=True).filter(task__name__icontains=searchfor) | Standards.objects.filter(agency__pk=ag, public=True).filter(created_standard_by__last_name__icontains=searchfor)|Standards.objects.filter(agency__pk=ag, public=True).filter(created_standard_by__first_name__icontains=searchfor)
results = list(results)
final_results = []
i = 0
for ele in results:
tempele = {}
tempele['id'] = ele.pk
tempele['name'] = ele.name
# First 100 chars of the Content
tempele['content'] = ele.content[:100]
tempele['first_name'] = ele.created_standard_by.first_name
tempele['last_name'] = ele.created_standard_by.last_name
tempele['first_name_mod'] = ele.last_modified_by.first_name
tempele['last_name_mod'] = ele.last_modified_by.last_name
tempele['created'] = formats.date_format(ele.created_standard_date, "d.m.Y")
tempele['last_modified_on'] = formats.date_format(ele.last_modified_on, "d.m.Y")
final_results.append(tempele)
i += 1
return JsonResponse({'res' : final_results})
else:
return HttpResponse("Request method is not a GET")
def searchStandardRouter(request):
if request.method == 'GET':
return redirect('/standards/standard/'+request.GET['s_id']+'/single')
else:
return redirect('dashboard')