Initial Editor for pages implemented
This commit is contained in:
parent
30b872ee2d
commit
dfcf8e15fd
2
mycreole
2
mycreole
@ -1 +1 @@
|
||||
Subproject commit 057388e3b44b5fe42b133fe030c41aa6a254de58
|
||||
Subproject commit 8a2da2b84379df346d4f24c8fc5c1e6fe62c75e9
|
@ -2,8 +2,12 @@ from django.urls.base import reverse
|
||||
|
||||
|
||||
def url_page(request, rel_path):
|
||||
return reverse('pages-pages', kwargs={'rel_path': rel_path})
|
||||
return reverse('page-page', kwargs={'rel_path': rel_path})
|
||||
|
||||
|
||||
def url_helpview(request, page):
|
||||
return reverse('pages-helpview', kwargs={'page': page})
|
||||
return reverse('page-helpview', kwargs={'page': page})
|
||||
|
||||
|
||||
def url_edit(request, rel_path):
|
||||
return reverse('page-edit', kwargs={'rel_path': rel_path})
|
||||
|
@ -1,8 +1,16 @@
|
||||
# TODO: Implement access control for pages
|
||||
|
||||
def read_attachment(request, rel_path):
|
||||
def read_page(request, rel_path):
|
||||
return True
|
||||
|
||||
|
||||
def write_page(request, rel_path):
|
||||
return request.user.is_authenticated and request.user.username in ['root', 'dirk']
|
||||
|
||||
|
||||
def read_attachment(request, rel_path):
|
||||
return read_page(request, rel_path)
|
||||
|
||||
|
||||
def modify_attachment(request, rel_path):
|
||||
return True
|
||||
return write_page(request, rel_path)
|
||||
|
212
pages/context.py
212
pages/context.py
@ -4,6 +4,7 @@ import logging
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
|
||||
from pages import access
|
||||
from .help import actionbar as actionbar_add_help
|
||||
import mycreole
|
||||
import pages
|
||||
@ -18,6 +19,7 @@ logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__)
|
||||
|
||||
ATTACHMENT_UID = 'attachment'
|
||||
BACK_UID = 'back'
|
||||
EDIT_UID = 'edit'
|
||||
HELP_UID = 'help'
|
||||
|
||||
|
||||
@ -56,12 +58,7 @@ def add_back_menu(request, bar):
|
||||
|
||||
def menubar(context, request, caller_name, **kwargs):
|
||||
bar = context[context.MENUBAR]
|
||||
# replace_profile(request, bar)
|
||||
add_help_menu(request, bar)
|
||||
# add_tasklist_menu(request, bar)
|
||||
# add_filter_submenu(request, bar, VIEW_TASKLIST_UID)
|
||||
# add_projectlist_menu(request, bar)
|
||||
# add_printview_menu(request, bar)
|
||||
finalise_bar(request, bar)
|
||||
|
||||
|
||||
@ -78,18 +75,27 @@ def add_help_menu(request, bar):
|
||||
|
||||
def actionbar(context, request, caller_name, **kwargs):
|
||||
bar = context[context.ACTIONBAR]
|
||||
if caller_name == 'pages':
|
||||
# acc = acc_task(kwargs['task'], request.user)
|
||||
# if acc.modify or acc.modify_limited:
|
||||
# add_edittask_menu(request, bar, kwargs['task'].id)
|
||||
# if acc.add_comments:
|
||||
# add_newcomment_menu(request, bar, kwargs['task'].id)
|
||||
add_manageupload_menu(request, bar, kwargs['upload_path'])
|
||||
if caller_name == 'page':
|
||||
if access.write_page(request, kwargs["rel_path"]):
|
||||
add_edit_menu(request, bar, kwargs["rel_path"])
|
||||
if access.modify_attachment(request, kwargs["rel_path"]):
|
||||
add_manageupload_menu(request, bar, kwargs['upload_path'])
|
||||
elif caller_name == 'helpview':
|
||||
actionbar_add_help(context, request, **kwargs)
|
||||
finalise_bar(request, bar)
|
||||
|
||||
|
||||
def add_edit_menu(request, bar, rel_path):
|
||||
bar.append_entry(
|
||||
EDIT_UID, # uid
|
||||
_('Edit'), # name
|
||||
color_icon_url(request, 'edit.png'), # icon
|
||||
pages.url_edit(request, rel_path), # url
|
||||
True, # left
|
||||
False # active
|
||||
)
|
||||
|
||||
|
||||
def add_manageupload_menu(request, bar, upload_path):
|
||||
bar.append_entry(
|
||||
ATTACHMENT_UID, # uid
|
||||
@ -105,185 +111,3 @@ def finalise_bar(request, bar):
|
||||
if len(bar) == 0:
|
||||
bar.append_entry(*empty_entry_parameters(request))
|
||||
|
||||
|
||||
"""from .access import create_project_possible, create_task_possible, acc_task
|
||||
from django.db.models.functions import Lower
|
||||
import patt
|
||||
from .search import common_searches
|
||||
from themes import empty_entry_parameters, color_icon_url, gray_icon_url
|
||||
from users.context import PROFILE_ENTRY_UID
|
||||
|
||||
|
||||
COMMENTNEW_UID = 'commentnew'
|
||||
CREATE_PROJECT_UID = 'create-project'
|
||||
CREATE_TASK_UID = 'create-task'
|
||||
PRINTVIEW_UID = 'printview'
|
||||
TASKEDIT_UID = 'taskedit'
|
||||
VIEW_PROJECTLIST_UID = 'view-projectlist'
|
||||
VIEW_TASKLIST_UID = 'view-tasklist'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def replace_profile(request, bar):
|
||||
try:
|
||||
bar.replace_entry(
|
||||
PROFILE_ENTRY_UID,
|
||||
PROFILE_ENTRY_UID, # uid
|
||||
request.user.username, # name
|
||||
color_icon_url(request, 'user.png'), # icon
|
||||
patt.url_profile(request), # url
|
||||
False, # left
|
||||
False # active
|
||||
)
|
||||
except ValueError:
|
||||
pass # Profile entry does not exist, so exchange is not needed (e.g. no user is logged in)
|
||||
|
||||
|
||||
|
||||
|
||||
def add_tasklist_menu(request, bar):
|
||||
bar.append_entry(
|
||||
VIEW_TASKLIST_UID, # uid
|
||||
_('Tasklist'), # name
|
||||
color_icon_url(request, 'task.png'), # icon
|
||||
patt.url_tasklist(request), # url
|
||||
True, # left
|
||||
patt.is_tasklistview(request) # active
|
||||
)
|
||||
|
||||
|
||||
def add_projectlist_menu(request, bar):
|
||||
bar.append_entry(
|
||||
VIEW_PROJECTLIST_UID, # uid
|
||||
_('Projectlist'), # name
|
||||
color_icon_url(request, 'folder.png'), # icon
|
||||
patt.url_projectlist(request), # url
|
||||
True, # left
|
||||
patt.is_projectlistview(request) # active
|
||||
)
|
||||
|
||||
|
||||
def add_printview_menu(request, bar):
|
||||
bar.append_entry(
|
||||
PRINTVIEW_UID, # uid
|
||||
_('Printview'), # name
|
||||
color_icon_url(request, 'print.png'), # icon
|
||||
patt.url_printview(request), # url
|
||||
True, # left
|
||||
patt.is_printview(request) # active
|
||||
)
|
||||
|
||||
|
||||
def add_newtask_menu(request, bar, project_id):
|
||||
bar.append_entry(
|
||||
CREATE_TASK_UID, # uid
|
||||
_('New Task'), # name
|
||||
color_icon_url(request, 'plus.png'), # icon
|
||||
patt.url_tasknew(request, project_id), # url
|
||||
True, # left
|
||||
False # active
|
||||
)
|
||||
|
||||
|
||||
def add_edittask_menu(request, bar, task_id):
|
||||
bar.append_entry(
|
||||
TASKEDIT_UID, # uid
|
||||
_('Edit'), # name
|
||||
color_icon_url(request, 'edit.png'), # icon
|
||||
patt.url_taskedit(request, task_id), # url
|
||||
True, # left
|
||||
False # active
|
||||
)
|
||||
|
||||
|
||||
def add_newcomment_menu(request, bar, task_id):
|
||||
bar.append_entry(
|
||||
COMMENTNEW_UID, # uid
|
||||
_('Add Comment'), # name
|
||||
color_icon_url(request, 'edit2.png'), # icon
|
||||
patt.url_commentnew(request, task_id), # url
|
||||
True, # left
|
||||
False # active
|
||||
)
|
||||
|
||||
|
||||
def add_newproject_menu(request, bar):
|
||||
bar.append_entry(
|
||||
CREATE_PROJECT_UID, # uid
|
||||
_('New Project'), # name
|
||||
color_icon_url(request, 'plus.png'), # icon
|
||||
patt.url_projectnew(request), # url
|
||||
True, # left
|
||||
False # active
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def add_filter_submenu(request, bar, menu_uid):
|
||||
bar.append_entry_to_entry(
|
||||
menu_uid,
|
||||
menu_uid + '-easysearch', # uid
|
||||
_('Easysearch'), # name
|
||||
gray_icon_url(request, 'search.png'), # icon
|
||||
patt.url_easysearch(request), # url
|
||||
True, # left
|
||||
False # active
|
||||
)
|
||||
if patt.get_search_query(request) is not None:
|
||||
bar.append_entry_to_entry(
|
||||
menu_uid,
|
||||
menu_uid + '-save', # uid
|
||||
_('Save Search as Filter'), # name
|
||||
gray_icon_url(request, 'save.png'), # icon
|
||||
patt.url_filteredit(request), # url
|
||||
True, # left
|
||||
False # active
|
||||
)
|
||||
bar.append_entry_to_entry(
|
||||
menu_uid,
|
||||
menu_uid + '-all', # uid
|
||||
_('All Tasks'), # name
|
||||
gray_icon_url(request, 'task.png'), # icon
|
||||
patt.url_tasklist(request), # url
|
||||
True, # left
|
||||
False # active
|
||||
)
|
||||
cs = common_searches(request)
|
||||
for common_filter_id in cs:
|
||||
bar.append_entry_to_entry(
|
||||
menu_uid,
|
||||
menu_uid + '-common', # uid
|
||||
_(cs[common_filter_id][0]), # name
|
||||
gray_icon_url(request, 'filter.png'), # icon
|
||||
patt.url_tasklist(request, common_filter_id=common_filter_id), # url
|
||||
True, # left
|
||||
False # active
|
||||
)
|
||||
for s in request.user.search_set.order_by(Lower('name')):
|
||||
active = patt.is_tasklistview(request, s.id)
|
||||
if active is True:
|
||||
url = patt.url_filteredit(request, s.id)
|
||||
else:
|
||||
url = patt.url_tasklist(request, user_filter_id=s.id)
|
||||
if active:
|
||||
icon = 'settings.png'
|
||||
else:
|
||||
icon = 'favourite.png'
|
||||
bar.append_entry_to_entry(
|
||||
menu_uid,
|
||||
menu_uid + '-sub', # uid
|
||||
s.name, # name
|
||||
gray_icon_url(request, icon), # icon
|
||||
url, # url
|
||||
True, # left
|
||||
active # active
|
||||
)
|
||||
"""
|
||||
|
14
pages/forms.py
Normal file
14
pages/forms.py
Normal file
@ -0,0 +1,14 @@
|
||||
from typing import Any, Mapping
|
||||
from django import forms
|
||||
from django.forms.renderers import BaseRenderer
|
||||
from django.forms.utils import ErrorList
|
||||
|
||||
|
||||
class EditForm(forms.Form): # Note that it is not inheriting from forms.ModelForm
|
||||
page_txt = forms.CharField(max_length=20000, label="Page source text", widget=forms.Textarea(attrs={"rows": "20"}))
|
||||
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
page_data = kwargs.pop("page_data")
|
||||
super().__init__(*args, **kwargs)
|
||||
page_txt = self.fields['page_txt']
|
||||
page_txt.initial = page_data
|
12
pages/messages.py
Normal file
12
pages/messages.py
Normal file
@ -0,0 +1,12 @@
|
||||
from django.contrib import messages
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
|
||||
def permission_denied_msg_page(request, rel_path):
|
||||
# TODO: Add translation for this message
|
||||
messages.error(request, _("Permission denied: You don't have sufficient acces to the Page '%s'. Please contact the adminstrator.") % rel_path)
|
||||
|
||||
|
||||
def unavailable_msg_page(request, rel_path):
|
||||
# TODO: Add translation for this message
|
||||
messages.info(request, _("Unavailable: The Page '%s' is not available. Create it or follow a valid link, please.") % rel_path)
|
@ -1,10 +1,12 @@
|
||||
from django.conf import settings
|
||||
|
||||
import fstools
|
||||
from pages import messages
|
||||
import mycreole
|
||||
import os
|
||||
|
||||
|
||||
class page(object):
|
||||
class creol_page(object):
|
||||
SPLITCHAR = ":"
|
||||
FOLDER_ATTACHMENTS = "attachments"
|
||||
FOLDER_CONTENT = 'content'
|
||||
@ -35,13 +37,24 @@ class page(object):
|
||||
def content_file_name(self):
|
||||
return os.path.join(settings.PAGES_ROOT, self.content_folder_name, self.FOLDER_CONTENT, self.FILE_NAME)
|
||||
|
||||
def __read_content__(self):
|
||||
if self.is_available():
|
||||
@property
|
||||
def raw_page_src(self):
|
||||
try:
|
||||
with open(self.content_file_name, 'r') as fh:
|
||||
return fh.read()
|
||||
else:
|
||||
# TODO: Create message for creation or no content dependent of user has write access
|
||||
return "Page not available. Create it."
|
||||
except FileNotFoundError:
|
||||
return ""
|
||||
|
||||
def update_page(self, page_txt):
|
||||
folder = os.path.dirname(self.content_file_name)
|
||||
if not os.path.exists(folder):
|
||||
fstools.mkdir(folder)
|
||||
with open(self.content_file_name, 'w') as fh:
|
||||
fh.write(page_txt)
|
||||
|
||||
def render_to_html(self, request):
|
||||
return mycreole.render(request, self.__read_content__(), self.attachment_path, "next_anchor")
|
||||
if self.is_available():
|
||||
return mycreole.render(request, self.raw_page_src, self.attachment_path, "next_anchor")
|
||||
else:
|
||||
messages.unavailable_msg_page(request, self._rel_path)
|
||||
return ""
|
||||
|
20
pages/templates/pages/page_form.html
Normal file
20
pages/templates/pages/page_form.html
Normal file
@ -0,0 +1,20 @@
|
||||
{% extends "themes/"|add:settings.page_theme|add:"/base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<form class="form" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<input type="submit" name="save" value="{% trans "Save" %}" class="button" />
|
||||
{% if not disable_preview %}<input type="submit" formaction="#preview" name="preview" value="{% trans "Preview" %}" class="button" />{% endif %}
|
||||
{{ form_comment.as_p }}
|
||||
</form>
|
||||
|
||||
{% if page_content %}
|
||||
<div class="preview-spacer" id="preview"></div>
|
||||
<div class="preview">
|
||||
{{ page_content|safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
@ -4,11 +4,15 @@ from django.utils.translation import gettext as _
|
||||
|
||||
import logging
|
||||
|
||||
import config
|
||||
from . import access
|
||||
from . import messages
|
||||
from . import url_page
|
||||
import config
|
||||
from .context import context_adaption
|
||||
from .forms import EditForm
|
||||
from .help import help_pages
|
||||
from .page import page
|
||||
import mycreole
|
||||
from .page import creol_page
|
||||
from themes import Context
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -18,21 +22,73 @@ def root(request):
|
||||
return HttpResponseRedirect(url_page(request, config.STARTPAGE))
|
||||
|
||||
|
||||
def pages(request, rel_path=''):
|
||||
def page(request, rel_path):
|
||||
context = Context(request) # needs to be executed first because of time mesurement
|
||||
#
|
||||
p = page(rel_path)
|
||||
p = creol_page(rel_path)
|
||||
if access.read_page(request, rel_path):
|
||||
page_content = p.render_to_html(request)
|
||||
else:
|
||||
messages.permission_denied_msg_page(request, rel_path)
|
||||
page_content = ""
|
||||
#
|
||||
context_adaption(
|
||||
context,
|
||||
request,
|
||||
rel_path=rel_path,
|
||||
title=p.title,
|
||||
upload_path=p.attachment_path,
|
||||
page_content=p.render_to_html(request)
|
||||
page_content=page_content
|
||||
)
|
||||
return render(request, 'pages/page.html', context=context)
|
||||
|
||||
|
||||
def edit(request, rel_path):
|
||||
if access.write_page(request, rel_path):
|
||||
context = Context(request) # needs to be executed first because of time mesurement
|
||||
#
|
||||
p = creol_page(rel_path)
|
||||
#
|
||||
if not request.POST:
|
||||
form = EditForm(page_data=p.raw_page_src)
|
||||
#
|
||||
context_adaption(
|
||||
context,
|
||||
request,
|
||||
form=form,
|
||||
# TODO: Add translation
|
||||
title=_("Edit page %s") % repr(p.title),
|
||||
upload_path=p.attachment_path,
|
||||
)
|
||||
return render(request, 'pages/page_form.html', context=context)
|
||||
else:
|
||||
save = request.POST.get("save")
|
||||
page_txt = request.POST.get("page_txt")
|
||||
preview = request.POST.get("preview")
|
||||
#
|
||||
if save is not None:
|
||||
p.update_page(page_txt)
|
||||
return HttpResponseRedirect(url_page(request, rel_path))
|
||||
elif preview is not None:
|
||||
form = EditForm(page_data=page_txt)
|
||||
#
|
||||
context_adaption(
|
||||
context,
|
||||
request,
|
||||
form=form,
|
||||
# TODO: Add translation
|
||||
title=_("Edit page %s") % repr(p.title),
|
||||
upload_path=p.attachment_path,
|
||||
page_content=mycreole.render(request, page_txt, p.attachment_path, 'next-anchor')
|
||||
)
|
||||
return render(request, 'pages/page_form.html', context=context)
|
||||
else:
|
||||
return HttpResponseRedirect(url_page(request, rel_path))
|
||||
else:
|
||||
messages.permission_denied_msg_page(request, rel_path)
|
||||
return HttpResponseRedirect(url_page(request, rel_path))
|
||||
|
||||
|
||||
def search(request):
|
||||
context = Context(request) # needs to be executed first because of time mesurement
|
||||
context_adaption(
|
||||
|
11
piki/urls.py
11
piki/urls.py
@ -24,11 +24,12 @@ import pages.views
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
#
|
||||
path('', pages.views.root, name='pages-root'),
|
||||
path('pages/', pages.views.root, name='pages-root'),
|
||||
path('pages/<path:rel_path>', pages.views.pages, name='pages-pages'),
|
||||
path('helpview/', pages.views.helpview, name='pages-helpview'),
|
||||
path('helpview/<str:page>', pages.views.helpview, name='pages-helpview'),
|
||||
path('', pages.views.root, name='page-root'),
|
||||
path('page/', pages.views.root, name='page-root'),
|
||||
path('page/<path:rel_path>', pages.views.page, name='page-page'),
|
||||
path('pageedit/<path:rel_path>/', pages.views.edit, name='page-edit'),
|
||||
path('helpview/', pages.views.helpview, name='page-helpview'),
|
||||
path('helpview/<str:page>', pages.views.helpview, name='page-helpview'),
|
||||
path('search/', pages.views.search, name='search'),
|
||||
path('mycreole/', include('mycreole.urls')),
|
||||
path('users/', include('users.urls')),
|
||||
|
Loading…
x
Reference in New Issue
Block a user