Initial Attachment Management
This commit is contained in:
parent
5f30383c83
commit
057388e3b4
@ -89,6 +89,11 @@ def render(request, text, attachment_target_path, next_anchor=''):
|
|||||||
return creole.creole2html(text)
|
return creole.creole2html(text)
|
||||||
|
|
||||||
|
|
||||||
|
def url_delete(request, rel_path, next_anchor=''):
|
||||||
|
nxt = request.GET.get('next', request.get_full_path())
|
||||||
|
return reverse('mycreole-delete', kwargs={'rel_path': rel_path}) + '?next=%s' % nxt + ('' if not next_anchor else '#%s' % next_anchor)
|
||||||
|
|
||||||
|
|
||||||
def url_upload(request, rel_path, next_anchor=''):
|
def url_upload(request, rel_path, next_anchor=''):
|
||||||
nxt = request.GET.get('next', request.get_full_path())
|
nxt = request.GET.get('next', request.get_full_path())
|
||||||
return reverse('mycreole-upload', kwargs={'rel_path': rel_path}) + '?next=%s' % nxt + ('' if not next_anchor else '#%s' % next_anchor)
|
return reverse('mycreole-upload', kwargs={'rel_path': rel_path}) + '?next=%s' % nxt + ('' if not next_anchor else '#%s' % next_anchor)
|
||||||
|
32
context.py
32
context.py
@ -1,11 +1,35 @@
|
|||||||
|
from django.utils.translation import gettext as _
|
||||||
|
import logging
|
||||||
|
from mycreole import url_upload
|
||||||
from users.context import menubar as user_menubar
|
from users.context import menubar as user_menubar
|
||||||
import themes
|
from patt.context import navigationbar
|
||||||
|
from themes import color_icon_url
|
||||||
|
|
||||||
|
try:
|
||||||
|
from config import APP_NAME as ROOT_LOGGER_NAME
|
||||||
|
except ImportError:
|
||||||
|
ROOT_LOGGER_NAME = 'root'
|
||||||
|
logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__)
|
||||||
|
|
||||||
|
NEW_ATTACHMENT_UID = 'new_attachment'
|
||||||
|
|
||||||
|
|
||||||
def context_adaption(context, request, title, **kwargs):
|
def context_adaption(context, request, title, rel_path, **kwargs):
|
||||||
context.set_additional_title(title)
|
context.set_additional_title(title)
|
||||||
user_menubar(context[context.MENUBAR], request)
|
user_menubar(context[context.MENUBAR], request)
|
||||||
context[context.NAVIGATIONBAR].append_entry(*themes.empty_entry_parameters(request))
|
navigationbar(context, request)
|
||||||
context[context.ACTIONBAR].append_entry(*themes.empty_entry_parameters(request))
|
add_new(request, context[context.ACTIONBAR], rel_path, kwargs.get('next'))
|
||||||
for key in kwargs:
|
for key in kwargs:
|
||||||
context[key] = kwargs[key]
|
context[key] = kwargs[key]
|
||||||
|
logger.debug("context adapted: %s", repr(context))
|
||||||
|
|
||||||
|
|
||||||
|
def add_new(request, bar, rel_path, nxt):
|
||||||
|
bar.append_entry(
|
||||||
|
NEW_ATTACHMENT_UID, # uid
|
||||||
|
_('New Attachment'), # name
|
||||||
|
color_icon_url(request, 'plus.png'), # icon
|
||||||
|
url_upload(request, rel_path, nxt), # url
|
||||||
|
True, # left
|
||||||
|
False # active
|
||||||
|
)
|
||||||
|
17
templates/mycreole/delete.html
Normal file
17
templates/mycreole/delete.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{% extends "themes/"|add:settings.page_theme|add:"/base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Delete Attachment</h1>
|
||||||
|
Are you sure deleting {{ filename }}?
|
||||||
|
|
||||||
|
<form class="form" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="next" value="{{ next }}">
|
||||||
|
<input type="submit" name="yes" value="{% trans "Yes" %}" class="button" />
|
||||||
|
<input type="submit" name="no" value="{% trans "No" %}" class="button" />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock content %}
|
29
templates/mycreole/manageuploads.html
Normal file
29
templates/mycreole/manageuploads.html
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{% extends "themes/"|add:settings.page_theme|add:"/base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>Attachments</h1>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Size</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
{% for key, value in attachments.items %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ key }}</td>
|
||||||
|
<td>{{ value.size }}</td>
|
||||||
|
<td>
|
||||||
|
{% for icon, url, alt in value.actions %}
|
||||||
|
<a href="{{ url }}"><img src="{{ icon }}" alt={{ alt }}></a>
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock content %}
|
@ -5,6 +5,9 @@
|
|||||||
<form class="form" method="post" enctype="multipart/form-data">
|
<form class="form" method="post" enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" name="next" value="{{ next }}">
|
<input type="hidden" name="next" value="{{ next }}">
|
||||||
|
{% if rel_path_is_directory %}
|
||||||
|
<p><label for="id_filename">Filename:</label> <input type="text" name="filename" maxlength="150" required id="id_filename"></p>
|
||||||
|
{% endif %}
|
||||||
<label class="required" for="f_file">Upload</label>
|
<label class="required" for="f_file">Upload</label>
|
||||||
<input class="required" required="required" type="file" name="file" id="f_file">
|
<input class="required" required="required" type="file" name="file" id="f_file">
|
||||||
<input type="submit" value="{% trans "Upload" %}" class="button" />
|
<input type="submit" value="{% trans "Upload" %}" class="button" />
|
||||||
|
1
urls.py
1
urls.py
@ -5,5 +5,6 @@ from . import views
|
|||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('attachment/<path:rel_path>', views.mycreole_attachment, name='mycreole-attachment'),
|
path('attachment/<path:rel_path>', views.mycreole_attachment, name='mycreole-attachment'),
|
||||||
path('upload/<path:rel_path>', views.mycreole_upload, name='mycreole-upload'),
|
path('upload/<path:rel_path>', views.mycreole_upload, name='mycreole-upload'),
|
||||||
|
path('delete/<path:rel_path>', views.mycreole_delete, name='mycreole-delete'),
|
||||||
path('manageuploads/<path:rel_path>', views.mycreole_manageuploads, name='mycreole-manageuploads'),
|
path('manageuploads/<path:rel_path>', views.mycreole_manageuploads, name='mycreole-manageuploads'),
|
||||||
]
|
]
|
||||||
|
95
views.py
95
views.py
@ -2,11 +2,14 @@ from .context import context_adaption
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.shortcuts import render, redirect, HttpResponse
|
from django.shortcuts import render, redirect, HttpResponse
|
||||||
from django.http import HttpResponseNotFound, HttpResponseForbidden
|
from django.http import HttpResponseNotFound, HttpResponseForbidden
|
||||||
|
import fstools
|
||||||
import importlib
|
import importlib
|
||||||
import mimetypes
|
import mimetypes
|
||||||
|
from mycreole import url_upload, url_attachment, url_delete
|
||||||
import logging
|
import logging
|
||||||
import mycreole
|
import mycreole
|
||||||
import os
|
import os
|
||||||
|
import stringtools
|
||||||
import themes
|
import themes
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
|
||||||
@ -26,6 +29,13 @@ def get_method(import_string):
|
|||||||
return getattr(module, class_str)
|
return getattr(module, class_str)
|
||||||
|
|
||||||
|
|
||||||
|
def get_next(request):
|
||||||
|
if not request.POST:
|
||||||
|
return request.GET.get('next', '/')
|
||||||
|
else:
|
||||||
|
return request.POST.get('next', '/')
|
||||||
|
|
||||||
|
|
||||||
def access(access_type, request, rel_path):
|
def access(access_type, request, rel_path):
|
||||||
def log_warning(access_type, e):
|
def log_warning(access_type, e):
|
||||||
logger.warning('Could not import %s_access method for checking access rights: %s - %s', access_type, type(e).__name__, e)
|
logger.warning('Could not import %s_access method for checking access rights: %s - %s', access_type, type(e).__name__, e)
|
||||||
@ -66,10 +76,20 @@ def mycreole_upload(request, rel_path):
|
|||||||
if access('modify', request, rel_path):
|
if access('modify', request, rel_path):
|
||||||
if not request.POST:
|
if not request.POST:
|
||||||
context = themes.Context(request)
|
context = themes.Context(request)
|
||||||
context_adaption(context, request, 'Upload %s' % rel_path, next=request.GET.get('next', '/'))
|
context_adaption(
|
||||||
|
context,
|
||||||
|
request,
|
||||||
|
'Upload %s' % rel_path,
|
||||||
|
os.path.dirname(rel_path),
|
||||||
|
rel_path_is_directory=os.path.isdir(mycreole.get_full_path(rel_path)),
|
||||||
|
next=request.GET.get('next', '/')
|
||||||
|
)
|
||||||
return render(request, 'mycreole/upload.html', context=context)
|
return render(request, 'mycreole/upload.html', context=context)
|
||||||
else:
|
else:
|
||||||
|
filename = request.POST.get('filename')
|
||||||
full_path = mycreole.get_full_path(rel_path)
|
full_path = mycreole.get_full_path(rel_path)
|
||||||
|
if filename is not None:
|
||||||
|
full_path = os.path.join(full_path, filename)
|
||||||
try:
|
try:
|
||||||
os.makedirs(os.path.dirname(full_path), exist_ok=True)
|
os.makedirs(os.path.dirname(full_path), exist_ok=True)
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
@ -77,12 +97,81 @@ def mycreole_upload(request, rel_path):
|
|||||||
else:
|
else:
|
||||||
with open(full_path, 'wb') as fh:
|
with open(full_path, 'wb') as fh:
|
||||||
fh.write(request.FILES['file'].read())
|
fh.write(request.FILES['file'].read())
|
||||||
|
messages.info(request, 'File %s successfully uploaded.' % os.path.basename(full_path))
|
||||||
return redirect(request.POST.get('next', '/'))
|
return redirect(request.POST.get('next', '/'))
|
||||||
else:
|
else:
|
||||||
messages.error(request, "Upload: Access denied!")
|
messages.error(request, "Upload: Access denied!")
|
||||||
return redirect(request.GET.get('next', '/'))
|
return redirect(request.GET.get('next', '/'))
|
||||||
|
|
||||||
|
|
||||||
|
def mycreole_delete(request, rel_path):
|
||||||
|
context = themes.Context(request) # needs to be executed first because of time mesurement
|
||||||
|
nxt = get_next(request)
|
||||||
|
modify_access = access('modify', request, rel_path)
|
||||||
|
full_path = mycreole.get_full_path(rel_path)
|
||||||
|
if not modify_access:
|
||||||
|
messages.error(request, 'Detele Attachment: Access denied!')
|
||||||
|
else:
|
||||||
|
if not request.POST:
|
||||||
|
context_adaption(
|
||||||
|
context,
|
||||||
|
request,
|
||||||
|
'Delete %s' % os.path.basename(rel_path),
|
||||||
|
os.path.dirname(rel_path),
|
||||||
|
next=nxt,
|
||||||
|
filename=os.path.basename(rel_path)
|
||||||
|
)
|
||||||
|
return render(request, 'mycreole/delete.html', context=context)
|
||||||
|
else:
|
||||||
|
if request.POST.get('yes') is not None:
|
||||||
|
try:
|
||||||
|
os.remove(full_path)
|
||||||
|
except Exception:
|
||||||
|
messages.error(request, 'Error while deleting file from filesystem.')
|
||||||
|
logger.exception('Fatal error while deleting Attachment!')
|
||||||
|
else:
|
||||||
|
messages.info(request, "Attachment %s deleted..." % os.path.basename(full_path))
|
||||||
|
else:
|
||||||
|
messages.info(request, 'Delete request aborded.')
|
||||||
|
return redirect(nxt)
|
||||||
|
|
||||||
|
|
||||||
def mycreole_manageuploads(request, rel_path):
|
def mycreole_manageuploads(request, rel_path):
|
||||||
messages.error(request, 'Manage Uploads: Not yet implemented!')
|
context = themes.Context(request) # needs to be executed first because of time mesurement
|
||||||
return redirect(request.GET.get('next', '/'))
|
nxt = get_next(request)
|
||||||
|
read_access = access('read', request, rel_path)
|
||||||
|
modify_access = access('modify', request, rel_path)
|
||||||
|
#
|
||||||
|
if not read_access:
|
||||||
|
messages.error(request, "Manageupload: Access denied!")
|
||||||
|
return redirect(nxt)
|
||||||
|
|
||||||
|
basepath = mycreole.get_full_path(rel_path)
|
||||||
|
if not os.path.exists(basepath):
|
||||||
|
logger.info('Creating path for attachments: %s', basepath)
|
||||||
|
fstools.mkdir(basepath)
|
||||||
|
logger.debug("Searching for files in %s", basepath)
|
||||||
|
attachments = {}
|
||||||
|
for file in fstools.filelist(basepath):
|
||||||
|
filename = os.path.basename(file)
|
||||||
|
actions = []
|
||||||
|
if modify_access:
|
||||||
|
actions.append((themes.gray_icon_url(request, 'delete.png'), url_delete(request, os.path.join(rel_path, filename)), 'delete'))
|
||||||
|
actions.append((themes.gray_icon_url(request, 'shuffle.png'), url_upload(request, os.path.join(rel_path, filename)), 'replace'))
|
||||||
|
actions.append((themes.gray_icon_url(request, 'view.png'), url_attachment(os.path.join(rel_path, filename)), 'view'))
|
||||||
|
attachments[filename] = {
|
||||||
|
'size': stringtools.physical_value_repr(os.path.getsize(file), 'B'),
|
||||||
|
'modify_access': modify_access,
|
||||||
|
'actions': actions,
|
||||||
|
}
|
||||||
|
logger.debug("%d attachments detected: %s", len(attachments), ', '.join(attachments.keys()))
|
||||||
|
#
|
||||||
|
mycreole.context.context_adaption(
|
||||||
|
context,
|
||||||
|
request,
|
||||||
|
'Manageuploads for %s' % rel_path,
|
||||||
|
rel_path,
|
||||||
|
next=nxt,
|
||||||
|
attachments=attachments
|
||||||
|
)
|
||||||
|
return render(request, 'mycreole/manageuploads.html', context=context)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user