+# -*- coding: utf-8 -*-
+import json
import urllib
-from django.utils import simplejson
import oauth2
from apiclient.models import OAuthConnection
from apiclient.settings import WL_CONSUMER_KEY, WL_CONSUMER_SECRET, WL_API_URL
+from django.conf import settings
if WL_CONSUMER_KEY and WL_CONSUMER_SECRET:
token = oauth2.Token(conn.token, conn.token_secret)
client = oauth2.Client(wl_consumer, token)
if data is not None:
- data = simplejson.dumps(data)
+ data = json.dumps(data)
data = urllib.urlencode({"data": data})
resp, content = client.request(
"%s%s" % (WL_API_URL, path),
method="POST",
body=data)
else:
- resp, content = client.request(
- "%s%s" % (WL_API_URL, path))
+ resp, content = client.request("%s%s" % (WL_API_URL, path))
status = resp['status']
if status == '200':
- return simplejson.loads(content)
+ return json.loads(content)
elif status.startswith('2'):
return
+ elif settings.DEBUG:
+ raise ApiError(content)
elif status == '401':
raise ApiError('User not authorized for publishing.')
else:
raise ApiError("WL API call error [code %s]" % status)
-
+# -*- coding: utf-8 -*-
from django.conf import settings
WL_CONSUMER_KEY = getattr(settings, 'APICLIENT_WL_CONSUMER_KEY', None)
WL_CONSUMER_SECRET = getattr(settings, 'APICLIENT_WL_CONSUMER_SECRET', None)
-WL_API_URL = getattr(settings, 'APICLIENT_WL_API_URL',
- 'http://wolnelektury.pl/api/')
+WL_API_URL = getattr(settings, 'APICLIENT_WL_API_URL', 'https://edukacjamedialna.edu.pl/api/')
-WL_REQUEST_TOKEN_URL = getattr(settings, 'APICLIENT_WL_REQUEST_TOKEN_URL',
- WL_API_URL + 'oauth/request_token/')
-WL_ACCESS_TOKEN_URL = getattr(settings, 'APICLIENT_WL_ACCESS_TOKEN_URL',
- WL_API_URL + 'oauth/access_token/')
-WL_AUTHORIZE_URL = getattr(settings, 'APICLIENT_WL_AUTHORIZE_URL',
- WL_API_URL + 'oauth/authorize/')
+WL_REQUEST_TOKEN_URL = getattr(settings, 'APICLIENT_WL_REQUEST_TOKEN_URL', WL_API_URL + 'oauth/request_token/')
+WL_ACCESS_TOKEN_URL = getattr(settings, 'APICLIENT_WL_ACCESS_TOKEN_URL', WL_API_URL + 'oauth/access_token/')
+WL_AUTHORIZE_URL = getattr(settings, 'APICLIENT_WL_AUTHORIZE_URL', WL_API_URL + 'oauth/authorize/')
-import cgi
+# -*- coding: utf-8 -*-
+import urlparse
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from apiclient.models import OAuthConnection
from apiclient import wl_consumer
-from apiclient.settings import (WL_REQUEST_TOKEN_URL, WL_ACCESS_TOKEN_URL,
- WL_AUTHORIZE_URL)
+from apiclient.settings import (WL_REQUEST_TOKEN_URL, WL_ACCESS_TOKEN_URL, WL_AUTHORIZE_URL)
@login_required
if resp['status'] != '200':
raise Exception("Invalid response %s." % resp['status'])
- request_token = dict(cgi.parse_qsl(content))
+ request_token = dict(urlparse.parse_qsl(content))
conn = OAuthConnection.get(request.user)
# this might reset existing auth!
token.set_verifier(oauth_verifier)
client = oauth2.Client(wl_consumer, token)
resp, content = client.request(WL_ACCESS_TOKEN_URL, method="POST")
- access_token = dict(cgi.parse_qsl(content))
-
- conn.access = True
- conn.token = access_token['oauth_token']
- conn.token_secret = access_token['oauth_token_secret']
- conn.save()
+ access_token = dict(urlparse.parse_qsl(content))
+
+ if 'oauth_token' in access_token:
+ conn.access = True
+ conn.token = access_token['oauth_token']
+ conn.token_secret = access_token['oauth_token_secret']
+ conn.save()
+ else:
+ return HttpResponse(request.GET.get('error'))
return HttpResponseRedirect('/')
def assert_publishable(self):
assert self.chunk_set.exists(), _('No chunks in the book.')
try:
- changes = self.get_current_changes(publishable=True)
+ changes = self.get_current_changes()
except self.NoTextError:
raise AssertionError(_('Not all chunks have publishable revisions.'))
try:
bi = self.wldocument(changes=changes, strict=True).book_info
+ if not bi.audience:
+ raise ValidationError('No audience specified')
+ if not bi.type:
+ raise ValidationError('No type specified')
except ParseError, e:
raise AssertionError(_('Invalid XML') + ': ' + unicode(e))
except NoDublinCore:
from librarian.parser import WLDocument
return WLDocument.from_string(
- self.materialize(publishable=publishable, changes=changes),
+ self.wl1_xml(publishable=publishable, changes=changes),
provider=RedakcjaDocProvider(publishable=publishable),
parse_dublincore=parse_dublincore,
strict=strict)
Publishes a book on behalf of a (local) user.
"""
self.assert_publishable()
- changes = self.get_current_changes(publishable=True)
- book_xml = self.materialize(changes=changes)
- apiclient.api_call(user, "books/", {"book_xml": book_xml})
+ changes = self.get_current_changes()
+ book_xml = self.wl1_xml(changes=changes)
+ apiclient.api_call(user, "lessons/", {"lesson_xml": book_xml})
# record the publish
br = BookPublishRecord.objects.create(book=self, user=user)
for c in changes:
ChunkPublishRecord.objects.create(book_record=br, change=c)
post_publish.send(sender=br)
+
+ def wl1_xml(self, publishable=True, changes=None):
+ from lxml import etree
+ import re
+ from StringIO import StringIO
+ from urllib import unquote
+ import os.path
+ from django.conf import settings
+ from fnpdjango.utils.text.slughifi import slughifi
+
+ def _register_function(f):
+ """ Register extension function with lxml """
+ ns = etree.FunctionNamespace('http://wolnelektury.pl/functions')
+ ns[f.__name__] = f
+ return f
+
+ @_register_function
+ def slugify(context, text):
+ """Remove unneeded whitespace from beginning and end"""
+ if isinstance(text, list):
+ text = ''.join(text)
+ return slughifi(text)
+
+ @_register_function
+ def rmext(context, text):
+ if isinstance(text, list):
+ text = ''.join(text)
+ text = unquote(text)
+ if '.' in text:
+ name, ext = text.rsplit('.', 1)
+ if ext.lower() in ('doc', 'docx', 'odt', 'pdf', 'jpg', 'jpeg'):
+ text = name
+ return text
+
+ t = etree.parse(os.path.join(settings.PROJECT_ROOT, 'xslt/wl2to1.xslt'))
+ ft = self.materialize(publishable=publishable, changes=changes)
+ ft = ft.replace(' ', ' ')
+ f2 = StringIO(ft)
+ i1 = etree.parse(f2)
+
+ for sect in i1.findall('//section'):
+ if sect[0].text == u'Przebieg zajęć':
+ # Prostujemy.
+ first = sect.find('section')
+ subs = first.findall('.//section')
+ for sub in subs:
+ sect.append(sub)
+ break
+ else:
+ # print 'BRAK PRZEBIEGU'
+ raise ValueError('Brak przebiegu')
+
+ i1.getroot().attrib['redslug'] = self.slug
+ i1.getroot().attrib['wlslug'] = self.slug # THIS!
+ # print '.',
+ w1t = i1.xslt(t)
+ for h in w1t.findall('//aktywnosc/opis'):
+ if not re.match(r'\d\.\s', h[0].text):
+ raise AssertionError('Niepoprawny nagłówek (aktywnosc/opis): %s' % repr(h[0].text))
+ h[0].text = h[0].text[3:]
+ return etree.tostring(w1t, encoding='utf-8')
{% with book.0 as chunk %}
<tr>
<td><input type="checkbox" name="select_book" value="{{book.id}}" data-chunk-id="{{chunk.id}}"/></td>
+ <td><a href="{% url 'catalogue_book' book.slug %}" title='{% trans "Lesson settings" %}'>[L]</a></td>
<td><a target="_blank"
href="{% url 'wiki_editor' book.slug %}">
{{ book.title }}</a></td>
<table id="file-list"{% if viewed_user %} class="book-list-user"{% endif %}>
<thead><tr>
- <th></th>
+ <th></th><th></th>
<th class='book-search-column'>
<form>
<input title='Szukaj w tytułach modułów' name="title"
from django.views.decorators.http import require_POST
from django.template import RequestContext
-from apiclient import NotAuthorizedError
+from apiclient import NotAuthorizedError, ApiError
from catalogue import forms
from catalogue import helpers
from catalogue.helpers import active_tab, ajax
book.publish(request.user)
except NotAuthorizedError:
return http.HttpResponseRedirect(reverse('apiclient_oauth'))
- except BaseException, e:
+ except ApiError, e:
return http.HttpResponse(e)
else:
return http.HttpResponseRedirect(book.get_absolute_url())
-Subproject commit 9d7a8f4916f03faa473d31a219102558f1844475
+Subproject commit 309c5b2981dcc3536cfb82352e3b1dbb5db5167d
-Subproject commit 85ab1e2d4b363dc747eacda08fa254586905cf25
+Subproject commit d0475d381f12b2c89c7c514c4f7f7d2ebc421d0a
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:wl="http://wolnelektury.pl/functions"
+ xmlns:dc="http://purl.org/dc/elements/1.1/" >
+<xsl:output encoding="utf-8" indent="yes" omit-xml-declaration = "yes" version="2.0" />
+
+<xsl:template match="section">
+ <xsl:choose>
+ <xsl:when test="not(ancestor::*)">
+ <utwor xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wl="http://wolnelektury.pl/functions">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description>
+ <xsl:attribute name="rdf:about">
+ <xsl:text>http://redakcja.edukacjamedialna.edu.pl/documents/book/</xsl:text>
+ <xsl:value-of select="@redslug" />
+ <xsl:text>/</xsl:text>
+ </xsl:attribute>
+ <dc:title xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/"><xsl:apply-templates select="header/text()" /></dc:title>
+ <dc:identifier.url xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <xsl:text>http://edukacjamedialna.edu.pl/lekcje/</xsl:text>
+ <xsl:value-of select="@wlslug" />
+ <xsl:text>/</xsl:text>
+ </dc:identifier.url>
+
+ <!--dc:creator.expert xml:lang="pl" ></dc:creator.expert>
+ <dc:creator.methodologist xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/"></dc:creator.methodologist>
+ <dc:creator.scenario xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/"></dc:creator.scenario>
+ <dc:creator.textbook xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/"></dc:creator.textbook-->
+
+ <xsl:apply-templates select="metadata" mode="meta" />
+
+ <dc:publisher xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Fundacja Nowoczesna Polska</dc:publisher>
+ <dc:rights xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Creative Commons Uznanie autorstwa - Na tych samych warunkach 3.0</dc:rights>
+ <dc:rights.license xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">http://creativecommons.org/licenses/by-sa/3.0/</dc:rights.license>
+ <dc:format xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">xml</dc:format>
+ <!--dc:type xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">added-var</dc:type-->
+ <dc:date xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">2015-01-12</dc:date>
+ <!--dc:audience xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/"><!- -liceum - -><xsl:value-of select="//dc:audience/text()" /></dc:audience-->
+ <dc:language xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">pol</dc:language>
+ </rdf:Description>
+ </rdf:RDF>
+ <powiesc>
+ <xsl:apply-templates />
+ </powiesc>
+ </utwor>
+ </xsl:when>
+ <xsl:when test="count(ancestor::*) = 3">
+ <aktywnosc>
+ <opis><xsl:apply-templates select="header" /><xsl:apply-templates select="div" mode="opis" /></opis>
+ <xsl:apply-templates select="div" mode="aktywnosc" />
+ <xsl:apply-templates select="section" mode="error" />
+ </aktywnosc>
+</xsl:when>
+<xsl:when test='header/text() = "Zadanie dla ucznia..."'>
+
+</xsl:when>
+ <xsl:otherwise><xsl:apply-templates /></xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- TODO language-dependent: description, audience, requires (subject.competence?) -->
+<xsl:template match="dc:creator.expert|dc:creator.scenario|dc:creator.textbook|dc:description|dc:subject.curriculum|dc:creator.methodologist|dc:subject.competence|dc:audience|dc:type|dc:requires" mode="meta">
+ <xsl:copy><xsl:apply-templates /></xsl:copy>
+</xsl:template>
+
+<xsl:template match="metadata"></xsl:template>
+<xsl:template match="aside"></xsl:template>
+
+
+<xsl:template match="header">
+ <xsl:choose>
+ <xsl:when test="count(ancestor::*) = 1">
+ <nazwa_utworu><xsl:apply-templates /></nazwa_utworu>
+ </xsl:when>
+ <xsl:when test="count(ancestor::*) = 2">
+ <naglowek_rozdzial><xsl:apply-templates /></naglowek_rozdzial>
+ </xsl:when>
+ <xsl:when test="count(ancestor::*) = 3">
+ <naglowek_podrozdzial><xsl:apply-templates /></naglowek_podrozdzial>
+ </xsl:when>
+ <xsl:when test="count(ancestor::*) = 4">
+ <akap><xsl:apply-templates /></akap>
+ </xsl:when>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template match="div">
+ <xsl:choose>
+ <xsl:when test="@class = 'p'">
+ <akap><xsl:apply-templates /></akap>
+ </xsl:when>
+ <xsl:when test="@class = 'list'">
+ <lista typ="punkt"><xsl:apply-templates /></lista>
+ </xsl:when>
+ <xsl:when test="@class = 'list.itemized'">
+ <lista typ="punkt"><xsl:apply-templates /></lista>
+ </xsl:when>
+ <xsl:when test="@class = 'list.enum'">
+ <lista typ="num"><xsl:apply-templates /></lista>
+ </xsl:when>
+ <xsl:when test="@class = 'list.definitions'">
+ <lista typ="slowniczek"><xsl:apply-templates /></lista>
+ </xsl:when>
+ <xsl:when test="@class = 'list.bibliography'">
+ <lista typ="czytelnia"><xsl:apply-templates /></lista>
+ </xsl:when>
+ <xsl:when test="@class = 'item'">
+ <punkt><xsl:apply-templates /></punkt>
+ </xsl:when>
+ <xsl:when test="@class = 'defined'">
+ <xsl:choose>
+ <xsl:when test="count(ancestor::*) = 4 ">
+ <definiendum><xsl:apply-templates /></definiendum>
+ </xsl:when>
+ <xsl:otherwise>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <NIEZNANY_DIV><xsl:value-of select="@class" /></NIEZNANY_DIV>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="div" mode="opis">
+ <xsl:choose>
+ <xsl:when test="@class = 'p'">
+ <akap><xsl:apply-templates /></akap>
+ </xsl:when>
+ <xsl:when test="@class = 'list'">
+ <lista typ="punkt"><xsl:apply-templates /></lista>
+ </xsl:when>
+ <xsl:when test="@class = 'list.itemized'">
+ <lista typ="punkt"><xsl:apply-templates /></lista>
+ </xsl:when>
+ <xsl:when test="@class = 'item'">
+ <punkt><xsl:apply-templates /></punkt>
+ </xsl:when>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="div" mode="aktywnosc">
+ <xsl:choose>
+ <xsl:when test="@class = 'list.definitions'">
+ <xsl:apply-templates mode="defs" />
+ </xsl:when>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template match="div" mode="defs">
+ <xsl:choose>
+ <xsl:when test="div/text() = 'Czas'"><czas><xsl:apply-templates /></czas></xsl:when>
+ <xsl:when test="div/text() = 'Metoda'"><forma><xsl:apply-templates /></forma></xsl:when>
+ <xsl:when test="div/text() = 'Pomoce'"><pomoce><xsl:apply-templates /></pomoce></xsl:when>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="span">
+ <xsl:choose>
+ <xsl:when test="@class = 'link'">
+ <link>
+ <xsl:choose>
+ <xsl:when test="starts-with(@href, 'file://')">
+ <xsl:attribute name="material">
+ <xsl:value-of select="wl:rmext(substring(@href, 8))" />
+ </xsl:attribute>
+ </xsl:when>
+ <xsl:when test="starts-with(@href, 'http')">
+ <xsl:attribute name="url">
+ <xsl:value-of select="@href" />
+ </xsl:attribute>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:attribute name="url">
+ <xsl:value-of select="text()" />
+ </xsl:attribute>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:apply-templates />
+ </link>
+ </xsl:when>
+ <xsl:when test="@class = 'emp'">
+ <wyroznienie><xsl:apply-templates /></wyroznienie>
+ </xsl:when>
+ <xsl:when test="@class='cite'">
+ <dlugi_cytat><xsl:apply-templates /></dlugi_cytat>
+ </xsl:when>
+ <xsl:otherwise>
+ <NIEZNANY_SPAN><xsl:value-of select="@class" /></NIEZNANY_SPAN>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<xsl:template match="section" mode="error">
+ NIEZNANA_SEKCJA
+</xsl:template>
+
+</xsl:stylesheet>
Pillow
oauth2
httplib2 # oauth2 dependency
+texml
## Book conversion library
# git+git://github.com/fnp/librarian.git@master#egg=librarian