Initial Attachment Management

This commit is contained in:
Dirk Alders 2021-04-10 19:58:45 +02:00
parent 5f30383c83
commit 057388e3b4
7 changed files with 175 additions and 7 deletions

View File

@ -89,6 +89,11 @@ def render(request, text, attachment_target_path, next_anchor=''):
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=''):
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)

View File

@ -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
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)
user_menubar(context[context.MENUBAR], request)
context[context.NAVIGATIONBAR].append_entry(*themes.empty_entry_parameters(request))
context[context.ACTIONBAR].append_entry(*themes.empty_entry_parameters(request))
navigationbar(context, request)
add_new(request, context[context.ACTIONBAR], rel_path, kwargs.get('next'))
for key in kwargs:
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
)

View 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 %}

View 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 %}

View File

@ -5,6 +5,9 @@
<form class="form" method="post" enctype="multipart/form-data">
{% csrf_token %}
<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>
<input class="required" required="required" type="file" name="file" id="f_file">
<input type="submit" value="{% trans "Upload" %}" class="button" />

View File

@ -5,5 +5,6 @@ from . import views
urlpatterns = [
path('attachment/<path:rel_path>', views.mycreole_attachment, name='mycreole-attachment'),
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'),
]

View File

@ -2,11 +2,14 @@ from .context import context_adaption
from django.conf import settings
from django.shortcuts import render, redirect, HttpResponse
from django.http import HttpResponseNotFound, HttpResponseForbidden
import fstools
import importlib
import mimetypes
from mycreole import url_upload, url_attachment, url_delete
import logging
import mycreole
import os
import stringtools
import themes
from django.contrib import messages
@ -26,6 +29,13 @@ def get_method(import_string):
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 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)
@ -66,10 +76,20 @@ def mycreole_upload(request, rel_path):
if access('modify', request, rel_path):
if not request.POST:
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)
else:
filename = request.POST.get('filename')
full_path = mycreole.get_full_path(rel_path)
if filename is not None:
full_path = os.path.join(full_path, filename)
try:
os.makedirs(os.path.dirname(full_path), exist_ok=True)
except PermissionError:
@ -77,12 +97,81 @@ def mycreole_upload(request, rel_path):
else:
with open(full_path, 'wb') as fh:
fh.write(request.FILES['file'].read())
messages.info(request, 'File %s successfully uploaded.' % os.path.basename(full_path))
return redirect(request.POST.get('next', '/'))
else:
messages.error(request, "Upload: Access denied!")
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):
messages.error(request, 'Manage Uploads: Not yet implemented!')
return redirect(request.GET.get('next', '/'))
context = themes.Context(request) # needs to be executed first because of time mesurement
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)