Initial mycreole implementation
This commit is contained in:
parent
b5f611468f
commit
dd0edc2d56
103
__init__.py
Normal file
103
__init__.py
Normal file
@ -0,0 +1,103 @@
|
||||
import creole
|
||||
from django.conf import settings
|
||||
from django.urls.base import reverse
|
||||
from .help import MYCREOLE_HELP
|
||||
import importlib
|
||||
import os
|
||||
import shutil
|
||||
|
||||
|
||||
def get_full_path(rel_path):
|
||||
try:
|
||||
return os.path.join(settings.MYCREOLE_ROOT, *rel_path.split('/'))
|
||||
except AttributeError:
|
||||
raise AttributeError("You need to define a root directory for mycreole in settings.py: MYCREOLE_ROOT")
|
||||
|
||||
|
||||
def delete_attachment_target_path(attachment_target_path):
|
||||
shutil.rmtree(get_full_path(attachment_target_path), True)
|
||||
|
||||
|
||||
def mycreole_help_pagecontent():
|
||||
return creole.creole2html(MYCREOLE_HELP)
|
||||
|
||||
|
||||
def render_simple(text):
|
||||
return creole.creole2html(text)
|
||||
|
||||
|
||||
def render(request, text, attachment_target_path, next_anchor=''):
|
||||
def get_attachment_name(text, state):
|
||||
end_idx = text.index(']]' if state == '[' else '}}')
|
||||
try:
|
||||
split_idx = text.index('|')
|
||||
except ValueError:
|
||||
split_idx = len(text)
|
||||
return text[:min(end_idx, split_idx)]
|
||||
|
||||
# Call the additional filters before rendering
|
||||
try:
|
||||
ext_filters = settings.MYCREOLE_EXT_FILTERS
|
||||
except AttributeError:
|
||||
pass # No filters defined
|
||||
else:
|
||||
for function_string in ext_filters:
|
||||
m_name, f_name = function_string.rsplit('.', 1)
|
||||
try:
|
||||
mod = importlib.import_module(m_name)
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
func = getattr(mod, f_name)
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
text = func(text)
|
||||
|
||||
if not attachment_target_path.endswith('/'):
|
||||
attachment_target_path += '/'
|
||||
try:
|
||||
render_txt = ''
|
||||
while len(text) > 0:
|
||||
try:
|
||||
link_pos = text.index('[[attachment:')
|
||||
except ValueError:
|
||||
link_pos = len(text)
|
||||
try:
|
||||
embed_pos = text.index('{{attachment:')
|
||||
except ValueError:
|
||||
embed_pos = len(text)
|
||||
pos = min(link_pos, embed_pos)
|
||||
render_txt += text[:pos]
|
||||
text = text[pos + 13:]
|
||||
if link_pos != embed_pos:
|
||||
if link_pos < embed_pos:
|
||||
state = '['
|
||||
else:
|
||||
state = '{'
|
||||
attachment_name = get_attachment_name(text, state)
|
||||
text = text[len(attachment_name):]
|
||||
rel_path = attachment_target_path + attachment_name
|
||||
if os.path.isfile(get_full_path(rel_path)):
|
||||
render_txt += 2 * state + url_attachment(rel_path)
|
||||
else:
|
||||
render_txt += '[[%s|Upload]]' % url_upload(request, rel_path, next_anchor)
|
||||
text = text[text.index(']]' if state == '[' else '}}') + 2:]
|
||||
return creole.creole2html(render_txt)
|
||||
except:
|
||||
return creole.creole2html(text)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
def url_attachment(rel_path):
|
||||
return reverse('mycreole-attachment', kwargs={'rel_path': rel_path})
|
||||
|
||||
|
||||
def url_manage_uploads(request, rel_path):
|
||||
nxt = request.GET.get('next', request.get_full_path())
|
||||
return reverse('mycreole-manageuploads', kwargs={'rel_path': rel_path}) + '?next=%s' % nxt
|
3
admin.py
Normal file
3
admin.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
5
apps.py
Normal file
5
apps.py
Normal file
@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class MycreoleConfig(AppConfig):
|
||||
name = 'mycreole'
|
11
context.py
Normal file
11
context.py
Normal file
@ -0,0 +1,11 @@
|
||||
from users.context import menubar as user_menubar
|
||||
import themes
|
||||
|
||||
|
||||
def context_adaption(context, request, title, **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))
|
||||
for key in kwargs:
|
||||
context[key] = kwargs[key]
|
118
help.py
Normal file
118
help.py
Normal file
@ -0,0 +1,118 @@
|
||||
MYCREOLE_HELP = """\
|
||||
= Creole Markup
|
||||
|
||||
The Fields //"Description"// and //"Name"// of Tasks and Projects are interpreted as creole. \
|
||||
See http://www.wikicreole.org for more details.
|
||||
|
||||
== Text Markup
|
||||
| =Name | =Syntax | =Result |
|
||||
| Normal | {{{text}}} | text |
|
||||
| Bold | {{{**text**}}} | **text** |
|
||||
| Italics | {{{//text//}}} | //text// |
|
||||
| Underline | {{{__text__}}} | __text__ |
|
||||
| Raw Link | {{{https://python.org}}} | https://python.org |
|
||||
| Text Link | {{{[[https://python.org|Python]]}}} | [[https://python.org|Python]] |
|
||||
| Image | {{{ {{/media/theme/logo.png|logo}} }}} | {{/media/theme/logo.png|logo}} |
|
||||
| Attachment Text Link | {{{[[attachment:file.ext|Python]]}}} | |
|
||||
| Attachment Image | {{{ {{attachment:logo.png|logo}} }}} | |
|
||||
|
||||
== Paragraph Markup
|
||||
=== Bullet List
|
||||
{{{
|
||||
* Entry One
|
||||
* Entry Two
|
||||
** Subentry Two.One
|
||||
}}}
|
||||
results in:
|
||||
* Entry One
|
||||
* Entry Two
|
||||
** Subentry Two.One
|
||||
|
||||
=== Numbered List
|
||||
{{{
|
||||
# Entry One
|
||||
# Entry Two
|
||||
## Subentry Two.One
|
||||
}}}
|
||||
results in:
|
||||
# Entry One
|
||||
# Entry Two
|
||||
## Subentry Two.One
|
||||
|
||||
=== Headings
|
||||
{{{ = Large Heading }}}
|
||||
results in:
|
||||
= Large Heading
|
||||
|
||||
{{{ == Medium Heading }}}
|
||||
results in:
|
||||
== Medium Heading
|
||||
|
||||
{{{ === Small Heading }}}
|
||||
results in:
|
||||
=== Small Heading
|
||||
|
||||
=== Line Break
|
||||
{{{
|
||||
Multiple
|
||||
line text
|
||||
}}}
|
||||
results in:
|
||||
|
||||
Multiple
|
||||
line text
|
||||
|
||||
=== No Line Break
|
||||
{{{
|
||||
Single \\
|
||||
Line
|
||||
}}}
|
||||
results in:
|
||||
|
||||
Single \
|
||||
Line
|
||||
|
||||
=== Paragraph
|
||||
{{{
|
||||
Part 1
|
||||
|
||||
Part 2
|
||||
}}}
|
||||
results in:
|
||||
|
||||
Part 1
|
||||
|
||||
Part 2
|
||||
|
||||
=== Horizontal Line
|
||||
{{{
|
||||
----
|
||||
}}}
|
||||
results in:
|
||||
----
|
||||
|
||||
=== Table
|
||||
{{{
|
||||
| =Header 1 | =Header 2 | =Header 3 |
|
||||
| body row 1 | column 2 | column 3 |
|
||||
| body row 2 | - | - |
|
||||
|
||||
}}}
|
||||
results in:
|
||||
|
||||
| =Header 1 | =Header 2 | =Header 3 |
|
||||
| body row 1 | column 2 | column 3 |
|
||||
| body row 2 | - | - |
|
||||
|
||||
=== Unprocessed (raw) Text
|
||||
{{{
|
||||
{{{
|
||||
unprocessde data! <div>
|
||||
}}\0}
|
||||
}}}
|
||||
results in:
|
||||
|
||||
{{{
|
||||
unprocessde data! <div>
|
||||
}}}
|
||||
"""
|
0
migrations/__init__.py
Normal file
0
migrations/__init__.py
Normal file
3
models.py
Normal file
3
models.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
12
templates/mycreole/upload.html
Normal file
12
templates/mycreole/upload.html
Normal file
@ -0,0 +1,12 @@
|
||||
{% extends "themes/"|add:settings.page_theme|add:"/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<form class="form" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="next" value="{{ next }}">
|
||||
<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" />
|
||||
</form>
|
||||
{% endblock content %}
|
0
templatetags/__init__.py
Normal file
0
templatetags/__init__.py
Normal file
16
templatetags/mycreole.py
Normal file
16
templatetags/mycreole.py
Normal file
@ -0,0 +1,16 @@
|
||||
from django import template
|
||||
from django.utils.safestring import mark_safe
|
||||
import mycreole
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag(name='render_creole_simple')
|
||||
def render_creole_simple(text):
|
||||
return mark_safe(mycreole.render_simple(text))
|
||||
|
||||
|
||||
@register.simple_tag(name='render_creole', takes_context=True)
|
||||
def render_creole(context, text, attachment_target_path, next_anchor=''):
|
||||
request = context['request']
|
||||
return mark_safe(mycreole.render(request, text, attachment_target_path, next_anchor))
|
3
tests.py
Normal file
3
tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
9
urls.py
Normal file
9
urls.py
Normal file
@ -0,0 +1,9 @@
|
||||
from django.urls import path
|
||||
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('manageuploads/<path:rel_path>', views.mycreole_manageuploads, name='mycreole-manageuploads'),
|
||||
]
|
84
views.py
Normal file
84
views.py
Normal file
@ -0,0 +1,84 @@
|
||||
from .context import context_adaption
|
||||
from django.conf import settings
|
||||
from django.shortcuts import render, redirect, HttpResponse
|
||||
from django.http import HttpResponseNotFound, HttpResponseForbidden
|
||||
import importlib
|
||||
import mimetypes
|
||||
import logging
|
||||
import mycreole
|
||||
import os
|
||||
import themes
|
||||
from django.contrib import messages
|
||||
|
||||
logger = logging.getLogger('APP')
|
||||
|
||||
|
||||
def get_method(import_string):
|
||||
class_data = import_string.split(".")
|
||||
module_path = ".".join(class_data[:-1])
|
||||
class_str = class_data[-1]
|
||||
#
|
||||
module = importlib.import_module(module_path)
|
||||
return getattr(module, class_str)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
try:
|
||||
method_name = settings.MYCREOLE_ATTACHMENT_ACCESS[access_type]
|
||||
except (AttributeError, KeyError) as e:
|
||||
log_warning(access_type, e)
|
||||
return False
|
||||
else:
|
||||
if method_name in [True, None]:
|
||||
return True
|
||||
elif method_name is False:
|
||||
return False
|
||||
else:
|
||||
try:
|
||||
return get_method(method_name)(request, rel_path)
|
||||
except AttributeError as e:
|
||||
log_warning(access_type, e)
|
||||
return False
|
||||
|
||||
|
||||
def mycreole_attachment(request, rel_path):
|
||||
full_path = mycreole.get_full_path(rel_path)
|
||||
if access('read', request, rel_path):
|
||||
if os.path.isfile(full_path):
|
||||
mimetypes.init()
|
||||
mime_type = mimetypes.types_map.get(os.path.splitext(full_path)[1])
|
||||
data = open(full_path, 'rb').read()
|
||||
return HttpResponse(data, content_type=mime_type)
|
||||
else:
|
||||
return HttpResponseNotFound(rel_path)
|
||||
else:
|
||||
return HttpResponseForbidden(rel_path)
|
||||
|
||||
|
||||
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', '/'))
|
||||
return render(request, 'mycreole/upload.html', context=context)
|
||||
else:
|
||||
full_path = mycreole.get_full_path(rel_path)
|
||||
try:
|
||||
os.makedirs(os.path.dirname(full_path), exist_ok=True)
|
||||
except PermissionError:
|
||||
raise PermissionError("Ensure that we have access to MYCREOLE_ROOT=%s" % repr(settings.MYCREOLE_ROOT))
|
||||
else:
|
||||
with open(full_path, 'wb') as fh:
|
||||
fh.write(request.FILES['file'].read())
|
||||
return redirect(request.POST.get('next', '/'))
|
||||
else:
|
||||
messages.error(request, "Upload: Access denied!")
|
||||
return redirect(request.GET.get('next', '/'))
|
||||
|
||||
|
||||
def mycreole_manageuploads(request, rel_path):
|
||||
messages.error(request, 'Manage Uploads: Not yet implemented!')
|
||||
return redirect(request.GET.get('next', '/'))
|
Loading…
x
Reference in New Issue
Block a user