-
+
FNP Redakcja
Copyright © 2010 Fundacja Nowoczesna Polska <fundacja@nowoczesnapolska.org.pl>
-
- For full list of contributors see AUTHORS file.
+
+ For full list of contributors see AUTHORS file.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
$ npm install
$ ./node_modules/.bin/mocha -u tdd $(find -name *_test.js)
-
\ No newline at end of file
+# -*- coding: utf-8 -*-
from django.db import models
from django.contrib.auth.models import User
o = cls(user=user)
o.save()
return o
-
-
+# -*- coding: utf-8 -*-
"""
This file demonstrates two different styles of tests (one doctest and one
unittest). These will both pass when you run "manage.py test".
from django.test import TestCase
+
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
>>> 1 + 1 == 2
True
"""}
-
+# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
-urlpatterns = patterns('apiclient.views',
+urlpatterns = patterns(
+ 'apiclient.views',
url(r'^oauth/$', 'oauth', name='apiclient_oauth'),
url(r'^oauth_callback/$', 'oauth_callback', name='apiclient_oauth_callback'),
)
raise Exception("Invalid response %s." % resp['status'])
request_token = dict(urlparse.parse_qsl(content))
-
+
conn = OAuthConnection.get(request.user)
# this might reset existing auth!
conn.access = False
conn.save()
url = "%s?oauth_token=%s&oauth_callback=%s" % (
- WL_AUTHORIZE_URL,
+ WL_AUTHORIZE_URL,
request_token['oauth_token'],
request.build_absolute_uri(reverse("apiclient_oauth_callback")),
)
+# -*- coding: utf-8 -*-
import os
from subprocess import call
from optparse import make_option
class Command(BaseCommand):
-
+
option_list = BaseCommand.option_list + (
- make_option('--node-bin-path',
+ make_option(
+ '--node-bin-path',
action='store',
dest='node_bin_path',
type='string',
default=None,
help='Path to node binary'),
- make_option('--npm-bin',
+ make_option(
+ '--npm-bin',
action='store',
dest='npm_bin',
type='string',
default='npm',
help='Path to npm binary'),
- make_option('--editor-npm-env',
+ make_option(
+ '--editor-npm-env',
action='store',
dest='editor_npm_env',
type='string',
default=None,
help='Destination path of npm environment, defaults to ./node_modules'),
- make_option('--editor-optimize',
+ make_option(
+ '--editor-optimize',
action='store',
dest='editor_optimize',
type='string',
assert os.path.isdir(npm_env)
os.symlink(npm_env, os.path.join(rng_base_dir, 'node_modules'))
try:
- call([options['npm_bin'], 'install'], cwd = rng_base_dir)
+ call([options['npm_bin'], 'install'], cwd=rng_base_dir)
except OSError:
raise CommandError('Something went wrong, propably npm binary not found. Tried: %s' % options['npm_bin'])
if options['node_bin_path']:
# grunt needs npm binary to be foundable in PATH
os.environ['PATH'] = '%s:%s' % (options['node_bin_path'], os.environ['PATH'])
- args = ['./node_modules/.bin/grunt', 'build', '--output-dir=%s' % build_dir]
+ args = ['./node_modules/.bin/grunt', 'build', '--output-dir=%s' % build_dir]
if options['editor_optimize']:
args.append('--optimize=%s' % options['editor_optimize'])
- call(args, cwd = rng_base_dir)
+ call(args, cwd=rng_base_dir)
- call_command('collectstatic', interactive = False, ignore_patterns = ['editor'])
+ call_command('collectstatic', interactive=False, ignore_patterns=['editor'])
- # pragma: no cover
+# pragma: no cover
+# -*- coding: utf-8 -*-
from django.contrib import admin
from catalogue import models
+
class BookAdmin(admin.ModelAdmin):
list_display = ['title', 'public', '_published', '_new_publishable', 'project']
list_filter = ['public', '_published', '_new_publishable', 'project']
TRIM_BEGIN = " TRIM_BEGIN "
TRIM_END = " TRIM_END "
-MASTERS = ['powiesc',
- 'opowiadanie',
- 'liryka_l',
- 'liryka_lp',
- 'dramat_wierszowany_l',
- 'dramat_wierszowany_lp',
- 'dramat_wspolczesny',
- ]
+MASTERS = [
+ 'powiesc',
+ 'opowiadanie',
+ 'liryka_l',
+ 'liryka_lp',
+ 'dramat_wierszowany_l',
+ 'dramat_wierszowany_lp',
+ 'dramat_wspolczesny',
+]
self.publishable = publishable
def by_slug(self, slug):
- return IOFile.from_string(Book.objects.get(dc_slug=slug
- ).materialize(publishable=self.publishable
- ).encode('utf-8'))
+ return IOFile.from_string(
+ Book.objects.get(dc_slug=slug).materialize(publishable=self.publishable).encode('utf-8'))
def serve_file(file_path, name, mime_type):
from django.shortcuts import get_object_or_404
from catalogue.models import Book, Chunk
+
class PublishTrackFeed(Feed):
title = u"Planowane publikacje"
link = "/"
def items(self, obj):
tag, published = obj
- books = Book.objects.filter(public=True, _on_track__gte=tag.ordering
- ).order_by('-_on_track', 'title')
+ books = Book.objects.filter(public=True, _on_track__gte=tag.ordering).order_by('-_on_track', 'title')
if published is not None:
books = books.filter(_published=published)
return books
from catalogue.constants import MASTERS
from catalogue.models import Book, Chunk, Template
+
class DocumentCreateForm(forms.ModelForm):
"""
Form used for creating new documents.
def __init__(self, *args, **kwargs):
super(DocumentCreateForm, self).__init__(*args, **kwargs)
- self.fields['slug'].widget.attrs={'class': 'autoslug'}
- self.fields['title'].widget.attrs={'class': 'autoslug-source'}
+ self.fields['slug'].widget.attrs = {'class': 'autoslug'}
+ self.fields['title'].widget.attrs = {'class': 'autoslug-source'}
self.fields['template'].queryset = Template.objects.filter(is_main=True)
def clean(self):
Form used for uploading new documents.
"""
file = forms.FileField(required=True, label=_('ZIP file'))
- dirs = forms.BooleanField(label=_('Directories are documents in chunks'),
- widget = forms.CheckboxInput(attrs={'disabled':'disabled'}))
+ dirs = forms.BooleanField(
+ label=_('Directories are documents in chunks'),
+ widget=forms.CheckboxInput(attrs={'disabled': 'disabled'}))
def clean(self):
- file = self.cleaned_data['file']
+ zip_file = self.cleaned_data['zip_file']
import zipfile
try:
- z = self.cleaned_data['zip'] = zipfile.ZipFile(file)
+ z = self.cleaned_data['zip'] = zipfile.ZipFile(zip_file)
except zipfile.BadZipfile:
raise forms.ValidationError("Should be a ZIP file.")
if z.testzip():
"""
Form used for editing a chunk.
"""
- user = forms.ModelChoiceField(queryset=
- User.objects.annotate(count=Count('chunk')).
- order_by('last_name', 'first_name'), required=False,
- label=_('Assigned to'))
+ user = forms.ModelChoiceField(
+ queryset=User.objects.annotate(count=Count('chunk')).order_by('last_name', 'first_name'),
+ required=False,
+ label=_('Assigned to'))
class Meta:
model = Chunk
def __init__(self, *args, **kwargs):
super(ChunkForm, self).__init__(*args, **kwargs)
- self.fields['gallery_start'].widget.attrs={'class': 'number-input'}
- self.fields['slug'].widget.attrs={'class': 'autoslug'}
- self.fields['title'].widget.attrs={'class': 'autoslug-source'}
+ self.fields['gallery_start'].widget.attrs = {'class': 'number-input'}
+ self.fields['slug'].widget.attrs = {'class': 'autoslug'}
+ self.fields['title'].widget.attrs = {'class': 'autoslug-source'}
def clean_slug(self):
slug = self.cleaned_data['slug']
Form for appending a book to another book.
It means moving all chunks from book A to book B and deleting A.
"""
- append_to = forms.ModelChoiceField(queryset=Book.objects.all(),
- label=_("Append to"))
+ append_to = forms.ModelChoiceField(queryset=Book.objects.all(), label=_("Append to"))
def __init__(self, book, *args, **kwargs):
- ret = super(BookAppendForm, self).__init__(*args, **kwargs)
+ super(BookAppendForm, self).__init__(*args, **kwargs)
self.fields['append_to'].queryset = Book.objects.exclude(pk=book.pk)
- return ret
class BookForm(forms.ModelForm):
exclude = ['project']
def __init__(self, *args, **kwargs):
- ret = super(BookForm, self).__init__(*args, **kwargs)
+ super(BookForm, self).__init__(*args, **kwargs)
self.fields['slug'].widget.attrs.update({"class": "autoslug"})
self.fields['title'].widget.attrs.update({"class": "autoslug-source"})
- return ret
class ReadonlyBookForm(BookForm):
"""Form used for not editing a Book."""
def __init__(self, *args, **kwargs):
- ret = super(ReadonlyBookForm, self).__init__(*args, **kwargs)
+ super(ReadonlyBookForm, self).__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs.update({"readonly": True})
- return ret
class ChooseMasterForm(forms.Form):
In a subclass, provide an XmlUpdater class in the `updater' attribute.
"""
option_list = BaseCommand.option_list + (
- make_option('-q', '--quiet', action='store_false', dest='verbose',
+ make_option(
+ '-q', '--quiet', action='store_false', dest='verbose',
default=True, help='Less output'),
- make_option('-d', '--dry-run', action='store_true', dest='dry_run',
+ make_option(
+ '-d', '--dry-run', action='store_true', dest='dry_run',
default=False, help="Don't actually touch anything"),
- make_option('-u', '--username', dest='username', metavar='USER',
+ make_option(
+ '-u', '--username', dest='username', metavar='USER',
help='Assign commits to this user (required, preferably yourself).'),
)
args = "[slug]..."
+ updater = NotImplemented
+
def handle(self, *args, **options):
verbose = options.get('verbose')
dry_run = options.get('dry_run')
import csv
from optparse import make_option
import re
-import sys
import urllib
import urllib2
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
- make_option('-r', '--redakcja', dest='redakcja', metavar='URL',
+ make_option(
+ '-r', '--redakcja', dest='redakcja', metavar='URL',
help='Base URL of Redakcja documents',
default=REDAKCJA_URL),
- make_option('-q', '--quiet', action='store_false', dest='verbose', default=True,
+ make_option(
+ '-q', '--quiet', action='store_false', dest='verbose', default=True,
help='Less output'),
- make_option('-f', '--force', action='store_true', dest='force', default=False,
+ make_option(
+ '-f', '--force', action='store_true', dest='force', default=False,
help='Force assignment overwrite'),
)
help = 'Imports ticket assignments from Redmine.'
if ticket_done:
done_tickets += 1
-
# Print results
print
print "Results:"
print " %s (%d tickets)" % (name, unknown_users[name])
print
-
transaction.commit()
transaction.leave_transaction_management()
-
from catalogue.management.commands import XmlUpdaterCommand
+def fix_wluri(elem, change, verbose):
+ try:
+ WLURI.strict(elem.text)
+ except ValidationError:
+ correct_field = unicode(WLURI.from_slug(
+ WLURI(elem.text.strip()).slug))
+ try:
+ WLURI.strict(correct_field)
+ except ValidationError:
+ # Can't make a valid WLURI out of it, leave as is.
+ return False
+ if verbose:
+ print "Changing %s from %s to %s" % (
+ elem.tag, elem.text, correct_field
+ )
+ elem.text = correct_field
+ return True
+
+
class FixDC(XmlUpdater):
commit_desc = "auto-fixing DC"
retain_publishable = True
only_first_chunk = True
- def fix_wluri(elem, change, verbose):
- try:
- WLURI.strict(elem.text)
- except ValidationError:
- correct_field = unicode(WLURI.from_slug(
- WLURI(elem.text.strip()).slug))
- try:
- WLURI.strict(correct_field)
- except ValidationError:
- # Can't make a valid WLURI out of it, leave as is.
- return False
- if verbose:
- print "Changing %s from %s to %s" % (
- elem.tag, elem.text, correct_field
- )
- elem.text = correct_field
- return True
for field in BookInfo.FIELDS:
if field.validator == WLURI:
XmlUpdater.fixes_elements('.//' + field.uri)(fix_wluri)
+ # unused
@XmlUpdater.fixes_elements(".//" + RDFNS("Description"))
def fix_rdfabout(elem, change, verbose):
correct_about = change.tree.book.correct_about()
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
- make_option('-q', '--quiet', action='store_false', dest='verbose', default=True,
- help='Less output'),
+ make_option('-q', '--quiet', action='store_false', dest='verbose', default=True, help='Less output'),
)
help = 'Imports XML files from WL.'
previous_books = slugs.get(info.slug)
if previous_books:
if len(previous_books) > 1:
- print self.style.ERROR("There is more than one book "
- "with slug %s:"),
+ print self.style.ERROR("There is more than one book with slug %s:"),
previous_book = previous_books[0]
comm = previous_book.slug
else:
previous_book = None
comm = '*'
- print book_count, info.slug , '-->', comm
- Book.import_xml_text(xml_text, title=info.title[:255],
+ print book_count, info.slug, '-->', comm
+ Book.import_xml_text(
+ xml_text, title=info.title[:255],
slug=info.slug[:128], previous_book=previous_book,
commit_args=commit_args)
book_count += 1
book_count, )
print
-
transaction.commit()
transaction.leave_transaction_management()
-
# -*- coding: utf-8 -*-
from optparse import make_option
-import sys
-from django.contrib.auth.models import User
from django.core.management.base import BaseCommand
from django.core.management.color import color_style
from django.db import transaction
-from slughifi import slughifi
from catalogue.models import Book
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
- make_option('-s', '--slug', dest='new_slug', metavar='SLUG',
+ make_option(
+ '-s', '--slug', dest='new_slug', metavar='SLUG',
help='New slug of the merged book (defaults to common part of all slugs).'),
- make_option('-t', '--title', dest='new_title', metavar='TITLE',
+ make_option(
+ '-t', '--title', dest='new_title', metavar='TITLE',
help='New title of the merged book (defaults to common part of all titles).'),
- make_option('-q', '--quiet', action='store_false', dest='verbose', default=True,
+ make_option(
+ '-q', '--quiet', action='store_false', dest='verbose', default=True,
help='Less output'),
- make_option('-g', '--guess', action='store_true', dest='guess', default=False,
+ make_option(
+ '-g', '--guess', action='store_true', dest='guess', default=False,
help='Try to guess what merges are needed (but do not apply them).'),
- make_option('-d', '--dry-run', action='store_true', dest='dry_run', default=False,
+ make_option(
+ '-d', '--dry-run', action='store_true', dest='dry_run', default=False,
help='Dry run: do not actually change anything.'),
- make_option('-f', '--force', action='store_true', dest='force', default=False,
+ make_option(
+ '-f', '--force', action='store_true', dest='force', default=False,
help='On slug conflict, hide the original book to archive.'),
)
help = 'Merges multiple books into one.'
args = '[slug]...'
-
def print_guess(self, dry_run=True, force=False):
from collections import defaultdict
from pipes import quote
import re
-
+
def read_slug(slug):
- res = []
- res.append((re.compile(ur'__?(przedmowa)$'), -1))
- res.append((re.compile(ur'__?(cz(esc)?|ksiega|rozdzial)__?(?P<n>\d*)$'), None))
- res.append((re.compile(ur'__?(rozdzialy__?)?(?P<n>\d*)-'), None))
-
+ res = [
+ (re.compile(ur'__?(przedmowa)$'), -1),
+ (re.compile(ur'__?(cz(esc)?|ksiega|rozdzial)__?(?P<n>\d*)$'), None),
+ (re.compile(ur'__?(rozdzialy__?)?(?P<n>\d*)-'), None),
+ ]
+
for r, default in res:
m = r.search(slug)
if m:
except IndexError:
return default, slug[:start]
return None, slug
-
+
def file_to_title(fname):
""" Returns a title-like version of a filename. """
parts = (p.replace('_', ' ').title() for p in fname.split('__'))
return ' / '.join(parts)
-
+
merges = defaultdict(list)
slugs = []
for b in Book.objects.all():
n, ns = read_slug(b.slug)
if n is not None:
merges[ns].append((n, b))
-
+
conflicting_slugs = []
for slug in sorted(merges.keys()):
merge_list = sorted(merges[slug])
if len(merge_list) < 2:
continue
-
+
merge_slugs = [b.slug for i, b in merge_list]
if slug in slugs and slug not in merge_slugs:
conflicting_slugs.append(slug)
-
+
title = file_to_title(slug)
print "./manage.py merge_books %s%s--title=%s --slug=%s \\\n %s\n" % (
'--dry-run ' if dry_run else '',
quote(title), slug,
" \\\n ".join(merge_slugs)
)
-
+
if conflicting_slugs:
if force:
print self.style.NOTICE('# These books will be archived:')
for slug in conflicting_slugs:
print '#', slug
-
def handle(self, *slugs, **options):
-
self.style = color_style()
force = options.get('force')
if slugs[0] != new_slug and Book.objects.filter(slug=new_slug).exists():
self.style.ERROR('Book already exists, skipping!')
-
if dry_run and verbose:
print self.style.NOTICE('DRY RUN: nothing will be changed.')
print
chunk.slug = chunk_slugs[j]
chunk.save()
-
transaction.commit()
transaction.leave_transaction_management()
-
+# -*- coding: utf-8 -*-
from django.db import models
+
class VisibleManager(models.Manager):
def get_query_set(self):
return super(VisibleManager, self).get_query_set().exclude(_hidden=True)
from django.contrib.auth.models import User as AuthUser
+
class User(AuthUser):
class Meta:
proxy = True
return instance
def make_chunk_slug(self, proposed):
- """
+ """
Finds a chunk slug not yet used in the book.
"""
slugs = set(c.slug for c in self)
# and move the gallery starts
if gm.was_merged:
- for chunk in self[len(self) - len_other:]:
- old_start = chunk.gallery_start or 1
- chunk.gallery_start = old_start + gm.dest_size - gm.num_deleted
- chunk.save()
+ for chunk in self[len(self) - len_other:]:
+ old_start = chunk.gallery_start or 1
+ chunk.gallery_start = old_start + gm.dest_size - gm.num_deleted
+ chunk.save()
other.delete()
return changes
def materialize(self, publishable=False, changes=None):
- """
+ """
Get full text of the document compiled from chunks.
Takes the current versions of all texts
or versions most recently tagged for publishing,
@models.permalink
def get_absolute_url(self):
- return ("wiki_editor", [self.book.slug, self.slug])
+ return "wiki_editor", [self.book.slug, self.slug]
def pretty_name(self, book_length=None):
title = self.book.title
title += " (%d/%d)" % (self.number, book_length)
return title
-
# Creating and manipulation
# =========================
while not new_chunk:
new_slug = self.book.make_chunk_slug(slug)
try:
- new_chunk = self.book.chunk_set.create(number=self.number+1,
- slug=new_slug[:50], title=title[:255], **kwargs)
+ new_chunk = self.book.chunk_set.create(
+ number=self.number+1, slug=new_slug[:50], title=title[:255], **kwargs)
except IntegrityError:
pass
return new_chunk
else:
return cls.objects.get(book__slug=book_slug, slug=chunk_slug)
-
# State & cache
# =============
def refresh(self):
"""This should be done offline."""
- self.changed
- self.hidden
- self.short_html
+ self.changed()
+ self.hidden()
+ self.short_html()
if created:
instance.chunk_set.create(number=1, slug='1')
models.signals.post_save.connect(listener_create, sender=Book)
-
+# -*- coding: utf-8 -*-
from django.db import models
+# -*- coding: utf-8 -*-
from django.dispatch import Signal
post_publish = Signal()
+# -*- coding: utf-8 -*-
from celery.task import task
from django.utils import translation
finally:
translation.activate(prev_language)
+
def refresh_instance(instance):
_refresh_by_pk.delay(type(instance), instance.pk, translation.get_language())
+# -*- coding: utf-8 -*-
from __future__ import absolute_import
-from re import split
from django.db.models import Q, Count
from django import template
from django.utils.translation import ugettext_lazy as _
class ChunksList(object):
def __init__(self, chunk_qs):
- #self.chunk_qs = chunk_qs#.annotate(
- #book_length=Count('book__chunk')).select_related(
- #'book')#, 'stage__name',
- #'user')
+ # self.chunk_qs = chunk_qs#.annotate(
+ # book_length=Count('book__chunk')).select_related(
+ # 'book')#, 'stage__name',
+ # 'user')
self.chunk_qs = chunk_qs.select_related('book__hidden')
self.book_qs = chunk_qs.values('book_id')
chunks = chunks.filter(_states_dict[state])
chunks = foreign_filter(chunks, arg_or_GET('user'), 'user', User, 'username')
- chunks = foreign_filter(chunks, arg_or_GET('stage'), 'stage', Chunk.tag_model, 'slug')
+ chunks = foreign_filter(chunks, arg_or_GET('stage'), 'stage', Chunk.tag_model)
chunks = search_filter(chunks, arg_or_GET('title'), ['book__title', 'title'])
chunks = foreign_filter(chunks, arg_or_GET('project'), 'book__project', Project, 'pk')
return chunks
+# -*- coding: utf-8 -*-
from __future__ import absolute_import
from django.core.urlresolvers import reverse
@register.filter
def nice_name(user):
return user.get_full_name() or user.username
-
+# -*- coding: utf-8 -*-
from django import template
register = template.Library()
+# -*- coding: utf-8 -*-
from re import split
from django import template
class SetGetParameter(template.Node):
def __init__(self, values):
self.values = values
-
+
def render(self, context):
request = template.Variable('request').resolve(context)
params = request.GET.copy()
del(params[key])
else:
params[key] = template.Variable(value).resolve(context)
- return '?%s' % params.urlencode()
+ return '?%s' % params.urlencode()
@register.tag
+# -*- coding: utf-8 -*-
from __future__ import absolute_import
from datetime import timedelta
for item in qs:
tag = 'stage' if item.tags.count() else 'change'
chunk = item.tree
- w = WallItem(tag)
+ w = WallItem(tag)
if user and item.author != user:
w.header = _('Related edit')
else:
w.header = _('Edit')
w.title = chunk.pretty_name()
w.summary = item.description
- w.url = reverse('wiki_editor',
- args=[chunk.book.slug, chunk.slug]) + '?diff=%d' % item.revision
+ w.url = reverse('wiki_editor', args=[chunk.book.slug, chunk.slug]) + '?diff=%d' % item.revision
w.timestamp = item.created_at
w.user = item.author
w.user_name = item.author_name
next_day = day + timedelta(1)
qs = qs.filter(submit_date__gte=day, submit_date__lt=next_day)
for item in qs:
- w = WallItem('comment')
+ w = WallItem('comment')
w.header = _('Comment')
w.title = item.content_object
w.summary = item.comment
comments_wall(user, max_len),
], max_len)}
+
@register.inclusion_tag("catalogue/wall.html", takes_context=True)
def day_wall(context, day):
return {
self.assertEqual(self.book2.materialize(), 'book 2')
def test_split_book(self):
- self.book1.chunk_set.create(number=2, title='Second chunk',
- slug='book3')
+ self.book1.chunk_set.create(number=2, title='Second chunk', slug='book3')
self.book1[1].commit('I survived!')
self.assertEqual(len(self.book1), 2)
self.book1.split()
- self.assertEqual(set([b.slug for b in Book.objects.all()]),
- set(['book2', '1', 'book3']))
+ self.assertEqual(set([b.slug for b in Book.objects.all()]), {'book2', '1', 'book3'})
self.assertEqual(
Book.objects.get(slug='book3').materialize(),
'I survived!')
def setUp(self):
self.user = User.objects.create(username='tester')
self.book1 = Book.create(self.user, 'book 1', slug='book1')
- self.book1.chunk_set.create(number=2, title='Second chunk',
- slug='book 1 / 2')
- c=self.book1[1]
- c.gallery_start=3
-
+ self.book1.chunk_set.create(number=2, title='Second chunk', slug='book 1 / 2')
+ c = self.book1[1]
+ c.gallery_start = 3
+
self.scandir = join(settings.MEDIA_ROOT, settings.IMAGE_DIR)
if not exists(self.scandir):
makedirs(self.scandir)
f.close()
book.gallery = basename(d)
-
def test_both_indexed(self):
self.book2 = Book.create(self.user, 'book 2', slug='book2')
- self.book2.chunk_set.create(number=2, title='Second chunk of second book',
- slug='book 2 / 2')
+ self.book2.chunk_set.create(number=2, title='Second chunk of second book', slug='book 2 / 2')
c = self.book2[1]
c.gallery_start = 3
c.save()
-
- print "gallery starts:",self.book2[0].gallery_start, self.book2[1].gallery_start
+
+ print "gallery starts:", self.book2[0].gallery_start, self.book2[1].gallery_start
self.make_gallery(self.book1, {
- '1-0001_1l' : 'aa',
- '1-0001_2r' : 'bb',
- '1-0002_1l' : 'cc',
- '1-0002_2r' : 'dd',
- })
+ '1-0001_1l': 'aa',
+ '1-0001_2r': 'bb',
+ '1-0002_1l': 'cc',
+ '1-0002_2r': 'dd',
+ })
self.make_gallery(self.book2, {
- '1-0001_1l' : 'dd', # the same, should not be moved
- '1-0001_2r' : 'ff',
- '2-0002_1l' : 'gg',
- '2-0002_2r' : 'hh',
- })
+ '1-0001_1l': 'dd', # the same, should not be moved
+ '1-0001_2r': 'ff',
+ '2-0002_1l': 'gg',
+ '2-0002_2r': 'hh',
+ })
self.book1.append(self.book2)
'2-0001_2r',
'3-0002_1l',
'3-0002_2r',
- ])
+ ])
self.assertEqual((4, 6), (self.book1[2].gallery_start, self.book1[3].gallery_start))
-
-
+
def test_none_indexed(self):
self.book2 = Book.create(self.user, 'book 2', slug='book2')
self.make_gallery(self.book1, {
- '0001_1l' : 'aa',
- '0001_2r' : 'bb',
- '0002_1l' : 'cc',
- '0002_2r' : 'dd',
- })
+ '0001_1l': 'aa',
+ '0001_2r': 'bb',
+ '0002_1l': 'cc',
+ '0002_2r': 'dd',
+ })
self.make_gallery(self.book2, {
- '0001_1l' : 'ee',
- '0001_2r' : 'ff',
- '0002_1l' : 'gg',
- '0002_2r' : 'hh',
- })
+ '0001_1l': 'ee',
+ '0001_2r': 'ff',
+ '0002_1l': 'gg',
+ '0002_2r': 'hh',
+ })
self.book1.append(self.book2)
'1-0001_2r',
'1-0002_1l',
'1-0002_2r',
- ])
-
+ ])
- def test_none_indexed(self):
- import nose.tools
+ def test_none_indexed2(self):
self.book2 = Book.create(self.user, 'book 2', slug='book2')
self.make_gallery(self.book1, {
- '1-0001_1l' : 'aa',
- '1-0001_2r' : 'bb',
- '1002_1l' : 'cc',
- '1002_2r' : 'dd',
- })
+ '1-0001_1l': 'aa',
+ '1-0001_2r': 'bb',
+ '1002_1l': 'cc',
+ '1002_2r': 'dd',
+ })
self.make_gallery(self.book2, {
- '0001_1l' : 'ee',
- '0001_2r' : 'ff',
- '0002_1l' : 'gg',
- '0002_2r' : 'hh',
- })
+ '0001_1l': 'ee',
+ '0001_2r': 'ff',
+ '0002_1l': 'gg',
+ '0002_2r': 'hh',
+ })
self.book1.append(self.book2)
'1-0001_2r',
'1-0002_1l',
'1-0002_2r',
- ])
-
+ ])
class SimpleUpdater(XmlUpdater):
@XmlUpdater.fixes_elements('.//' + DCNS('title'))
def fix_title(element, **kwargs):
- element.text = element.text + " fixed"
+ element.text += " fixed"
return True
def setUp(self):
self.assertEqual(
Book.objects.get(slug='test-book').wldocument(
publishable=False).book_info.title,
- self.title + " fixed"
- )
+ self.title + " fixed")
from catalogue.views import GalleryView, GalleryPackageView
-urlpatterns = patterns('catalogue.views',
+urlpatterns = patterns(
+ 'catalogue.views',
url(r'^$', RedirectView.as_view(url='catalogue/')),
url(r'^catalogue/$', 'document_list', name='catalogue_document_list'),
url(r'^user/(?P<username>[^/]+)/$', 'user', name='catalogue_user'),
url(r'^users/$', 'users', name='catalogue_users'),
url(r'^activity/$', 'activity', name='catalogue_activity'),
- url(r'^activity/(?P<isodate>\d{4}-\d{2}-\d{2})/$',
+ url(r'^activity/(?P<isodate>\d{4}-\d{2}-\d{2})/$',
'activity', name='catalogue_activity'),
url(r'^upload/$',
'create_missing', name='catalogue_create_missing'),
url(r'^book/(?P<slug>[^/]+)/publish$', 'publish', name="catalogue_publish"),
- #url(r'^(?P<name>[^/]+)/publish/(?P<version>\d+)$', 'publish', name="catalogue_publish"),
+ # url(r'^(?P<name>[^/]+)/publish/(?P<version>\d+)$', 'publish', name="catalogue_publish"),
url(r'^book/(?P<slug>[^/]+)/$', 'book', name="catalogue_book"),
- url(r'^book/(?P<slug>[^/]+)/gallery/$',
- login_required()(GalleryView.as_view()),
- name="catalogue_book_gallery"),
+ url(r'^book/(?P<slug>[^/]+)/gallery/$', login_required()(GalleryView.as_view()), name="catalogue_book_gallery"),
url(r'^book/(?P<slug>[^/]+)/gallery/package$',
- permission_required('catalogue.change_book')(GalleryPackageView.as_view()),
- name="catalogue_book_gallery_package"),
+ permission_required('catalogue.change_book')(GalleryPackageView.as_view()),
+ name="catalogue_book_gallery_package"),
url(r'^book/(?P<slug>[^/]+)/xml$', 'book_xml', name="catalogue_book_xml"),
url(r'^book/(?P<slug>[^/]+)/txt$', 'book_txt', name="catalogue_book_txt"),
url(r'^book/(?P<slug>[^/]+)/html$', 'book_html', name="catalogue_book_html"),
if request.method == "POST":
form = forms.DocumentCreateForm(request.POST, request.FILES)
if form.is_valid():
-
+
if request.user.is_authenticated():
creator = request.user
else:
if request.method == 'POST':
ids = map(int, filter(lambda i: i.strip() != '', request.POST.get('ids').split(',')))
chunks = map(lambda i: Chunk.objects.get(id=i), ids)
-
+
stage = request.POST.get('stage')
if stage:
try:
stage = Chunk.tag_model.objects.get(slug=stage)
except Chunk.DoesNotExist:
stage = None
-
+
for c in chunks:
c.stage = stage
user = User.objects.get(username=username)
except User.DoesNotExist, e:
user = None
-
+
for c in chunks:
c.user = user
def _trim(text, trim_begin=True, trim_end=True):
- """
+ """
Cut off everything before RE_TRIM_BEGIN and after RE_TRIM_END, so
that eg. one big XML file can be compiled from many small XML files.
"""
def compile_text(parts):
- """
+ """
Compiles full text from an iterable of parts,
trimming where applicable.
"""
name_elem = deepcopy(element)
for tag in 'extra', 'motyw', 'pa', 'pe', 'pr', 'pt', 'uwaga':
for a in name_elem.findall('.//' + tag):
- a.text=''
+ a.text = ''
del a[:]
name = etree.tostring(name_elem, method='text', encoding='utf-8').strip()
while parent[0] is not element:
del parent[0]
element, parent = parent, parent.getparent()
- chunks[:0] = [[name,
- unicode(etree.tostring(copied, encoding='utf-8'), 'utf-8')
- ]]
+ chunks[:0] = [[name, unicode(etree.tostring(copied, encoding='utf-8'), 'utf-8')]]
parts = src.findall('.//naglowek_rozdzial')
- chunks[:0] = [[u'początek',
- unicode(etree.tostring(src, encoding='utf-8'), 'utf-8')
- ]]
+ chunks[:0] = [[u'początek', unicode(etree.tostring(src, encoding='utf-8'), 'utf-8')]]
for ch in chunks[1:]:
ch[1] = add_trim_begin(ch[1])
from django.utils.translation import ugettext_lazy as _
from cover.models import Image
+
class ImageAddForm(forms.ModelForm):
class Meta:
model = Image
"""Form used for not editing a Book."""
def __init__(self, *args, **kwargs):
- ret = super(ReadonlyImageEditForm, self).__init__(*args, **kwargs)
+ super(ReadonlyImageEditForm, self).__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs.update({"readonly": True})
- return ret
def save(self, *args, **kwargs):
- raise AssertionError, "ReadonlyImageEditForm should not be saved."
+ raise AssertionError("ReadonlyImageEditForm should not be saved.")
class FlickrForm(forms.Form):
def clean_source_url(self):
def normalize_html(html):
return re.sub('[\t\n]', '', html)
-
+
url = self.cleaned_data['source_url']
m = re.match(r'(https?://)?(www\.|secure\.)?flickr\.com/photos/(?P<author>[^/]+)/(?P<img>\d+)/?', url)
if not m:
# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
-import re
-from urlparse import urljoin
-from django.conf import settings
from django.core.files.base import ContentFile
from django.db import models
from django.db.models.signals import post_save
author = models.CharField(max_length=255, verbose_name=_('author'))
license_name = models.CharField(max_length=255, verbose_name=_('license name'))
license_url = models.URLField(max_length=255, blank=True, verbose_name=_('license URL'))
- source_url = models.URLField(verbose_name=_('source URL'), null = True)
- download_url = models.URLField(unique=True, verbose_name=_('image download URL'), null = True)
+ source_url = models.URLField(verbose_name=_('source URL'), null=True)
+ download_url = models.URLField(unique=True, verbose_name=_('image download URL'), null=True)
file = models.ImageField(upload_to='cover/image', editable=True, verbose_name=_('file'))
class Meta:
@models.permalink
def get_absolute_url(self):
- return ('cover_image', [self.id])
+ return 'cover_image', [self.id]
def get_full_url(self):
return "http://%s%s" % (Site.objects.get_current().domain, self.get_absolute_url())
if instance.pk and not instance.file:
t = URLOpener().open(instance.download_url).read()
instance.file.save("%d.jpg" % instance.pk, ContentFile(t))
-
-
\ No newline at end of file
self.assertEqual(form.cleaned_data['title'], u"Pirate Stańczyk")
self.assertEqual(form.cleaned_data['license_name'], "CC BY 2.0")
self.assertEqual(form.cleaned_data['license_url'], "http://creativecommons.org/licenses/by/2.0/deed.en")
- self.assertEqual(form.cleaned_data['download_url'], "https://farm8.staticflickr.com/7069/6941928577_415844c58e_o.jpg")
+ self.assertEqual(form.cleaned_data['download_url'],
+ "https://farm8.staticflickr.com/7069/6941928577_415844c58e_o.jpg")
from django.conf.urls import patterns, url
-urlpatterns = patterns('cover.views',
+urlpatterns = patterns(
+ 'cover.views',
url(r'^preview/$', 'preview_from_xml', name='cover_preview'),
url(r'^preview/(?P<book>[^/]+)/$', 'preview', name='cover_preview'),
- url(r'^preview/(?P<book>[^/]+)/(?P<chunk>[^/]+)/$',
- 'preview', name='cover_preview'),
- url(r'^preview/(?P<book>[^/]+)/(?P<chunk>[^/]+)/(?P<rev>\d+)/$',
- 'preview', name='cover_preview'),
+ url(r'^preview/(?P<book>[^/]+)/(?P<chunk>[^/]+)/$', 'preview', name='cover_preview'),
+ url(r'^preview/(?P<book>[^/]+)/(?P<chunk>[^/]+)/(?P<rev>\d+)/$', 'preview', name='cover_preview'),
url(r'^image/$', 'image_list', name='cover_image_list'),
url(r'^image/(?P<pk>\d+)/?$', 'image', name='cover_image'),
+# -*- coding: utf-8 -*-
from datetime import datetime
import os.path
from django.contrib.auth.models import User
from django.core.files.base import ContentFile
-from django.core.files.storage import FileSystemStorage
from django.db import models, transaction
from django.db.models.base import ModelBase
from django.utils.translation import ugettext_lazy as _
class Tag(models.Model):
"""A tag (e.g. document stage) which can be applied to a Change."""
name = models.CharField(_('name'), max_length=64)
- slug = models.SlugField(_('slug'), unique=True, max_length=64,
- null=True, blank=True)
+ slug = models.SlugField(_('slug'), unique=True, max_length=64, null=True, blank=True)
ordering = models.IntegerField(_('ordering'))
_object_cache = {}
def data_upload_to(instance, filename):
return "%d/%d" % (instance.tree.pk, instance.pk)
+
class Change(models.Model):
"""
Single document change related to previous change. The "parent"
- argument points to the version against which this change has been
+ argument points to the version against which this change has been
recorded. Initial text will have a null parent.
-
+
Data file contains a gzipped text of the document.
"""
author = models.ForeignKey(User, null=True, blank=True, verbose_name=_('author'))
- author_name = models.CharField(_('author name'), max_length=128,
- null=True, blank=True,
- help_text=_("Used if author is not set.")
- )
- author_email = models.CharField(_('author email'), max_length=128,
- null=True, blank=True,
- help_text=_("Used if author is not set.")
- )
+ author_name = models.CharField(
+ _('author name'), max_length=128,
+ null=True, blank=True,
+ help_text=_("Used if author is not set."))
+ author_email = models.CharField(
+ _('author email'), max_length=128,
+ null=True, blank=True,
+ help_text=_("Used if author is not set."))
revision = models.IntegerField(_('revision'), db_index=True)
- parent = models.ForeignKey('self',
- null=True, blank=True, default=None,
- verbose_name=_('parent'),
- related_name="children")
+ parent = models.ForeignKey(
+ 'self',
+ null=True, blank=True, default=None,
+ verbose_name=_('parent'), related_name="children")
- merge_parent = models.ForeignKey('self',
- null=True, blank=True, default=None,
- verbose_name=_('merge parent'),
- related_name="merge_children")
+ merge_parent = models.ForeignKey(
+ 'self',
+ null=True, blank=True, default=None,
+ verbose_name=_('merge parent'),
+ related_name="merge_children")
description = models.TextField(_('description'), blank=True, default='')
- created_at = models.DateTimeField(editable=False, db_index=True,
- default=datetime.now)
+ created_at = models.DateTimeField(editable=False, db_index=True, default=datetime.now)
publishable = models.BooleanField(_('publishable'), default=False)
class Meta:
if self.author:
return "%s %s <%s>" % (
self.author.first_name,
- self.author.last_name,
+ self.author.last_name,
self.author.email)
else:
return "%s <%s>" % (
self.author_email
)
-
def save(self, *args, **kwargs):
"""
take the next available revision number if none yet
f.close()
return unicode(text, 'utf-8')
- def merge_with(self, other, author=None,
- author_name=None, author_email=None,
- description=u"Automatic merge."):
+ def merge_with(self, other, author=None, author_name=None, author_email=None, description=u"Automatic merge."):
"""Performs an automatic merge after straying commits."""
assert self.tree_id == other.tree_id # same tree
if other.parent_id == self.pk:
class DocumentMeta(ModelBase):
- "Metaclass for Document models."
- def __new__(cls, name, bases, attrs):
+ """Metaclass for Document models."""
+ def __new__(mcs, name, bases, attrs):
- model = super(DocumentMeta, cls).__new__(cls, name, bases, attrs)
+ model = super(DocumentMeta, mcs).__new__(mcs, name, bases, attrs)
if not model._meta.abstract:
# create a real Tag object and `stage' fk
model.tag_model = create_tag_model(model)
- models.ForeignKey(model.tag_model, verbose_name=_('stage'),
+ models.ForeignKey(
+ model.tag_model, verbose_name=_('stage'),
null=True, blank=True).contribute_to_class(model, 'stage')
# create real Change model and `head' fk
model.change_model = create_change_model(model)
- models.ForeignKey(model.change_model,
- null=True, blank=True, default=None,
- verbose_name=_('head'),
- help_text=_("This document's current head."),
- editable=False).contribute_to_class(model, 'head')
+ models.ForeignKey(
+ model.change_model,
+ null=True, blank=True, default=None,
+ verbose_name=_('head'),
+ help_text=_("This document's current head."),
+ editable=False).contribute_to_class(model, 'head')
- models.ForeignKey(User, null=True, blank=True, editable=False,
+ models.ForeignKey(
+ User, null=True, blank=True, editable=False,
verbose_name=_('creator'), related_name="created_%s" % name.lower()
).contribute_to_class(model, 'creator')
# default repository path
REPO_PATH = os.path.join(settings.MEDIA_ROOT, 'dvcs')
- user = models.ForeignKey(User, null=True, blank=True,
+ user = models.ForeignKey(
+ User, null=True, blank=True,
verbose_name=_('user'), help_text=_('Work assignment.'))
class Meta:
change = self.change_set.get(pk=change)
return change.materialize()
- def commit(self, text, author=None, author_name=None, author_email=None,
- publishable=False, **kwargs):
+ def commit(self, text, author=None, author_name=None, author_email=None, publishable=False, **kwargs):
"""Commits a new revision.
This will automatically merge the commit into the main branch,
# set stage to next tag after the commited one
self.stage = max(tags, key=lambda t: t.ordering).get_next()
- change = self.change_set.create(author=author,
- author_name=author_name,
- author_email=author_email,
- description=kwargs.get('description', ''),
- publishable=publishable,
- parent=parent)
+ change = self.change_set.create(
+ author=author,
+ author_name=author_name,
+ author_email=author_email,
+ description=kwargs.get('description', ''),
+ publishable=publishable,
+ parent=parent)
change.tags = tags
change.data.save('', ContentFile(text.encode('utf-8')))
if self.head:
# merge new change as new head
- self.head = self.head.merge_with(change, author=author,
- author_name=author_name,
- author_email=author_email)
+ self.head = self.head.merge_with(
+ change, author=author,
+ author_name=author_name,
+ author_email=author_email)
else:
self.head = change
self.save()
+# -*- coding: utf-8 -*-
from django.dispatch import Signal
post_commit = Signal()
+# -*- coding: utf-8 -*-
from zlib import compress, decompress
-from django.core.files.base import ContentFile, File
+from django.core.files.base import ContentFile
from django.core.files.storage import FileSystemStorage
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
from nose.tools import *
from django.test import TestCase
from dvcs.models import Document
class DocumentModelTests(TestCase):
def assertTextEqual(self, given, expected):
- return self.assertEqual(given, expected,
- "Expected '''%s'''\n differs from text: '''%s'''" % (expected, given)
- )
+ return self.assertEqual(
+ given, expected,
+ "Expected '''%s'''\n differs from text: '''%s'''" % (expected, given))
def test_empty_file(self):
doc = ADocument.objects.create()
- self.assertTextEqual(doc.materialize(), u"")
+ self.assertTextEqual(doc.materialize(), "")
def test_single_commit(self):
doc = ADocument.objects.create()
- doc.commit(text=u"Ala ma kota", description="Commit #1")
- self.assertTextEqual(doc.materialize(), u"Ala ma kota")
+ doc.commit(text="Ala ma kota", description="Commit #1")
+ self.assertTextEqual(doc.materialize(), "Ala ma kota")
def test_chained_commits(self):
doc = ADocument.objects.create()
- text1 = u"""
+ text1 = """
Line #1
Line #2 is cool
"""
- text2 = u"""
+ text2 = """
Line #1
Line #2 is hot
"""
- text3 = u"""
+ text3 = """
Line #1
... is hot
Line #3 ate Line #2
def test_parallel_commit_noconflict(self):
doc = ADocument.objects.create()
- text1 = u"""
+ text1 = """
Line #1
Line #2
"""
- text2 = u"""
+ text2 = """
Line #1 is hot
Line #2
"""
- text3 = u"""
+ text3 = """
Line #1
Line #2
Line #3
"""
- text_merged = u"""
+ text_merged = """
Line #1 is hot
Line #2
Line #3
c1 = doc.commit(description="Commit #2", text=text2)
commits = doc.change_set.count()
c2 = doc.commit(description="Commit #3", text=text3, parent=base)
- self.assertEqual(doc.change_set.count(), commits + 2,
- u"Parallel commits should create an additional merge commit")
+ self.assertEqual(
+ doc.change_set.count(), commits + 2,
+ "Parallel commits should create an additional merge commit")
self.assertTextEqual(doc.materialize(), text_merged)
def test_parallel_commit_conflict(self):
doc = ADocument.objects.create()
- text1 = u"""
+ text1 = """
Line #1
Line #2
Line #3
"""
- text2 = u"""
+ text2 = """
Line #1
Line #2 is hot
Line #3
"""
- text3 = u"""
+ text3 = """
Line #1
Line #2 is cool
Line #3
"""
- text_merged = u"""
+ text_merged = """
Line #1
<<<<<<<
Line #2 is hot
c1 = doc.commit(description="Commit #2", text=text2)
commits = doc.change_set.count()
c2 = doc.commit(description="Commit #3", text=text3, parent=base)
- self.assertEqual(doc.change_set.count(), commits + 2,
- u"Parallel commits should create an additional merge commit")
+ self.assertEqual(
+ doc.change_set.count(), commits + 2,
+ "Parallel commits should create an additional merge commit")
self.assertTextEqual(doc.materialize(), text_merged)
-
def test_multiple_parallel_commits(self):
- text_a1 = u"""
+ text_a1 = """
Line #1
Line #2
Line #3
"""
- text_a2 = u"""
+ text_a2 = """
Line #1 *
Line #2
Line #3
"""
- text_b1 = u"""
+ text_b1 = """
Line #1
Line #2 **
Line #3
"""
- text_c1 = u"""
+ text_c1 = """
Line #1
Line #2
Line #3 ***
"""
- text_merged = u"""
+ text_merged = """
Line #1 *
Line #2 **
Line #3 ***
"""
-
doc = ADocument.objects.create()
c1 = doc.commit(description="Commit A1", text=text_a1)
c2 = doc.commit(description="Commit A2", text=text_a2, parent=c1)
c4 = doc.commit(description="Commit C1", text=text_c1, parent=c1)
self.assertTextEqual(doc.materialize(), text_merged)
-
def test_prepend_history(self):
doc1 = ADocument.objects.create()
doc2 = ADocument.objects.create()
with self.assertRaises(AssertionError):
doc.prepend_history(doc)
self.assertTextEqual(doc.materialize(), 'Commit 1')
-
+# -*- coding: utf-8 -*-
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _
at = escape(_('at'))
dot = escape(_('dot'))
mangled = "%s %s %s" % (name, at, (' %s ' % dot).join(domain.split('.')))
- return mark_safe("<a class='mangled' data-addr1='%(name)s' "
- "data-addr2='%(domain)s'>%(mangled)s</a>" % {
+ return mark_safe(
+ "<a class='mangled' data-addr1='%(name)s' data-addr2='%(domain)s'>%(mangled)s</a>" % {
'name': name.encode('rot13'),
'domain': domain.encode('rot13'),
'mangled': mangled,
+# -*- coding: utf-8 -*-
from django import forms
+
class UploadForm(forms.Form):
files = forms.FileField()
+# -*- coding: utf-8 -*-
from django import template
register = template.Library()
+
@register.simple_tag
def upload_js():
return """
<td class="name"><span>{%=file.name%}</span></td>
<td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
{% if (file.error) { %}
- <td class="error" colspan="2"><span class="label label-important">{%=locale.fileupload.error%}</span> {%=locale.fileupload.errors[file.error] || file.error%}</td>
+ <td class="error" colspan="2">
+ <span class="label label-important">{%=locale.fileupload.error%}</span>
+ {%=locale.fileupload.errors[file.error] || file.error%}
+ </td>
{% } else if (o.files.valid && !i) { %}
<td>
- <div class="progress progress-success progress-striped active"><div class="bar" style="width:0%;"></div></div>
+ <div class="progress progress-success progress-striped active">
+ <div class="bar" style="width:0%;"></div>
+ </div>
</td>
<td class="start">{% if (!o.options.autoUpload) { %}
<button class="btn btn-success">
<td></td>
<td class="name"><span>{%=file.name%}</span></td>
<td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
- <td class="error" colspan="2"><span class="label label-important">{%=locale.fileupload.error%}</span> {%=locale.fileupload.errors[file.error] || file.error%}</td>
+ <td class="error" colspan="2">
+ <span class="label label-important">{%=locale.fileupload.error%}</span>
+ {%=locale.fileupload.errors[file.error] || file.error%}
+ </td>
{% } else { %}
<td class="preview">{% if (file.thumbnail_url) { %}
- <a href="{%=file.url%}" title="{%=file.name%}" rel="gallery" download="{%=file.name%}"><img src="{%=file.thumbnail_url%}"></a>
+ <a href="{%=file.url%}" title="{%=file.name%}" rel="gallery" download="{%=file.name%}">
+ <img src="{%=file.thumbnail_url%}">
+ </a>
{% } %}</td>
<td class="name">
- <a href="{%=file.url%}" title="{%=file.name%}" rel="{%=file.thumbnail_url&&'gallery'%}" download="{%=file.name%}">{%=file.name%}</a>
+ <a href="{%=file.url%}" title="{%=file.name%}" rel="{%=file.thumbnail_url&&'gallery'%}"
+ download="{%=file.name%}">{%=file.name%}</a>
</td>
<td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
<td colspan="2"></td>
+# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
from fileupload.views import UploadView
-urlpatterns = patterns('',
+urlpatterns = patterns(
+ '',
url(r'^(?P<path>(?:.*/)?)$', UploadView.as_view(), name='fileupload'),
)
-
class UploadViewMixin(object):
def get_safe_path(self, filename=""):
"""Finds absolute filesystem path of the browsed dir of file.
-
+
Makes sure it's inside MEDIA_ROOT.
-
+
"""
path = os.path.abspath(os.path.join(settings.MEDIA_ROOT, self.get_directory(), filename))
# WTF how would that be possible?
for chunk in f.chunks():
destination.write(chunk)
data.append({
- 'name': f.name,
+ 'name': f.name,
'url': self.get_url(f.name),
'thumbnail_url': thumbnail(self.get_directory() + f.name),
'delete_url': "%s?file=%s" % (
- # pragma: no cover
+# pragma: no cover
+# -*- coding: utf-8 -*-
from django.contrib import admin
-from django.utils.translation import ugettext_lazy as _
from django import forms
-from django.utils import simplejson as json
+import json
from toolbar import models
from django.core.management.base import NoArgsCommand
from toolbar.models import Button, ButtonGroup
-from django.utils import simplejson as json
+import json
import re
if params[-1] == u')':
params = params[:-1]
try:
- v = son.loads(re.sub(u'([\\w-]+)\\s*:', u'"\\1": ', params).encode('utf-8'))
+ v = json.loads(re.sub(u'([\\w-]+)\\s*:', u'"\\1": ', params).encode('utf-8'))
except ValueError, e:
print "Unable to fix '%s' " % b.params
print "Try to fix this button manually and rerun the script."
- # pragma: no cover
+# pragma: no cover
+# -*- coding: utf-8 -*-
from django.contrib import admin
from wiki import models
"""
id = forms.CharField(widget=forms.HiddenInput)
- publishable = forms.BooleanField(required=False, initial=True,
- label=_('Publishable'))
+ publishable = forms.BooleanField(required=False, initial=True, label=_('Publishable'))
revision = forms.IntegerField(widget=forms.HiddenInput)
help_text=_(u"If you completed a life cycle stage, select it."),
)
- publishable = forms.BooleanField(required=False, initial=False,
+ publishable = forms.BooleanField(
+ required=False, initial=False,
label=_('Publishable'),
- help_text=_(u"Mark this revision as publishable.")
- )
+ help_text=_(u"Mark this revision as publishable."))
for_cybernauts = forms.BooleanField(
required=False, initial=False,
def __repr__(self):
return "Theme(name=%r)" % self.name
-
def filter_line(line):
- return DIFF_RE.sub(diff_replace, html_escape(line)).replace('\x01', '</span>')
+ return DIFF_RE.sub(diff_replace, html_escape(line)).replace('\x01', '</span>')
def format_changeset(a, b, change):
- return (a[0], filter_line(a[1]), b[0], filter_line(b[1]), change)
+ return a[0], filter_line(a[1]), b[0], filter_line(b[1]), change
def html_diff_table(la, lb, context=None):
+# -*- coding: utf-8 -*-
from django.conf import settings
GALLERY_URL = settings.MEDIA_URL + 'images/'
from django.conf.urls import patterns, url
-urlpatterns = patterns('wiki.views',
+urlpatterns = patterns(
+ 'wiki.views',
url(r'^edit/(?P<slug>[^/]+)/(?:(?P<chunk>[^/]+)/)?$',
'editor', name="wiki_editor"),
+# -*- coding: utf-8 -*-
from datetime import datetime
import os
import logging
import urllib
+import json
from django.conf import settings
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _
from django.views.decorators.http import require_POST, require_GET
from django.shortcuts import get_object_or_404, render
-from django.utils import simplejson
-from django.contrib.auth.decorators import login_required
from catalogue.models import Book, Chunk, Template
import nice_diff
from wiki import forms
-from wiki.helpers import (JSONResponse, JSONFormInvalid, JSONServerError,
- ajax_require_permission)
+from wiki.helpers import JSONResponse, JSONFormInvalid, ajax_require_permission
from wiki.models import Theme
#
"date": localize(change.created_at),
"publishable": _("Publishable") + "\n" if change.publishable else "",
"tag": ',\n'.join(unicode(tag) for tag in change.tags.all()),
- "published": _("Published") + ": " + \
- localize(change.publish_log.order_by('-book_record__timestamp')[0].book_record.timestamp) \
- if change.publish_log.exists() else "",
+ "published": (
+ _("Published") + ": " +
+ localize(change.publish_log.order_by('-book_record__timestamp')[0].book_record.timestamp)
+ if change.publish_log.exists() else ""),
})
return changes
else:
text = chunk.materialize()
return render(request, template_name, {
- 'serialized_document_data': simplejson.dumps({
+ 'serialized_document_data': json.dumps({
'document': text,
'document_id': chunk.id,
'title': chunk.book.title,
'stage': chunk.stage.name if chunk.stage else None,
'assignment': chunk.user.username if chunk.user else None
}),
- 'serialized_templates': simplejson.dumps([
+ 'serialized_templates': json.dumps([
{'id': t.id, 'name': t.name, 'content': t.content} for t in Template.objects.filter(is_partial=True)
]),
'forms': {
parent = None
stage = form.cleaned_data['stage_completed']
tags = [stage] if stage else []
- publishable = (form.cleaned_data['publishable'] and
- request.user.has_perm('catalogue.can_pubmark'))
+ publishable = form.cleaned_data['publishable'] and request.user.has_perm('catalogue.can_pubmark')
doc.commit(author=author,
text=text,
parent=parent,
return JSONFormInvalid(form)
else:
revision = request.GET.get("revision", None)
-
+
try:
revision = int(revision)
except (ValueError, TypeError):
docA = ""
docB = doc.at_revision(revB).materialize()
- return http.HttpResponse(nice_diff.html_diff_table(docA.splitlines(),
- docB.splitlines(), context=3))
+ return http.HttpResponse(nice_diff.html_diff_table(docA.splitlines(), docB.splitlines(), context=3))
@never_cache
+# -*- coding: utf-8 -*-
import os
from fabric.api import env, require
def run(self, *args, **kwargs):
env.project_name = 'redakcja'
env.hosts = [self.host]
- for k,v in self.env_vars.items():
+ for k, v in self.env_vars.items():
env[k] = v
require('app_path')
+# -*- coding: utf-8 -*-
from fnpdjango.deploy import DebianGunicorn
from base import Environment
env1 = Environment(
- host = '',
- user = '',
- app_path = '',
- services = [
+ host='',
+ user='',
+ app_path='',
+ services=[
DebianGunicorn('')
],
- node_bin_path = '/usr/bin',
- npm_bin = 'npm',
-)
\ No newline at end of file
+ node_bin_path='/usr/bin',
+ npm_bin='npm',
+)
-Subproject commit d0475d381f12b2c89c7c514c4f7f7d2ebc421d0a
+Subproject commit 3b0b98465bc1862306b05bb8305a1abbf40ca310
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):
else:
return char
-def slughifi(value, do_slugify=True, overwrite_char_map={}):
+
+def slughifi(value, do_slugify=True, overwrite_char_map=None):
"""
High Fidelity slugify - slughifi.py, v 0.1
Examples :
- >>> text = 'C\'est déjà l\'été.'
+ >>> text = "C'est déjà l'été."
>>> slughifi(text)
'cest-deja-lete'
- >>> slughifi(text, overwrite_char_map={u'\'': '-',})
+ >>> slughifi(text, overwrite_char_map={u"'": '-',})
'c-est-deja-l-ete'
>>> slughifi(text, do_slugify=False)
"""
+ if not overwrite_char_map:
+ overwrite_char_map = {}
+
# unicodification
if type(value) != UnicodeType:
value = unicode(value, 'utf-8', 'ignore')
char_map.update(overwrite_char_map)
# try to replace chars
- value = re.sub('[^a-zA-Z0-9\\s\\-]{1}', replace_char, value)
+ value = re.sub('[^a-zA-Z0-9\\s\\-]', replace_char, value)
# apply django default slugify
if do_slugify:
value = slugify(value)
return value.encode('ascii', 'ignore')
-
self.repo.dirstate.setparents(parent_node)
node = self._commit([repo_file], text, user)
- partial = lambda filename: repo_file == filename
+ def partial(filename):
+ return 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]
def save_data(self, title, data, **kwargs):
"""Save data as specified page."""
+ temp_path = tempfile.mkdtemp(dir=self.path)
+ file_path = os.path.join(temp_path, 'saved')
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()
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) ]
+ if not filename.startswith('.') and filename.endswith(type)]
def changed_since(self, rev):
"""Return all pages that changed since specified repository revision."""
for page in self.all_pages():
yield page
return
+ return
current = self.repo.lookup('tip')
status = self.repo.status(current, last)
modified, added, removed, deleted, unknown, ignored, clean = status
+# -*- coding: utf-8 -*-
"""
Mercurial ui module replacement.
"""
import mercurial.ui
import logging
+
class SilentUI(mercurial.ui.ui):
def __init__(self, *args, **kwargs):
return text
def traceback(self, exc=None):
- if exc is not None: self.__logger.exception()
+ if exc is not None:
+ self.__logger.exception()
def progress(self, *args, **kwargs):
pass
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:
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)
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)
+ 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)
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)
- self.repo.save_text(title=title,
- text=text1, author=author,
- comment=comment, parent=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)
+ 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
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)
ok_(title in self.repo, "Document not in repository.")
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"},
+ {"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:
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"},
+ {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.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"},
+ {"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):
assert_equal(entry["tag"], [])
def test_add_many_tags(self):
- TAG_USER = "mike_the_tagger"
tags = [
(2, "production", "mike"),
(2, "finished", "jeremy"),
"""
import urllib2
import functools
-import django.utils.simplejson as json
+import json
import logging
logger = logging.getLogger("fnp.lib.wlapi")
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
+ try:
+ 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:
import wlapi
-class FakeDocument():
+class FakeDocument:
def __init__(self):
self.text = "Some Text"
-# -*- coding: utf-8
+# -*- coding: utf-8 -*-
+
def settings(request):
from django.conf import settings
import subprocess
process = subprocess.Popen(["git", "show", "--oneline"], stdout=subprocess.PIPE)
data, _err = process.communicate()
- # get app version
+ # get app version
VERSION = data.splitlines()[0].split()[0]
else:
VERSION = ''
+# -*- coding: utf-8 -*-
from __future__ import absolute_import
from os import path
from redakcja.settings.common import *
DATABASES = {
'default': {
- 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
- 'NAME': path.join(PROJECT_ROOT, 'dev.sqlite'), # Or path to database file if using sqlite3.
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': path.join(PROJECT_ROOT, 'dev.sqlite'),
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
}
}
-try:
- LOGGING_CONFIG_FILE
-except NameError:
- LOGGING_CONFIG_FILE = os.path.join(PROJECT_ROOT, 'config',
- ('logging.cfg' if not DEBUG else 'logging.cfg.dev'))
+LOGGING_CONFIG_FILE = os.path.join(PROJECT_ROOT, 'config', ('logging.cfg' if not DEBUG else 'logging.cfg.dev'))
try:
import logging
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'pl'
-#import locale
-#locale.setlocale(locale.LC_ALL, '')
+# import locale
+# locale.setlocale(locale.LC_ALL, '')
SITE_ID = 1
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
- "redakcja.context_processors.settings", # this is instead of media
+ "redakcja.context_processors.settings", # this is instead of media
'django.core.context_processors.csrf',
"django.core.context_processors.request",
)
IMAGE_DIR = 'images/'
-
-import djcelery
-djcelery.setup_loader()
+try:
+ import djcelery
+ djcelery.setup_loader()
+except ImportError:
+ pass
BROKER_BACKEND = "djkombu.transport.DatabaseTransport"
BROKER_HOST = "localhost"
from redakcja.settings.compress import *
except ImportError:
pass
-
+# -*- coding: utf-8 -*-
+
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
-# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
+ # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
# CSS and JS files to compress
PIPELINE_CSS = {
'detail': {
- 'source_filenames': (
+ 'source_filenames': (
'css/master.css',
'css/toolbar.css',
'css/gallery.css',
),
'output_filename': 'compressed/catalogue_styles.css',
},
- 'book': {
+ 'book': {
'source_filenames': (
'css/book.css',
),
),
'output_filename': 'compressed/catalogue_scripts.js',
},
- 'book': {
+ 'book': {
'source_filenames': (
'js/book_text/jquery.eventdelegation.js',
'js/book_text/jquery.scrollto.js',
+# -*- coding: utf-8 -*-
from redakcja.settings.test import *
NOSE_ARGS = ()
+# -*- coding: utf-8 -*-
#
# Nose tests
#
DATABASES = {
'default': {
- 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
- 'NAME': '', # Or path to database file if using sqlite3.
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': '',
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
admin.autodiscover()
-urlpatterns = patterns('',
+urlpatterns = patterns(
+ '',
# Auth
url(r'^accounts/login/$', 'django_cas.views.login', name='login'),
url(r'^accounts/logout/$', 'django_cas.views.logout', name='logout'),
(r'^comments/', include('django.contrib.comments.urls')),
- url(r'^$', RedirectView.as_view(url= '/documents/')),
+ url(r'^$', RedirectView.as_view(url='/documents/')),
url(r'^documents/', include('catalogue.urls')),
url(r'^apiclient/', include('apiclient.urls')),
url(r'^editor/', include('wiki.urls')),
url(r'^cover/', include('cover.urls')),
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', dict(packages=['wiki'])),
-
)
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
if getattr(settings, 'SERVE_FILES_WITH_DEBUG_FALSE', False):
- urlpatterns += patterns('',
- (r'^%s(?P<path>.*)$' % settings.STATIC_URL[1:], 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}),
- (r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:], 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
-)
+ urlpatterns += patterns(
+ '',
+ (
+ r'^%s(?P<path>.*)$' % settings.STATIC_URL[1:],
+ 'django.views.static.serve',
+ {'document_root': settings.STATIC_ROOT}
+ ),
+ (
+ r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:],
+ 'django.views.static.serve',
+ {'document_root': settings.MEDIA_ROOT}
+ ),
+ )
+# -*- coding: utf-8 -*-
import os
-import os.path
import sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
httplib2 # oauth2 dependency
texml
-## Book conversion library
-# git+git://github.com/fnp/librarian.git@master#egg=librarian
-
## Django
Django>=1.5,<1.6
django-pipeline>=1.2,<1.3
print "This is a dry run, to really change dates, run with --seriously"
for b in Book.objects.all():
fix(b, me, dry_run)
-
-
-
+# -*- coding: utf-8 -*-\r
import os\r
from django.conf import settings\r
\r
if not os.path.exists(settings.STATIC_ROOT_SYMLINK):\r
- os.symlink(settings.STATIC_ROOT, settings.STATIC_ROOT_SYMLINK)
\ No newline at end of file
+ os.symlink(settings.STATIC_ROOT, settings.STATIC_ROOT_SYMLINK)\r
+# -*- coding: utf-8 -*-\r
import os\r
import inspect\r
-from urlparse import urlparse\r
\r
from django.test import LiveServerTestCase\r
from django.test.client import Client\r
from django.conf import settings\r
-from django.contrib.auth.models import User, Permission\r
+from django.contrib.auth.models import User\r
from django.utils.translation import ugettext as _\r
\r
-from selenium import webdriver, selenium\r
-from selenium.webdriver.support.wait import WebDriverWait\r
+from selenium import webdriver\r
\r
\r
class SeleniumTestCase(LiveServerTestCase):\r
LiveServerTestCase.setUpClass()\r
cls.browser = getattr(webdriver, os.environ.get('TEST_BROWSER', 'Firefox'))()\r
cls.browser.implicitly_wait(5)\r
- \r
+\r
@classmethod\r
def tearDownClass(cls):\r
LiveServerTestCase.tearDownClass()\r
cls.browser.quit()\r
- \r
+\r
def setUp(self):\r
self.browser.delete_all_cookies()\r
- \r
- def create_user(self, username = 'testuser', passwd = 'passwd', do_login = False):\r
+\r
+ def create_user(self, username='testuser', passwd='passwd', do_login=False):\r
user = User.objects.create_user(username, '', passwd)\r
user._plain_passwd = passwd\r
if do_login:\r
self.login_user(user)\r
return user\r
- \r
+\r
def create_super_user(self, *args, **kwargs):\r
user = self.create_user(*args, **kwargs)\r
user.is_superuser = True\r
user.save()\r
return user\r
- \r
+\r
def login_user(self, user):\r
client = Client()\r
- client.login(username = user.username, password = user._plain_passwd)\r
+ client.login(username=user.username, password=user._plain_passwd)\r
\r
if not self.browser.current_url.startswith(self.live_server_url):\r
self.browser.get(self.live_server_url+'/not_existing_url')\r
- \r
- self.browser.find_element_by_tag_name('body') # Make sure the page is actually loaded before setting the cookie\r
+\r
+ self.browser.find_element_by_tag_name('body') # Make sure the page is actually loaded before setting the cookie\r
self.browser.delete_cookie(settings.SESSION_COOKIE_NAME)\r
- self.browser.add_cookie(dict(name = settings.SESSION_COOKIE_NAME, \r
- value = client.cookies[settings.SESSION_COOKIE_NAME].value,\r
- path = '/')\r
- )\r
- \r
+ self.browser.add_cookie(dict(name=settings.SESSION_COOKIE_NAME,\r
+ value=client.cookies[settings.SESSION_COOKIE_NAME].value,\r
+ path='/'))\r
+\r
def get_main_page(self):\r
self.browser.get(self.live_server_url)\r
self.browser.find_element_by_tag_name('body')\r
return MainPage(self.browser)\r
\r
- \r
+\r
class Page(object):\r
def __init__(self, browser):\r
self.browser = browser\r
- \r
- \r
+\r
+\r
class MainPage(Page):\r
\r
def __init__(self, browser):\r
Page.__init__(self, browser)\r
self.tab = None\r
- \r
+\r
@property\r
def element(self):\r
return self.browser.find_element_by_tag_name('body')\r
- \r
+\r
def select_tab(self, tab_title):\r
for a in self.element.find_element_by_id('tabs-nav-left').find_elements_by_tag_name('a'):\r
if a.text == tab_title:\r
a.click()\r
self.tab = find_tab_class(tab_title)(self.browser)\r
return\r
- raise Exception, 'Tab not found'\r
- \r
- \r
-def find_tab_class(tab_title): \r
+ raise Exception('Tab not found')\r
+\r
+\r
+def find_tab_class(tab_title):\r
for obj in globals().values():\r
if inspect.isclass(obj) and issubclass(obj, MainPageTabBase) and getattr(obj, 'tab_title', None) == tab_title:\r
return obj\r
raise NotImplementedError\r
- \r
+\r
\r
class MainPageTabBase(Page):\r
def __init__(self, browser):\r
Page.__init__(self, browser)\r
- \r
+\r
@property\r
def element(self):\r
return self.browser.find_element_by_id('content')\r
- \r
+\r
\r
class AddBookPage(MainPageTabBase):\r
tab_title = _('Add')\r
- \r
+\r
def put_title(self, title):\r
self.element.find_element_by_id('id_title').send_keys(title)\r
- \r
+\r
def put_text(self, text):\r
self.element.find_element_by_id('id_text').send_keys(text)\r
- \r
+\r
def submit(self):\r
self.browser.find_element_by_css_selector('table.editable button').click()\r
return self.browser\r
- \r
- \r
+\r
+\r
class BooksListPage(MainPageTabBase):\r
tab_title = _('All')\r
- \r
+\r
@property\r
def visible_books_count(self):\r
return len(self.element.find_element_by_id('file-list').find_elements_by_tag_name('tr')) - 2\r
- \r
-
\ No newline at end of file
-from tests.integration.base import SeleniumTestCase, MainPage, _\r
+# -*- coding: utf-8 -*-\r
+from tests.integration.base import SeleniumTestCase, _\r
+\r
\r
class SmokeTest(SeleniumTestCase):\r
\r
def test_add_book(self):\r
- user = self.create_super_user(do_login = True)\r
- \r
+ user = self.create_super_user(do_login=True)\r
+\r
page = self.get_main_page()\r
page.select_tab(_('All'))\r
assert page.tab.visible_books_count == 0\r
- \r
+\r
page.select_tab(_('Add'))\r
page.tab.put_title('Test title')\r
page.tab.put_text('Test text')\r
page.tab.submit()\r
page.select_tab(_('All'))\r
assert page.tab.visible_books_count == 1\r
-
\ No newline at end of file