Commit 42264e9c authored by gijs's avatar gijs
Browse files

Started on pad management

parent 9069d587
......@@ -175,7 +175,7 @@ class Pad(models.Model):
return self.display_slug
def get_absolute_url(self):
return reverse('ethertoff.views.xhtml', args=[self.display_slug.replace('.md','')])
return reverse('xhtml', kwargs={'slug': self.display_slug.replace('.md','')})
@property
def padid(self):
......
......@@ -4,7 +4,7 @@
import datetime
import time
import urllib
from urlparse import urlparse
from urllib.parse import urlparse
# Framework imports
from django.shortcuts import render_to_response, get_object_or_404
......@@ -193,7 +193,7 @@ def pad(request, pk):
author.authorID,
time.mktime(expires.timetuple()).__str__()
)
except Exception, e:
except Exception as e:
response = render_to_response(
'etherpad-lite/pad.html',
{
......
......@@ -21,7 +21,7 @@ from django.template.loader import render_to_string
# Django Apps import
#from django.contrib.sites.models import Site
from django.contrib.sites.models import Site
from etherpadlite.models import Pad, PadAuthor
from ethertoff.settings import BACKUP_DIR
......@@ -99,9 +99,9 @@ short_names = {
}
HOST = None
#if Site.objects.count() > 0:
#site = Site.objects.all()[0]
#HOST = site.domain
if Site.objects.count() > 0:
site = Site.objects.all()[0]
HOST = site.domain
def query_results_to_template_articles(query_results):
"""
......@@ -115,10 +115,9 @@ def query_results_to_template_articles(query_results):
return template_articles
for s, p, o in query_results:
print(s.encode('utf-8'), p.encode('utf-8'), o.encode('utf-8'))
uri = unicode(s).strip()
key = unicode(p).strip()
value = unicode(o).strip()
uri = s.strip()
key = p.strip()
value = o.strip()
if uri != current_uri:
if article:
......@@ -172,7 +171,8 @@ def snif():
for pad in Pad.objects.all():
i += 1
txt = "checking pad %s of %s: %s" % (i, total, pad.display_slug)
print(txt.encode('utf-8'))
print(txt)
print(host + pad.get_absolute_url())
# We only want to index the articles—
# For now we can distinguish them because they have url’s
# ending in ‘.md’
......@@ -182,7 +182,7 @@ def snif():
try:
result = g.parse(host + pad.get_absolute_url())
print("succesfully parsed")
except(HTTPError, e):
except error.HTTPError as e:
if e.code == 403:
# Some of the pads will not be public yet—
# They gives a ‘403 FORBIDDEN’ response
......@@ -195,7 +195,7 @@ def snif():
d = query_results_to_template_articles(g.query(sparql_query))
with open(os.path.join(BACKUP_DIR, "index.json"), 'w') as f:
f.write(json.dumps(d, indent=2, ensure_ascii=False).encode('utf-8'))
json.dump(d, f, indent=2, ensure_ascii=False)
# with open(os.path.join(BACKUP_DIR, "index.html"), 'w') as f:
# f.write(render_to_string("home.html", {"articles" : d}).encode('utf-8'))
......
......@@ -132,9 +132,19 @@ STATIC_URL = '/static/'
# Examples: "http://example.com/media/", "http://media.example.com/"
MEDIA_URL = '/media/'
PADS_PER_PAGE = 25
PAD_FORCE_EXTENSION = True
PAD_ALLOWED_EXTENSIONS = ['.md', '.css', '.html']
PAD_DEFAULT_EXTENSION = '.md'
SITE_ID = 1
PAD_NAMESPACE_SEPARATOR = '::'
PAD_NAMESPACE_SEPARATOR_DISPLAY = ' → '
try:
LOCAL_SETTINGS
except NameError:
......
......@@ -12,6 +12,7 @@
@font-size: 17px;
@font-size-small: 12px;
@line-height: 21px;
@highlight-color: #f2f2ff;
/* BLOCKS ------------------------------------- */
* {
-webkit-box-sizing: border-box;
......@@ -514,3 +515,42 @@ div#go-up {
background-color: white;
padding: 30px;
}
.manage_list li {
border-bottom: 1px solid #c6c6fe;
padding: 0.5em 0 0.5em 0;
}
.manage_list li:hover {
background-color: @highlight-color;
}
.manage_list li .actions {
float: right;
}
.manage_list li .actions .button {
border: 1px solid;
padding: 3px 15px;
letter-spacing: 1px;
font-size: 60%;
text-transform: uppercase;
font-family: @sans;
}
.manage_list li .actions .button--delete:hover {
color: crimson;
}
.pagination {
text-align: center;
padding-top: .5em;
}
.pagination .step-links.previous {
float: left;
}
.pagination .step-links.next {
float: right;
}
{% extends "base.html" %}
{% load wikify %}
{% block content %}
<ul id="pads_list" class="manage_list">
{% for name, folder in tree.folders.items %}
<li><a href="{% url 'manage' name|addPath:folderPath %}">🗀 {{ name }}</a></li>
{% endfor %}
{% if folderPath %}
<li><a href="{% url 'pad-create' folderPath|pathString %}">+ create pad</a></li>
{% else %}
<li><a href="{% url 'pad-create' %}">+ create pad</a></li>
{% endif %}
{% for pad in tree.pads %}
<li>
<a data-uid="{{ pad.display_slug }}" href="{% if mode == 'write' %}{% url 'pad-write' slug=pad.display_slug %}{% else %}{% url 'pad-read' 'r' pad.display_slug %}{% endif %}" class="pad-link">
{{ pad.display_slug|stripPath:folderPath|dewikify }}
</a>
<section class="actions">
<a href="{% url 'pad-delete' pad.pk %}" class="button button--delete">delete</a>
</section>
</li>
{% endfor %}
</ul>
{% endblock %}
\ No newline at end of file
{% extends "base.html" %}
{% load wikify %}
{% block content %}
<ul id="pads_list" class="manage_list">
{% for pad in pads %}
<li>
<a data-uid="{{ pad.display_slug }}" href="{% if mode == 'write' %}{% url 'pad-write' slug=pad.display_slug %}{% else %}{% url 'pad-read' 'r' pad.display_slug %}{% endif %}" class="pad-link">{{ pad.display_slug|dewikify }}</a>
<section class="actions">
<a href="{% url 'pad-delete' pad.pk %}" class="button button--delete">delete</a>
</section>
</li>
{% endfor %}
</ul>
<section class="pagination">
<section class="step-links previous">
{% if pads.has_previous %}
<a href="{% url 'manage' 1 %}">&laquo; first</a>
<a href="{% url 'manage' pads.previous_page_number %}">previous</a>
{% endif %}
</section>
Page {{ pads.number }} of {{ pads.paginator.num_pages }}
<section class="step-links next">
{% if pads.has_next %}
<a href="{% url 'manage' pads.next_page_number %}">next</a>
<a href="{% url 'manage' pads.paginator.num_pages %}">last &raquo;</a>
{% endif %}
</section>
</section>
{% endblock %}
\ No newline at end of file
{% extends "base.html" %}
{% block title %}{{title}}{% endblock %}
{% block content %}
<form action="{{action}}" method="post">{% csrf_token %}
<p>{{question}}</p>
<a href="{% url 'manage' %}">cancel</a>
<input class="submit" type="submit" name="confirm" value="Delete" />
</form>
{% endblock %}
......@@ -2,6 +2,7 @@
from django import template
from django.template.defaultfilters import stringfilter
from ethertoff.settings import PAD_NAMESPACE_SEPARATOR, PAD_NAMESPACE_SEPARATOR_DISPLAY
register = template.Library()
......@@ -9,5 +10,33 @@ register = template.Library()
@stringfilter
def dewikify(name):
name = name.replace('-', ' ')
name = name.replace('::', u' → ')
name = name.replace(PAD_NAMESPACE_SEPARATOR, PAD_NAMESPACE_SEPARATOR_DISPLAY)
return name
@register.filter
def wikifyPath(value):
return value.replace('/', PAD_NAMESPACE_SEPARATOR)
@register.filter
def stripPath(value, path):
if path is not None and len(path) > 0:
from ethertoff.settings import PAD_NAMESPACE_SEPARATOR as PNS
pathstring = '{}{}'.format(PNS.join(path), PNS)
return value.replace(pathstring, '')
return value
@register.filter
def addPath(value, path):
return '{}{}'.format(pathString(path), value)
@register.filter
def pathString(path):
if path is not None and len(path) > 0:
return '{}/'.format('/'.join(path))
return ''
def ensureTrailingSlash(path):
if path[-1] != '/':
return '{}/'.format(path)
return path
\ No newline at end of file
from django.contrib.auth import views as auth_views
# from etherpadlite.views import padDelete
from django.urls import path, re_path
from . import views
#from django.conf.urls import *
......@@ -30,6 +31,9 @@ urlpatterns = [
path('', views.home, name='home'),
path('admin/', admin.site.urls),
path('all/', views.all, name='all'), # TemplateView.as_view(template_name = 'all.html')
#re_path(r'manage/(?P<page>[\d]+)?/?$', views.manage, name='manage'),
path('manage/', views.manage, name='manage'),
path('manage/<path:path>', views.manage, name='manage'),
path('publish/', views.publish, name='publish'),
path('css-screen/', views.css, name='css-screen'),
path('css-print/', views.cssprint, name='css-print'),
......@@ -42,6 +46,8 @@ urlpatterns = [
{'template_name': 'logout.html'}, name='logout'),
path('accounts/password_change', auth_views.PasswordChangeView.as_view(), name="password_change"),
path('create/', views.padCreate, name='pad-create'),
path('create/<path:prefix>', views.padCreate, name='pad-create'),
re_path('^delete/(?P<pk>\d+)/$', views.padDelete, name='pad-delete'),
re_path(r'(?P<mode>[r|s|p])/(?P<slug>[^/]+)$', views.pad_read, name='pad-read'),
#re_path(r'r/(?P<slug>[^/]+)$', views.pad, name='pad-read'),
#re_path(r's/(?P<slug>[^/]+)$', views.pad, name='pad-slide'),
......
......@@ -29,6 +29,7 @@ from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import login_required
from django.utils.translation import ugettext_lazy as _
from django.db import IntegrityError
from django.core.paginator import Paginator
# Django Apps import
......@@ -38,6 +39,7 @@ from etherpadlite import config
from django.contrib.sites.shortcuts import get_current_site
from ethertoff.management.commands.index import snif
from ethertoff.templatetags.wikify import wikifyPath, ensureTrailingSlash
# By default, the homepage is the pad called ‘start’ (props to DokuWiki!)
try:
......@@ -49,6 +51,8 @@ try:
except ImportError:
BACKUP_DIR = None
from ethertoff.settings import PAD_FORCE_EXTENSION, PAD_ALLOWED_EXTENSIONS, PAD_DEFAULT_EXTENSION, PADS_PER_PAGE, PAD_NAMESPACE_SEPARATOR
"""
Set up an HTMLParser for the sole purpose of unescaping
Etherpad’s HTML entities.
......@@ -58,36 +62,54 @@ cf http://fredericiana.com/2010/10/08/decoding-html-entities-to-text-in-python/
h = HTMLParser()
unescape = h.unescape
allowed_extensions = ['.md', '.html', '.css']
default_extension = '.md'
"""
Create a regex for our include template tag
"""
include_regex = re.compile("{%\s?include\s?\"([\w._-]+)\"\s?%}")
def savePad(pad, slug, n=0):
if n < 25:
try:
if n > 0:
base, ext = os.path.splitext(slug)
pad.display_slug = '{base}-{n}{ext}'.format(base=base, ext=ext, n=n)
pad.name=slugify(pad.display_slug)[:42]
pad.save()
except IntegrityError:
savePad(pad, slug, n+1)
return pad
return False
def makeLeaf ():
return { 'folders': {}, 'pads': [] }
def insertAt (path=[], tree=[], pad=''):
if len(path) > 1:
key = path.pop(0)
if not key in tree['folders']:
tree['folders'][key] = makeLeaf()
tree['folders'][key] = insertAt(path, tree['folders'][key], pad)
else:
tree['pads'].append(pad)
return tree
def insertPad (pad, tree):
if PAD_NAMESPACE_SEPARATOR in pad.display_slug:
path = pad.display_slug.split(PAD_NAMESPACE_SEPARATOR)
else:
path = []
return insertAt(path, tree, pad)
# FIXME: better name
def treatPadName (name, n=0):
name, ext = os.path.splitext(name)
if n > 0:
name = '{}-{}'.format(name, n)
if PAD_FORCE_EXTENSION:
if ext not in PAD_ALLOWED_EXTENSIONS:
ext = PAD_DEFAULT_EXTENSION
name = '{}{}'.format(name, ext)
return name
def createPad (slug, server, group, n=0):
if n < 25:
try:
if n > 0:
base, ext = os.path.splitext(slug)
safe_slug = '{base}-{n}{ext}'.format(base=base, ext=ext, n=n)
else:
safe_slug = slug
safe_slug = treatPadName(slug, n)
pad = Pad(
name=slugify(safe_slug)[:42], # This is the slug internally used by etherpad
display_slug=safe_slug, # This is the slug we get to change afterwards
......@@ -104,7 +126,7 @@ def createPad (slug, server, group, n=0):
return False
@login_required(login_url='/accounts/login')
def padCreate(request):
def padCreate(request, prefix=''):
"""
Create a pad
"""
......@@ -116,19 +138,12 @@ def padCreate(request):
if request.method == 'POST': # Process the form
form = forms.PadCreate(request.POST)
if form.is_valid():
n, ext = os.path.splitext(form.cleaned_data['name'])
n = re.sub(r'\s+', '_', n)
if ext in allowed_extensions:
n = '{}{}'.format(n, ext)
else:
n = '{}{}'.format(n, default_extension)
pad = createPad(slug=n, server=group.server, group=group)
slug = re.sub(r'\s+', '_', form.cleaned_data['name'])
pad = createPad(slug=slug, server=group.server, group=group)
return HttpResponseRedirect(reverse('pad-write', args=(pad.display_slug,) ))
else: # No form to process so create a fresh one
form = forms.PadCreate({'group': group.groupID})
form = forms.PadCreate({'group': group.groupID, 'name': wikifyPath(ensureTrailingSlash(prefix))})
con = {
'form': form,
......@@ -143,6 +158,31 @@ def padCreate(request):
)
@login_required(login_url='/etherpad')
def padDelete(request, pk):
"""Delete a given pad
"""
pad = get_object_or_404(Pad, pk=pk)
# Any form submissions will send us back to the profile
if request.method == 'POST':
if 'confirm' in request.POST:
pad.delete()
return HttpResponseRedirect('/manage/')
con = {
'action': reverse('pad-delete', kwargs={'pk': pk}),
'question': _('Really delete the pad {}?'.format(str(pad))),
'title': _('Deleting {}'.format(str(pad))),
}
con.update(csrf(request))
return render(
request,
'pads/confirm.html',
con
)
@login_required(login_url='/accounts/login')
def pad(request, pk=None, slug=None): # pad_write
"""
......@@ -263,8 +303,11 @@ def pad_read(request, mode="r", slug=None):
articles = []
SITE = get_current_site(request)
href = "http://%s" % SITE.domain + request.path
# FIXME: construct url based on settings?
#href = "http://%s" % SITE.domain + request.path
href = request.path
prev = None
next = None
for i, article in enumerate(articles):
......@@ -426,10 +469,35 @@ def publish(request):
tpl_params['message'] = ""
return render(request, "publish.html", tpl_params)
@login_required(login_url='/accounts/login')
# def manage(request, page=1):
def manage(request, path=[]):
if len(path) > 0:
path = path.split('/')
pads = Pad.objects.filter(display_slug__startswith='::'.join(path) + '::')
else:
pads = Pad.objects.all()
# paginator = Paginator(pads, PADS_PER_PAGE)
tree = makeLeaf()
for pad in pads:
tree = insertPad(pad, tree)
if len(path) > 0:
for key in path:
tree = tree['folders'][key]
return render(request, "manage-tree.html", {'tree': tree, 'folderPath': path })
else:
# return render(request, "manage.html", {'pads': paginator.get_page(page)})
return render(request, "manage-tree.html", {'tree': tree, 'folderPath': path })
@login_required(login_url='/accounts/login')
def all(request):
return render(request, "all.html")
def padOrFallbackPath(request, slug, fallbackPath, mimeType):
try:
pad = Pad.objects.get(display_slug=slug)
......
......@@ -15,4 +15,5 @@ python-dateutil>=2.7.3
pytz>=2018.4
rdflib>=4.2.2
six>=1.11.0
South>=1.0.2
\ No newline at end of file
South>=1.0.2
html5lib
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment