zwischenpush

This commit is contained in:
holger.trampe 2020-02-18 22:34:27 +01:00
commit 919039201c
143 changed files with 2899 additions and 2966 deletions

4
.gitignore vendored
View File

@ -1,3 +1,4 @@
media/agencydata/*
media/agencymain/*
!media/agencymain/default.jpg
!media/agencymain/linkdefault.png
@ -31,4 +32,5 @@ users/migrations/*
!users/migrations/__init__.py
users/__pycache__/*
orga/__pycache__/*
orga/__pycache__/*

View File

@ -1,22 +0,0 @@
{% 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

@ -1,43 +0,0 @@
{% 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

@ -1,101 +0,0 @@
{% 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

@ -1,172 +0,0 @@
{% 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 %}

View File

@ -1,7 +1,7 @@
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 .views import AreasManagement, AreasAddArea, AreaDeleteView, AreaUpdateView
from . import views
'''
@ -12,11 +12,7 @@ Permissions definiert in models.py bei USERS und dann hier vor die View geschrie
'''
urlpatterns = [
path('', permission_required('users.areas_management')(AreasManagement.as_view(template_name="areas/areas_management.html")), name='areas-management'),
path('addarea/', permission_required('users.areas_management')(AreasAddArea.as_view(template_name="areas/areas_add.html")), name='areas-addarea'),
path('areas/<int:pk>/delete', permission_required('users.areas_management')(AreaDeleteView.as_view()), name='areas-delete'),
path('area/<int:pk>/', permission_required('users.areas_management')(AreaUpdateView.as_view()), name='areas-manage'),
path('areaajax/', views.area_addareas_ajax, name="area-ajaxview"),
path('areaajax/', views.area_addareas_ajax, name="area-ajaxview"),
path('updateorder/', views.area_neworder, name="area-ajaxorder")
]

View File

@ -7,129 +7,41 @@ from .forms import AreaAddAreaForm
from django.contrib.auth.models import User
from django.http import HttpResponse, JsonResponse
import json
from django.contrib.auth.decorators import login_required
class AreasManagement(LoginRequiredMixin, ListView):
model = Areas
# Adding active_link
# Loading only user same agency
# Change context and return for template-data
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# # Get all Users of the Same Agency as logged user
areas_of_agency = Areas.objects.filter(agency__pk=self.request.user.profile.agency.pk).order_by('areaorder')
context.update({'active_link' : 'areasmanagement', 'areas_of_agency':areas_of_agency})
return context
class AreasAddArea(LoginRequiredMixin, CreateView):
model = Areas
success_url = '/areas'
#fields = ['name', 'color', 'desc', 'usersfield']
form_class = AreaAddAreaForm
#def get(self,request,*args, **kwargs):
# # User ist der hier Aufgerufene, bzw. das Profil!
# return render (request, self.template_name, {'form':self.form_class(self.request.user), 'active_link': 'areasmanagement'})
# Adding active_link
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({'active_link' : 'areasmanagement'})
return context
def form_valid(self, form):
# Send message to the site
messages.success(self.request, f'Bereich angelegt!')
# SAVE OBJECTS TO SIGNALE!
form.instance.agency = self.request.user.profile.agency
form.instance.created_area_by = self.request.user
return super().form_valid(form)
class AreaDeleteView(LoginRequiredMixin, DeleteView):
model = Areas
success_url = '/areas'
template_name = 'areas/area_confirm_delete.html'
def delete(self, request, *args, **kwargs):
area = Areas.objects.get(pk=kwargs['pk'])
response = super(AreaDeleteView, self).delete(request, *args, **kwargs)
name = area.name
messages.success(request, f'Bereich ' +name+ ' wurde gelöscht!')
return response
def get_context_data(self, **kwargs):
context = super(AreaDeleteView, self).get_context_data(**kwargs)
context['active_link'] = 'areasmanagement'
return context
# Hier andere Nutzer ändern, wenn man Usersmanagement darf!
class AreaUpdateView(LoginRequiredMixin, UpdateView):
model = Areas
template_name = 'areas/areas_update.html'
success_url = '/areas'
form_class = AreaAddAreaForm
def form_valid(self, form):
# Send message to the site
messages.success(self.request, f'Bereich aktualisiert!')
print(form)
return super().form_valid(form)
# Form wird geladen; Checkboxen werden vorbereitet und hier rausgerendert.
#def get(self,request,*args, **kwargs):
# # User ist der hier Aufgerufene, bzw. das Profil!
# loggeduser = request.user
#
# return render (request, self.template_name, {'form':self.form_class(loggeduser), 'active_link': 'usersmanagement'})
def get_context_data(self, **kwargs):
context = super(AreaUpdateView, self).get_context_data(**kwargs)
area = Areas.objects.get(pk=context['object'].pk)
# User still in Area
context['added_users'] = area.usersfield.all()
# Get all Users from same Agency which are NOT in context_added_users
possible_users = User.objects.filter(profile__agency__pk=self.request.user.profile.agency.pk).exclude(pk__in=context['added_users'])
context['possible_users'] = possible_users
# Active-Link for Base-Design
context['active_link'] = 'areasmanagement'
# Area ID
context['objectid'] = context['object'].pk
return context
@login_required
def area_addareas_ajax(request):
if request.method == 'GET':
if request.method == 'GET':
# ADD USER TO MANY-TO-MANY USERSFIELD
if request.GET['action'] == 'adduser':
area = Areas.objects.get(pk=request.GET['objectid'])
area.usersfield.add(User.objects.get(pk=request.GET['userid']))
area.save()
if(area.agency == request.user.profile.agency):
area.usersfield.add(User.objects.get(pk=request.GET['userid']))
area.save()
# REMOVE USER TO MANY-TO-MANY USERSFIELD
elif request.GET['action'] == 'remuser':
area = Areas.objects.get(pk=request.GET['objectid'])
area.usersfield.remove(User.objects.get(pk=request.GET['userid']))
area.save()
if(area.agency == request.user.profile.agency):
area.usersfield.remove(User.objects.get(pk=request.GET['userid']))
area.save()
userid = request.GET['userid']
workinguser = User.objects.get(pk=userid)
username_clean = workinguser.first_name + " " + workinguser.last_name
# Getting Remaining-Users
area = Areas.objects.get(pk=request.GET['objectid'])
added_users = area.usersfield.all()
possible_users = User.objects.filter(profile__agency__pk=request.user.profile.agency.pk).exclude(pk__in=added_users)
possible_users_js = list(possible_users.values())
# Cleaned out, that only data is neede will send to the side (first/last-name and id)
final_possible_users = {}
for ele in possible_users_js:
final_possible_users.update({'first_name':ele['first_name'],'last_name':ele['last_name'],'id':ele['id']})
# Counter for remaining users to show/hide "Keine Mitarbeiter"-Div
remaining_users_counter = len(added_users)
return JsonResponse({'userid' : userid, 'username_clean' : username_clean, 'remaining_users':possible_users_js, 'remaining_users_counter' : final_possible_users})
if(area.agency == request.user.profile.agency):
added_users = area.usersfield.all()
possible_users = User.objects.filter(profile__agency__pk=request.user.profile.agency.pk).exclude(pk__in=added_users)
possible_users_js = list(possible_users.values())
# Cleaned out, that only data is neede will send to the side (first/last-name and id)
final_possible_users = {}
for ele in possible_users_js:
final_possible_users.update({'first_name':ele['first_name'],'last_name':ele['last_name'],'id':ele['id']})
# Counter for remaining users to show/hide "Keine Mitarbeiter"-Div
remaining_users_counter = len(added_users)
return JsonResponse({'userid' : userid, 'username_clean' : username_clean, 'remaining_users':possible_users_js, 'remaining_users_counter' : final_possible_users})
else:
return HttpResponse("Request method is not a GET")
@ -146,14 +58,16 @@ def area_addareas_ajax(request):
Save all areas after drag n drop elements in table
'''
@login_required
def area_neworder(request):
if request.method == 'GET':
if request.GET['action'] == 'newareaorder':
neworderdata = json.loads(request.GET['finalod'])
for ele in neworderdata:
for ele in neworderdata:
area = Areas.objects.get(pk=ele['id'])
area.areaorder = ele['neworder']
area.save()
if(area.agency == request.user.profile.agency):
area.areaorder = ele['neworder']
area.save()
return HttpResponse("UPDATED")
else:
return HttpResponse("Request method is not a GET")

View File

@ -1,15 +0,0 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

View File

@ -1,156 +0,0 @@
Youtube Plugin for CKEditor 4
=============================
Copyright © 2017 Jonnas Fonini <jonnasfonini@gmail.com>.
This work is free. You can redistribute it and/or modify it under the
terms of the Do What The Fuck You Want To Public License, Version 2,
as published by Sam Hocevar. See the LICENSE file for more details.
This plugin allow you to insert Youtube videos using embed code or just the video URL.
## Installation
### With NPM
1. npm install ckeditor-youtube-plugin
2. Add the plugin to CKEditor (config.js):
````js
CKEDITOR.plugins.addExternal('youtube', '../node_modules/ckeditor-youtube-plugin/youtube/');
config.extraPlugins = 'youtube';
````
You may need to adjust the plugin path. The example is assuming that you have the following directory structure:
```
project
└───ckeditor
│ └───config.js
└───node_modules
└───ckeditor-youtube-plugin
```
### Manual
Follow these steps:
1. Download the latest version of the plugin from Github.
2. Extract the downloaded file into the CKEditor's **plugins** folder.
3. Enable the plugin by changing or adding the extraPlugins line in your configuration (config.js):
````js
config.extraPlugins = 'youtube';
````
## Configuration
The default options can be overriden on config.js.
Video width:
```js
config.youtube_width = '640';
```
Video height:
```js
config.youtube_height = '480';
```
Make responsive (ignore width and height, fit to width):
```js
config.youtube_responsive = true;
```
Show related videos:
```js
config.youtube_related = true;
```
Use old embed code:
```js
config.youtube_older = false;
```
Enable privacy-enhanced mode:
```js
config.youtube_privacy = false;
```
Start video automatically:
```js
config.youtube_autoplay = false;
```
Show player controls:
```js
config.youtube_controls = true;
```
Disable the change of settings. The elements on the list will be disabled (but still visible).
See the available element list below.
```js
config.youtube_disabled_fields = ['txtEmbed', 'chkAutoplay'];
```
#### List of UI elements
* txtEmbed
* txtUrl
* txtWidth
* txtHeight
* chkResponsive
* chkNoEmbed
* chkRelated
* chkOlderCode
* chkPrivacy
* chkAutoplay
* txtStartAt
* chkControls
## How to use
If everything is ok, a Youtube icon should appear on the CKEditor toolbar. Click it,
paste your embed code or video URL and the video will be inserted.
## Translators
Thanks to those who helped translate the plugin
* Eyed Farra (ar)
* N. Petkov (bg)
* Lukáš Říha (cs)
* Sven Jansen (de)
* Dimitris Kotsakis (el)
* Victor (pollin14) (es)
* Kevin Rudissaar (et)
* Asier Iturralde Sarasola (eu)
* Jami Pietilä (fi)
* BiomanRouge (fr)
* Moshe Simantov (he)
* Karmacsi Gábor (hu)
* Francesco Zanoni (it)
* Yayoshi Nobuhide (ja)
* MinSoo Kim (ko)
* Holger Lockertsen (nb, nn)
* Patrick van Lier (nl)
* Michał Zalewski, Wirek (pl)
* Samuel Diogo (pt-br)
* Alexander Ustimenko (ru)
* ivanbarlog (sk)
* Çağdaş Yiğit (tr)
* Mykola Pukhalskyi (uk)
* Vu Thao (vi)
* trowa (zh)
[![Licensed under the WTFPL](http://www.wtfpl.net/wp-content/uploads/2012/12/wtfpl-badge-2.png "Licensed under the WTFPL")](http://www.wtfpl.net)

View File

@ -1,19 +0,0 @@
{
"name": "ckeditor-youtube-plugin",
"version": "2.1.13",
"homepage": "https://github.com/fonini/ckeditor-youtube-plugin",
"authors": [
"Jonnas Fonini"
],
"license": "MIT",
"dependencies": {
"ckeditor": ">= 4.0.0"
},
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}

View File

@ -1,22 +0,0 @@
{
"name": "ckeditor-youtube-plugin",
"description": "Youtube plugin for CKEditor",
"version": "2.1.13",
"author": "fonini",
"repository": {
"type": "git",
"url": "https://github.com/fonini/ckeditor-youtube-plugin"
},
"keywords": [
"CKEditor",
"youtube",
"embed"
],
"files": [
"youtube/",
"LICENSE.md",
"README.md",
"bower.json",
"package.json"
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'ar', {
button : 'شيفرة تضمين اليوتيوب',
title : 'شيفرة تضمين اليوتيوب',
txtEmbed : 'الصق شيفرة التضمين هنا',
txtUrl : 'الصق رابط فيديو اليوتيوب',
txtWidth : 'العرض',
txtHeight : 'الطول',
chkRelated : 'اظهر الفيديوهات المقترحة في نهاية الفيديو',
txtStartAt : 'ابدأ عند (ss او mm:ss او hh:mm:ss)',
chkPrivacy : 'تفعيل وضع تحسين الخصوصية',
chkOlderCode : 'استخدم شيفرة التضمين القديمة',
chkAutoplay : 'Autoplay',
chkControls: 'إظهار عناصر التحكم بالمشغّل',
noCode : 'يجب عليك ادخال شيفرة التضمين او الرابط',
invalidEmbed : 'شيفرة التضمين التي قمت بإدخالها تبدو غير صحيحة',
invalidUrl : 'الرابط الذي قمت بإدخاله يبدو غير صحيح',
or : 'او',
noWidth : 'يجب عليك ادخال العرض',
invalidWidth : 'يجب عليك ادخال عرض صحيح',
noHeight : 'يجب عليك ادخال الطول',
invalidHeight : 'يجب عليك ادخال طول صحيح',
invalidTime : 'يجب عليك ادخال وقت بداية صحيح',
txtResponsive : 'Responsive video'
});

View File

@ -1,25 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'bg', {
button : 'Вмъкни YouTube видео',
title : 'Вграждане на YouTube видео',
txtEmbed : 'Въведете кода за вграждане тук',
txtUrl : 'Въведете YouTube видео URL',
txtWidth : 'Ширина',
txtHeight : 'Височина',
chkRelated : 'Показва предложени видеоклипове в края на клипа',
txtStartAt : 'Стартирай в (ss или mm:ss или hh:mm:ss)',
chkPrivacy : 'Активирай режим за поверителност',
chkOlderCode : 'Използвай стар код за вграждане',
chkAutoplay: 'Авто стартиране',
chkControls: 'Показва контролите на плейъра',
noCode : 'Трябва да въведете код за вграждане или URL адрес',
invalidEmbed : 'Кодът за вграждане, който сте въвели, не изглежда валиден',
invalidUrl : 'Въведеният URL адрес не изглежда валиден',
or : 'или',
noWidth : 'Трябва да заложите ширината',
invalidWidth : 'Заложете валидна ширина',
noHeight : 'Трябва да заложите височина',
invalidHeight : 'Заложете валидна височина',
invalidTime : 'Заложете валидно време за стартиране',
txtResponsive : 'Напасва по ширина (игнорира Ширина и Височина)',
txtNoEmbed : 'Само видео изображение и връзка'
});

View File

@ -1,25 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'cs', {
button : 'Vložit video YouTube',
title : 'Vložit video YouTube',
txtEmbed : 'Zde vložte kód pro vložení',
txtUrl : 'Vložte adresu URL videa YouTube',
txtWidth : 'Šířka',
txtHeight : 'Výška',
chkRelated : 'Po dohrání videa zobrazit navrhovaná videa',
txtStartAt : 'Začít přehrávat v čase (ss nebo mm:ss nebo hh:mm:ss)',
chkPrivacy : 'Povolit režim s rozšířeným soukromím',
chkOlderCode : 'Použít starý kód pro vložení',
chkAutoplay : 'Automatické spuštění přehrávání',
chkControls : 'Zobrazit ovladače přehrávání',
noCode : 'Musíte vložit kód pro vložení nebo adresu URL',
invalidEmbed : 'Vložený kód pro vložení zřejmě není platný',
invalidUrl : 'Zadaná adresa URL zřejmě není platná',
or : 'nebo',
noWidth : 'Musíte zadat šířku',
invalidWidth : 'Zadejte platnou šířku',
noHeight : 'Musíte zadat výšku',
invalidHeight : 'Zadejte platnou výšku',
invalidTime : 'Zadejte platný počáteční čas',
txtResponsive : 'Responzivní design (ignorovat výšku a šířku, uzpůsobit šířce)',
txtNoEmbed : 'Pouze obrázek videa s odkazem'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'de', {
button : 'YouTube Video einbinden',
title : 'YouTube Video einbinden',
txtEmbed : 'Embed Code hier einfügen',
txtUrl : 'YouTube Video URL hier einfügen',
txtWidth : 'Breite',
txtHeight : 'Höhe',
chkRelated : 'Vorschläge am Ende des Videos einblenden',
txtStartAt : 'Start bei Position (ss oder mm:ss oder hh:mm:ss)',
chkPrivacy : 'Erweiterten Datenschutzmodus aktivieren',
chkOlderCode : 'Benutze alten Embed Code',
chkAutoplay : 'Autoplay',
chkControls : 'Player-Steuerelemente anzeigen',
noCode : 'Sie müssen einen Embed Code oder URL angeben',
invalidEmbed : 'Der angegebene Embed Code scheint nicht gültig zu sein.',
invalidUrl : 'Die angegebene URL scheint nicht gültig zu sein.',
or : 'oder',
noWidth : 'Geben Sie eine Breite an',
invalidWidth : 'Geben Sie eine gültige Breite an',
noHeight : 'Geben Sie eine Höhe an',
invalidHeight : 'Geben Sie eine gültige Höhe an',
invalidTime : 'Geben Sie eine gültige Startzeit an',
txtResponsive : 'Automatische Größe (ignoriert Breite und Höhe)'
});

View File

@ -1,23 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'el', {
button: 'Ενσωμάτωση Youtube βίντεο',
title: 'Ενσωμάτωση Youtube βίντεο',
txtEmbed: 'Επικόλλησε τον κώδικα ενσωμάτωσης',
txtUrl: 'Επικόλλησε το URL του βίντεο',
txtWidth: 'Πλάτος',
txtHeight: 'Ύψος',
chkRelated: 'Εμφάνιση προτεινόμενων βίντεο μόλις ολοκληρωθεί',
txtStartAt: 'Χρόνος εκκίνησης (ss or mm:ss or hh:mm:ss)',
chkPrivacy: 'Ενεργοποίηση λειτουργίας ενισχυμένου απορρήτου',
chkOlderCode: 'Χρήση παλαιού κώδικα ενσωμάτωσης',
chkAutoplay: 'Αυτόματη εκκίνηση',
chkControls: 'Εμφάνιση στοιχείων ελέγχου προγράμματος αναπαραγωγής',
noCode: 'Χρειάζεται κώδικας ενσωμάτωσης ή URL',
invalidEmbed: 'Ο κώδικας ενσωμάτωσης που εισήγατε δεν μοιάζει σωστός',
invalidUrl: 'Το URL που εισήγατε δεν μοιάζει σωστό',
or: 'ή',
noWidth: 'Συμπληρώστε το πλάτος',
invalidWidth: 'Λανθασμένο πλάτος',
noHeight: 'Συμπληρώστε το ύψος',
invalidHeight: 'Λανθασμένο ύψος',
invalidTime: 'Λανθασμένος χρόνος εκκίνησης'
});

View File

@ -1,25 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'en', {
button : 'Embed YouTube Video',
title : 'Embed YouTube Video',
txtEmbed : 'Paste Embed Code Here',
txtUrl : 'Paste YouTube Video URL',
txtWidth : 'Width',
txtHeight : 'Height',
chkRelated : 'Show suggested videos at the video\'s end',
txtStartAt : 'Start at (ss or mm:ss or hh:mm:ss)',
chkPrivacy : 'Enable privacy-enhanced mode',
chkOlderCode : 'Use old embed code',
chkAutoplay: 'Autoplay',
chkControls: 'Show player controls',
noCode : 'You must input an embed code or URL',
invalidEmbed : 'The embed code you\'ve entered doesn\'t appear to be valid',
invalidUrl : 'The URL you\'ve entered doesn\'t appear to be valid',
or : 'or',
noWidth : 'You must inform the width',
invalidWidth : 'Inform a valid width',
noHeight : 'You must inform the height',
invalidHeight : 'Inform a valid height',
invalidTime : 'Inform a valid start time',
txtResponsive : 'Make Responsive (ignore width and height, fit to width)',
txtNoEmbed : 'Video image and link only'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'es', {
button : 'Embed YouTube video',
title : 'Embed YouTube video',
txtEmbed : 'Pegar el código embed',
txtUrl : 'Pegar la URL al video de Youtube',
txtWidth : 'Anchura',
txtHeight : 'Altura',
chkRelated : 'Mostrar videos sugeridos al final de este video',
txtStartAt : 'Comenzar en (ss or mm:ss or hh:mm:ss)',
chkPrivacy : 'Habilitar el modo privacy-enhanced',
chkOlderCode : 'Usar código embed viejo',
chkAutoplay: 'Autoplay',
chkControls: 'Mostrar controles del reproductor',
noCode : 'Debes de introducir un código embed o URL',
invalidEmbed : 'El código embed introducido parece no ser valido',
invalidUrl : 'La URL introducida parece no ser valida',
or : 'o',
noWidth : 'Debes de dar la anchura',
invalidWidth : 'Da una anchura valida',
noHeight : 'Debes dar una altura valida',
invalidHeight : 'Da una altura valida',
invalidTime : 'Da un tiempo de valido',
txtResponsive : 'Hacer responsivo (ignorar anchura y altura, ajustar a la anchura)'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'et', {
button : 'Lisa YouTube video',
title : 'YouTube video lisamine',
txtEmbed : 'Kleepige manustatud kood siia',
txtUrl : 'Kleepige YouTube video veebiaadress',
txtWidth : 'Laius',
txtHeight : 'Kõrgus',
chkRelated : 'Näita soovitatud videosi antud video lõppus',
txtStartAt : 'Alguskoht: (ss või mm:ss või hh:mm:ss)',
chkPrivacy : 'Aktiveerige privaatsust täiendav režiim',
chkOlderCode : 'Kasutage vana manuskoodi',
chkAutoplay: 'Automaatesitlus',
chkControls : 'Kuva pleieri nupud',
noCode : 'Te peate sisestama video manuskoodi või veebiaadressi',
invalidEmbed : 'Manuskood mille sisestasite ei paista olevat korrektne',
invalidUrl : 'Veebiaadress mille sisestasite ei paista olevat korrektne',
or : 'või',
noWidth : 'Te peate sisestama video laiuse',
invalidWidth : 'Sisestage korrektne laius',
noHeight : 'Te peate sisestama video kõrguse',
invalidHeight : 'Sisestage korrektne kõrgus',
invalidTime : 'Sisestage korrektne algusaeg',
txtResponsive : 'Aktiveerige ekraani laiusega ühilduv režiim'
});

View File

@ -1,25 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'eu', {
button : 'Kapsulatu YouTube-ko bideoa',
title : 'Kapsulatu YouTube-ko bideoa',
txtEmbed : 'Itsatsi kapsulatzeko kodea hemen',
txtUrl : 'Itsatsi YouTube-ko bideoaren URLa',
txtWidth : 'Zabalera',
txtHeight : 'Altuera',
chkRelated : 'Erakutsi gomendatutako bideoak amaieran',
txtStartAt : 'Hasi hemendik (ss edo mm:ss edo hh:mm:ss)',
chkPrivacy : 'Gaitu pribatutasun hobetuko modua',
chkOlderCode : 'Erabili kapsulatzeko kode zaharra',
chkAutoplay: 'Erreproduzitu automatikoki',
chkControls: 'Erakutsi erreproduzigailuaren kontrolak',
noCode : 'Kapsulatzeko kode bat edo URL bat sartu behar duzu',
invalidEmbed : 'Sartu duzun kapsulatzeko kodea ez da baliozkoa',
invalidUrl : 'Sartu duzun URLa ez da baliozkoa',
or : 'edo',
noWidth : 'Zabalera sartu behar duzu',
invalidWidth : 'Sartu baliozko zabalera bat',
noHeight : 'Altuera sartu behar duzu',
invalidHeight : 'Sartu baliozko altuera bat',
invalidTime : 'Sartu baliozko hasierako denbora bat',
txtResponsive : 'Egin moldagarria (ez ikusia egin zabalera eta altuerari, zabalerara doitu)',
txtNoEmbed : 'Bideoaren irudia eta esteka soilik'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'fi', {
button : 'Upota YouTube-video',
title : 'Upota YouTube-video',
txtEmbed : 'Syötä YouTube-videon upotuskoodi',
txtUrl : 'Syötä YouTube-videon www-osoite',
txtWidth : 'Leveys',
txtHeight : 'Korkeus',
chkRelated : 'Näytä suositukset lopussa',
txtStartAt : 'Aloitusaika (ss tai mm:ss tai tt:mm:ss)',
chkPrivacy : 'Aktivoi yksityisyyttä parantava tila',
chkOlderCode : 'Käytä vanhaa upotuskoodia',
chkAutoplay: 'Soita automaattisesti',
chkControls : 'Näytä soittimen ohjaimet',
noCode : 'Sinun täytyy syötää upotuskoodi tai www-osoite',
invalidEmbed : 'Upotuskoodi on virheellinen',
invalidUrl : 'Www-osoite on virheellinen',
or : 'tai',
noWidth : 'Syötä leveys',
invalidWidth : 'Leveys on virheellinen',
noHeight : 'Syötä korkeus',
invalidHeight : 'Korkeus on virheellinen',
invalidTime : 'Aloitusaika on virheellinen',
txtResponsive : 'Responsiivinen leveys (sovita leveys)'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'fr', {
button : 'Insérer une vidéo Youtube',
title : 'Insérer une vidéo youtube',
txtEmbed : 'Coller le code embed ici',
txtUrl : 'Coller l\'url de la vidéo ici',
txtWidth : 'Largeur',
txtHeight : 'Hauteur',
chkRelated : 'Montrer les suggestions de vidéo à la fin',
txtStartAt : 'Commencer à (ss ou mm:ss ou hh:mm:ss)',
chkPrivacy : 'Activer la protection de la vie privée',
chkOlderCode : 'Utiliser l\'ancien code embed',
chkAutoplay : 'Autoplay',
chkControls : 'Afficher les commandes du lecteur',
noCode : 'Vous devez entrer un code embed ou une url',
invalidEmbed : 'Le code embed est invalide',
invalidUrl : 'L\'url est invalide',
or : 'ou',
noWidth : 'Vous devez saisir une largeur',
invalidWidth : 'La largeur saisie est invalide',
noHeight : 'Vous devez saisir une hauteur',
invalidHeight : 'La hauteur saisie est invalide',
invalidTime : 'Le temps de départ de la vidéo est invalide',
txtResponsive : 'Responsive video'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'he', {
button : 'שבץ וידאו של YouTube',
title : 'שבץ וידאו של YouTube',
txtEmbed : 'הדבק את קוד השיבוץ כאן',
txtUrl : 'הדבק כתובת וידאו YouTube',
txtWidth : 'אורך',
txtHeight : 'גובה',
chkRelated : 'הצג סרטונים מומלצים בסוף הודיאו',
txtStartAt : 'התחל ב (ss או mm:ss או hh:mm:ss)',
chkPrivacy : 'הפעל מצב פרטיות המשופרת',
chkOlderCode : 'השתמש בקוד הטמעה ישן',
chkAutoplay: 'הפעלה אוטומטית',
chkControls : 'הצג פקדי נגן',
noCode : 'אתה חייב להזין קוד embed כתובת וידאו אתר',
invalidEmbed : 'קוד ההטמעה שהוזן אינו נראה חוקי',
invalidUrl : 'כתובת הוידאו אינה נראת חוקית',
or : 'או',
noWidth : 'חובה להזין אורך',
invalidWidth : 'האורך שהוזן שגוי',
noHeight : 'חובה להזין גובה',
invalidHeight : 'הגובה שהוזן שגוי',
invalidTime : 'זמן התחלה שהוזן שגוי',
txtResponsive : 'הפוך לרספונסיבי (התעלם מרוחב וגובה, התאם לרוחב)'
});

View File

@ -1,25 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'hu', {
button : 'Youtube videó beillesztése',
title : 'Youtube videó beillesztése',
txtEmbed : 'Illessze be a beágyazott kódot',
txtUrl : 'Illessze be a Youtube videó URL-jét',
txtWidth : 'Szélesség',
txtHeight : 'Magasság',
txtStartAt : 'Kezdő időpont (ss vagy mm:ss vagy hh:mm:ss)',
chkRelated : 'Ajánlott videók megjelenítése, amikor a videó befejeződik',
chkPrivacy : 'Fokozott adatvédelmi mód engedélyezése',
chkOlderCode : 'Régi beágyazott kód használata',
chkAutoplay : 'Automatikus lejátszás',
chkControls : 'Lejátszásvezérlők mutatása',
noCode : 'A beágyazott kód, vagy az URL megadása kötelező',
invalidEmbed : 'A beágyazott kód érvénytelen',
invalidUrl : 'A megadott URL érvénytelen',
or : 'vagy',
noWidth : 'A szélesség megadása kötelező',
invalidWidth : 'Érvényes szélességet adjon meg',
noHeight : 'A magasság megadása kötelező',
invalidHeight : 'Érvényes magasságot adjon meg',
invalidTime : 'Érvényes kezdő időpontot adjon meg',
txtResponsive : 'Reszponzív videó',
txtNoEmbed : 'Csak kép és hivatkozás jelenjen meg'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'it', {
button : 'Incorpora video Youtube',
title : 'Incorpora video Youtube',
txtEmbed : 'Incolla qui il codice di incorporamento',
txtUrl : 'Incolla l\'URL del video Youtube',
txtWidth : 'Larghezza',
txtHeight : 'Altezza',
chkRelated : 'Mostra i video suggeriti dopo il video',
txtStartAt : 'Inizia a (ss o mm:ss o hh:mm:ss)',
chkPrivacy : 'Abilita la protezione della privacy',
chkOlderCode : 'Usa il vecchio codice di incorporamento',
chkAutoplay : 'Autoplay',
chkControls : 'Mostra i controlli del player',
noCode : 'Devi inserire un codice di incorporamento o un URL',
invalidEmbed : 'Il codice di incorporamento inserito non sembra valido',
invalidUrl : 'L\'URL inserito non sembra valido',
or : 'o',
noWidth : 'Devi indicare la larghezza',
invalidWidth : 'Indica una larghezza valida',
noHeight : 'Devi indicare l\'altezza',
invalidHeight : 'Indica un\'altezza valida',
invalidTime : 'Indica un tempo di inizio valido',
txtResponsive : 'Responsive video'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'ja', {
button : 'Youtube動画埋め込み',
title : 'Youtube動画埋め込み',
txtEmbed : '埋め込みコードを貼り付けてください',
txtUrl : 'URLを貼り付けてください',
txtWidth : '幅',
txtHeight : '高さ',
chkRelated : '動画が終わったら関連動画を表示する',
txtStartAt : '開始時間(秒)',
chkPrivacy : 'プライバシー強化モードを有効にする',
chkOlderCode : '以前の埋め込みコードを使用する',
chkAutoplay : '自動再生',
chkControls: 'プレーヤーのコントロールを表示する',
noCode : '埋め込みコードまたはURLを入力してください',
invalidEmbed : '不適切な埋め込みコードが入力されました',
invalidUrl : '不適切なURLが入力されました',
or : 'または',
noWidth : '幅を指定してください',
invalidWidth : '幅指定に誤りがあります',
noHeight : '高さを指定してください',
invalidHeight : '高さ指定に誤りがあります',
invalidTime : '開始時間を正の整数で入力してください',
txtResponsive : 'レスポンシブ表示'
});

View File

@ -1,25 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'ko', {
button : '유투브 비디오 삽입',
title : '유투브 비디오 삽입',
txtEmbed : '여기 embed 코드를 붙여넣으세요',
txtUrl : '유투브 주소(URL)를 붙여넣으세요',
txtWidth : '너비',
txtHeight : '높이',
chkRelated : '비디오 마지막에 추천 영상 보이기',
txtStartAt : '시작 시점 (ss 또는 mm:ss 또는 hh:mm:ss)',
chkPrivacy : '개인정보 보호 모드 활성화',
chkOlderCode : '옛날 embed 코드 사용',
chkAutoplay: '자동 재생',
chkControls: '플레이어 컨트롤 표시',
noCode : 'embed 코드 또는 URL을 입력해야 합니다',
invalidEmbed : '입력하신 embed 코드가 유효하지 않습니다',
invalidUrl : '입력하신 주소(URL)가 유효하지 않습니다',
or : '또는',
noWidth : '너비를 알려주세요',
invalidWidth : '너비가 유효하지 않습니다',
noHeight : '높이를 알려주세요',
invalidHeight : '높이가 유효하지 않습니다',
invalidTime : '시작 시점이 유효하지 않습니다',
txtResponsive : '반응형 너비 (입력한 너비와 높이를 무시하고 창 너비에 맞춤)',
txtNoEmbed : '비디오 이미지와 링크만 달기'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'nb', {
button : 'Bygg inn YouTube-video',
title : 'Bygg inn YouTube-video',
txtEmbed : 'Lim inn embed-kode her',
txtUrl : 'Lim inn YouTube video-URL',
txtWidth : 'Bredde',
txtHeight : 'Høyde',
chkRelated : 'Vis foreslåtte videoer når videoen er ferdig',
txtStartAt : 'Start ved (ss eller mm:ss eller hh:mm:ss)',
chkPrivacy : 'Bruk personverntilpasset modus',
chkOlderCode : 'Bruk gammel embedkode',
chkAutoplay: 'Spill automatisk',
chkControls: 'Vis spillerkontrollene',
noCode : 'Du må legge inn en embed-kode eller URL',
invalidEmbed : 'Emded-koden du la inn ser ikke ut til å være gyldig',
invalidUrl : 'URLen du la inn ser ikke ut til å være gyldig',
or : 'eller',
noWidth : 'Du må legge inn bredde',
invalidWidth : 'Legg inn en gyldig bredde',
noHeight : 'Du må legge inn høyde',
invalidHeight : 'Legg inn en gyldig høyde',
invalidTime : 'Legg inn gyldig starttid',
txtResponsive : 'Gjør responsiv (ignorer bredde og høyde, tilpass bredde på sida)'
});

View File

@ -1,25 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'nl', {
button : 'Youtube video insluiten',
title : 'Youtube video insluiten',
txtEmbed : 'Plak embedcode hier',
txtUrl : 'Plak video URL',
txtWidth : 'Breedte',
txtHeight : 'Hoogte',
chkRelated : 'Toon gesuggereerde video aan het einde van de video',
txtStartAt : 'Starten op (ss of mm:ss of hh:mm:ss)',
chkPrivacy : 'Privacy-enhanced mode inschakelen',
chkOlderCode : 'Gebruik oude embedcode',
chkAutoplay: 'Automatisch starten',
chkControls: 'Afspeelbediening weergeven',
noCode : 'U moet een embedcode of url ingeven',
invalidEmbed : 'De ingegeven embedcode lijkt niet geldig',
invalidUrl : 'De ingegeven url lijkt niet geldig',
or : 'of',
noWidth : 'U moet een breedte ingeven',
invalidWidth : 'U moet een geldige breedte ingeven',
noHeight : 'U moet een hoogte ingeven',
invalidHeight : 'U moet een geldige starttijd ingeven',
invalidTime : 'Inform a valid start time',
txtResponsive : 'Responsive video',
txtNoEmbed : 'Alleen video afbeelding en link'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'nn', {
button : 'Bygg inn YouTube-video',
title : 'Bygg inn YouTube-video',
txtEmbed : 'Lim inn embed-kode her',
txtUrl : 'Lim inn YouTube video-URL',
txtWidth : 'Breidde',
txtHeight : 'Høgde',
chkRelated : 'Vis foreslåtte videoar når videoen er ferdig',
txtStartAt : 'Start ved (ss eller mm:ss eller hh:mm:ss)',
chkPrivacy : 'Bruk personverntilpassa modus',
chkOlderCode : 'Bruk gamal embedkode',
chkAutoplay: 'Spel automatisk',
chkControls: 'Vis spillerkontrollene',
noCode : 'Du må leggja inn ein embed-kode eller URL',
invalidEmbed : 'Emded-koden du la inn ser ikkje ut til å vera gyldig',
invalidUrl : 'URLen du la inn ser ikkje ut til å vera gyldig',
or : 'eller',
noWidth : 'Du må leggja inn breidde',
invalidWidth : 'Legg inn ei gyldig breidde',
noHeight : 'Du må leggja inn høgde',
invalidHeight : 'Legg inn ei gyldig høgde',
invalidTime : 'Legg inn gyldig starttid',
txtResponsive : 'Gjer responsiv (ignorer breidde og høgde, tilpass breidda på sida)'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'pl', {
button : 'Załącznik wideo z YouTube',
title : 'Załącznik wideo z YouTube',
txtEmbed : 'Wklej kod do umieszczenia',
txtUrl : 'Wklej adres URL do wideo z YouTube',
txtWidth : 'Szerokość',
txtHeight : 'Wysokość',
chkRelated : 'Pokaż sugerowane filmy po zakończeniu odtwarzania',
txtStartAt : 'Rozpocznij od (ss lub mm:ss lub gg:mm:ss)',
chkPrivacy : 'Włącz rozszerzony tryb prywatności',
chkOlderCode : 'Użyj starego kodu',
chkAutoplay: 'Autoodtwarzanie',
chkControls: 'Pokaż elementy sterujące odtwarzacza',
noCode : 'Musisz wprowadzić kod lub adres URL',
invalidEmbed : 'Wprowadzony kod nie jest poprawny',
invalidUrl : 'Wprowadzony adres URL nie jest poprawny',
or : 'lub',
noWidth : 'Musisz wpisać szerokość',
invalidWidth : 'Wprowadzona szerokość nie jest poprawna',
noHeight : 'Musisz wprowadzić wysokość',
invalidHeight : 'Wprowadzona wysokość nie jest poprawna',
invalidTime : 'Musisz wprowadzić poprawny czas rozpoczęcia',
txtResponsive : 'El. responsywny (ignoruj szerokość i wysokość, dopasuj do szerokości)'
});

View File

@ -1,25 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'pt-br', {
button : 'Inserir Vídeo do Youtube',
title : 'Inserir Vídeo do Youtube',
txtEmbed : 'Cole aqui o código embed de um vídeo do Youtube',
txtUrl : 'Cole aqui uma URL de um vídeo do Youtube',
txtWidth : 'Largura',
txtHeight : 'Altura',
chkRelated : 'Mostrar vídeos sugeridos ao final do vídeo',
txtStartAt : 'Iniciar em (ss ou mm:ss ou hh:mm:ss)',
chkPrivacy : 'Ativar o modo de privacidade aprimorada',
chkOlderCode : 'Usar código de incorporação antigo',
chkAutoplay : 'Reproduzir automaticamente',
chkControls: 'Mostrar controles do player',
noCode : 'Você precisa informar um código embed ou uma URL',
invalidEmbed : 'O código informado não parece ser válido',
invalidUrl : 'A URL informada não parece ser válida',
or : 'ou',
noWidth : 'Você deve informar a largura do vídeo',
invalidWidth : 'Informe uma largura válida',
noHeight : 'Você deve informar a altura do vídeo',
invalidHeight : 'Informe uma altura válida',
invalidTime : 'O tempo informado é inválido',
txtResponsive : 'Vídeo responsivo',
txtNoEmbed : 'Somente imagem e link para o vídeo'
});

View File

@ -1,25 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'pt', {
button : 'Inserir Vídeo do Youtube',
title : 'Inserir Vídeo do Youtube',
txtEmbed : 'Cole aqui o código embed de um vídeo do Youtube',
txtUrl : 'Cole aqui uma URL de um vídeo do Youtube',
txtWidth : 'Largura',
txtHeight : 'Altura',
chkRelated : 'Mostrar vídeos sugeridos quando o vídeo terminar',
txtStartAt : 'Iniciar em (ss ou mm:ss ou hh:mm:ss)',
chkPrivacy : 'Ativar o modo de privacidade otimizada',
chkOlderCode : 'Usar código de incorporação antigo',
chkAutoplay : 'Reproduzir automaticamente',
chkControls: 'Mostrar controles do player',
noCode : 'Você precisa informar um código embed ou uma URL',
invalidEmbed : 'O código informado não parece ser válido',
invalidUrl : 'A URL informada não parece ser válida',
or : 'ou',
noWidth : 'Você deve informar a largura do vídeo',
invalidWidth : 'Informe uma largura válida',
noHeight : 'Você deve informar a altura do vídeo',
invalidHeight : 'Informe uma altura válida',
invalidTime : 'O tempo informado é inválido',
txtResponsive : 'Vídeo responsivo',
txtNoEmbed : 'Somente imagem e link para o vídeo'
});

View File

@ -1,25 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'ru', {
button : 'Вставить YouTube видео',
title : 'Вставить YouTube видео',
txtEmbed : 'Вставьте HTML-код сюда',
txtUrl : 'Вставьте адрес видео (URL)',
txtWidth : 'Ширина',
txtHeight : 'Высота',
chkRelated : 'Показать похожие видео после завершения просмотра',
txtStartAt : 'Начать с (сс или мм:сс или чч:мм:сс)',
chkPrivacy : 'Включить режим повышенной конфиденциальности',
chkOlderCode : 'Использовать старый код вставки',
chkAutoplay: 'Автозапуск',
chkControls: 'Показать панель управления',
noCode : 'Вы должны ввести HTML-код или адрес',
invalidEmbed : 'Ваш HTML-код не похож на правильный',
invalidUrl : 'Ваш адрес видео не похож на правильный',
or : 'или',
noWidth : 'Вы должны указать ширину',
invalidWidth : 'Укажите правильную ширину',
noHeight : 'Вы должны указать высоту',
invalidHeight : 'Укажите правильную высоту',
invalidTime : 'Укажите правильное время начала',
txtResponsive : 'Растягиваемое видео',
txtNoEmbed : 'Не встраивать видео (обложка-ссылка на YouTube)'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'sk', {
button : 'Vložiť YouTube video',
title : 'Vložiť YouTube video',
txtEmbed : 'Vložiť Youtube Embed Video kódu',
txtUrl : 'Vložiť pomocou YouTube video URL',
txtWidth : 'Šírka',
txtHeight : 'Výška',
chkRelated : 'Zobraziť odporúčané videá po prehratí',
txtStartAt : 'Začať prehrávanie videa (ss alebo mm:ss alebo hh:mm:ss)',
chkPrivacy : 'Povoliť pokročilý mód súkromia',
chkOlderCode : 'Použiť starú metódu vkladania',
chkAutoplay: 'Automatické prehrávanie',
chkControls: 'Zobraziť ovládacie prvky prehrávača',
noCode : 'Musíte vložiť Youtube Embed kód alebo URL',
invalidEmbed : 'Vložený kód nie je valídny',
invalidUrl : 'Vložená URL nie je platná',
or : 'alebo',
noWidth : 'Prosím, zadajte šírku videa',
invalidWidth : 'Zadajte valídnu šírku videa',
noHeight : 'Prosím, zadajte výšku videa',
invalidHeight : 'Zadajte valídnu výšku videa',
invalidTime : 'Zadajte valídny formát začiatku prehrávania videa',
txtResponsive : 'Prispôsobit rozmery videa rozmerom obrazovky (ignoruje šírku a výšku, prispôsobí sa šírke obrazovky)'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'tr', {
button : 'Youtube Video Gömün (Embed)',
title : 'Youtube Video',
txtEmbed : 'Youtube gömülü kodu (embed) buraya yapıştırınız',
txtUrl : 'Youtube linkinizi buraya yapıştırınız',
txtWidth : 'Genişlik',
txtHeight : 'Yükseklik',
chkRelated : 'Önerilen videoları video bitiminde göster',
txtStartAt : 'Video başlangıç anı (ss ya da dd:ss ya da ss:dd:ss)',
chkPrivacy : 'Gizlilik modunu etkinleştir',
chkOlderCode : 'Eski gömülü kodu (embed) kullan',
chkAutoplay: 'Otomatik',
chkControls: 'Oynatıcı kontrollerini göster',
noCode : 'Gömülü kod (embed) veya url yapıştırmak zorundasınız',
invalidEmbed : 'Verdiğiniz gömülü kod (embed) ile video bulunamadı',
invalidUrl : 'Verdiğiniz linkte video bulunamadı',
or : 'ya da',
noWidth : 'Genişliği belirtmek zorundasınız',
invalidWidth : 'Bir genişlik belirtin',
noHeight : 'Yükseliği belirtmek zorundasınız',
invalidHeight : 'Yükseklik belirtin',
invalidTime : 'Başlangıç anını doğru girin, örneğin: 13 (13. saniye) ya da 12:25 (12. dakika 25. saniye) ya da 01.25.33 (1 saat 25 dakika 33 saniye)',
txtResponsive : 'Responsive video'
});

View File

@ -1,25 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'uk', {
button : 'Вставити YouTube-відео',
title : 'Вставити YouTube-відео',
txtEmbed : 'Вставте HTML-код сюди',
txtUrl : 'Вставте URL-адресу сюди',
txtWidth : 'Ширина',
txtHeight : 'Висота',
chkRelated : 'Показати пропоновані відео в кінці',
txtStartAt : 'Почати з (сс або хх:сс або гг:хх:сс)',
chkPrivacy : 'Увімкнути режим підвищеної конфіденційності',
chkOlderCode : 'Використовувати старий код вставки',
chkAutoplay: 'Автовідтворення',
chkControls: 'Показувати елементи управління плеєром',
noCode : 'Ви повинні ввести HTML-код або URL-адресу',
invalidEmbed : 'Код вставки, який ви додали не вірний',
invalidUrl : 'URL-адреса, яку ви додали не вірна',
or : 'або',
noWidth : 'Укажіть ширину',
invalidWidth : 'Укажіть правильну ширину',
noHeight : 'Укажіть висоту',
invalidHeight : 'Укажіть правильну висоту',
invalidTime : 'Укажіть правильний час початку',
txtResponsive : 'Адаптивне (таке, яке розтягується) відео',
txtNoEmbed : 'Додати лише обкладинку та посилання на YouTube'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'vi', {
button : 'Embed Youtube Video',
title : 'Nhúng Video Youtube',
txtEmbed : 'Dãn mã nhúng Embed vào đây',
txtUrl : 'Dãn đường dẫn video Youtube',
txtWidth : 'Rộng',
txtHeight : 'Cao',
chkRelated : 'Hiển thị các video được đề xuất khi video kết thúc',
txtStartAt : 'Bắt đầu (ss hoặc mm:ss hoặc hh:mm:ss)',
chkPrivacy : 'Kích hoạt chế độ bảo mật nâng cao',
chkOlderCode : 'Sử dụng mã nhúng cũ',
chkAutoplay: 'Tự động chạy video',
chkControls: 'Hiển thị các điều khiển trình phát',
noCode : 'Bạn phải nhập mã nhúng hoặc URL',
invalidEmbed : 'Mã nhúng bạn đã nhập không đúng',
invalidUrl : 'URL bạn đã nhập không đúng',
or : 'hoặc',
noWidth : 'Bạn phải chiều rộng',
invalidWidth : 'Chiều rộng hợp lệ',
noHeight : 'Bạn phải chiều cao',
invalidHeight : 'Chiều cao hợp lệ',
invalidTime : 'Thời gian bắt đầu không đúng',
txtResponsive : 'Responsive video'
});

View File

@ -1,24 +0,0 @@
CKEDITOR.plugins.setLang('youtube', 'zh', {
button: '嵌入 Youtube 影片',
title: '嵌入 Youtube 影片',
txtEmbed: '貼上嵌入碼',
txtUrl: '貼上 Youtube 影片 URL',
txtWidth: '寬',
txtHeight: '高',
txtResponsive: '使用自適應縮放模式 (忽略設定的長寬, 以寬為基準縮放)',
chkRelated: '影片結束時顯示建議影片',
txtStartAt: '開始時間 (ss or mm:ss or hh:mm:ss)',
chkPrivacy: '啟用加強隱私模式',
chkOlderCode: '使用舊的嵌入碼',
chkAutoplay: '自動播放',
chkControls: '显示播放器控件',
noCode: '必須輸入嵌入碼',
invalidEmbed: '錯誤的嵌入碼',
invalidUrl: '錯誤的URL',
or: '或',
noWidth: '必須設定寬',
invalidWidth: '寬設定錯誤',
noHeight: '必須設定高',
invalidHeight: '高設定錯誤',
invalidTime: '開始時間設定錯誤'
});

View File

@ -1,449 +0,0 @@
/*
* Youtube Embed Plugin
*
* @author Jonnas Fonini <jonnasfonini@gmail.com>
* @version 2.1.13
*/
(function () {
CKEDITOR.plugins.add('youtube', {
lang: [ 'en', 'bg', 'pt', 'pt-br', 'ja', 'hu', 'it', 'fr', 'tr', 'ru', 'de', 'ar', 'nl', 'pl', 'vi', 'zh', 'el', 'he', 'es', 'nb', 'nn', 'fi', 'et', 'sk', 'cs', 'ko', 'eu', 'uk'],
init: function (editor) {
editor.addCommand('youtube', new CKEDITOR.dialogCommand('youtube', {
allowedContent: 'div{*}(*); iframe{*}[!width,!height,!src,!frameborder,!allowfullscreen,!allow]; object param[*]; a[*]; img[*]'
}));
editor.ui.addButton('Youtube', {
label : editor.lang.youtube.button,
toolbar : 'insert',
command : 'youtube',
icon : this.path + 'images/icon.png'
});
CKEDITOR.dialog.add('youtube', function (instance) {
var video,
disabled = editor.config.youtube_disabled_fields || [];
return {
title : editor.lang.youtube.title,
minWidth : 510,
minHeight : 200,
onShow: function () {
for (var i = 0; i < disabled.length; i++) {
this.getContentElement('youtubePlugin', disabled[i]).disable();
}
},
contents :
[{
id : 'youtubePlugin',
expand : true,
elements :
[{
id : 'txtEmbed',
type : 'textarea',
label : editor.lang.youtube.txtEmbed,
onChange : function (api) {
handleEmbedChange(this, api);
},
onKeyUp : function (api) {
handleEmbedChange(this, api);
},
validate : function () {
if (this.isEnabled()) {
if (!this.getValue()) {
alert(editor.lang.youtube.noCode);
return false;
}
else
if (this.getValue().length === 0 || this.getValue().indexOf('//') === -1) {
alert(editor.lang.youtube.invalidEmbed);
return false;
}
}
}
},
{
type : 'html',
html : editor.lang.youtube.or + '<hr>'
},
{
type : 'hbox',
widths : [ '70%', '15%', '15%' ],
children :
[
{
id : 'txtUrl',
type : 'text',
label : editor.lang.youtube.txtUrl,
onChange : function (api) {
handleLinkChange(this, api);
},
onKeyUp : function (api) {
handleLinkChange(this, api);
},
validate : function () {
if (this.isEnabled()) {
if (!this.getValue()) {
alert(editor.lang.youtube.noCode);
return false;
}
else{
video = ytVidId(this.getValue());
if (this.getValue().length === 0 || video === false)
{
alert(editor.lang.youtube.invalidUrl);
return false;
}
}
}
}
},
{
type : 'text',
id : 'txtWidth',
width : '60px',
label : editor.lang.youtube.txtWidth,
'default' : editor.config.youtube_width != null ? editor.config.youtube_width : '640',
validate : function () {
if (this.getValue()) {
var width = parseInt (this.getValue()) || 0;
if (width === 0) {
alert(editor.lang.youtube.invalidWidth);
return false;
}
}
else {
alert(editor.lang.youtube.noWidth);
return false;
}
}
},
{
type : 'text',
id : 'txtHeight',
width : '60px',
label : editor.lang.youtube.txtHeight,
'default' : editor.config.youtube_height != null ? editor.config.youtube_height : '360',
validate : function () {
if (this.getValue()) {
var height = parseInt(this.getValue()) || 0;
if (height === 0) {
alert(editor.lang.youtube.invalidHeight);
return false;
}
}
else {
alert(editor.lang.youtube.noHeight);
return false;
}
}
}
]
},
{
type : 'hbox',
widths : [ '55%', '45%' ],
children :
[
{
id : 'chkResponsive',
type : 'checkbox',
label : editor.lang.youtube.txtResponsive,
'default' : editor.config.youtube_responsive != null ? editor.config.youtube_responsive : false
},
{
id : 'chkNoEmbed',
type : 'checkbox',
label : editor.lang.youtube.txtNoEmbed,
'default' : editor.config.youtube_noembed != null ? editor.config.youtube_noembed : false
}
]
},
{
type : 'hbox',
widths : [ '55%', '45%' ],
children :
[
{
id : 'chkRelated',
type : 'checkbox',
'default' : editor.config.youtube_related != null ? editor.config.youtube_related : true,
label : editor.lang.youtube.chkRelated
},
{
id : 'chkOlderCode',
type : 'checkbox',
'default' : editor.config.youtube_older != null ? editor.config.youtube_older : false,
label : editor.lang.youtube.chkOlderCode
}
]
},
{
type : 'hbox',
widths : [ '55%', '45%' ],
children :
[
{
id : 'chkPrivacy',
type : 'checkbox',
label : editor.lang.youtube.chkPrivacy,
'default' : editor.config.youtube_privacy != null ? editor.config.youtube_privacy : false
},
{
id : 'chkAutoplay',
type : 'checkbox',
'default' : editor.config.youtube_autoplay != null ? editor.config.youtube_autoplay : false,
label : editor.lang.youtube.chkAutoplay
}
]
},
{
type : 'hbox',
widths : [ '55%', '45%'],
children :
[
{
id : 'txtStartAt',
type : 'text',
label : editor.lang.youtube.txtStartAt,
validate : function () {
if (this.getValue()) {
var str = this.getValue();
if (!/^(?:(?:([01]?\d|2[0-3]):)?([0-5]?\d):)?([0-5]?\d)$/i.test(str)) {
alert(editor.lang.youtube.invalidTime);
return false;
}
}
}
},
{
id : 'chkControls',
type : 'checkbox',
'default' : editor.config.youtube_controls != null ? editor.config.youtube_controls : true,
label : editor.lang.youtube.chkControls
}
]
}
]
}
],
onOk: function()
{
var content = '';
var responsiveStyle = '';
if (this.getContentElement('youtubePlugin', 'txtEmbed').isEnabled()) {
content = this.getValueOf('youtubePlugin', 'txtEmbed');
}
else {
var url = 'https://', params = [], startSecs, paramAutoplay='';
var width = this.getValueOf('youtubePlugin', 'txtWidth');
var height = this.getValueOf('youtubePlugin', 'txtHeight');
if (this.getContentElement('youtubePlugin', 'chkPrivacy').getValue() === true) {
url += 'www.youtube-nocookie.com/';
}
else {
url += 'www.youtube.com/';
}
url += 'embed/' + video;
if (this.getContentElement('youtubePlugin', 'chkRelated').getValue() === false) {
params.push('rel=0');
}
if (this.getContentElement('youtubePlugin', 'chkAutoplay').getValue() === true) {
params.push('autoplay=1');
paramAutoplay='autoplay';
}
if (this.getContentElement('youtubePlugin', 'chkControls').getValue() === false) {
params.push('controls=0');
}
startSecs = this.getValueOf('youtubePlugin', 'txtStartAt');
if (startSecs) {
var seconds = hmsToSeconds(startSecs);
params.push('start=' + seconds);
}
if (params.length > 0) {
url = url + '?' + params.join('&');
}
if (this.getContentElement('youtubePlugin', 'chkResponsive').getValue() === true) {
content += '<div class="youtube-embed-wrapper" style="position:relative;padding-bottom:56.25%;padding-top:30px;height:0;overflow:hidden">';
responsiveStyle = 'style="position:absolute;top:0;left:0;width:100%;height:100%"';
}
if (this.getContentElement('youtubePlugin', 'chkOlderCode').getValue() === true) {
url = url.replace('embed/', 'v/');
url = url.replace(/&/g, '&amp;');
if (url.indexOf('?') === -1) {
url += '?';
}
else {
url += '&amp;';
}
url += 'hl=' + (this.getParentEditor().config.language ? this.getParentEditor().config.language : 'en') + '&amp;version=3';
content += '<object width="' + width + '" height="' + height + '" ' + responsiveStyle + '>';
content += '<param name="movie" value="' + url + '"></param>';
content += '<param name="allowFullScreen" value="true"></param>';
content += '<param name="allowscriptaccess" value="always"></param>';
content += '<embed src="' + url + '" type="application/x-shockwave-flash" ';
content += 'width="' + width + '" height="' + height + '" '+ responsiveStyle + ' allowscriptaccess="always" ';
content += 'allowfullscreen="true"></embed>';
content += '</object>';
}
else
if (this.getContentElement('youtubePlugin', 'chkNoEmbed').getValue() === true) {
var imgSrc = '//img.youtube.com/vi/' + video + '/sddefault.jpg';
content += '<a href="' + url + '" ><img width="' + width + '" height="' + height + '" src="' + imgSrc + '" ' + responsiveStyle + '/></a>';
}
else {
content += '<iframe allow="' + paramAutoplay + ';" width="' + width + '" height="' + height + '" src="' + url + '" ' + responsiveStyle;
content += 'frameborder="0" allowfullscreen></iframe>';
}
if (this.getContentElement('youtubePlugin', 'chkResponsive').getValue() === true) {
content += '</div>';
}
}
var element = CKEDITOR.dom.element.createFromHtml(content);
var instance = this.getParentEditor();
instance.insertElement(element);
}
};
});
}
});
})();
function handleLinkChange(el, api) {
var video = ytVidId(el.getValue());
var time = ytVidTime(el.getValue());
if (el.getValue().length > 0) {
el.getDialog().getContentElement('youtubePlugin', 'txtEmbed').disable();
}
else {
el.getDialog().getContentElement('youtubePlugin', 'txtEmbed').enable();
}
if (video && time) {
var seconds = timeParamToSeconds(time);
var hms = secondsToHms(seconds);
el.getDialog().getContentElement('youtubePlugin', 'txtStartAt').setValue(hms);
}
}
function handleEmbedChange(el, api) {
if (el.getValue().length > 0) {
el.getDialog().getContentElement('youtubePlugin', 'txtUrl').disable();
}
else {
el.getDialog().getContentElement('youtubePlugin', 'txtUrl').enable();
}
}
/**
* JavaScript function to match (and return) the video Id
* of any valid Youtube Url, given as input string.
* @author: Stephan Schmitz <eyecatchup@gmail.com>
* @url: http://stackoverflow.com/a/10315969/624466
*/
function ytVidId(url) {
var p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;
return (url.match(p)) ? RegExp.$1 : false;
}
/**
* Matches and returns time param in YouTube Urls.
*/
function ytVidTime(url) {
var p = /t=([0-9hms]+)/;
return (url.match(p)) ? RegExp.$1 : false;
}
/**
* Converts time in hms format to seconds only
*/
function hmsToSeconds(time) {
var arr = time.split(':'), s = 0, m = 1;
while (arr.length > 0) {
s += m * parseInt(arr.pop(), 10);
m *= 60;
}
return s;
}
/**
* Converts seconds to hms format
*/
function secondsToHms(seconds) {
var h = Math.floor(seconds / 3600);
var m = Math.floor((seconds / 60) % 60);
var s = seconds % 60;
var pad = function (n) {
n = String(n);
return n.length >= 2 ? n : "0" + n;
};
if (h > 0) {
return pad(h) + ':' + pad(m) + ':' + pad(s);
}
else {
return pad(m) + ':' + pad(s);
}
}
/**
* Converts time in youtube t-param format to seconds
*/
function timeParamToSeconds(param) {
var componentValue = function (si) {
var regex = new RegExp('(\\d+)' + si);
return param.match(regex) ? parseInt(RegExp.$1, 10) : 0;
};
return componentValue('h') * 3600
+ componentValue('m') * 60
+ componentValue('s');
}
/**
* Converts seconds into youtube t-param value, e.g. 1h4m30s
*/
function secondsToTimeParam(seconds) {
var h = Math.floor(seconds / 3600);
var m = Math.floor((seconds / 60) % 60);
var s = seconds % 60;
var param = '';
if (h > 0) {
param += h + 'h';
}
if (m > 0) {
param += m + 'm';
}
if (s > 0) {
param += s + 's';
}
return param;
}

View File

@ -1,6 +1,6 @@
from django import forms
from django.forms import ModelForm
from .models import Data
from .models import Data, DataFile
class CloudAddFileForm(forms.ModelForm):

View File

@ -1,14 +1,14 @@
from django.db import models
from django.contrib.auth.models import User
from users.models import Agency
from users.models import Agency, AgencyGroup
# Create your models here.
from django.db import models
from django.utils import timezone
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/agency_<id>/<subdirs>/<filename>
return 'agency_{0}/{1}/{2}'.format(instance.agency.pk, instance.subdir, filename)
# file will be uploaded to MEDIA_ROOT/agency_<id>/files/<subdirs>/<filename>
return 'agencydata/agency_{0}/files/{1}'.format(instance.agency.pk, filename)
class Data(models.Model):
@ -19,5 +19,35 @@ class Data(models.Model):
owner = models.ForeignKey(User, on_delete=models.PROTECT)
agency = models.ForeignKey(Agency, on_delete=models.CASCADE, default=None)
def __str__(self):
def __str__(self):
return str(self.file.name)
class DataDir(models.Model):
name = models.CharField(max_length=2000, default="", blank=True, null=True)
is_root = models.BooleanField(default=False)
dirs = models.ManyToManyField('self', blank=True, related_name='dirs_in_dirs', symmetrical = False)
visibleby = models.ManyToManyField(AgencyGroup, blank=True, related_name='visible_by_user')
date_created = models.DateTimeField(default = timezone.now)
date_last_modified = models.DateTimeField(default = timezone.now)
owner = models.ForeignKey(User, on_delete=models.PROTECT, blank=True, null=True)
agency = models.ForeignKey(Agency, on_delete=models.CASCADE)
parent = models.ForeignKey('DataDir', on_delete=models.CASCADE, blank=True, null=True, related_name='dir_in_dir')
def __str__(self):
return str(self.name)
class DataFile(models.Model):
name = models.CharField(max_length=2000, default="", blank=True, null=True)
file = models.FileField(null=True, max_length=255, upload_to=user_directory_path, blank=True)
date_created = models.DateTimeField(default = timezone.now)
date_last_modified = models.DateTimeField(default = timezone.now)
owner = models.ForeignKey(User, on_delete=models.PROTECT, default=None, blank=True, null=True)
agency = models.ForeignKey(Agency, on_delete=models.CASCADE, default=None, blank=True, null=True)
parent = models.ForeignKey(DataDir, on_delete=models.PROTECT, related_name='thisfileindir', blank=True, null=True)
def __str__(self):
return str(self.name)

View File

@ -1,51 +1,741 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% load counter_tag %}
{% load static %}
{% block content %}
<div class="content-section col-12">
<h3>Dateien</h3>
<hr>
<p>
Hier können Sie Dateien und Ordner für ihre Agentur verwalten.
</p>
<form method="POST" id="fileuploadform" enctype="multipart/form-data" class="col-6">
{% csrf_token %}
{{form.media}}
{{form|crispy}}
<div class="mt-2">
<button class="btn btn-primary" type="submit">Hochladen</button>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script src="{% static 'users/js/jsLists.js' %}"></script>
<link href="{% static 'users/css/jsLists.css' %}" rel="stylesheet">
<style>
.icon-hover:hover{
color: gray;
}
a.disabled {
pointer-events: none;
cursor: default;
}
</style>
<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="fileerr" class="toast alert-danger" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="mr-auto">Daten gefunden</strong>
</div>
<div class="toast-body">
<div id="toast_errcontent">Achtung! In Unterverzeichnissen befinden sich Dateien. Es können nur Ordner ohne Unterordner gelöscht werden!</div>
</div>
</div>
</form>
<div class="mt-4">
<p>
{% if all_files %}
<table class="table table-hover">
</div>
<div class="content-section col-12">
<h3>Dateien&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Hier können Sie Dateien und Ordner für ihre Agentur verwalten." class="far fa-question-circle"></i></small></h3>
<hr>
</div>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item" aria-current="page"><a href="{% url 'cloud-main' 'first' %}"><i class="fas fa-home"></i></a></li>
{% for cr in breadcrump %}
{% if forloop.last %}
<li class="breadcrumb-item" active>{{cr}}</li>
{% else %}
<li class="breadcrumb-item"><a href="{% url 'cloud-main' cr.pk %}">{{cr.name}}</a></li>
{% endif %}
{% endfor %}
{% if user|usergperm:"filedirmanager" %}
<li class="breadcrumb-item" active><i onclick="javascript:addDirModal()" class="fas fa-folder-plus icon-hover"></i></li>
{% endif %}
</ol>
</nav>
{% if user|usergperm:"filesviewer" %}
<table class="table table-hover" id="dirfilestable">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col"><small><i data-toggle="tooltip" data-placement="top" title="Ziehen Sie Dateien direkt auf die Ordner, um sie in die Ordner hochzuladen oder in den unteren Bereich, um Dateien in diesen Ordner hochzuladen." class="far fa-question-circle"></i></small></th>
<th scope="col">Name</th>
<th scope="col">Eigentümer</th>
<th scope="col">Datum</th>
<th scope="col"></th>
<th scope="col">Erstellt</th>
<th scope="col">Geändert</th>
<th></th>
</tr>
</thead>
<tbody>
{% for ele in all_files %}
<tr>
<td>{{forloop.counter}}</td>
<td>{{ele.file}}</td>
<td>{{ele.owner.first_name}} {{ele.owner.last_name}}</td>
<td>{{ele.date_created}}</td>
<td>Optionen</td>
</tr>
{% endfor %}
<tbody>
{% for d in dirs %}
{% setbool False %}
{% for dirgroup in d.visibleby.all %}
{% if user|has_group:dirgroup.group.name %}
{% setbool True %}
{% endif %}
{% endfor %}
{% if d.visibleby.all|length == 0 %}
{% setbool True %}
{% endif %}
{% getbool as groupchecker %}
<tr id="dir_{{d.pk}}" class="droppable_tr">
<td id="dir_{{d.pk}}_icon"><i class="fas fa-folder" ></i>
</td>
<td>
{% if groupchecker %}
<a href="{% url 'cloud-main' d.pk %}">{{d.name}}</a>
{% else %}
<span class="text-secondary"><i class="fas fa-lock"></i>&nbsp;{{d.name}}</span>
{% endif %}
</td>
<td>{{d.owner.first_name}} {{d.owner.last_name}}</td>
<td>{{d.date_created|date:"d.m.Y G:i"}}</td>
<td>{{d.date_last_modified|date:"d.m.Y G:i"}}</td>
<td>
{% if user|usergperm:"filedirmanager" and groupchecker%}
<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">Ordneroptionen</div>
<a class="dropdown-item" href="javascript:changeDirName({{d.pk}})">Umbenennen</a>
<a class="dropdown-item" href="javascript:showGroupChangeModal({{d.pk}})">Zugriff einschränken</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="javascript:delDataDirObje({{d.pk}})" >Löschen</a>
</div>
</div>
{% endif %}
</td>
</tr>
{% endfor %}
{% for file in files %}
<tr>
<td>
<i class="fas fa-file" ></i>
</td>
<td><a href="{{file.file.url}}" download>{{file.name}}</a></td>
<td>{{file.owner.first_name}} {{file.owner.last_name}}</td>
<td>{{file.date_created|date:"d.m.Y G:i"}}</td>
<td>{{file.date_last_modified|date:"d.m.Y G:i"}}</td>
<td>
{% if user|usergperm:"filesmanager" %}
<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">Dateioptionen</div>
<a class="dropdown-item" href="javascript:moveFile({{file.pk}})">Verschieben</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="javascript:delDataFileObje({{file.pk}})" >Löschen</a>
</div>
</div>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="alert alert-primary" role="alert">
Für Ihre Agentur wurden noch keine Dateien hochgeladen.
</div>
{% endif %}
</p>
{% endif %}
{% if user|usergperm:"filesmanager" %}
<form method="POST" id="uploadFileForm" enctype="multipart/form-data">
<input type="file" id="uploadedfile" name="uploadedfile" style="display:none">
</form>
<div class="alert alert-secondary droppable_div text-center mt-5" id="{{parentid}}_div" role="alert" style="line-height: 45px; text-align: center;">
<button type="button" class="btn btn-primary btn-sm" id="uploadButton" onclick="javascript:uploadButtonPush()"><i class="fas fa-plus"></i></button>&nbsp;&nbsp;&nbsp;zum Hochladen klicken oder neue Dateien hier hineinziehen.<p><small>Dateien werden im aktuellen Ordner
<b>{% if breadcrump|length == 0 %}
Heimverzeichnis
{% else %}
{{breadcrump.0}}
{% endif %}</b>
gespeichert.
</small></p>
</div>
{% endif %}
<!-- MODAL CHANGE DIRNAME -->
<div class="modal fade" id="changeName" 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">
<span id="actualName"></span>&nbsp;Umbenennen
</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">Name:</label>
<input class="form-control" id="changename" type="text" value="" placeholder="Ordnername" onkeyup="javascript:validateNewName(this.value)">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">Abrechen</button>&nbsp;
<button id="doUpdateName" type="button" class="btn btn-success" data-dismiss="modal" onclick="javascript:updateName()" disabled="false">Speichern</button>
</div>
</div>
</div>
</div>
{% endblock content %}
</div>
<!-- CONFIRMA DELETE DIR -->
<div class="modal fade" id="delDataObj" 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">Ordner 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">
Mit löschen fortfahren? Alle Dateien in diesem Verzeichnis werden ebenfalls gelöscht!
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal" onclick="javascript:doDelDataDir()">Löschen</button>&nbsp;&nbsp;
<button type="button" class="btn btn-success" data-dismiss="modal">Abbrechen</button>
</div>
</div>
</div>
</div>
<!-- FILE FORBIDDEN DELETE FILE -->
<div class="modal fade" id="forbiddenFileType" 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">Datei nicht erlaubt</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">
Diesen Dateitypen dürfen Sie nicht hochladen.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
<!-- CONFIRMA DELETE FILE -->
<div class="modal fade" id="delDataFile" 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">Datei 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">
Datei <b><span id="filenametodel"></span></b> wirklich löschen?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal" onclick="javascript:doDelDataFile()">Löschen</button>&nbsp;&nbsp;
<button type="button" class="btn btn-success" data-dismiss="modal">Abbrechen</button>
</div>
</div>
</div>
</div>
<!-- CONFIRMA MOVE/DIR -->
<div class="modal fade" id="moveDataModal" 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">Datei Verschieben</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">
Bitte neues Verzeichnis auswählen:
<div id="agencydirlist"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal">Abbrechen</button>
</div>
</div>
</div>
</div>
<!-- MODEAL ADD DIR -->
<div class="modal fade" id="addDir" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="" aria-hidden="false">
<div class="modal-dialog " role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="mainmodalArea_title">
{% if breadcrump|length == 0 %}
Ordner in Heimverzeichnis der Agentur erstellen
{% else %}
Ordner in {{breadcrump.0}} erstellen
{% endif %}
</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">Name:</label>
<input class="form-control" id="newdirname" type="text" value="" placeholder="Ordnername" onkeyup="javascript:validateDirName(this.value, 0)">
</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:addDirAction()" disabled="true">Ordner anlegen</button>
</div>
</div>
</div>
</div>
<!-- CHANGE GROUPS -->
<div class="modal fade" id="changeGroupOfDataObj" 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">Zugriffe einschränken</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">
Welche Gruppen dürfen auf diese Daten Zugriff haben?
<p><small>Ist keine Gruppe ausgewählt, darf jeder der Agentur diese Daten sehen!</small></p>
<div class="row">
<div class="col-6">
{% for g in agencygroups %}
{% if forloop.counter|divisibleby:6 %}
</div> <div class="col-6">
<div class="custom-control custom-checkbox mb-2">
<input type="checkbox" class="custom-control-input groupclass" name="group_{{g.pk}}" id="group_{{g.pk}}" onchange="javascript:changeGroup({{g.pk}}, this.checked)">
<label class="custom-control-label" for="group_{{g.pk}}" >{{g.agencygroupname}}</label>
</div>
{% else %}
<div class="custom-control custom-checkbox mb-2">
<input type="checkbox" class="custom-control-input groupclass" name="group_{{g.pk}}" id="group_{{g.pk}}" onchange="javascript:changeGroup({{g.pk}}, this.checked)">
<label class="custom-control-label" for="group_{{g.pk}}" >{{g.agencygroupname}}</label>
</div>
{% endif %}
{% endfor %}
</div></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal">Beenden</button>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$(".toast").toast({
autohide: true,
delay : 5000
});
});
//GROUPS
function showGroupChangeModal(tochangeid){
$("#changeGroupOfDataObj").modal("toggle");
$(".groupclass").attr("checked", false);
workingdirid = tochangeid;
$.ajax(
{
type: "GET",
url: "{% url 'cloud-adddir' parentid %}",
data:{
action : "getgroupsofdir",
dirid : workingdirid
},
success: function( data )
{
for(i = 0; i < data["data"]["gdir"].length; i++){
$("#group_" + data["data"]["gdir"][i]['id']).attr("checked", true);
}
}
});
}
$('#changeGroupOfDataObj').on('hidden.bs.modal', function (e) {
window.location = window.location
})
function changeGroup(groupid, value){
$.ajax(
{
type: "GET",
url: "{% url 'cloud-adddir' parentid %}",
data:{
action : "changedirgroups",
groupid : groupid,
dirid : workingdirid,
value : value
},
success: function( data )
{
}
});
}
//MOVING OPERATIONS
function moveFile(fileid)
{
workingfileid = fileid;
workingdirid = false;
$("#moveDataModal").modal("toggle");
$.ajax(
{
type: "GET",
url: "{% url 'cloud-adddir' parentid %}",
data:{
action : "getdirlist"
},
success: function( data )
{
$("#agencydirlist").html("");
html = ['<ul id="simple_list"><li><i class="fa fa-folder"></i>&nbsp;<a href="javascript:targetParentToMove({{rootid}})"><b><u>Heimverzeichnis<u></b></a>'];
createList(data["data"]["agencydirlist"], l);
$("#agencydirlist").html(html);
}
});
}
var html = ['<ul id="simple_list"><li><i class="fa fa-folder"></i>&nbsp;<a href="javascript:targetParentToMove({{rootid}})"><b><u>Heimverzeichnis<u></b></a>'];
let l = 2;
//Create UL-LI-List for tree
function createList(arr, l) {
html.push('<ul>');
$.each(arr, function(i, val) {
if(val.parent == ""){
html.push('<li><i class="fa fa-folder mt-2"></i>&nbsp;<a href="javascript:targetParentToMove('+val.id+')"><b>' + val.name + '</b></a>');
}
else {
html.push('<li class="ml-'+l+' mt-2"><i class="fa fa-folder" ></i><a href="javascript:targetParentToMove('+val.id+')">&nbsp;'+val.name+'</a></li>');
}
if (val.subdirs) {
createList(val.subdirs, l+1)
}
html.push('</li>');
});
html.push('</ul>');
}
function targetParentToMove(parid){
$.ajax(
{
type: "GET",
url: "{% url 'cloud-adddir' parentid %}",
data:{
action : "movefile",
fileid : workingfileid,
newpar : parid
},
success: function( data )
{
window.location = window.location
}
});
}
// preventing page from redirecting
$("html").on("dragover", function(e) {
e.preventDefault();
e.stopPropagation();
});
$("html").on("drop", function(e) { e.preventDefault(); e.stopPropagation(); });
uploadtoparent = {{parentid}};
</script>
{% if user|usergperm:"filesmanager" %}
<script type="text/javascript">
$( ".droppable_tr" ).on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
currentid = e["currentTarget"]['id'];
$("#" + currentid + "_icon").html("");
$("#" + currentid + "_icon").html('<i class="fas fa-folder-open"></i>');
$("#" + currentid).addClass('table-secondary');
});
$('.droppable_tr').on('drop', function (e) {
e.stopPropagation();
e.preventDefault();
uploadtoparent = e["currentTarget"]['id'].split("_")[1];
uploadAction(e.originalEvent.dataTransfer.files[0], e["currentTarget"]['id'].split("_")[1]);
$("#" + currentid).removeClass('table-secondary');
$("#" + currentid + "_icon").html("");
$("#" + currentid + "_icon").html('<i class="fas fa-folder"></i>');
});
$('.droppable_tr').on('dragleave', function (e) {
e.stopPropagation();
e.preventDefault();
currentid = e["currentTarget"]['id'];
$("#" + currentid + "_icon").html("");
$("#" + currentid + "_icon").html('<i class="fas fa-folder"></i>');
$("#" + currentid).removeClass('table-secondary');
});
$( ".droppable_div" ).on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
currentid = e["currentTarget"]['id'];
$("#{{parentid}}_div").addClass('bg-secondary');
});
$('.droppable_div').on('drop', function (e) {
e.stopPropagation();
e.preventDefault();
$("#{{parentid}}_div").removeClass('bg-secondary');
uploadAction(e.originalEvent.dataTransfer.files[0], e["currentTarget"]['id'].split("_")[0]);
});
$('.droppable_div').on('dragleave', function (e) {
e.stopPropagation();
e.preventDefault();
currentid = e["currentTarget"]['id'];
$("#{{parentid}}_div").removeClass('bg-secondary');
});
allowedtypes = "application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, text/plain, application/pdf, image/*"
function uploadAction(filetodo, parid){
var formData = new FormData($("#uploadFileForm")[0]);
formData.append("uploadedfile", filetodo);
var bar = $('.bar');
var percent = $('.percent');
if(allowedtypes.includes(filetodo.type) && filetodo.type.length > 0){
$.ajax({
url: "{% url 'cloud-adddir' %}" + parid,
headers: {
"X-CSRFTOKEN": "{{ csrf_token }}"
},
data: formData,
type: 'POST',
cache: false,
processData: false,
contentType: false,
beforeSend: function(){
$("#uploadModalProgress").modal("toggle");
},
uploadProgress: function(event, position, total, percentComplete){
var percentVal = percentComplete + '%';
},
success: function(data) {
if(data["success"] == true){
window.location = window.location;
}
else{
$("#forbiddenFileType").modal("toggle")
}
}
});
}
else{
$("#forbiddenFileType").modal("toggle")
}
}
</script>
{% endif %}
<script type="text/javascript">
$('#uploadedfile').on('change', function() {
uploadAction($("#uploadedfile")[0]['files'][0], {{parentid}});
});
function uploadButtonPush(){
$("#uploadedfile").click();
}
//FILE OPERATIONS
workingfileid = false;
function delDataFileObje(fileid){
workingfileid = fileid;
$("#delDataFile").modal("toggle");
$.ajax(
{
type: "GET",
url: "{% url 'cloud-adddir' parentid %}",
data:{
action : "getname_file",
id : workingfileid
},
success: function( data )
{
$("#filenametodel").html("");
$("#filenametodel").html(data["data"]["filename"]);
}
});
}
function doDelDataFile(){
$.ajax(
{
type: "GET",
url: "{% url 'cloud-adddir' parentid %}",
data:{
action : "del_file",
id : workingfileid
},
success: function( data )
{
window.location = window.location;
}
});
}
workingdirid = false;
// DIR FUNCTIONS
function delDataDirObje(id){
workingdirid = id;
$("#delDataObj").modal("toggle");
}
function doDelDataDir(){
$("#delDataObj").modal("toggle");
$.ajax(
{
type: "GET",
url: "{% url 'cloud-adddir' parentid %}",
data:{
action : "del_dir",
id : workingdirid
},
success: function( data )
{
if(data["success"]){
window.location = window.location;
}
else{
$("#fileerr").toast("show");
}
}
});
}
function changeDirName(dirid){
$("#changeName").modal("toggle");
workingdirid = dirid;
$.ajax(
{
type: "GET",
url: "{% url 'cloud-adddir' parentid %}",
data:{
action : "getname_dir",
id : dirid
},
success: function( data )
{
$("#actualName").html("Ordner <b>" + data["data"]['dirname'] + "</b>");
$("#changename").val(data["data"]['dirname']);
$("#doUpdateName").attr("disabled", false);
}
});
}
function updateName(){
$.ajax(
{
type: "GET",
url: "{% url 'cloud-adddir' parentid %}",
data:{
action : "change_dir_name",
id : workingdirid,
newdirname : $("#changename").val()
},
success: function( data )
{
$("#changeName").modal("toggle");
window.location = window.location;
}
});
}
function addDirModal(){
$("#addDir").modal("toggle");
$("#newdirname").val("");
$("#doActionTaskModal").attr("disabled", true)
}
//VALIDATE FOR CORRECT INPUT IN GROUP
function validateNewName(newdirname){
var letters = /^[A-Za-zßäöüÄÖÜ_\-0-9 ]+$/;
if(newdirname.length > 0){
if(!newdirname.match(letters))
{
$("#doUpdateName").attr("disabled", true);
}
else{
$("#doUpdateName").attr("disabled", false);
}
}
else{
$("#doUpdateName").attr("disabled", true);
}
}
//VALIDATE FOR CORRECT INPUT IN GROUP
function validateDirName(newdirname){
var letters = /^[A-Za-zßäöüÄÖÜ_\-0-9 ]+$/;
if(newdirname.length > 0){
if(!newdirname.match(letters))
{
$("#doActionTaskModal").attr("disabled", true);
}
else{
$("#doActionTaskModal").attr("disabled", false);
}
}
else{
$("#doActionTaskModal").attr("disabled", true);
}
}
function addDirAction(){
$.ajax(
{
type: "GET",
url: "{% url 'cloud-adddir' parentid %}",
data:{
action : "adddir",
parent : {{parentid}},
newdirname : $("#newdirname").val()
},
success: function( data )
{
window.location = window.location;
}
});
}
</script>
{% endblock %}

View File

@ -1,6 +1,9 @@
from django.urls import path
from .views import CloudMain
from . import views
urlpatterns = [
path('', CloudMain.as_view(template_name="cloud/cloud_main.html"), name='cloud-main'),
path('<slug:pk>', CloudMain, name='cloud-main'),
path('clajax/', views.adddirbyajax, name="cloud-adddir"),
path('clajax/<slug:parent>', views.adddirbyajax, name="cloud-adddir"),
]

View File

@ -9,25 +9,225 @@ from django.views.generic.edit import FormView
from .forms import CloudAddFileForm
from django.conf import settings
from django.core.files.storage import default_storage
# Create your views here.
class CloudMain(LoginRequiredMixin, FormView):
form_class = CloudAddFileForm
success_url = '/cloud/'
from digitaleagentur.settings import BASE_DIR
from django.http import JsonResponse
import os
from .models import DataDir, DataFile
from datetime import datetime
from users.models import AgencyGroup
def form_valid(self, form):
form = CloudAddFileForm(self.request.POST, self.request.FILES['file'])
'''
tempdata = Data(file=self.request.FILES['file'], subdir="subdir1/subdir2", agency=self.request.user.profile.agency, owner=self.request.user)
tempdata.save()
return super().form_valid(form)
Prüft, ob ein Nutzer in diesen Ordner Zugriffsrechte hat. Läuft den gesamten Strang bis nach oben,
ob ein Übergeordneter Ordner Rechte einschränkt.
'''
@login_required
def checkUserDirRights(request, startdir, userid):
canview = True
user = User.objects.get(pk=userid, profile__agency=request.user.profile.agency)
usergroups=list(user.groups.all())
grouptomach = []
singleObj = DataDir.objects.get(pk=startdir.pk, agency=request.user.profile.agency)
# AGENCYCHECK
if(singleObj.agency.pk == user.profile.agency.pk):
# Get dirs to check
while( singleObj.is_root != True and canview == True):
for g in singleObj.visibleby.all():
grouptomach.append(g.group)
if(len(grouptomach) == 0):
canview = True
else:
if(len(set(usergroups).intersection(grouptomach)) > 0):
canview = True
else:
canview = False
grouptomach = []
singleObj = DataDir.objects.get(pk=singleObj.parent.pk, agency=request.user.profile.agency)
else:
canview = False
return canview
@login_required
def CloudMain(request, pk):
diragency = []
alldirs = []
context = {}
breadcrump = []
files = []
rootid = list(DataDir.objects.filter(is_root=True, agency=request.user.profile.agency))[0].pk
if(pk == "first"):
diragency = list(DataDir.objects.filter(is_root=True, agency=request.user.profile.agency))[0]
alldirs = DataDir.objects.filter(is_root=False, agency=request.user.profile.agency, parent=diragency).order_by("name")
context = {
'active_link' : 'cloud',
'dirs' : alldirs,
'parentid' : diragency.pk,
'files' : DataFile.objects.filter(parent=diragency, agency=request.user.profile.agency).order_by("name"),
'agencygroups' : AgencyGroup.objects.filter(agency=request.user.profile.agency).order_by("agencygroupname"),
"rootid" : rootid
}
else:
# CHECK IF USER HAS RIGHTS TO SEE THIS DIR
groupsofdir = DataDir.objects.get(pk=pk, agency=request.user.profile.agency)
if checkUserDirRights(request, groupsofdir, request.user.pk):
alldirs = DataDir.objects.filter(is_root=False, agency=request.user.profile.agency, parent=pk).order_by("name")
vieweddir = list(DataDir.objects.filter(pk=pk, agency=request.user.profile.agency))[0]
singleObj = DataDir.objects.get(pk=pk, agency=request.user.profile.agency)
while( singleObj.is_root != True):
breadcrump.append(singleObj)
singleObj = DataDir.objects.get(pk=singleObj.parent.pk, agency=request.user.profile.agency)
breadcrump = breadcrump[::-1]
context = {
'active_link' : 'cloud',
'dirs' : alldirs,
'parentid' : pk,
'breadcrump' : breadcrump,
'files' : DataFile.objects.filter(parent=vieweddir, agency=request.user.profile.agency).order_by("name"),
'agencygroups' : AgencyGroup.objects.filter(agency=request.user.profile.agency).order_by("agencygroupname"),
"rootid" : rootid
}
else:
context = {
'active_link' : 'cloud',
}
return render(request, 'cloud/noentrie.html', context)
return render(request, 'cloud/cloud_main.html', context)
# Change context and return for template-data
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
all_files = Data.objects.filter(agency__pk=self.request.user.profile.agency.pk)
context.update({'active_link' : 'cloud', 'all_files': all_files})
return context
@login_required
def adddirbyajax(request, parent):
success = True
data = {}
if(request.method == "GET"):
# NEW DIR
if(request.GET.get("action") == "adddir"):
parentid = request.GET.get("parent")
newdirname = request.GET.get("newdirname")
parent_obj = DataDir.objects.get(pk=parentid, agency=request.user.profile.agency)
tempdir = DataDir(name=newdirname, parent=parent_obj, agency=request.user.profile.agency, owner=request.user)
tempdir.save()
parent_obj.dirs.add(tempdir)
parent_obj.save()
# RETURN DIRNAME
elif(request.GET.get("action") == "getname_dir"):
dirobj = DataDir.objects.get(pk=request.GET.get('id'), agency=request.user.profile.agency)
data = {'dirname' : dirobj.name}
# RETURN COMPLETE AGENCY DIR LIST
elif(request.GET.get("action") == "getdirlist"):
data = {'agencydirlist' : loadAgencyDirList(request)}
# RETURN FILENAME
elif(request.GET.get("action") == "getname_file"):
fileobj = DataFile.objects.get(pk=request.GET.get('id'), agency=request.user.profile.agency)
data = {'filename' : fileobj.name}
# DELETE FILE
elif(request.GET.get("action") == "del_file"):
DataFile.objects.filter(pk=request.GET.get('id'), agency=request.user.profile.agency).delete()
# CHANGE DIR NAME
elif(request.GET.get("action") == "change_dir_name"):
dirobj = DataDir.objects.get(pk=request.GET.get('id'), agency=request.user.profile.agency)
dirobj.name = request.GET.get("newdirname")
dirobj.date_last_modified = datetime.now()
dirobj.save()
# DELETE DIR
elif(request.GET.get("action") == "del_dir"):
try:
DataFile.objects.filter(parent=request.GET.get('id'), agency=request.user.profile.agency).delete()
DataDir.objects.filter(parent=request.GET.get('id'), agency=request.user.profile.agency).delete()
DataDir.objects.get(pk=request.GET.get('id'), agency=request.user.profile.agency).delete()
except:
success = False
# MOVE FILE
elif(request.GET.get("action") == "movefile"):
tempdatafile = DataFile.objects.get(pk=request.GET.get('fileid'), agency=request.user.profile.agency)
tempdatafile.parent = DataDir.objects.get(pk=request.GET.get('newpar'), agency=request.user.profile.agency)
tempdatafile.date_last_modified = datetime.now()
tempdatafile.save()
# GROUPS
# DIR
elif(request.GET.get("action") == "changedirgroups"):
dirid = request.GET.get('dirid')
groupid = request.GET.get('groupid')
value = request.GET.get('value')
if(value == "true"):
DataDir.objects.get(pk=dirid, agency=request.user.profile.agency).visibleby.add(AgencyGroup.objects.get(pk=groupid, agency=request.user.profile.agency))
else:
DataDir.objects.get(pk=dirid, agency=request.user.profile.agency).visibleby.remove(AgencyGroup.objects.get(pk=groupid, agency=request.user.profile.agency))
# GET GROUPS
elif(request.GET.get("action") == "getgroupsofdir"):
dirid = request.GET.get('dirid')
allgroupsofdir = DataDir.objects.get(pk=dirid, agency=request.user.profile.agency).visibleby.all()
grouopsid = []
for ag in allgroupsofdir:
grouopsid.append({"id" : ag.pk})
print(grouopsid)
data = {"gdir" : grouopsid}
elif request.method == 'POST':
tempdir = False
tempdir = DataDir.objects.get(pk=parent)
# VALIDATE FILE-TYPE
file_ext = request.FILES['uploadedfile'].name.split(".")[1]
allowed_types = ["txt", "TXT", "png", "PNG", "jpeg", "JPEG", "jpg", "JPG", "PDF", "pdf", "csv", "CSV", "DOC", "doc", "DOCX", "docx", "ODT", "odt", "PPT", "ppt", "PPTX", "pptx"]
file_ok = False
for t in allowed_types:
if t == file_ext:
file_ok = True
if(file_ok):
tempdatafile = DataFile(file=request.FILES['uploadedfile'], name=request.FILES['uploadedfile'].name, owner=request.user, parent=tempdir, agency=request.user.profile.agency)
tempdatafile.save()
data = {'savedobj_id' : tempdatafile.pk, 'savedobj_name' : tempdatafile.name}
else:
success = False
return JsonResponse({"success" : success, "data" : data})
@login_required
def loadAgencyDirList(request):
alldirs = []
diragency = list(DataDir.objects.filter(is_root=True, agency=request.user.profile.agency))[0]
alldirs_root = DataDir.objects.filter(is_root=False, agency=request.user.profile.agency, parent=diragency).order_by("name")
for d in alldirs_root:
alldirs.append({"id" : d.pk, "parent" : "", "name" : d.name, 'subdirs' : getsubdirs(request, d.pk)})
return alldirs
@login_required
def getsubdirs(request, dirid):
subdirs = []
actid = False
if(isinstance(dirid, DataDir)):
actid = dirid.pk
else:
actid = dirid
alldirs_sub = DataDir.objects.filter(is_root=False, agency=request.user.profile.agency, parent=dirid).order_by("name")
for subdir in alldirs_sub:
tempsubsubdir = DataDir.objects.filter(is_root=False, agency=request.user.profile.agency, parent=subdir).order_by("name")
if(len(tempsubsubdir) > 0):
subdirs.append({"id" : subdir.pk, "parent" : actid, "name" : subdir.name, 'subdirs' : getsubdirs(request, subdir)})
else:
subdirs.append({"id" : subdir.pk, "parent" : actid, "name" : subdir.name, 'subdirs' : []})
return subdirs

View File

@ -29,9 +29,13 @@ DEBUG = True
ALLOWED_HOSTS = ['digitale-agentur.com', 'www.digitale-agentur.com', 'localhost']
# Application definition
INSTALLED_APPS = [
'notificsys.apps.NotificsysConfig',
'users.apps.UsersConfig',
'dasettings.apps.DASettingsConfig',
'areas.apps.AreasConfig',
'orga.apps.OrgaConfig',
'cloud.apps.CloudConfig',
@ -40,17 +44,19 @@ INSTALLED_APPS = [
'standards.apps.StandardsConfig',
'news.apps.NewsConfig',
'crispy_forms',
'colorful',
'ckeditor',
'colorful',
'django_summernote',
'ckeditor_uploader',
'django.contrib.admin',
'mathfilters',
'django.contrib.humanize',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'bootstrap_datepicker_plus'
'bootstrap_datepicker_plus',
'django_cleanup',
'django_user_agents',
]
MIDDLEWARE = [
@ -61,6 +67,7 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django_user_agents.middleware.UserAgentMiddleware',
]
ROOT_URLCONF = 'digitaleagentur.urls'
@ -83,41 +90,6 @@ TEMPLATES = [
WSGI_APPLICATION = 'digitaleagentur.wsgi.application'
# CKEDITOR
CKEDITOR_JQUERY_URL = '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'
CKEDITOR_UPLOAD_PATH = "uploadsCK/" # <-- this folder you uploaded image saved in s3 under media folder
CKEDITOR_RESTRICT_BY_USER = False
CKEDITOR_REQUIRE_STAFF=False
AWS_QUERYSTRING_AUTH = True
CKEDITOR_IMAGE_BACKEND = "pillow"
#CKEDITOR_PLUGINS.addExternal('youtube', "../ckeditorplugins/youtube/youtube/plugin.js");
CKEDITOR_CONFIGS = {
'default': {
'skin': 'moono-lisa',
'toolbar_Basic': [
['Source', '-', 'Bold', 'Italic']
],
'toolbar_YourCustomToolbarConfig': [
{'name': 'basicstyles',
'items': ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat']},
{'name': 'paragraph',
'items': ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-',
'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl',
'Language']},
{'name': 'links', 'items': ['Link', 'Unlink']},
{'name': 'styles', 'items': ['Styles', 'Format', 'Font', 'FontSize']},
{'name': 'colors', 'items': ['TextColor', 'BGColor']},
{'name': 'tools', 'items': ['Maximize', 'ShowBlocks']},
{'name': 'insert',
'items': ['Image', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar', 'PageBreak']},
'/', # put this to force next toolbar on new line
],
'toolbar': 'YourCustomToolbarConfig', # put selected toolbar config here
},
}
# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
@ -130,6 +102,8 @@ DATABASES = {
'PORT' : 3306
}
}
# Password validation
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
@ -202,7 +176,15 @@ EMAIL_HOST_USER = "support@digitale-agentur.com"
EMAIL_HOST_PASSWORD = "aPx9m3!7x3m@8o!t"
DEFAULT_FROM_EMAIL = "support@digitale-agentur.com"
# FOR DATEPICKER
BOOTSTRAP4 = {
'include_jquery': True,
}
OPTIONS={
'libraries': {
'counter_tag': 'standards.tags',
},
}

View File

@ -5,9 +5,7 @@ from django.conf import settings
from django.conf.urls.static import static
from users.views import AgencyCreateView
from . import views
from ckeditor_uploader.views import upload
from django.contrib.auth.decorators import login_required
'''
Main URLS
@ -27,6 +25,7 @@ urlpatterns = [
path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name='login'),
path('', include('users.urls'), name="dashboard-first"),
path('admin/', admin.site.urls),
path('dasettings/', include('dasettings.urls'), name="dasettings"),
path('dashboard/', include('users.urls'), name="dashboard"),
path('areas/', include('areas.urls'), name="areas-management"),
path('tasks/', include('tasks.urls'), name="tasks-management"),
@ -42,11 +41,7 @@ urlpatterns = [
path('register/', AgencyCreateView.as_view(template_name='users/register.html'), name='register'),
path('register/done', views.registerdone, name='register-done'),
path('summernote/', include('django_summernote.urls')),
path('notifications/', include('notificsys.urls'), name="notifications")
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
#urlpatterns += [
# path('ckeditor/upload/', login_required(upload), name='ckeditor_upload'),
# path('ckeditor/', include('ckeditor_uploader.urls')),
#]

View File

@ -1,8 +0,0 @@
3D-Druck
+ Gute Struktur
+ Shortucts
+ Planemodellierung - Als VIdeo noch ein
HTML
- Erweiterten Kurs

View File

@ -1,8 +0,0 @@
3D-Druck
+ Gute Struktur
+ Shortucts
+ Planemodellierung - Als VIdeo noch ein
HTML
- Erweiterten Kurs

View File

@ -1,8 +0,0 @@
3D-Druck
+ Gute Struktur
+ Shortucts
+ Planemodellierung - Als VIdeo noch ein
HTML
- Erweiterten Kurs

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

View File

@ -1,6 +1,7 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% if request.user.profile.agency.module_news %}
<div class="content-section col-6">
<h3>News anlegen</h3>
<hr>
@ -20,4 +21,7 @@ $(document).ready(function() {
});
});
</script>
{% else %}
<h3>Das Modul News wurde in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -1,6 +1,7 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% if request.user.profile.agency.module_news %}
<div class="content-section">
<div class="media">
<div class="media-body">
@ -16,4 +17,7 @@
</div>
</form>
</div>
{% else %}
<h3>Das Modul News wurde in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -1,14 +1,12 @@
{% extends "users/base.html" %}
{% block content %}
{% if request.user.profile.agency.module_news %}
<div class="content-section col-12">
<h3>News</h3>
<h3>News&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Hier können aktuelle Nachrichten für die Agentur erstellt und verwaltet werden." class="far fa-question-circle"></i></small></h3>
<hr>
<p>
Hier können aktuelle Nachrichten für die Agentur erstellt und verwaltet werden.
</p>
<div class="row">
<div class="content-section col-4">
<a class="btn btn-primary" href="{% url 'news-add' %} ">News anlegen</a>
<a class="btn btn-primary" href="{% url 'news-add' %} " data-toggle="tooltip" data-placement="top" title="Neue News für Ihre Agentur erstellen"><i class="fas fa-plus"></i>&nbsp;News</a>
</div>
</div>
<hr>
@ -162,4 +160,7 @@ $('#news_tabs a').on('click', function (e) {
});
</script>
{% else %}
<h3>Das Modul News wurde in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -1,5 +1,6 @@
{% extends "users/base.html" %}
{% block content %}
{% if request.user.profile.agency.module_news %}
<div class="content-section col-12">
<small>
<h2>{{news.name}}</h2>
@ -12,4 +13,7 @@
{{news.media}}
{{news.content|safe}}
</div>
{% else %}
<h3>Das Modul News wurde in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -1,6 +1,7 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% if request.user.profile.agency.module_news %}
<div class="content-section col-6">
<h3>News bearbeiten</h3>
<hr>
@ -20,4 +21,7 @@ $(document).ready(function() {
});
});
</script>
{% else %}
<h3>Das Modul News wurde in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -1,5 +1,6 @@
from django.urls import path
from .views import NewsManagement, NewsAdd, NewsDeleteView
from django.contrib.auth.decorators import login_required, permission_required
from . import views
'''
Permissions definiert in models.py bei USERS und dann hier vor die View geschrieben!
@ -7,9 +8,9 @@ Permissions definiert in models.py bei USERS und dann hier vor die View geschrie
urlpatterns = [
path('', NewsManagement.as_view(template_name="news/news_management.html"), name='news-management'),
path('newsadd/', views.NewsAdd, name='news-add'),
path('newsupdate/<int:id>/', views.NewsUpdate, name='news-update'),
path('news/<int:pk>/delete', NewsDeleteView.as_view(), name='news-delete'),
path('newsadd/', permission_required('users.modulenews')(views.NewsAdd), name='news-add'),
path('newsupdate/<int:id>/', permission_required('users.modulenews')(views.NewsUpdate), name='news-update'),
path('news/<int:pk>/delete', permission_required('users.modulenews')(NewsDeleteView.as_view()), name='news-delete'),
#path('ajax/loadtasks/', views.load_tasks, name='ajax_loadtasks'),
#path('standard/<int:pk>/changestat', views.StandardChangePublic, name="standard-status"),
path('news/<int:pk>/single', views.NewsSingle, name="news-single"),

View File

@ -21,7 +21,7 @@ class NewsManagement(LoginRequiredMixin, ListView):
news = News.objects.filter(agency__pk=self.request.user.profile.agency.pk).filter(go_online_on__lt=filterdate).filter(go_offline_on__gt=filterdate).order_by('-created_date')
news_arch = News.objects.filter(agency__pk=self.request.user.profile.agency.pk).filter(go_offline_on__lt=filterdate).order_by('-created_date')
context = super().get_context_data(**kwargs)
context.update({'active_link' : 'newsmanagement', 'news' : news, 'news_arch' : news_arch})
context.update({'active_link' : 'dashboard', 'news' : news, 'news_arch' : news_arch})
return context
'''
class NewsAddNews(LoginRequiredMixin, CreateView):
@ -57,7 +57,7 @@ def NewsAdd(request):
new_news.save()
messages.success(request, f'News gespeichert!')
return redirect('news-management')
return redirect('users-dashboard')
else:
normalForm = NewsAddNews(instance=request.user)
@ -67,19 +67,19 @@ def NewsAdd(request):
context = {
'normalForm' : normalForm,
#'editorForm' : editorForm,
'active_link' : 'newsmanagement'
'active_link' : 'dashboard'
}
return render(request, 'news/news_addnews.html', context)
@login_required
def NewsUpdate(request, id):
news = News.objects.get(pk=id)
news = News.objects.get(pk=id, agency=request.user.profile.agency)
if request.method == 'POST':
normalForm = NewsAddNews(request.POST, instance=news)
#editorForm = NewsAddNewsEditor(request.POST, instance=news)
if normalForm.is_valid():
news = News.objects.get(pk=id)
news = News.objects.get(pk=id, agency=request.user.profile.agency)
news.last_modified_by = request.user
news.last_modified_on = datetime.now()
news.go_online_on = normalForm.cleaned_data['go_online_on']
@ -98,7 +98,7 @@ def NewsUpdate(request, id):
context = {
'normalForm' : normalForm,
#'editorForm' : editorForm,
'active_link' : 'newsmanagement',
'active_link' : 'dashboard',
'news_id' : news.pk,
}
return render(request, 'news/news_update.html', context)
@ -116,9 +116,10 @@ class NewsDeleteView(LoginRequiredMixin, DeleteView):
@login_required
def NewsSingle(request, pk):
news = News.objects.get(pk=pk)
news = News.objects.get(pk=pk, agency=request.user.profile.agency)
context = {
'active_link':'newsmanagement',
'active_link':'dashboard',
'news' : news
}
}
return render(request, 'news/news_single.html', context)

View File

@ -50,6 +50,7 @@ for(i = 0; i < data.length; i++){
//Creates nested array from data
function unflatten(arr) {
console.log(arr);
var tree = [],
mappedArr = {},
arrElem,
@ -78,7 +79,7 @@ function unflatten(arr) {
return tree;
}
var html = ['<ul class="tree">'];
var html = ['<ul class="tree" >'];
//Create UL-LI-List for tree
function createList(arr) {

View File

@ -1,153 +0,0 @@
{% extends "users/base.html" %}
{% block content %}
<script src="https://cdn.syncfusion.com/ej2/dist/ej2.min.js" type="text/javascript"></script>
<link href="https://cdn.syncfusion.com/ej2/material.css" rel="stylesheet">
<div class="content-section">
<h3>{{request.user.profile.agency.name}}</h3>
<hr>
<h4>Organigramm</h4>
<div class="text-center">
<div id="diagram"></div>
</div>
<div id="spinner" class="text-center" style="margin-top: 15%; width: 100%; height: 100%; display: none;">
<div class="spinner-border text-danger" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
</div>
<script type="text/javascript">
var data = [
{ 'id': 'parent', 'role': "", 'name': '{{request.user.profile.agency.name}}', 'color': '#71AF17', "imageUrl": ""},
{% for u in agencyuser %}
{% if u.profile.parent == u %}
{ 'id': '{{u.pk}}' , 'name': "{{u.first_name}} {{u.last_name}}",'role': '{{u.profile.get_func_display}}\n{{u.profile.compfunc}}', 'manager': 'parent', 'color': '#1859B7', "imageUrl": "{{u.profile.get_photo_url}}", 'userid' : '{{u.pk}}' },
{% else %}
{ 'id': '{{u.pk}}', 'name': "{{u.first_name}} {{u.last_name}}", 'role': '{{u.profile.get_func_display}}\n{{u.profile.compfunc}}', 'manager': '{{u.profile.parent.pk}}', 'color': '#1859B7', "imageUrl": "{{u.profile.get_photo_url }}", 'userid' : '{{u.pk}}'},
{% endif %}
{% endfor %}
];
var items = new ej.data.DataManager(data);
var diagram = new ej.diagrams.Diagram({
width: "1350px", height: "800px",
/*tool: ej.diagrams.DiagramTools.ZoomPan,*/
dataSourceSettings: {
// set the unique field from data source
id: 'id',
// set the field which is used to identify the reporting person
parentId: 'manager',
// define the employee data
dataManager: items
},
layout: {
// set the layout type
type: 'OrganizationalChart',
},
getConnectorDefaults: connectorDefaults,
setNodeTemplate: setNodeTemplate,
// hide the gridlines in the diagram
snapSettings: { constraints: ej.diagrams.SnapConstraints.None }
});
diagram.appendTo('#diagram');
diagram.selectionChange = goToUser
function goToUser(){
if(diagram.selectedItems['nodes'][0] != undefined){
selected_id = diagram.selectedItems['nodes'][0]['properties']['data']['id'];
if(selected_id != 'parent'){
$("#diagram").hide();
$("#spinner").show();
window.location.href = "/orga/single/"+selected_id;
}
else{
$("#diagram").hide();
$("#spinner").show();
window.location.href = "/orga/";
}
}
}
//Define the common settings for connectors.
function connectorDefaults(connector) {
connector.targetDecorator.shape = 'None';
connector.type = 'Orthogonal';
connector.style.strokeColor = 'gray';
return connector;
}
//Funtion to add the Template of the Node.
function setNodeTemplate(obj, diagram) {
// create the stack panel
var content = new ej.diagrams.StackPanel();
content.id = obj.id + '_outerstack';
content.orientation = 'Horizontal';
content.style.strokeColor = 'gray';
content.padding = { left: 5, right: 10, top: 5, bottom: 5 };
// create the image element to map the image data from the data source
var image = new ej.diagrams.ImageElement();
if(obj['properties']['data']['id'] == 'parent'){
image.id = obj.id + '_pic';
image.width = 0; image.height = 0; image.style.strokeColor = 'none';
image.source = obj.data.imageUrl;
}
else{
image.id = obj.id + '_pic';
image.width = 75; image.height = 75; image.style.strokeColor = 'none';
image.source = obj.data.imageUrl;
}
// create the stack panel to append the text elements.
var innerStack = new ej.diagrams.StackPanel();
innerStack.style.strokeColor = 'none';
innerStack.margin = { left: 5, right: 0, top: 0, bottom: 0 };
innerStack.id = obj.id + '_innerstack';
if(obj['properties']['data']['id'] == 'parent'){
var text = new ej.diagrams.TextElement();
text.style.bold = true;
text.style.fontSize = 24;
text.id = obj.id + '_name';
text.content = obj.data.name;
}
else{
var text = new ej.diagrams.TextElement();
text.style.bold = true;
text.style.fontSize = 18;
text.id = obj.id + '_name';
text.content = obj.data.name;
}
// create the text element to map the name data from the data source
if(obj['properties']['data']['id'] == 'parent'){
var desigText = new ej.diagrams.TextElement();
desigText.id = obj.id + '_desig';
desigText.style.fontSize = 0;
desigText.content = obj.data.role;
}
else{
var desigText = new ej.diagrams.TextElement();
desigText.id = obj.id + '_desig';
desigText.style.fontSize = 16;
desigText.content = obj.data.role;
}
// create the text element to map the role data from the data source
// append the text elements
innerStack.children = [text, desigText];
// append the image and inner stack elements
content.children = [image, innerStack];
return content;
}
</script>
{% endblock content %}

View File

@ -17,9 +17,12 @@ def mainorga(request):
# Check, if parented users are invisible. Remove them and give user an info!
for ele in nonvisibleuser:
for vis in agencyuser:
if vis.profile.parent.profile.pk == ele.pk:
agencyuser.remove(vis)
invisible_users += 1
try:
if vis.profile.parent.profile.pk == ele.pk:
agencyuser.remove(vis)
invisible_users += 1
except:
pass
context = {
'active_link' : 'orga',
@ -32,7 +35,7 @@ def mainorga(request):
@login_required
def singleorga(request, pk):
user = User.objects.get(pk=pk)
user = User.objects.get(pk=pk, profile__agency=request.user.profile.agency)
'''
VON GROß NACH KLEIN - SINNLOS
prios = Prio.objects.filter(user__pk=pk).order_by('-prio')[::-1]
@ -64,7 +67,7 @@ def singleorga(request, pk):
'user_id' : user_id,
'prios' : prios,
'mail' : user.email,
'userfunc' : user.profile.get_func_display,
'userfunc' : "CHANGE",
'imageurl' : user.profile.get_photo_url,
'compfunc' : user.profile.compfunc,
'phoneland' : user.profile.phoneland,

View File

@ -1,6 +1,7 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% if request.user.profile.agency.module_quicklinks %}
<div class="content-section col-6">
<h3>Quicklink anlegen</h3>
<hr>
@ -13,4 +14,7 @@
<a class="btn" href="{% url 'ql-management' %} ">Abbrechen</a>
</form>
</div>
{% else %}
<h3>Das Modul Quicklinks wurden in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -1,6 +1,7 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% if request.user.profile.agency.module_quicklinks %}
<div class="content-section">
<div class="media">
<div class="media-body">
@ -17,4 +18,7 @@
</div>
</form>
</div>
{% else %}
<h3>Das Modul Quicklinks wurden in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -1,15 +1,14 @@
{% extends "users/base.html" %}
{% load counter_tag %}
{% block content %}
{% if request.user.profile.agency.module_quicklinks %}
<div class="content-section col-12">
<h3>Quicklinks</h3>
<h3>Quicklinks&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Quicklinks helfen zur schnellen Verlinkung von oft genutzten Diensten." class="far fa-question-circle"></i></small></h3>
<hr>
<p>
Quicklinks helfen zur schnellen Verlinkung von oft genutzten Diensten.
</p>
{% if perms.users.ql_management %}
{% if user|usergperm:"modulequicklinks" %}
<div class="row">
<div class="content-section col-4">
<a class="btn btn-primary" href="{% url 'ql-addql' %}">Quicklink anlegen</a>
<a class="btn btn-primary" href="{% url 'ql-addql' %}"><i class="fas fa-plus"></i>&nbsp;Quicklink</a>
</div>
</div>
{% endif %}
@ -86,4 +85,7 @@ function saveDefQL(){
});
}
</script>
{% else %}
<h3>Das Modul Quicklinks wurden in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -1,6 +1,7 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% if request.user.profile.agency.module_quicklinks %}
<div class="content-section col-6">
<h3>Quicklink aktualisieren</h3>
<hr>
@ -15,4 +16,7 @@
<a class="btn" href="{% url 'ql-management' %} ">Abbrechen</a>
</form>
</div>
{% else %}
<h3>Das Modul Quicklinks wurden in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -6,11 +6,10 @@ from . import views
'''
Permissions definiert in models.py bei USERS und dann hier vor die View geschrieben!
'''
urlpatterns = [
path('', QlManagement.as_view(template_name="quicklinks/ql_management.html"), name='ql-management'),
path('addql/', permission_required('users.ql_management')(QlAdd.as_view(template_name="quicklinks/ql_add.html")), name='ql-addql'),
path('addql/<int:pk>/delete', permission_required('users.ql_management')(QlDeleteView.as_view()), name='ql-delete'),
path('addql/<int:pk>/', permission_required('users.ql_management')(QlUpdateView.as_view()), name='ql-update'),
path('addql/', permission_required('users.modulequicklinks')(QlAdd.as_view(template_name="quicklinks/ql_add.html")), name='ql-addql'),
path('addql/<int:pk>/delete', permission_required('users.modulequicklinks')(QlDeleteView.as_view()), name='ql-delete'),
path('addql/<int:pk>/', permission_required('users.modulequicklinks')(QlUpdateView.as_view()), name='ql-update'),
path('lerg/', views.loaddefaultql, name="ql-ajaxloaddef"),
]

View File

@ -5,12 +5,12 @@ from .models import QuickLinks
from .forms import QlAddQlForm
from django.contrib import messages
from django.shortcuts import redirect
from django.http import HttpResponse
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.decorators import login_required
# Create your views here.
class QlManagement(LoginRequiredMixin, ListView):
model = QuickLinks
# Adding active_link
# Loading only user same agency
# Change context and return for template-data
@ -68,6 +68,7 @@ class QlUpdateView(LoginRequiredMixin, UpdateView):
context['active_link'] = 'quicklinks'
return context
@login_required
def loaddefaultql(request):
if request.method == 'GET':
if request.GET['action'] == 'adddefql':

View File

@ -3,6 +3,8 @@ from django.forms import ModelForm
from .models import Standards
from areas.models import Areas
from tasks.models import Tasks
from django.contrib.auth.models import User
from users.models import Profile, UserFullName
from django_summernote.widgets import SummernoteInplaceWidget
@ -12,16 +14,19 @@ class StandardAddStandard(forms.ModelForm):
class Meta:
model =Standards
widgets = {
'content': SummernoteInplaceWidget(),
'content': SummernoteInplaceWidget()
}
labels = {
"name" : "Titel",
"area" : "Übergeordneter Bereich",
"task" : "Aufgabenbereich",
"content": "Inhalt",
"public" : "Direkt veröffentlichen?"
"public" : "Direkt veröffentlichen?",
"representative" : "Vertreter",
"executor" : "Ausführender",
"authority" : "Verantwortlicher",
}
fields = ['name', 'area', 'task', 'content', 'public']
fields = ['name', 'area', 'task', 'content', 'public', "authority", "executor", "representative"]
'''
Hier werden die Elemente für die DropDowns erstellt, damit
@ -45,6 +50,13 @@ class StandardAddStandard(forms.ModelForm):
elif self.instance.pk:
self.fields['task'].queryset = Tasks.objects.none()
self.fields['representative'].queryset = UserFullName.objects.filter(profile__agency__pk=kwargs['instance'].profile.agency.pk)
self.fields['executor'].queryset = UserFullName.objects.filter(profile__agency__pk=kwargs['instance'].profile.agency.pk)
self.fields['authority'].queryset = UserFullName.objects.filter(profile__agency__pk=kwargs['instance'].profile.agency.pk)
self.fields['checked_groups'] = forms.CharField(initial="", required=False, widget=forms.HiddenInput())
self.fields['added_files'] = forms.CharField(initial="", required=False, widget=forms.HiddenInput())
self.fields['added_standards'] = forms.CharField(initial="", required=False, widget=forms.HiddenInput())
class StandardAddStandardEditor(forms.ModelForm):
@ -70,9 +82,12 @@ class StandardUpdateStandard(forms.ModelForm):
"name" : "Titel",
"area" : "Übergeordneter Bereich",
"task" : "Aufgabenbereich",
"content": "Inhalt"
"content": "Inhalt",
"representative" : "Vertreter",
"executor" : "Ausführender",
"authority" : "Verantwortlicher",
}
fields = ['name', 'area', 'task', 'content']
fields = ['name', 'area', 'task', 'content', "authority", "executor", "representative"]
'''
Hier werden die Elemente für die DropDowns erstellt, damit
@ -99,6 +114,9 @@ class StandardUpdateStandard(forms.ModelForm):
elif loggeduser.pk:
self.fields['task'].queryset = Tasks.objects.filter(area__pk=standard.area.pk)
self.fields['representative'].queryset = UserFullName.objects.filter(profile__agency__pk=loggeduser.profile.agency.pk)
self.fields['executor'].queryset = UserFullName.objects.filter(profile__agency__pk=loggeduser.profile.agency.pk)
self.fields['authority'].queryset = UserFullName.objects.filter(profile__agency__pk=loggeduser.profile.agency.pk)
class StandardUpdateStandardEditor(forms.ModelForm):

View File

@ -4,6 +4,8 @@ from users.models import Agency
from django.urls import reverse
from areas.models import Areas
from tasks.models import Tasks
from cloud.models import DataFile
from users.models import AgencyGroup
import datetime
from django.utils import timezone
#from ckeditor_uploader.fields import RichTextUploadingField
@ -13,11 +15,9 @@ class Standards(models.Model):
agency = models.ForeignKey(Agency, on_delete=models.CASCADE)
area = models.ForeignKey(Areas, on_delete=models.CASCADE)
task = models.ForeignKey(Tasks, on_delete=models.CASCADE)
name = models.CharField(max_length=200, blank=False, default="")
#content = RichTextUploadingField(blank=True, verbose_name='Inhalt')
name = models.CharField(max_length=200, blank=False, default="")
content = models.TextField(blank=True, verbose_name='Inhalt', default="")
#content = models.CharField(max_length=200000, blank=True, verbose_name='Inhalt')
created_standard_by = models.ForeignKey(User, on_delete=models.PROTECT)
created_standard_date = models.DateTimeField(default=timezone.now, blank=True)
@ -29,6 +29,21 @@ class Standards(models.Model):
public = models.BooleanField(default=False)
# USER
# VERTRETER
representative = models.ForeignKey(User, on_delete=models.PROTECT, related_name="user_repr", blank=True, null=True)
# AUSFÜHRENDER
executor = models.ForeignKey(User, on_delete=models.PROTECT, related_name="user_executor", blank=True, null=True)
# VERANTWORTLICHER
authority = models.ForeignKey(User, on_delete=models.PROTECT, related_name="user_authority", blank=True, null=True)
# FILES
addedfiles = models.ManyToManyField(DataFile, blank=True)
# VERLINKTE STANDARDS
linked_standards = models.ManyToManyField('Standards', blank=True)
# GORUPS
visibleby = models.ManyToManyField(AgencyGroup, blank=True)
def __str__(self):
return f'{self.name}'

View File

@ -1,19 +1,307 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% load counter_tag %}
{% block content %}
<div class="content-section col-6">
<h3>Neuen Standard anlegen</h3>
<div class="content-section col-12">
<h3>Neuen Standard anlegen&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Legen Sie hier einen neuen Standard an." class="far fa-question-circle"></i></small></h3>
<hr>
<form method="POST" id="taskareaform">
{% csrf_token %}
{{normalForm|crispy}}
<form method="POST" id="addstandardform">
{% csrf_token %}
<div class="row"><div class="col-8">
{% for field in normalForm %}
{% if forloop.counter|divisibleby:6 %}
</div><div class="col-3">
{{field|as_crispy_field }}
{% else %}
{{field|as_crispy_field }}
{% endif %}
{% endfor %}
<!-- COLLAPSE AREA FOR GROUPS FILES AND LINKED STANDARDS -->
<div class="accordion" style="margin-top: 47px" id="additionalStandardInfos">
<div class="card">
<div class="card-header" id="st_groups">
<h5 class="mb-0">
<button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#stgroups_content" aria-expanded="false" aria-controls="stgroups_content">
Gruppen&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Legen Sie fest, welche Gruppe diesen Standard sehen kann. Ist keine ausgewählt, ist der Standard für alle sichtbar." class="far fa-question-circle"></i></small>
</button>
</h5>
</div>
<div id="stgroups_content" class="collapse" aria-labelledby="st_groups" data-parent="#additionalStandardInfos">
<div class="card-body">
{% for g in agencygroups %}
<div class="custom-control custom-checkbox mb-2">
<input type="checkbox" class="custom-control-input groupclass" onclick="javascript:groupsChange({{g.pk}}, this.checked)" name="group_{{g.pk}}" id="group_{{g.pk}}">
<label class="custom-control-label" for="group_{{g.pk}}" >{{g.agencygroupname}}</label>
</div>
{% endfor %}
</div>
</div>
</div>
{% if request.user.profile.agency.module_files %}
<div class="card">
<div class="card-header" id="st_files">
<h5 class="mb-0">
<button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#st_files_content" aria-expanded="false" aria-controls="st_files_content">
Dateien&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Fügen Sie ihren Standards Dateien zu. Diese liegen entweder bereits unter Dateien oder können iher direkt hochgeladen werden. Neu hochgeladene Dateien werden im Heimverzeichnis gespeichert." class="far fa-question-circle"></i></small>
</button>
</h5>
</div>
<div id="st_files_content" class="collapse" aria-labelledby="st_files" data-parent="#additionalStandardInfos">
<div class="card-body">
<div class="input-group mb-3">
<input class="form-control searchuserfieldstask" list="possfiles" id="searchfiles" type="text" onkeyup="javascript:updateLinkedFiles()" >
<div class="input-group-append">
<button type="button" onclick="javascript:clearSearchfieldAddFile()" class="btn btn-secondary" ><i class="fas fa-times"></i></button>
</div>
<datalist id="possfiles">
{% for f in files %}
<option id="file_{{f.pk}}" value="{{f.name}}">{{f.name}}</option>
{% endfor %}
</datalist>
</div>
Verlinkte Dateien:
<table id="linkedfiles" class="table table-hover table-sm">
</table>
<input type="file" id="uploadedfile" name="uploadedfile" style="display:none">
{% if user|usergperm:"filesmanager" %}
<div class="alert alert-secondary text-center mt-5" id="directdiv" role="alert" style="line-height: 17px; text-align: center;">
<button type="button" class="btn btn-primary btn-sm" id="uploadButton" onclick="javascript:uploadButtonPush()"><i class="fas fa-plus"></i></button>&nbsp;&nbsp;<small>klicken/hineinziehen<p class="mt-2">Dateien werden im <b>Heimverzeichnis</b>gespeichert.
</small></p>
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}
<div class="card">
<div class="card-header" id="st_linked">
<h5 class="mb-0">
<button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#st_linked_content" aria-expanded="false" aria-controls="st_linked_content">
Standards&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Verlinken Sie hier andere Standards, die etwas mit diesem Standard zutun haben." class="far fa-question-circle"></i></small>
</button>
</h5>
</div>
<div id="st_linked_content" class="collapse" aria-labelledby="st_linked" data-parent="#additionalStandardInfos">
<div class="card-body">
<div class="input-group mb-3">
<input class="form-control" list="possstandards" id="searchstandards" type="text" onkeyup="javascript:updateLinkedStandards()" >
<div class="input-group-append">
<button type="button" onclick="javascript:clearSearchfieldAddStandard()" class="btn btn-secondary" ><i class="fas fa-times"></i></button>
</div>
<datalist id="possstandards">
{% for s in standards %}
<option id="standard_{{s.pk}}" value="{{s.name|truncatechars:30}}">{{s.name|truncatechars:30}}</option>
{% endfor %}
</datalist>
</div>
Verlinkte Standards:
<table id="linkedstandards" class="table table-hover table-sm">
</table>
</div>
</div>
</div>
</div>
</div></div>
<p>Wenn ein Standard erstellt wurde, kann er nur von einer Person mit dem Recht <i>Standards bearbeiten und freischalten</i> veröffentlicht werden.</p>
<hr>
<button type="submit" class="btn btn-success" href="{% url 'standard-add' %} ">Standard anlegen</button>&nbsp;
<button type="submit" class="btn btn-success">Standard anlegen</button>&nbsp;
<a class="btn" href="{% url 'standards' %} ">Abbrechen</a>
</form>
</form>
</div>
<!-- FILE FORBIDDEN DELETE FILE -->
<div class="modal fade" id="forbiddenFileType" 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">Datei nicht erlaubt</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">
Diesen Dateitypen dürfen Sie nicht hochladen.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
<!-- FILE FORBIDDEN DELETE FILE -->
<div class="modal fade" id="forbiddenFileType" 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">Datei nicht erlaubt</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">
Diesen Dateitypen dürfen Sie nicht hochladen.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
//STANDARDS
actualStandards = [];
function clearSearchfieldAddStandard(){
$("#searchstandards").val("");
}
function updateLinkedStandards(){
var g = $('#searchstandards').val();
var id = $('#possstandards').find('option[value="' + g + '"]').attr('id');
if(id != undefined && id.length > 0){
tempid_standard = id.split("_")[1];
actualStandards.push(tempid_standard);
clearSearchfieldAddStandard();
$("#" + id).remove();
$("#linkedstandards").append('<tr id="standardadded_'+tempid_standard+'"><td>' + g + '</td><td><button type="button" class="btn btn-danger btn-sm" onclick="javascript:remStandard('+tempid_standard+', \''+g+'\')"><i class="fas fa-trash-alt"></i></button></td></tr>');
}
$("#id_added_standards").val(actualStandards);
}
function remStandard(id, name){
index_to_rem = actualStandards.indexOf(id);
actualStandards.splice(index_to_rem,1);
$('#possstandards').append('<option id="standard_'+id+'" value="'+ name +'">'+ name +'</option>');
$("#standardadded_" + id).remove();
$("#id_added_standards").val(actualStandards);
}
//FILES
// preventing page from redirecting
$("html").on("dragover", function(e) {
e.preventDefault();
e.stopPropagation();
});
$("html").on("drop", function(e) { e.preventDefault(); e.stopPropagation(); });
$( "#directdiv" ).on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
currentid = e["currentTarget"]['id'];
$("#directdiv").addClass('bg-secondary');
});
$('#directdiv').on('drop', function (e) {
e.stopPropagation();
e.preventDefault();
$("#directdiv").removeClass('bg-secondary');
uploadAction(e.originalEvent.dataTransfer.files[0], e["currentTarget"]['id'].split("_")[0]);
});
$('#directdiv').on('dragleave', function (e) {
e.stopPropagation();
e.preventDefault();
currentid = e["currentTarget"]['id'];
$("#directdiv").removeClass('bg-secondary');
});
allowedtypes = "application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, text/plain, application/pdf, image/*"
function uploadButtonPush(){
$("#uploadedfile").click();
}
$('#uploadedfile').on('change', function() {
uploadAction($("#uploadedfile")[0]['files'][0], {{parentid}});
});
function uploadAction(filetodo){
var formData = new FormData();
formData.append("uploadedfile", filetodo);
if(allowedtypes.includes(filetodo.type) && filetodo.type.length > 0){
$.ajax({
url: "{% url 'cloud-adddir' parentid %}",
headers: {
"X-CSRFTOKEN": "{{ csrf_token }}"
},
data: formData,
type: 'POST',
cache: false,
processData: false,
contentType: false,
success: function(data) {
if(data["success"] == true){
actualFiles.push(String(data["data"]["savedobj_id"]));
$("#id_added_files").val(actualFiles);
$("#linkedfiles") .append('<tr id="fileadded_'+data["data"]["savedobj_id"]+'"><td>' + data["data"]["savedobj_name"] + '</td><td><button type="button" class="btn btn-danger btn-sm" onclick="javascript:remFile('+data["data"]["savedobj_id"]+', \''+data["data"]["savedobj_name"]+'\')"><i class="fas fa-trash-alt"></i></button></td></tr>');
}
else{
$("#forbiddenFileType").modal("toggle")
}
}
});
}
else{
$("#forbiddenFileType").modal("toggle")
}
}
actualFiles = [];
function clearSearchfieldAddFile(){
$("#searchfiles").val("");
}
function updateLinkedFiles(){
var g = $('#searchfiles').val();
var id = $('#possfiles').find('option[value="' + g + '"]').attr('id');
if(id != undefined && id.length > 0){
tempid_file = id.split("_")[1];
actualFiles.push(tempid_file);
$("#id_added_files").val(actualFiles)
clearSearchfieldAddFile();
$("#" + id).remove();
$("#linkedfiles") .append('<tr id="fileadded_'+tempid_file+'"><td>' + g + '</td><td><button type="button" class="btn btn-danger btn-sm" onclick="javascript:remFile('+tempid_file+', \''+g+'\')"><i class="fas fa-trash-alt"></i></button></td></tr>');
}
}
function remFile(id, name){
index_to_rem = actualFiles.indexOf(id);
actualFiles.splice(index_to_rem,1);
$('#possfiles').append('<option id="file_'+id+'" value="'+ name +'">'+ name +'</option>');
$("#fileadded_" + id).remove();
$("#id_added_files").val(actualFiles);
}
//GROUPS
actualGroups = [];
function groupsChange(groupid, value){
if(value){
actualGroups.push(groupid);
}
else {
index_to_rem = actualGroups.indexOf(groupid)
actualGroups.splice(index_to_rem,1);
}
$("#id_checked_groups").val(actualGroups);
}
/*
Ajax-Request zum nachladen der Aufgaben nach Auswahl der Bereiche
*/

View File

@ -3,15 +3,12 @@
{% block content %}
<div class="content-section col-12">
<h3>Standards</h3>
<h3>Standards&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Standards dokumentieren und erläutern verschiedenen Verfahren, strukturiert nach Bereichen und Aufgaben." class="far fa-question-circle"></i></small></h3>
<small>Sichtbar sind alle veröffentlichten und von {{ user.first_name }} {{ user.last_name}} erstellten Standards.</small>
<hr>
<p>
Standards dokumentieren und erläutern verschiedenen Verfahren, strukturiert nach Bereichen und Aufgaben.
</p>
<div class="row">
<div class="content-section col-4">
<a class="btn btn-primary" href="{% url 'standard-add' %}">Standard anlegen</a>
<a class="btn btn-primary" href="{% url 'standard-add' %}"><i class="fas fa-plus"></i>&nbsp;Standard</a>
</div>
</div>
<hr>
@ -57,10 +54,27 @@
</h5>
{% setvar 0 %}
{% for standard in standards_of_agency %}
<!-- CHECK FOR GROUPVISIBLE -->
{% setbool False %}
{% for ag in standard.visibleby.all %}
{% if request.user|has_group:ag.group.name %}
{% setbool True %}
{% endif %}
{% endfor %}
{% if standard.visibleby.all|length == 0 %}
{% setbool True %}
{% endif %}
{% getbool as groupchecker %}
{% getvar as varcounter %}
{% if standard.task == task and standard.area == area and varcounter < 3 %}
{% incvar %}
<p class="card-text"><a href="{% url 'standard-single' standard.pk %}">{{standard.name}}</a></p>
{% if groupchecker %}
<p class="card-text"><a href="{% url 'standard-single' standard.pk %}">{{standard.name|truncatechars:28}}</a></p>
{% else %}
<p class="card-text text-secondary"><i class="fas fa-lock"></i>&nbsp;{{standard.name|truncatechars:28}}</p>
{% endif %}
{% endif %}
{% endfor %}
</div>

View File

@ -1,4 +1,5 @@
{% extends "users/base.html" %}
{% load counter_tag %}
{% block content %}
<div class="content-section col-12">
<nav aria-label="breadcrumb">
@ -18,13 +19,91 @@
</small>
<small><br />
Ansprechpartner:
{% for taskuser in standard.task.usersfield.all %}
{% for taskuser in standard.task.usersfield.all %}
&nbsp;<span class="badge badge-pill badge-primary" style="font-size: 1.1em; background-color: {{standard.task.area.color}}"><a href="{% url 'orga-single' taskuser.pk%}" style="color: #ffffff">{{taskuser.first_name}} {{taskuser.last_name}}</a></span>
{% endfor %}
{% if standard.authority %}
Verantwortlicher:&nbsp;<a href="{% url 'orga-single' standard.authority.pk%}"> {{standard.authority.first_name}} {{standard.authority.last_name}}</a>&nbsp;|&nbsp;
{% endif %}
{% if standard.executor %}
Ausführende Person:&nbsp;<a href="{% url 'orga-single' standard.executor.pk%}">{{standard.executor.first_name}} {{standard.executor.last_name}}</a>&nbsp;|&nbsp;
{% endif %}
{% if standard.representative %}
Vertreter:&nbsp;<a href="{% url 'orga-single' standard.representative.pk%}">{{standard.representative.first_name}} {{standard.representative.last_name}}</a>&nbsp;|&nbsp;
{% endif %}
</small>
<hr>
{{standard.media}}
{{standard.content|safe}}
<div class="row col">
{% if standard.addedfiles.all|length == 0 and standard.linked_standards.all|length == 0 %}
<div class="card col-12" style="min-height: 500px">
{% else %}
<div class="card col-9" style="min-height: 500px">
{% endif %}
<div class="card-body">
<h5 class="card-title"></h5>
<p class="card-text">
{{standard.media}}
{{standard.content|safe}}
</p>
</div>
</div>
<!-- FILES -->
<div class="col-3">
{% if standard.addedfiles.all|length > 0 %}
<div class="card col-14 ml-2 mb-3" style="">
<div class="card-body">
<h5 class="card-title">Dateien</h5>
<p class="card-text">
{% for files in standard.addedfiles.all %}
<a href="{{files.file.url}}" download>{{files.name|truncatechars:30}}</a><br />
{% endfor %}
</p>
</div>
</div>
{% endif %}
<!-- STANDARDS -->
{% if standard.linked_standards.all|length > 0 %}
<div class="card col-14 ml-2" style="">
<div class="card-body">
<h5 class="card-title">Verwandte Standards</h5>
<p class="card-text">
{% for standard in standard.linked_standards.all %}
{% setbool False %}
{% for ag in standard.visibleby.all %}
{% if request.user|has_group:ag.group.name %}
{% setbool True %}
{% endif %}
{% endfor %}
{% if standard.visibleby.all|length == 0 %}
{% setbool True %}
{% endif %}
{% getbool as groupchecker %}
{% if groupchecker %}
<a href="{% url 'standard-single' standard.pk %}">{{standard.name|truncatechars:30}}</a><br />
{% else %}
<i class="fas fa-lock"></i>&nbsp;{{standard.name|truncatechars:30}}</p>
{% endif %}
{% endfor %}
</p>
</div>
</div>
{% endif %}
</div>
</div>
{% for g in standard.visibleby.all %}
{{g.agencygroupname}}
{% endfor %}
</div>
{% endblock content %}

View File

@ -1,13 +1,122 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% load counter_tag %}
{% block content %}
<div class="content-section col-6">
<h3>Standard bearbeiten</h3>
<div class="content-section col-12">
<h3>Standard bearbeiten&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Aktualisieren Sie hier die Informationen des Standards." class="far fa-question-circle"></i></small></h3>
<hr>
<form method="POST" id="taskareaform">
{% csrf_token %}
{{normalForm|crispy}}
<div class="row"><div class="col-8">
{% for field in normalForm %}
{% if forloop.counter|divisibleby:5 %}
</div><div class="col-3">
{{field|as_crispy_field }}
{% else %}
{{field|as_crispy_field }}
{% endif %}
{% endfor %}
<!-- COLLAPSE AREA FOR GROUPS FILES AND LINKED STANDARDS -->
<div class="accordion" style="margin-top: 47px" id="additionalStandardInfos">
<div class="card">
<div class="card-header" id="st_groups">
<h5 class="mb-0">
<button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#stgroups_content" aria-expanded="false" aria-controls="stgroups_content">
Gruppen&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Legen Sie fest, welche Gruppe diesen Standard sehen kann. Ist keine ausgewählt, ist der Standard für alle sichtbar." class="far fa-question-circle"></i></small>
</button>
</h5>
</div>
<div id="stgroups_content" class="collapse" aria-labelledby="st_groups" data-parent="#additionalStandardInfos">
<div class="card-body">
{% for g in agencygroups %}
<div class="custom-control custom-checkbox mb-2">
{% if g in standard.visibleby.all %}
<input type="checkbox" class="custom-control-input groupclass" onclick="javascript:groupsChange({{g.pk}}, this.checked)" name="group_{{g.pk}}" id="group_{{g.pk}}" checked="true">
{% else %}
<input type="checkbox" class="custom-control-input groupclass" onclick="javascript:groupsChange({{g.pk}}, this.checked)" name="group_{{g.pk}}" id="group_{{g.pk}}">
{% endif %}
<label class="custom-control-label" for="group_{{g.pk}}" >{{g.agencygroupname}}</label>
</div>
{% endfor %}
</div>
</div>
</div>
{% if request.user.profile.agency.module_files %}
<div class="card">
<div class="card-header" id="st_files">
<h5 class="mb-0">
<button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#st_files_content" aria-expanded="false" aria-controls="st_files_content">
Dateien&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Fügen Sie ihren Standards Dateien zu. Diese liegen entweder bereits unter Dateien oder können iher direkt hochgeladen werden. Neu hochgeladene Dateien werden im Heimverzeichnis gespeichert." class="far fa-question-circle"></i></small>
</button>
</h5>
</div>
<div id="st_files_content" class="collapse" aria-labelledby="st_files" data-parent="#additionalStandardInfos">
<div class="card-body">
<div class="input-group mb-3">
<input class="form-control searchuserfieldstask" list="possfiles" id="searchfiles" type="text" onkeyup="javascript:updateLinkedFiles()" >
<div class="input-group-append">
<button type="button" onclick="javascript:clearSearchfieldAddFile()" class="btn btn-secondary" ><i class="fas fa-times"></i></button>
</div>
<datalist id="possfiles">
{% for f in possibleFilesByVisible %}
<option id="file_{{f.pk}}" value="{{f.name}}">{{f.name}}</option>
{% endfor %}
</datalist>
</div>
Verlinkte Dateien:
<table id="linkedfiles" class="table table-hover table-sm">
{% for f in standard.addedfiles.all %}
<tr id="fileadded_{{f.pk}}"><td>{{f.name|truncatechars:30}}</td><td><button type="button" class="btn btn-danger btn-sm" onclick="javascript:remFile({{f.pk}}, '{{f.name}}')"><i class="fas fa-trash-alt"></i></button></td></tr>
{% endfor %}
</table>
<input type="file" id="uploadedfile" name="uploadedfile" style="display:none">
{% if user|usergperm:"filesmanager" %}
<div class="alert alert-secondary text-center mt-5" id="directdiv" role="alert" style="line-height: 17px; text-align: center;">
<button type="button" class="btn btn-primary btn-sm" id="uploadButton" onclick="javascript:uploadButtonPush()"><i class="fas fa-plus"></i></button>&nbsp;&nbsp;<small>klicken/hineinziehen<p class="mt-2">Dateien werden im <b>Heimverzeichnis</b>gespeichert.
</small></p>
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}
<div class="card">
<div class="card-header" id="st_linked">
<h5 class="mb-0">
<button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#st_linked_content" aria-expanded="false" aria-controls="st_linked_content">
Standards&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Verlinken Sie hier andere Standards, die etwas mit diesem Standard zutun haben." class="far fa-question-circle"></i></small>
</button>
</h5>
</div>
<div id="st_linked_content" class="collapse" aria-labelledby="st_linked" data-parent="#additionalStandardInfos">
<div class="card-body">
<div class="input-group mb-3">
<input class="form-control" list="possstandards" id="searchstandards" type="text" onkeyup="javascript:updateLinkedStandards()" >
<div class="input-group-append">
<button type="button" onclick="javascript:clearSearchfieldAddStandard()" class="btn btn-secondary" ><i class="fas fa-times"></i></button>
</div>
<datalist id="possstandards">
{% for s in possiblestandards %}
<option id="standard_{{s.pk}}" value="{{s.name|truncatechars:30}}">{{s.name|truncatechars:30}}</option>
{% endfor %}
</datalist>
</div>
Verlinkte Standards:
<table id="linkedstandards" class="table table-hover table-sm">
{% for s in standard.linked_standards.all %}
<tr id="standardadded_{{s.pk}}"><td>{{s.name|truncatechars:30}}</td><td><button type="button" class="btn btn-danger btn-sm" onclick="javascript:remStandard({{s.pk}}, '{{s.name|truncatechars:30}}')"><i class="fas fa-trash-alt"></i></button></td></tr>
{% endfor %}
</table>
</div>
</div>
</div>
</div>
</div>
<p>Wenn ein Standard bearbeitet wurde, kann er nur von einer Person mit dem Recht <i>Standards bearbeiten und freischalten</i> wieder veröffentlicht werden. Ein Standard wird nach Bearbeitung als <i>Nicht veröffentlicht</i> gesetzt.</p>
<hr>
<button type="submit" class="btn btn-success" href="{% url 'standard-update' standard_id %} ">Aktualisieren</button>&nbsp;
@ -22,7 +131,211 @@
<a class="btn" href="{% url 'standards' %} ">Abbrechen</a>
</form>
</div>
<!-- FILE FORBIDDEN DELETE FILE -->
<div class="modal fade" id="forbiddenFileType" 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">Datei nicht erlaubt</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">
Diesen Dateitypen dürfen Sie nicht hochladen.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
//STANDARD
function clearSearchfieldAddStandard(){
$("#searchstandards").val("");
}
function remStandard(id, name){
$('#possstandards').append('<option id="standard_'+id+'" value="'+ name +'">'+ name +'</option>');
$("#standardadded_" + id).remove();
$.ajax({
url: "{% url 'update_standard_by_ajax' standard.pk %}",
data: {
action : 's_remstandard',
standardid : id
},
success: function (data) {}
});
}
function updateLinkedStandards(){
var g = $('#searchstandards').val();
var id = $('#possstandards').find('option[value="' + g + '"]').attr('id');
if(id != undefined && id.length > 0){
tempid_standard = id.split("_")[1];
clearSearchfieldAddStandard();
$("#" + id).remove();
$("#linkedstandards").append('<tr id="standardadded_'+tempid_standard+'"><td>' + g + '</td><td><button type="button" class="btn btn-danger btn-sm" onclick="javascript:remStandard('+tempid_standard+', \''+g+'\')"><i class="fas fa-trash-alt"></i></button></td></tr>');
}
$.ajax({
url: "{% url 'update_standard_by_ajax' standard.pk %}",
data: {
action : 's_addstandard',
standardid : tempid_standard
},
success: function (data) {}
});
}
//FILES
function remFile(fileid, filename){
console.log(fileid);
$("#fileadded_" + fileid).remove();
$('#possfiles').append('<option id="file_'+fileid+'" value="'+ filename +'">'+ filename +'</option>');
$.ajax({
url: "{% url 'update_standard_by_ajax' standard.pk %}",
data: {
action : 's_remfile',
fileid : fileid
},
success: function (data) {}
});
}
function clearSearchfieldAddFile(){
$("#searchfiles").val("");
}
function updateLinkedFiles(){
var g = $('#searchfiles').val();
var id = $('#possfiles').find('option[value="' + g + '"]').attr('id');
if(id != undefined && id.length > 0){
tempid_file = id.split("_")[1];
clearSearchfieldAddFile();
$("#" + id).remove();
$("#linkedfiles") .append('<tr id="fileadded_'+tempid_file+'"><td>' + g + '</td><td><button type="button" class="btn btn-danger btn-sm" onclick="javascript:remFile('+tempid_file+', \''+g+'\')"><i class="fas fa-trash-alt"></i></button></td></tr>');
$.ajax({
url: "{% url 'update_standard_by_ajax' standard.pk %}",
data: {
action : 's_addfile',
fileid : tempid_file
},
success: function (data) {}
});
}
}
//FILES
// preventing page from redirecting
$("html").on("dragover", function(e) {
e.preventDefault();
e.stopPropagation();
});
$("html").on("drop", function(e) { e.preventDefault(); e.stopPropagation(); });
$( "#directdiv" ).on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
currentid = e["currentTarget"]['id'];
$("#directdiv").addClass('bg-secondary');
});
$('#directdiv').on('drop', function (e) {
e.stopPropagation();
e.preventDefault();
$("#directdiv").removeClass('bg-secondary');
uploadAction(e.originalEvent.dataTransfer.files[0], e["currentTarget"]['id'].split("_")[0]);
});
$('#directdiv').on('dragleave', function (e) {
e.stopPropagation();
e.preventDefault();
currentid = e["currentTarget"]['id'];
$("#directdiv").removeClass('bg-secondary');
});
allowedtypes = "application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, text/plain, application/pdf, image/*"
function uploadButtonPush(){
$("#uploadedfile").click();
}
$('#uploadedfile').on('change', function() {
uploadAction($("#uploadedfile")[0]['files'][0], {{parentid}});
});
function uploadAction(filetodo){
var formData = new FormData();
formData.append("uploadedfile", filetodo);
if(allowedtypes.includes(filetodo.type) && filetodo.type.length > 0){
$.ajax({
url: "{% url 'cloud-adddir' parentid %}",
headers: {
"X-CSRFTOKEN": "{{ csrf_token }}"
},
data: formData,
type: 'POST',
cache: false,
processData: false,
contentType: false,
success: function(data) {
if(data["success"] == true){
$("#linkedfiles") .append('<tr id="fileadded_'+data["data"]["savedobj_id"]+'"><td>' + data["data"]["savedobj_name"] + '</td><td><button type="button" class="btn btn-danger btn-sm" onclick="javascript:remFile('+data["data"]["savedobj_id"]+', \''+data["data"]["savedobj_name"]+'\')"><i class="fas fa-trash-alt"></i></button></td></tr>');
$.ajax({
url: "{% url 'update_standard_by_ajax' standard.pk %}",
data: {
action : 's_addfile',
fileid : data["data"]["savedobj_id"]
},
success: function (data) {}
});
}
else{
$("#forbiddenFileType").modal("toggle")
}
}
});
}
else{
$("#forbiddenFileType").modal("toggle")
}
}
//GROUP CHANGE
function groupsChange(groupid, value){
if(value){
$.ajax({
url: "{% url 'update_standard_by_ajax' standard.pk %}",
data: {
action : 's_addgroup',
groupid : groupid
},
success: function (data) {}
});
}
else{
$.ajax({
url: "{% url 'update_standard_by_ajax' standard.pk %}",
data: {
action : 's_remgroup',
groupid : groupid
},
success: function (data) {}
});
}
}
/*
Ajax-Request zum nachladen der Aufgaben nach Auswahl der Bereiche
*/

View File

@ -1,9 +1,13 @@
from django import template
from django.contrib.auth.models import Group, User
from users.models import AgencyGroup
import os
register = template.Library()
b = 0
groupbool = False
@register.simple_tag
def setvar(value):
global b
@ -21,7 +25,63 @@ def incvar():
b += 1
return ''
@register.filter(name='has_group')
def has_group(user, group_name):
group = Group.objects.get(name=group_name)
in_group = False
for g in user.groups.all():
if g.name == group_name:
in_group = True
return in_group
@register.simple_tag
def setbool(value):
global groupbool
groupbool = value
return ''
@register.simple_tag
def getbool():
global groupbool
return groupbool
# usergperm
'''
Gibt TRUE zurück, wenn der User über eine Gruppe das gewünschte Recht hat.
Gibt FALSE zurück, wenn der User über eine Gruppe das gewünschte Recht NICHT hat.
@param:
user - einglogger Nutzer
perm - recht
'''
@register.filter(name="usergperm")
def usergperm(user, perm):
stat = False
if user.has_perm('users.'+perm):
stat = True
return stat
@register.filter(name="useringroupbyid")
def is_member(id, groupname):
usertocheck = User.objects.get(pk=id)
return usertocheck.groups.filter(name=groupname).exists()
# Return a Filename splitted to only see the LAST element!
@register.filter(name="splitdirstyle")
def split_dir_style(dirtosplit):
tempsplit = dirtosplit.split("\\")
return tempsplit[len(tempsplit)-1]
@register.filter(name="filename")
def filename(value):
return os.path.basename(value.file.name)
'''
class Counter:
count = 0

View File

@ -12,6 +12,7 @@ urlpatterns = [
path('standardadd/', views.StandardAdd, name='standard-add'),
path('standardupdate/<int:id>', views.StandardUpdate, name='standard-update'),
path('ajax/loadtasks/', views.load_tasks, name='ajax_loadtasks'),
path('ajups/<int:pk>', views.updatesbyajax, name='update_standard_by_ajax'),
path('standards/<int:pk>/delete', StandardDeleteView.as_view(), name='standard-delete'),
path('standard/<int:pk>/changestat', views.StandardChangePublic, name="standard-status"),
path('standard/<int:pk>/single', views.StandardSingle, name="standard-single"),

View File

@ -10,6 +10,9 @@ from django.contrib.auth.decorators import login_required
from tasks.models import Tasks
from areas.models import Areas
from datetime import datetime
from users.models import AgencyGroup
from cloud.models import DataFile, DataDir
from django.contrib.auth.decorators import login_required
# ALLE STANDARDS EINER AGENTUR
class StandardsManagement(LoginRequiredMixin, ListView):
@ -28,6 +31,42 @@ class StandardsManagement(LoginRequiredMixin, ListView):
context.update({'active_link' : 'standards', 'tasks': tasks, 'unpubstandards_of_user' : unpubstandards_of_user, 'standards_of_agency' : standards_of_agency, 'areas' : areas, 'standards_of_user' : standards_of_user})
return context
@login_required
def checkUserDirRights(request, startdir, userid):
canview = True
user = User.objects.get(pk=userid)
usergroups=list(user.groups.all())
grouptomach = []
singleObj = DataDir.objects.get(pk=startdir.pk)
# AGENCYCHECK
if(singleObj.agency.pk == user.profile.agency.pk):
# Get dirs to check
while( singleObj.is_root != True and canview == True):
for g in singleObj.visibleby.all():
grouptomach.append(g.group)
if(len(grouptomach) == 0):
canview = True
else:
if(len(set(usergroups).intersection(grouptomach)) > 0):
canview = True
else:
canview = False
grouptomach = []
singleObj = DataDir.objects.get(pk=singleObj.parent.pk)
else:
canview = False
return canview
@login_required
def StandardAdd(request):
if request.method == 'POST':
@ -53,9 +92,31 @@ def StandardAdd(request):
new_standard.name = normalForm.cleaned_data['name']
new_standard.content = editorForm.cleaned_data['content']
new_standard.public = normalForm.cleaned_data['public']
new_standard.representative = normalForm.cleaned_data['representative']
new_standard.executor = normalForm.cleaned_data['executor']
new_standard.authority = normalForm.cleaned_data['authority']
# GROUPS
new_standard.save()
# ADD GROUPS
groups = normalForm.cleaned_data['checked_groups'].split(",")
for g in groups:
new_standard.visibleby.add(AgencyGroup.objects.get(pk=g))
# ADD STANDARDS
standards = normalForm.cleaned_data['added_standards'].split(",")
for s in standards:
new_standard.linked_standards.add(Standards.objects.get(pk=s))
# ADD FILES
files = normalForm.cleaned_data['added_files'].split(",")
for f in files:
new_standard.addedfiles.add(DataFile.objects.get(pk=f))
tempstandardname = normalForm.cleaned_data['name']
if(new_standard.public and request.user.has_perm('users.standard_management')):
if(new_standard.public and request.user.has_perm('users.standardmanager')):
messages.success(request, f'Standard {tempstandardname} hinzugefügt und veröffentlicht.')
else:
new_standard.public = False
@ -66,19 +127,42 @@ def StandardAdd(request):
else:
normalForm = StandardAddStandard(instance=request.user)
editorForm = StandardAddStandardEditor(instance=request.user)
'''
Hier werden nur die Dateien dem aktuellen User zur Auswahl gestellt, auf die er auch Zugriff hat.
Das geht NICHT rekursiv! Es wird nur das oberste Verzeichnis geprüft! SPÄTER!
'''
possibleFilesByVisible = []
allfiles = DataFile.objects.filter(agency=request.user.profile.agency)
for f in allfiles:
actParent = DataDir.objects.get(pk=f.parent.pk)
if actParent.is_root:
possibleFilesByVisible.append(f)
else:
if(checkUserDirRights(request, actParent, request.user.pk)):
possibleFilesByVisible.append(f)
context = {
'normalForm' : normalForm,
'editorForm' : editorForm,
'active_link' : 'standards'
'active_link' : 'standards',
'agencygroups' : AgencyGroup.objects.filter(agency=request.user.profile.agency),
'files' : possibleFilesByVisible,
'parentid' : list(DataDir.objects.filter(agency=request.user.profile.agency, is_root=True))[0].pk,
'standards' : Standards.objects.filter(agency=request.user.profile.agency, public=True)
}
return render(request, 'standards/standards_add.html', context)
@login_required
def StandardUpdate(request, id):
standard = Standards.objects.get(pk=id)
standard = Standards.objects.get(pk=id, agency=request.user.profile.agency)
if request.method == 'POST':
#normalForm = StandardUpdateStandard(request.POST, instance=standard)
normalForm = StandardUpdateStandard(request.POST, instance=standard)
@ -91,7 +175,12 @@ def StandardUpdate(request, id):
existing_standard.task = normalForm.cleaned_data['task']
existing_standard.area = normalForm.cleaned_data['area']
existing_standard.name = normalForm.cleaned_data['name']
existing_standard.content = editorForm.cleaned_data['content']
existing_standard.content = editorForm.cleaned_data['content']
existing_standard.representative = normalForm.cleaned_data['representative']
existing_standard.executor = normalForm.cleaned_data['executor']
existing_standard.authority = normalForm.cleaned_data['authority']
'''
AKTUALISIERUNG
@ -101,7 +190,7 @@ def StandardUpdate(request, id):
aber keine Rechte und ist der Standarf public, wird er auf public=false gesetzt!
'''
if request.user.has_perm('users.standard_management'):
if request.user.has_perm('users.standardmanager'):
messages.success(request, f'Standard {existing_standard.name} aktualisiert!')
else:
if existing_standard.public:
@ -116,21 +205,51 @@ def StandardUpdate(request, id):
#normalForm = StandardUpdateStandard(instance=standard)
normalForm = StandardUpdateStandard(instance=standard)
editorForm = StandardUpdateStandardEditor(instance=standard)
'''
Hier werden nur die Dateien dem aktuellen User zur Auswahl gestellt, auf die er auch Zugriff hat.
Das geht NICHT rekursiv! Es wird nur das oberste Verzeichnis geprüft! SPÄTER!
'''
possibleFilesByVisible = []
allfiles = DataFile.objects.filter(agency=request.user.profile.agency)
for f in allfiles:
actParent = DataDir.objects.get(pk=f.parent.pk, agency=request.user.profile.agency)
if actParent.is_root:
possibleFilesByVisible.append(f)
else:
if(checkUserDirRights(request, actParent, request.user.pk) and f not in standard.addedfiles.all()):
possibleFilesByVisible.append(f)
possiblestandards = Standards.objects.filter(agency=request.user.profile.agency, public=True)
possiblestandards_final = []
for s in possiblestandards:
if s not in standard.linked_standards.all():
possiblestandards_final.append(s)
context = {
'normalForm' : normalForm,
'editorForm' : editorForm,
'standard' : standard,
'active_link' : 'standards',
'standard_id' : standard.pk,
'standard_status' : standard.public
'standard_status' : standard.public,
'possibleFilesByVisible' : possibleFilesByVisible,
'agencygroups' : AgencyGroup.objects.filter(agency=request.user.profile.agency),
'parentid' : list(DataDir.objects.filter(agency=request.user.profile.agency, is_root=True))[0].pk,
'possiblestandards' : possiblestandards_final
}
return render(request, 'standards/standards_update.html', context)
@login_required
def load_tasks(request):
areaid = request.GET.get('areaid')
tasks = Tasks.objects.filter(area__id=areaid).order_by('name')
tasks = Tasks.objects.filter(area__id=areaid, agency=request.user.profile.agency).order_by('name')
return render(request, 'standards/standards_tasklist.html', {'tasks': tasks})
@ -140,7 +259,7 @@ class StandardDeleteView(LoginRequiredMixin, DeleteView):
template_name = 'standards/standard_confirm_delete.html'
def delete(self, request, *args, **kwargs):
standard = Standards.objects.get(pk=kwargs['pk'])
standard = Standards.objects.get(pk=kwargs['pk'], agency=request.user.profile.agency)
response = super(StandardDeleteView, self).delete(request, *args, **kwargs)
names = standard.name
messages.success(request, f'Standard ' +names+ ' wurde gelöscht!')
@ -165,18 +284,37 @@ def StandardChangePublic(request, pk):
@login_required
def StandardSingle(request, pk):
standard = Standards.objects.get(pk=pk)
context = {
'active_link':'standards',
'standard' : standard
}
return render(request, 'standards/standards_single.html', context)
# CHECK IF USER HAS RIGHTS TO SEE THIS DIR
groupsofstandard = Standards.objects.get(pk=pk, agency=request.user.profile.agency)
userisingroup = False
if len(groupsofstandard.visibleby.all()) == 0:
userisingroup = True
else:
for ag in groupsofstandard.visibleby.all():
if ag.group in request.user.groups.all():
userisingroup = True
if userisingroup:
standard = Standards.objects.get(pk=pk)
context = {
'active_link':'standards',
'standard' : standard
}
return render(request, 'standards/standards_single.html', context)
else:
context = {
'active_link':'standards'
}
return render(request, 'standards/standards_noentrie.html', context)
@login_required
def StandardArea(request, pk):
standards = Standards.objects.filter(agency__pk=request.user.profile.agency.pk).filter(area__pk=pk)
area = Areas.objects.get(pk=pk)
area = Areas.objects.get(pk=pk, agency=request.user.profile.agency)
context = {
'active_link':'standards',
'standards_of_agency_area' : standards,
@ -188,8 +326,8 @@ def StandardArea(request, pk):
@login_required
def StandardTask(request, pk):
standards = Standards.objects.filter(agency__pk=request.user.profile.agency.pk).filter(task__pk=pk)
task = Tasks.objects.get(pk=pk)
area = Areas.objects.get(pk=task.area.pk)
task = Tasks.objects.get(pk=pk, agency=request.user.profile.agency)
area = Areas.objects.get(pk=task.area.pk, agency=request.user.profile.agency)
context = {
'active_link':'standards',
'standards_of_agency_task' : standards,
@ -201,3 +339,35 @@ def StandardTask(request, pk):
return render(request, 'standards/standard_task.html', context)
@login_required
def updatesbyajax(request, pk):
if(request.method == "GET"):
success = True
workingstandard = Standards.objects.get(pk=pk, agency=request.user.profile.agency)
# Check for correct user and userrights
if(request.user.profile.agency == workingstandard.agency and request.user.has_perm("standardmanager")):
# CHANGE GROUP
# ADD
if(request.GET["action"] == "s_addgroup"):
workingstandard.visibleby.add(AgencyGroup.objects.get(pk=request.GET["groupid"], agency=request.user.profile.agency))
# REMOVE
elif(request.GET["action"] == "s_remgroup"):
workingstandard.visibleby.remove(AgencyGroup.objects.get(pk=request.GET["groupid"], agency=request.user.profile.agency))
# FILES
# REMOVE
elif(request.GET["action"] == "s_remfile"):
workingstandard.addedfiles.remove(DataFile.objects.get(pk=request.GET["fileid"], agency=request.user.profile.agency))
# ADD
elif(request.GET["action"] == "s_addfile"):
workingstandard.addedfiles.add(DataFile.objects.get(pk=request.GET["fileid"], agency=request.user.profile.agency))
# STANDARD
# REMOVE
elif(request.GET["action"] == "s_remstandard"):
workingstandard.linked_standards.remove(Standards.objects.get(pk=request.GET["standardid"], agency=request.user.profile.agency))
# ADD
elif(request.GET["action"] == "s_addstandard"):
workingstandard.linked_standards.add(Standards.objects.get(pk=request.GET["standardid"], agency=request.user.profile.agency))
else:
success = False
return JsonResponse({"success" : success})

View File

@ -10,10 +10,9 @@ class TasksAddTaskForm(forms.ModelForm):
labels = {
"name" : "Aufgabenname",
"area" : "Übergeordneter Bereich",
"desc" : "Beschreibung",
"visible": "Im Organigramm sichtbar"
}
fields = ['name', 'area', 'desc', 'visible']
fields = ['name', 'area', 'visible']
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')

View File

@ -2,15 +2,15 @@
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section col-6">
<h3>Neue Aufgabe anlegen</h3>
<h3>Neue Tätigkeit anlegen</h3>
<hr>
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<p>Nachdem Erstellen der Aufgabe können Mitarbeiter zugewiesen werden.</p>
<hr>
<button type="submit" class="btn btn-success" href="{% url 'areas-addarea' %} ">Aufgabe anlegen</button>&nbsp;
<a class="btn" href="{% url 'tasks-management' %} ">Abbrechen</a>
<button type="submit" class="btn btn-success" href="{% url 'dasettings' %} ">Tätigkeit anlegen</button>&nbsp;
<a class="btn" href="{% url 'dasettings' %} ">Abbrechen</a>
</form>
</div>
{% endblock content %}

Some files were not shown because too many files have changed in this diff Show More