Remove some stale lib/ stuff.
from django.core.management.color import color_style
from django.db import transaction
-from slughifi import slughifi
+from fnpdjango.utils.text.slughifi import slughifi
from catalogue.models import Chunk
from django.core.management.color import color_style
from django.db import transaction
-from slughifi import slughifi
+from fnpdjango.utils.text.slughifi import slughifi
from catalogue.models import Book
from south.v2 import DataMigration
from django.conf import settings
-from slughifi import slughifi
+from fnpdjango.utils.text.slughifi import slughifi
META_REGEX = re.compile(r'\s*<!--\s(.*?)-->', re.DOTALL | re.MULTILINE)
STAGE_TAGS_RE = re.compile(r'^#stage-finished: (.*)$', re.MULTILINE)
from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
-from slughifi import slughifi
+from fnpdjango.utils.text.slughifi import slughifi
import apiclient
from django import template
register = template.Library()
-
-@register.filter
-def build_absolute_uri(uri, request):
- return request.build_absolute_uri(uri)
-
@register.filter
def username(user):
return ("%s %s" % (user.first_name, user.last_name)).lstrip() or user.username
if request.method == "POST":
form = forms.DocumentsUploadForm(request.POST, request.FILES)
if form.is_valid():
- import slughifi
+ from fnpdjango.utils.text.slughifi import slughifi
if request.user.is_authenticated():
creator = request.user
{% extends "catalogue/base.html" %}
{% load i18n %}
{% load thumbnail %}
-{% load build_absolute_uri from common_tags %}
+{% load build_absolute_uri from fnp_common %}
{% block content %}
<h1>{% trans "Cover image" %}</h1>
+++ /dev/null
-# -*- coding: utf-8 -*-
-import re
-from types import UnicodeType
-
-from django.template.defaultfilters import slugify
-
-# default unicode character mapping ( you may not see some chars, leave as is )
-char_map = {u'À': 'A', u'Á': 'A', u'Â': 'A', u'Ã': 'A', u'Ä': 'Ae', u'Å': 'A', u'Æ': 'A', u'Ā': 'A', u'Ą': 'A', u'Ă': 'A', u'Ç': 'C', u'Ć': 'C', u'Č': 'C', u'Ĉ': 'C', u'Ċ': 'C', u'Ď': 'D', u'Đ': 'D', u'È': 'E', u'É': 'E', u'Ê': 'E', u'Ë': 'E', u'Ē': 'E', u'Ę': 'E', u'Ě': 'E', u'Ĕ': 'E', u'Ė': 'E', u'Ĝ': 'G', u'Ğ': 'G', u'Ġ': 'G', u'Ģ': 'G', u'Ĥ': 'H', u'Ħ': 'H', u'Ì': 'I', u'Í': 'I', u'Î': 'I', u'Ï': 'I', u'Ī': 'I', u'Ĩ': 'I', u'Ĭ': 'I', u'Į': 'I', u'İ': 'I', u'IJ': 'IJ', u'Ĵ': 'J', u'Ķ': 'K', u'Ľ': 'K', u'Ĺ': 'K', u'Ļ': 'K', u'Ŀ': 'K', u'Ł': 'L', u'Ñ': 'N', u'Ń': 'N', u'Ň': 'N', u'Ņ': 'N', u'Ŋ': 'N', u'Ò': 'O', u'Ó': 'O', u'Ô': 'O', u'Õ': 'O', u'Ö': 'Oe', u'Ø': 'O', u'Ō': 'O', u'Ő': 'O', u'Ŏ': 'O', u'Œ': 'OE', u'Ŕ': 'R', u'Ř': 'R', u'Ŗ': 'R', u'Ś': 'S', u'Ş': 'S', u'Ŝ': 'S', u'Ș': 'S', u'Š': 'S', u'Ť': 'T', u'Ţ': 'T', u'Ŧ': 'T', u'Ț': 'T', u'Ù': 'U', u'Ú': 'U', u'Û': 'U', u'Ü': 'Ue', u'Ū': 'U', u'Ů': 'U', u'Ű': 'U', u'Ŭ': 'U', u'Ũ': 'U', u'Ų': 'U', u'Ŵ': 'W', u'Ŷ': 'Y', u'Ÿ': 'Y', u'Ý': 'Y', u'Ź': 'Z', u'Ż': 'Z', u'Ž': 'Z', u'à': 'a', u'á': 'a', u'â': 'a', u'ã': 'a', u'ä': 'ae', u'ā': 'a', u'ą': 'a', u'ă': 'a', u'å': 'a', u'æ': 'ae', u'ç': 'c', u'ć': 'c', u'č': 'c', u'ĉ': 'c', u'ċ': 'c', u'ď': 'd', u'đ': 'd', u'è': 'e', u'é': 'e', u'ê': 'e', u'ë': 'e', u'ē': 'e', u'ę': 'e', u'ě': 'e', u'ĕ': 'e', u'ė': 'e', u'ƒ': 'f', u'ĝ': 'g', u'ğ': 'g', u'ġ': 'g', u'ģ': 'g', u'ĥ': 'h', u'ħ': 'h', u'ì': 'i', u'í': 'i', u'î': 'i', u'ï': 'i', u'ī': 'i', u'ĩ': 'i', u'ĭ': 'i', u'į': 'i', u'ı': 'i', u'ij': 'ij', u'ĵ': 'j', u'ķ': 'k', u'ĸ': 'k', u'ł': 'l', u'ľ': 'l', u'ĺ': 'l', u'ļ': 'l', u'ŀ': 'l', u'ñ': 'n', u'ń': 'n', u'ň': 'n', u'ņ': 'n', u'ʼn': 'n', u'ŋ': 'n', u'ò': 'o', u'ó': 'o', u'ô': 'o', u'õ': 'o', u'ö': 'oe', u'ø': 'o', u'ō': 'o', u'ő': 'o', u'ŏ': 'o', u'œ': 'oe', u'ŕ': 'r', u'ř': 'r', u'ŗ': 'r', u'ś': 's', u'š': 's', u'ť': 't', u'ù': 'u', u'ú': 'u', u'û': 'u', u'ü': 'ue', u'ū': 'u', u'ů': 'u', u'ű': 'u', u'ŭ': 'u', u'ũ': 'u', u'ų': 'u', u'ŵ': 'w', u'ÿ': 'y', u'ý': 'y', u'ŷ': 'y', u'ż': 'z', u'ź': 'z', u'ž': 'z', u'ß': 'ss', u'ſ': 'ss', u'Α': 'A', u'Ά': 'A', u'Ἀ': 'A', u'Ἁ': 'A', u'Ἂ': 'A', u'Ἃ': 'A', u'Ἄ': 'A', u'Ἅ': 'A', u'Ἆ': 'A', u'Ἇ': 'A', u'ᾈ': 'A', u'ᾉ': 'A', u'ᾊ': 'A', u'ᾋ': 'A', u'ᾌ': 'A', u'ᾍ': 'A', u'ᾎ': 'A', u'ᾏ': 'A', u'Ᾰ': 'A', u'Ᾱ': 'A', u'Ὰ': 'A', u'Ά': 'A', u'ᾼ': 'A', u'Β': 'B', u'Γ': 'G', u'Δ': 'D', u'Ε': 'E', u'Έ': 'E', u'Ἐ': 'E', u'Ἑ': 'E', u'Ἒ': 'E', u'Ἓ': 'E', u'Ἔ': 'E', u'Ἕ': 'E', u'Έ': 'E', u'Ὲ': 'E', u'Ζ': 'Z', u'Η': 'I', u'Ή': 'I', u'Ἠ': 'I', u'Ἡ': 'I', u'Ἢ': 'I', u'Ἣ': 'I', u'Ἤ': 'I', u'Ἥ': 'I', u'Ἦ': 'I', u'Ἧ': 'I', u'ᾘ': 'I', u'ᾙ': 'I', u'ᾚ': 'I', u'ᾛ': 'I', u'ᾜ': 'I', u'ᾝ': 'I', u'ᾞ': 'I', u'ᾟ': 'I', u'Ὴ': 'I', u'Ή': 'I', u'ῌ': 'I', u'Θ': 'TH', u'Ι': 'I', u'Ί': 'I', u'Ϊ': 'I', u'Ἰ': 'I', u'Ἱ': 'I', u'Ἲ': 'I', u'Ἳ': 'I', u'Ἴ': 'I', u'Ἵ': 'I', u'Ἶ': 'I', u'Ἷ': 'I', u'Ῐ': 'I', u'Ῑ': 'I', u'Ὶ': 'I', u'Ί': 'I', u'Κ': 'K', u'Λ': 'L', u'Μ': 'M', u'Ν': 'N', u'Ξ': 'KS', u'Ο': 'O', u'Ό': 'O', u'Ὀ': 'O', u'Ὁ': 'O', u'Ὂ': 'O', u'Ὃ': 'O', u'Ὄ': 'O', u'Ὅ': 'O', u'Ὸ': 'O', u'Ό': 'O', u'Π': 'P', u'Ρ': 'R', u'Ῥ': 'R', u'Σ': 'S', u'Τ': 'T', u'Υ': 'Y', u'Ύ': 'Y', u'Ϋ': 'Y', u'Ὑ': 'Y', u'Ὓ': 'Y', u'Ὕ': 'Y', u'Ὗ': 'Y', u'Ῠ': 'Y', u'Ῡ': 'Y', u'Ὺ': 'Y', u'Ύ': 'Y', u'Φ': 'F', u'Χ': 'X', u'Ψ': 'PS', u'Ω': 'O', u'Ώ': 'O', u'Ὠ': 'O', u'Ὡ': 'O', u'Ὢ': 'O', u'Ὣ': 'O', u'Ὤ': 'O', u'Ὥ': 'O', u'Ὦ': 'O', u'Ὧ': 'O', u'ᾨ': 'O', u'ᾩ': 'O', u'ᾪ': 'O', u'ᾫ': 'O', u'ᾬ': 'O', u'ᾭ': 'O', u'ᾮ': 'O', u'ᾯ': 'O', u'Ὼ': 'O', u'Ώ': 'O', u'ῼ': 'O', u'α': 'a', u'ά': 'a', u'ἀ': 'a', u'ἁ': 'a', u'ἂ': 'a', u'ἃ': 'a', u'ἄ': 'a', u'ἅ': 'a', u'ἆ': 'a', u'ἇ': 'a', u'ᾀ': 'a', u'ᾁ': 'a', u'ᾂ': 'a', u'ᾃ': 'a', u'ᾄ': 'a', u'ᾅ': 'a', u'ᾆ': 'a', u'ᾇ': 'a', u'ὰ': 'a', u'ά': 'a', u'ᾰ': 'a', u'ᾱ': 'a', u'ᾲ': 'a', u'ᾳ': 'a', u'ᾴ': 'a', u'ᾶ': 'a', u'ᾷ': 'a', u'β': 'b', u'γ': 'g', u'δ': 'd', u'ε': 'e', u'έ': 'e', u'ἐ': 'e', u'ἑ': 'e', u'ἒ': 'e', u'ἓ': 'e', u'ἔ': 'e', u'ἕ': 'e', u'ὲ': 'e', u'έ': 'e', u'ζ': 'z', u'η': 'i', u'ή': 'i', u'ἠ': 'i', u'ἡ': 'i', u'ἢ': 'i', u'ἣ': 'i', u'ἤ': 'i', u'ἥ': 'i', u'ἦ': 'i', u'ἧ': 'i', u'ᾐ': 'i', u'ᾑ': 'i', u'ᾒ': 'i', u'ᾓ': 'i', u'ᾔ': 'i', u'ᾕ': 'i', u'ᾖ': 'i', u'ᾗ': 'i', u'ὴ': 'i', u'ή': 'i', u'ῂ': 'i', u'ῃ': 'i', u'ῄ': 'i', u'ῆ': 'i', u'ῇ': 'i', u'θ': 'th', u'ι': 'i', u'ί': 'i', u'ϊ': 'i', u'ΐ': 'i', u'ἰ': 'i', u'ἱ': 'i', u'ἲ': 'i', u'ἳ': 'i', u'ἴ': 'i', u'ἵ': 'i', u'ἶ': 'i', u'ἷ': 'i', u'ὶ': 'i', u'ί': 'i', u'ῐ': 'i', u'ῑ': 'i', u'ῒ': 'i', u'ΐ': 'i', u'ῖ': 'i', u'ῗ': 'i', u'κ': 'k', u'λ': 'l', u'μ': 'm', u'ν': 'n', u'ξ': 'ks', u'ο': 'o', u'ό': 'o', u'ὀ': 'o', u'ὁ': 'o', u'ὂ': 'o', u'ὃ': 'o', u'ὄ': 'o', u'ὅ': 'o', u'ὸ': 'o', u'ό': 'o', u'π': 'p', u'ρ': 'r', u'ῤ': 'r', u'ῥ': 'r', u'σ': 's', u'ς': 's', u'τ': 't', u'υ': 'y', u'ύ': 'y', u'ϋ': 'y', u'ΰ': 'y', u'ὐ': 'y', u'ὑ': 'y', u'ὒ': 'y', u'ὓ': 'y', u'ὔ': 'y', u'ὕ': 'y', u'ὖ': 'y', u'ὗ': 'y', u'ὺ': 'y', u'ύ': 'y', u'ῠ': 'y', u'ῡ': 'y', u'ῢ': 'y', u'ΰ': 'y', u'ῦ': 'y', u'ῧ': 'y', u'φ': 'f', u'χ': 'x', u'ψ': 'ps', u'ω': 'o', u'ώ': 'o', u'ὠ': 'o', u'ὡ': 'o', u'ὢ': 'o', u'ὣ': 'o', u'ὤ': 'o', u'ὥ': 'o', u'ὦ': 'o', u'ὧ': 'o', u'ᾠ': 'o', u'ᾡ': 'o', u'ᾢ': 'o', u'ᾣ': 'o', u'ᾤ': 'o', u'ᾥ': 'o', u'ᾦ': 'o', u'ᾧ': 'o', u'ὼ': 'o', u'ώ': 'o', u'ῲ': 'o', u'ῳ': 'o', u'ῴ': 'o', u'ῶ': 'o', u'ῷ': 'o', u'¨': '', u'΅': '', u'᾿': '', u'῾': '', u'῍': '', u'῝': '', u'῎': '', u'῞': '', u'῏': '', u'῟': '', u'῀': '', u'῁': '', u'΄': '', u'΅': '', u'`': '', u'῭': '', u'ͺ': '', u'᾽': '', u'А': 'A', u'Б': 'B', u'В': 'V', u'Г': 'G', u'Д': 'D', u'Е': 'E', u'Ё': 'E', u'Ж': 'ZH', u'З': 'Z', u'И': 'I', u'Й': 'I', u'К': 'K', u'Л': 'L', u'М': 'M', u'Н': 'N', u'О': 'O', u'П': 'P', u'Р': 'R', u'С': 'S', u'Т': 'T', u'У': 'U', u'Ф': 'F', u'Х': 'KH', u'Ц': 'TS', u'Ч': 'CH', u'Ш': 'SH', u'Щ': 'SHCH', u'Ы': 'Y', u'Э': 'E', u'Ю': 'YU', u'Я': 'YA', u'а': 'A', u'б': 'B', u'в': 'V', u'г': 'G', u'д': 'D', u'е': 'E', u'ё': 'E', u'ж': 'ZH', u'з': 'Z', u'и': 'I', u'й': 'I', u'к': 'K', u'л': 'L', u'м': 'M', u'н': 'N', u'о': 'O', u'п': 'P', u'р': 'R', u'с': 'S', u'т': 'T', u'у': 'U', u'ф': 'F', u'х': 'KH', u'ц': 'TS', u'ч': 'CH', u'ш': 'SH', u'щ': 'SHCH', u'ы': 'Y', u'э': 'E', u'ю': 'YU', u'я': 'YA', u'Ъ': '', u'ъ': '', u'Ь': '', u'ь': '', u'ð': 'd', u'Ð': 'D', u'þ': 'th', u'Þ': 'TH',
- u'ა': 'a', u'ბ': 'b', u'გ': 'g', u'დ': 'd', u'ე': 'e', u'ვ': 'v', u'ზ': 'z', u'თ': 't', u'ი': 'i', u'კ': 'k', u'ლ': 'l', u'მ': 'm', u'ნ': 'n', u'ო': 'o', u'პ': 'p', u'ჟ': 'zh', u'რ': 'r', u'ს': 's', u'ტ': 't', u'უ': 'u', u'ფ': 'p', u'ქ': 'k', u'ღ': 'gh', u'ყ': 'q', u'შ': 'sh', u'ჩ': 'ch', u'ც': 'ts', u'ძ': 'dz', u'წ': 'ts', u'ჭ': 'ch', u'ხ': 'kh', u'ჯ': 'j', u'ჰ': 'h' }
-
-def replace_char(m):
- char = m.group()
- if char_map.has_key(char):
- return char_map[char]
- else:
- return char
-
-def slughifi(value, do_slugify=True, overwrite_char_map={}):
- """
- High Fidelity slugify - slughifi.py, v 0.1
-
- Examples :
-
- >>> text = 'C\'est déjà l\'été.'
-
- >>> slughifi(text)
- 'cest-deja-lete'
-
- >>> slughifi(text, overwrite_char_map={u'\'': '-',})
- 'c-est-deja-l-ete'
-
- >>> slughifi(text, do_slugify=False)
- "C'est deja l'ete."
-
- # Normal slugify removes accented characters
- >>> slugify(text)
- 'cest-dj-lt'
-
- """
-
- # unicodification
- if type(value) != UnicodeType:
- value = unicode(value, 'utf-8', 'ignore')
-
- # overwrite chararcter mapping
- char_map.update(overwrite_char_map)
-
- # try to replace chars
- value = re.sub('[^a-zA-Z0-9\\s\\-]{1}', replace_char, value)
-
- # apply django default slugify
- if do_slugify:
- value = slugify(value)
-
- return value.encode('ascii', 'ignore')
-
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-import os
-import tempfile
-import datetime
-import mimetypes
-import urllib
-import functools
-
-import logging
-logger = logging.getLogger('fnp.hazlenut.vstorage')
-
-# Note: we have to set these before importing Mercurial
-os.environ['HGENCODING'] = 'utf-8'
-os.environ['HGMERGE'] = "internal:merge"
-
-import mercurial.hg
-import mercurial.revlog
-import mercurial.util
-
-from vstorage.hgui import SilentUI
-
-
-def urlquote(url, safe='/'):
- """Quotes URL
-
- >>> urlquote(u'Za\u017c\xf3\u0142\u0107 g\u0119\u015bl\u0105 ja\u017a\u0144')
- 'Za%C5%BC%C3%B3%C5%82%C4%87%20g%C4%99%C5%9Bl%C4%85%20ja%C5%BA%C5%84'
- """
- return urllib.quote(url.encode('utf-8', 'ignore'), safe)
-
-
-def urlunquote(url):
- """Unqotes URL
-
- # >>> urlunquote('Za%C5%BC%C3%B3%C5%82%C4%87_g%C4%99%C5%9Bl%C4%85_ja%C5%BA%C5%84')
- # u'Za\u017c\xf3\u0142\u0107_g\u0119\u015bl\u0105 ja\u017a\u0144'
- """
- return unicode(urllib.unquote(url), 'utf-8', 'ignore')
-
-
-def find_repo_path(path):
- """Go up the directory tree looking for a Mercurial repository (a directory containing a .hg subdirectory)."""
- while not os.path.isdir(os.path.join(path, ".hg")):
- old_path, path = path, os.path.dirname(path)
- if path == old_path:
- return None
- return path
-
-
-def with_working_copy_locked(func):
- """A decorator for locking the repository when calling a method."""
-
- @functools.wraps(func)
- def wrapped(self, *args, **kwargs):
- """Wrap the original function in locks."""
- wlock = self.repo.wlock()
- try:
- return func(self, *args, **kwargs)
- finally:
- wlock.release()
- return wrapped
-
-
-def with_storage_locked(func):
- """A decorator for locking the repository when calling a method."""
-
- @functools.wraps(func)
- def wrapped(self, *args, **kwargs):
- """Wrap the original function in locks."""
- lock = self.repo.lock()
- try:
- return func(self, *args, **kwargs)
- finally:
- lock.release()
- return wrapped
-
-
-def guess_mime(file_name):
- """
- Guess file's mime type based on extension.
- Default of text/x-wiki for files without an extension.
-
- >>> guess_mime('something.txt')
- 'text/plain'
- >>> guess_mime('SomePage')
- 'text/x-wiki'
- >>> guess_mime(u'ąęśUnicodePage')
- 'text/x-wiki'
- >>> guess_mime('image.png')
- 'image/png'
- >>> guess_mime('style.css')
- 'text/css'
- >>> guess_mime('archive.tar.gz')
- 'archive/gzip'
- """
-
- mime, encoding = mimetypes.guess_type(file_name, strict=False)
- if encoding:
- mime = 'archive/%s' % encoding
- if mime is None:
- mime = 'text/x-wiki'
- return mime
-
-
-class DocumentNotFound(Exception):
- pass
-
-
-class VersionedStorage(object):
- """
- Provides means of storing text pages and keeping track of their
- change history, using Mercurial repository as the storage method.
- """
-
- def __init__(self, path, charset=None):
- """
- Takes the path to the directory where the pages are to be kept.
- If the directory doen't exist, it will be created. If it's inside
- a Mercurial repository, that repository will be used, otherwise
- a new repository will be created in it.
- """
-
- self.charset = charset or 'utf-8'
- self.path = path
- if not os.path.exists(self.path):
- os.makedirs(self.path)
- self.repo_path = find_repo_path(self.path)
-
- self.ui = SilentUI()
-
- if self.repo_path is None:
- self.repo_path = self.path
- create = True
- else:
- create = False
-
- self.repo_prefix = self.path[len(self.repo_path):].strip('/')
- self.repo = mercurial.hg.repository(self.ui, self.repo_path,
- create=create)
-
- def reopen(self):
- """Close and reopen the repo, to make sure we are up to date."""
- self.repo = mercurial.hg.repository(self.ui, self.repo_path)
-
- def _file_path(self, title, type='.xml'):
- """ Return plain version if exists in repo, add extension otherwise. """
- path = os.path.join(self.path, urlquote(title, safe=''))
- if type and self._title_to_file(title, '') not in self.repo['tip']:
- path += type
- return path
-
- def _title_to_file(self, title, type=".xml"):
- """ Return plain version if exists in repo, add extension otherwise. """
- path = os.path.join(self.repo_prefix, urlquote(title, safe=''))
- if type and path not in self.repo['tip']:
- path += type
- return path
-
- def _file_to_title(self, filename):
- assert filename.startswith(self.repo_prefix)
- name = filename[len(self.repo_prefix):].strip('/').rsplit('.', 1)[0]
- return urlunquote(name)
-
- def __contains__(self, title):
- return self._title_to_file(title) in self.repo['tip']
-
- def __iter__(self):
- return self.all_pages()
-
- def merge_changes(self, changectx, repo_file, text, user, parent):
- """Commits and merges conflicting changes in the repository."""
- tip_node = changectx.node()
- filectx = changectx[repo_file].filectx(parent)
- parent_node = filectx.changectx().node()
-
- self.repo.dirstate.setparents(parent_node)
- node = self._commit([repo_file], text, user)
-
- partial = lambda filename: repo_file == filename
-
- # If p1 is equal to p2, there is no work to do. Even the dirstate is correct.
- p1, p2 = self.repo[None].parents()[0], self.repo[tip_node]
- if p1 == p2:
- return text
-
- try:
- mercurial.merge.update(self.repo, tip_node, True, False, partial)
- msg = 'merge of edit conflict'
- except mercurial.util.Abort:
- msg = 'failed merge of edit conflict'
-
- self.repo.dirstate.setparents(tip_node, node)
- # Mercurial 1.1 and later need updating the merge state
- try:
- mercurial.merge.mergestate(self.repo).mark(repo_file, "r")
- except (AttributeError, KeyError):
- pass
- return msg
-
- @with_working_copy_locked
- @with_storage_locked
- def save_file(self, title, file_name, **kwargs):
- """Save an existing file as specified page."""
-
- author = kwargs.get('author', u'anonymous').encode('utf-8')
- comment = kwargs.get('comment', u'Empty comment.').encode('utf-8')
- parent = kwargs.get('parent', None)
-
- repo_file = self._title_to_file(title)
- file_path = self._file_path(title)
- mercurial.util.rename(file_name, file_path)
- changectx = self._changectx()
-
- try:
- filectx_tip = changectx[repo_file]
- current_page_rev = filectx_tip.filerev()
- except mercurial.revlog.LookupError:
- self.repo[None].add([repo_file])
- current_page_rev = -1
-
- if parent is not None and current_page_rev != parent:
- msg = self.merge_changes(changectx, repo_file, comment, author, parent)
- author = '<wiki>'
- comment = msg.encode('utf-8')
-
- logger.debug("Commiting %r", repo_file)
-
- self._commit([repo_file], comment, author)
-
- def save_data(self, title, data, **kwargs):
- """Save data as specified page."""
- try:
- temp_path = tempfile.mkdtemp(dir=self.path)
- file_path = os.path.join(temp_path, 'saved')
- f = open(file_path, "wb")
- f.write(data)
- f.close()
-
- return self.save_file(title=title, file_name=file_path, **kwargs)
- finally:
- try:
- os.unlink(file_path)
- except OSError:
- pass
- try:
- os.rmdir(temp_path)
- except OSError:
- pass
-
- def save_text(self, **kwargs):
- """Save text as specified page, encoded to charset."""
- text = kwargs.pop('text')
- return self.save_data(data=text.encode(self.charset), **kwargs)
-
- def _commit(self, files, comment, user):
- match = mercurial.match.exact(self.repo_path, '', list(files))
- return self.repo.commit(match=match, text=comment, user=user, force=True)
-
- @with_working_copy_locked
- @with_storage_locked
- def delete_page(self, title, author=u'', comment=u''):
- user = author.encode('utf-8') or 'anon'
- text = comment.encode('utf-8') or 'deleted'
- repo_file = self._title_to_file(title)
- file_path = self._file_path(title)
- try:
- os.unlink(file_path)
- except OSError:
- pass
- self.repo[None].remove([repo_file])
- self._commit([repo_file], text, user)
-
- def page_text(self, title, revision=None):
- """Read unicode text of a page."""
- ctx = self._find_filectx(title, revision)
-
- if ctx is None:
- raise DocumentNotFound(title)
-
- return ctx.data().decode(self.charset, 'replace'), ctx.filerev()
-
- def page_text_by_tag(self, title, tag):
- """Read unicode text of a taged page."""
- fname = self._title_to_file(title)
- tag = u"{fname}#{tag}".format(**locals()).encode('utf-8')
-
- try:
- ctx = self.repo[tag][fname]
- return ctx.data().decode(self.charset, 'replace'), ctx.filerev()
- except IndexError:
- raise DocumentNotFound(fname)
-
- @with_working_copy_locked
- def page_file_meta(self, title):
- """Get page's inode number, size and last modification time."""
- try:
- (_st_mode, st_ino, _st_dev, _st_nlink, _st_uid, _st_gid, st_size,
- _st_atime, st_mtime, _st_ctime) = os.stat(self._file_path(title))
- except OSError:
- return 0, 0, 0
- return st_ino, st_size, st_mtime
-
- @with_working_copy_locked
- def page_meta(self, title, revision=None):
- """Get page's revision, date, last editor and his edit comment."""
- fctx = self._find_filectx(title, revision)
-
- if fctx is None:
- raise DocumentNotFound(title)
-
- return {
- "revision": fctx.filerev(),
- "date": datetime.datetime.fromtimestamp(fctx.date()[0]),
- "author": fctx.user().decode("utf-8", 'replace'),
- "comment": fctx.description().decode("utf-8", 'replace'),
- }
-
- def repo_revision(self):
- return self.repo['tip'].rev()
-
- def _changectx(self):
- return self.repo['tip']
-
- def page_mime(self, title):
- """
- Guess page's mime type based on corresponding file name.
- Default ot text/x-wiki for files without an extension.
- """
- return guess_mime(self._file_path(title))
-
- def _find_filectx(self, title, rev=None):
- """
- Find the revision of the file in repo.
- Only look for files still existing in repo's tip.
- """
- tip = self._changectx()
- file = self._title_to_file(title)
- logging.info('Looking for %s', file)
- if file in tip:
- fctx = tip[file]
- else:
- file = self._title_to_file(title, type='')
- logging.info('.xml not found, trying plain')
- if file in tip:
- fctx = tip[file]
- else:
- raise DocumentNotFound(title)
-
- if rev is not None:
- fctx = fctx.filectx(rev)
- fctx.filerev()
- return fctx
-
- def page_history(self, title):
- """Iterate over the page's history."""
-
- filectx_tip = self._find_filectx(title)
-
- maxrev = filectx_tip.filerev()
- minrev = 0
- for rev in range(maxrev, minrev - 1, -1):
- filectx = filectx_tip.filectx(rev)
- date = datetime.datetime.fromtimestamp(filectx.date()[0])
- author = filectx.user().decode('utf-8', 'replace')
- comment = filectx.description().decode("utf-8", 'replace')
- tags = [t.rsplit('#', 1)[-1] for t in filectx.changectx().tags() if '#' in t]
-
- yield {
- "version": rev,
- "date": date,
- "author": author,
- "description": comment,
- "tag": tags,
- }
-
- @with_working_copy_locked
- def add_page_tag(self, title, rev, tag, user, doctag=True):
- ctitle = self._title_to_file(title)
-
- if doctag:
- tag = u"{ctitle}#{tag}".format(**locals()).encode('utf-8')
-
- message = u"Assigned tag {tag!r} to version {rev!r} of {ctitle!r}".format(**locals()).encode('utf-8')
-
- fctx = self._find_filectx(title, rev)
- self.repo.tag(
- names=tag, node=fctx.node(), local=False,
- user=user, message=message, date=None,
- )
-
- def history(self):
- """Iterate over the history of entire wiki."""
-
- changectx = self._changectx()
- maxrev = changectx.rev()
- minrev = 0
- for wiki_rev in range(maxrev, minrev - 1, -1):
- change = self.repo.changectx(wiki_rev)
- date = datetime.datetime.fromtimestamp(change.date()[0])
- author = change.user().decode('utf-8', 'replace')
- comment = change.description().decode("utf-8", 'replace')
- for repo_file in change.files():
- if repo_file.startswith(self.repo_prefix):
- title = self._file_to_title(repo_file)
- try:
- rev = change[repo_file].filerev()
- except mercurial.revlog.LookupError:
- rev = -1
- yield title, rev, date, author, comment
-
- def all_pages(self, type=''):
- tip = self.repo['tip']
- """Iterate over the titles of all pages in the wiki."""
- return [self._file_to_title(filename) for filename in tip
- if not filename.startswith('.')
- and filename.endswith(type) ]
-
- def changed_since(self, rev):
- """Return all pages that changed since specified repository revision."""
-
- try:
- last = self.repo.lookup(int(rev))
- except IndexError:
- for page in self.all_pages():
- yield page
- return
- current = self.repo.lookup('tip')
- status = self.repo.status(current, last)
- modified, added, removed, deleted, unknown, ignored, clean = status
- for filename in modified + added + removed + deleted:
- if filename.startswith(self.repo_prefix):
- yield self._file_to_title(filename)
-
- def revert(self, pageid, rev, **commit_args):
- """ Make the given version of page the current version (reverting changes). """
-
- # Find the old version
- fctx = self._find_filectx(pageid, rev)
-
- # Restore the contents
- self.save_data(pageid, fctx.data(), **commit_args)
+++ /dev/null
-"""
- Mercurial ui module replacement.
-"""
-
-import mercurial.ui
-import logging
-
-class SilentUI(mercurial.ui.ui):
-
- def __init__(self, *args, **kwargs):
- super(SilentUI, self).__init__(*args, **kwargs)
-
- # make sure this doesn't collide with anything in Mercurial
- self.__logger = logging.getLogger('mercurial')
-
- def _is_trusted(self, fd, filename):
- """ Checks if config file is trusted - on server side, this isn't very useful. """
- return True
-
- def write(self, *args):
- if self._buffers:
- self._buffers[-1].extend([str(a) for a in args])
- else:
- self.__logger.info(''.join(args))
-
- def write_err(self, *args):
- self.__logger.error(''.join(args))
-
- def flush(self):
- pass
-
- def interactive(self):
- return False
-
- def _readline(self, prompt=''):
- return u''
-
- def status(self, *msg):
- self.__logger.debug(''.join(msg))
-
- def warn(self, *msg):
- self.__logger.warn(''.join(msg))
-
- def note(self, *msg):
- self.__logger.info(''.join(msg))
-
- def debug(self, *msg):
- self.__logger.debug(''.join(msg))
-
- def edit(self, text, user):
- return text
-
- def traceback(self, exc=None):
- if exc is not None: self.__logger.exception()
-
- def progress(self, *args, **kwargs):
- pass
+++ /dev/null
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-
-import os
-import tempfile
-from nose.tools import *
-from nose.core import runmodule
-
-import vstorage
-
-def clear_directory(top):
- for root, dirs, files in os.walk(top, topdown=False):
- for name in files:
- os.remove(os.path.join(root, name))
- for name in dirs:
- os.rmdir(os.path.join(root, name))
- try:
- os.removedirs(top)
- except OSError:
- pass
-
-
-class TestVersionedStorage(object):
- def setUp(self):
- self.repo_path = tempfile.mkdtemp()
- self.repo = vstorage.VersionedStorage(self.repo_path)
-
- def tearDown(self):
- clear_directory(self.repo_path)
-
- def test_save_text(self):
- text = u"test text"
- title = u"test title"
- author = u"test author"
- comment = u"test comment"
-
- self.repo.save_text(
- title=title,
- text=text,
- author=author,
- comment=comment,
- parent=None,
- )
-
- saved_text, rev = self.repo.page_text(title)
- assert_equal(saved_text, text)
- assert_equal(rev, 0)
-
- def test_save_text_noparent(self):
- text = u"test text"
- title = u"test title"
- author = u"test author"
- comment = u"test comment"
-
- self.repo.save_text(title=title,
- text=text, author=author,
- comment=comment, parent=None)
-
-
- saved_text, rev = self.repo.page_text(title)
- assert_equal(saved_text, text)
- assert_equal(rev, 0)
-
- def test_save_merge_no_conflict(self):
- text = u"test\ntext"
- title = u"test title"
- author = u"test author"
- comment = u"test comment"
- self.repo.save_text(title=title,
- text=text, author=author,
- comment=comment, parent=None)
- self.repo.save_text(title=title,
- text=text, author=author,
- comment=comment, parent=None)
-
- saved_text, rev = self.repo.page_text(title)
- assert_equal(saved_text, text)
- assert_equal(rev, 0)
-
- def test_save_merge_line_conflict(self):
- text = u"test\ntest\n"
- text1 = u"test\ntext\n"
- text2 = u"text\ntest\n"
- title = u"test title"
- author = u"test author"
- comment = u"test comment"
-
- self.repo.save_text(title=title,
- text=text, author=author,
- comment=comment, parent=None)
-
- saved_text, rev = self.repo.page_text(title)
- assert_equal(saved_text, text)
- assert_equal(rev, 0)
-
- self.repo.save_text(title=title,
- text=text1, author=author,
- comment=comment, parent=0)
-
- saved_text, rev = self.repo.page_text(title)
- assert_equal(saved_text, text1)
- assert_equal(rev, 1)
-
- self.repo.save_text(title=title,
- text=text2, author=author,
- comment=comment, parent=0)
-
- saved_text, rev = self.repo.page_text(title)
- # Other conflict markers placement can also be correct
- assert_equal(saved_text, u'''\
-text
-test
-<<<<<<< local
-=======
-text
->>>>>>> other
-''')
-
- def test_delete(self):
- text = u"text test"
- title = u"test title"
- author = u"test author"
- comment = u"test comment"
- self.repo.save_text(title=title,
- text=text, author=author,
- comment=comment, parent=None)
-
- ok_(title in self.repo, "Document not in repository.")
-
- self.repo.delete_page(title, author, comment)
-
- ok_(title not in self.repo, "Document in repository after delete")
-
- @raises(vstorage.DocumentNotFound)
- def test_document_not_found(self):
- self.repo.page_text(u'unknown entity')
-
- def test_open_existing_repository(self):
- self.repo.save_text(title=u'Python!', text=u'ham and spam')
- current_repo_revision = self.repo.repo_revision()
- same_repo = vstorage.VersionedStorage(self.repo_path)
- assert_equal(same_repo.repo_revision(), current_repo_revision)
-
- def test_history(self):
- COMMITS = [
- {"author": "bunny", "text":"1", "comment": "Oh yeah!"},
- {"author": "frank", "text":"2", "comment": "Second is the best!"},
- {"text":"3", "comment": "Third"},
- {"author": "welma", "text":"4", "comment": "Fourth"},
- ]
-
- for commit in COMMITS:
- self.repo.save_text(title=u"Sample", **commit)
-
- for n, entry in enumerate(reversed(list(self.repo.page_history(u"Sample")))):
- assert_equal(entry["version"], n)
- assert_equal(entry["author"], COMMITS[n].get("author", "anonymous"))
- assert_equal(entry["description"], COMMITS[n]["comment"])
- assert_equal(entry["tag"], [])
-
- def test_data_revert(self):
- COMMITS = [
- {u"title": u"one", "author": "bunny", "text":"1.1", "comment": "1"},
- {u"title": u"one", "author": "frank", "text":"1.2", "comment": "2"},
- {u"title": u"two", "author": "bunny", "text":"2.1", "comment": "3"},
- {u"title": u"one", "author": "frank", "text":"1.3", "comment": "4"},
- ]
-
- for commit in COMMITS:
- self.repo.save_text(**commit)
-
- # now revert last change on one
- self.repo.revert(u"one", 0)
- assert_equal(self.repo.page_text(u"one"), (u"1.1", 3))
- assert_equal(self.repo.page_text(u"two"), (u"2.1", 0))
-
- self.repo.revert(u"one", 2)
- assert_equal(self.repo.page_text(u"one"), (u"1.3", 4))
-
-class TestVSTags(object):
-
- TITLE_1 = "Sample"
-
- COMMITS = [
- {"author": "bunny", "text":"1", "comment": "Oh yeah!"},
- {"author": "frank", "text":"2", "comment": "Second is the best!"},
- {"text":"3", "comment": "Third"},
- {"author": "welma", "text":"4", "comment": "Fourth"},
- ]
-
- def setUp(self):
- self.repo_path = tempfile.mkdtemp()
- self.repo = vstorage.VersionedStorage(self.repo_path)
-
- # generate some history
- for commit in self.COMMITS:
- self.repo.save_text(title=u"Sample", **commit)
-
- # verify
- for n, entry in enumerate(reversed(list(self.repo.page_history(self.TITLE_1)))):
- assert_equal(entry["tag"], [])
-
- def tearDown(self):
- clear_directory(self.repo_path)
-
- def test_add_tag(self):
- TAG_USER = "mike_the_tagger"
- TAG_NAME = "production"
- TAG_VERSION = 2
-
- # Add tag
- self.repo.add_page_tag(self.TITLE_1, TAG_VERSION, TAG_NAME, TAG_USER)
-
- # check history again
- history = list(self.repo.page_history(self.TITLE_1))
- for entry in reversed(history):
- if entry["version"] == TAG_VERSION:
- assert_equal(entry["tag"], [TAG_NAME])
- else:
- assert_equal(entry["tag"], [])
-
- def test_add_many_tags(self):
- TAG_USER = "mike_the_tagger"
- tags = [
- (2, "production", "mike"),
- (2, "finished", "jeremy"),
- (0, "original", "jeremy"),
- ]
-
- for rev, name, user in tags:
- self.repo.add_page_tag(self.TITLE_1, rev, name, user)
-
- # check history again
- history = list(self.repo.page_history(self.TITLE_1))
- for entry in reversed(history):
- expected = [tag[1] for tag in tags if tag[0] == entry["version"]]
- assert_equal(set(entry["tag"]), set(expected))
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-"""
- Abstraction over API for wolnelektury.pl
-"""
-import urllib2
-import functools
-import django.utils.simplejson as json
-import logging
-logger = logging.getLogger("fnp.lib.wlapi")
-
-
-class APICallException(Exception):
-
- def __init__(self, cause=None):
- super(Exception, self).__init__()
- self.cause = cause
-
- def __unicode__(self):
- return u"%s, cause: %s" % (type(self).__name__, repr(self.cause))
-
- def __str__(self):
- return self.__unicode__().encode('utf-8')
-
-
-def api_call(path, format="json"):
- def wrapper(func):
-
- @functools.wraps(func)
- def wrapped(self, *args, **kwargs):
- generator = func(self, *args, **kwargs)
-
- data = generator.next()
-
- # prepare request
- rq = urllib2.Request(self.base_url + path + ".json")
-
- # will send POST when there is data, GET otherwise
- if data is not None:
- rq.add_data(json.dumps(data))
- rq.add_header("Content-Type", "application/json")
-
- try:
- anwser = json.load(self.opener.open(rq))
- return generator.send(anwser)
- except StopIteration:
- # by default, just return the anwser as a shorthand
- return anwser
- except urllib2.HTTPError, error:
- return self._http_error(error)
- except Exception, error:
- return self._error(error)
- return wrapped
-
- return wrapper
-
-
-class WLAPI(object):
-
- def __init__(self, **config_dict):
- self.base_url = config_dict['URL']
- self.auth_realm = config_dict['AUTH_REALM']
- self.auth_user = config_dict['AUTH_USER']
-
- digest_handler = urllib2.HTTPDigestAuthHandler()
- digest_handler.add_password(
- realm=self.auth_realm, uri=self.base_url,
- user=self.auth_user, passwd=config_dict['AUTH_PASSWD'])
-
- basic_handler = urllib2.HTTPBasicAuthHandler()
- basic_handler.add_password(
- realm=self.auth_realm, uri=self.base_url,
- user=self.auth_user, passwd=config_dict['AUTH_PASSWD'])
-
- self.opener = urllib2.build_opener(digest_handler, basic_handler)
-
- def _http_error(self, error):
- message = error.read()
- logger.debug("HTTP ERROR: %s", message)
- return self._error(message)
-
- def _error(self, error):
- raise APICallException(error)
-
- @api_call("books")
- def list_books(self):
- yield
-
- @api_call("books")
- def publish_book(self, document):
- yield {"text": document.text, "compressed": False}
+++ /dev/null
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-
-from nose.tools import *
-from nose.core import runmodule
-
-import wlapi
-
-
-class FakeDocument():
-
- def __init__(self):
- self.text = "Some Text"
-
-
-class TestWLAPI(object):
-
- def setUp(self):
- self.api = wlapi.WLAPI(
- URL="http://localhost:7000/api/",
- AUTH_REALM="WL API",
- AUTH_USER="platforma",
- AUTH_PASSWD="platforma",
- )
-
- def test_basic_call(self):
- assert_equal(self.api.list_books(), [])
-
- def test_publish_book(self):
- self.api.publish_book(FakeDocument())
-
-if __name__ == '__main__':
- runmodule()
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
- 'django_cas.backends.CASBackend',
+ 'fnpdjango.auth_backends.AttrCASBackend',
)
ROOT_URLCONF = 'redakcja.urls'
'djkombu',
'fileupload',
'pipeline',
+ 'fnpdjango',
'catalogue',
'cover',
## Django
Django>=1.5,<1.6
+fnpdjango<0.2
django-pipeline>=1.2,<1.3
django_cas>=2.1,<2.2
sorl-thumbnail>=11.09,<12