diff --git a/weboob/backends/dlfp/backend.py b/weboob/backends/dlfp/backend.py index 88092408..3d5191a1 100644 --- a/weboob/backends/dlfp/backend.py +++ b/weboob/backends/dlfp/backend.py @@ -22,6 +22,7 @@ from weboob.tools.backend import BaseBackend from weboob.tools.newsfeed import Newsfeed from weboob.tools.value import Value, ValueBool, ValuesDict from weboob.capabilities.messages import ICapMessages, ICapMessagesPost, Message, Thread, CantSendMessage +from weboob.capabilities.content import ICapContent, Content from .browser import DLFP from .tools import rssid, id2url @@ -30,7 +31,7 @@ from .tools import rssid, id2url __all__ = ['DLFPBackend'] -class DLFPBackend(BaseBackend, ICapMessages, ICapMessagesPost): +class DLFPBackend(BaseBackend, ICapMessages, ICapMessagesPost, ICapContent): NAME = 'dlfp' MAINTAINER = 'Romain Bignon' EMAIL = 'romain@weboob.org' @@ -58,6 +59,8 @@ class DLFPBackend(BaseBackend, ICapMessages, ICapMessagesPost): with self.browser: self.browser.close_session() + #### ICapMessages ############################################## + def iter_threads(self): whats = set() if self.config['get_news']: @@ -152,6 +155,10 @@ class DLFPBackend(BaseBackend, ICapMessages, ICapMessagesPost): self.storage.get('seen', message.thread.id, 'comments', default=[]) + [message.id]) self.storage.save() + def fill_thread(self, thread, fields): + return self.get_thread(thread) + + #### ICapMessagesReply ######################################### def post_message(self, message): if not message.parent: raise CantSendMessage('Posting news and diaries on DLFP is not supported yet') @@ -164,7 +171,29 @@ class DLFPBackend(BaseBackend, ICapMessages, ICapMessagesPost): message.title, message.content) - def fill_thread(self, thread, fields): - return self.get_thread(thread) + #### ICapContent ############################################### + def get_content(self, id): + if isinstance(id, basestring): + content = Content(id) + else: + content = id + id = content.id + + with self.browser: + data = self.browser.get_wiki_content(id) + + if data is None: + return None + + content.content = data + return content + + def push_content(self, content, message=None, minor=False): + with self.browser: + return self.browser.set_wiki_content(content.id, content.content, message) + + def get_content_preview(self, content): + with self.browser: + return self.browser.get_wiki_preview(content.id, content.content) OBJECTS = {Thread: fill_thread} diff --git a/weboob/backends/dlfp/browser.py b/weboob/backends/dlfp/browser.py index 95ffc744..dcf90367 100644 --- a/weboob/backends/dlfp/browser.py +++ b/weboob/backends/dlfp/browser.py @@ -19,12 +19,13 @@ import urllib import re -from weboob.tools.browser import BaseBrowser, BrowserHTTPError, BrowserIncorrectPassword +from weboob.tools.browser import BaseBrowser, BrowserHTTPNotFound, BrowserHTTPError, BrowserIncorrectPassword from weboob.capabilities.messages import CantSendMessage from .pages.index import IndexPage, LoginPage from .pages.news import ContentPage, NewCommentPage, NodePage, CommentPage, NewTagPage from .pages.board import BoardIndexPage +from .pages.wiki import WikiEditPage from .tools import id2url, url2id # Browser @@ -34,12 +35,15 @@ class DLFP(BaseBrowser): PAGES = {'https://linuxfr.org/?': IndexPage, 'https://linuxfr.org/login.html': LoginPage, 'https://linuxfr.org/news/[^\.]+': ContentPage, - 'https://linuxfr.org/wiki/[^\.]+': ContentPage, + 'https://linuxfr.org/wiki/(?!nouveau)[^/]+': ContentPage, + 'https://linuxfr.org/wiki': WikiEditPage, + 'https://linuxfr.org/wiki/nouveau': WikiEditPage, + 'https://linuxfr.org/wiki/[^\.]+/modifier': WikiEditPage, 'https://linuxfr.org/users/[\w\-_]+/journaux/[^\.]+': ContentPage, 'https://linuxfr.org/forums/[\w\-_]+/posts/[^\.]+': ContentPage, - 'https://linuxfr.org/nodes/(\d+)/comments/(\d+)$': CommentPage, + 'https://linuxfr.org/nodes/(\d+)/comments/(\d+)': CommentPage, 'https://linuxfr.org/nodes/(\d+)/comments/nouveau': NewCommentPage, - 'https://linuxfr.org/nodes/(\d+)/comments$': NodePage, + 'https://linuxfr.org/nodes/(\d+)/comments': NodePage, 'https://linuxfr.org/nodes/(\d+)/tags/nouveau': NewTagPage, 'https://linuxfr.org/board/index.xml': BoardIndexPage, } @@ -63,6 +67,66 @@ class DLFP(BaseBrowser): return url, _id + def get_wiki_content(self, _id): + url, _id = self.parse_id('W.%s' % _id) + if url is None: + return None + + try: + self.location('%s/modifier' % url) + except BrowserHTTPNotFound: + return '' + + assert self.is_on_page(WikiEditPage) + + return self.page.get_body() + + def _go_on_wiki_edit_page(self, name): + """ + Go on the wiki page named 'name'. + + Return True if this is a new page, or False if + the page already exist. + Return None if it isn't a right wiki page name. + """ + url, _id = self.parse_id('W.%s' % name) + if url is None: + return None + + try: + self.location('%s/modifier' % url) + except BrowserHTTPNotFound: + self.location('/wiki/nouveau') + new = True + else: + new = False + + assert self.is_on_page(WikiEditPage) + + return new + + def set_wiki_content(self, name, content, message): + new = self._go_on_wiki_edit_page(name) + if new is None: + return None + + if new: + title = name.replace('-', ' ') + else: + title = None + + self.page.post_content(title, content, message) + + def get_wiki_preview(self, name, content): + if self._go_on_wiki_edit_page(name) is None: + return None + + self.page.post_preview(content) + if self.is_on_page(WikiEditPage): + return self.page.get_preview_html() + elif self.is_on_page(ContentPage): + return self.page.get_article().body + def get_content(self, _id): url, _id = self.parse_id(_id) diff --git a/weboob/backends/dlfp/pages/wiki.py b/weboob/backends/dlfp/pages/wiki.py new file mode 100644 index 00000000..b0c06944 --- /dev/null +++ b/weboob/backends/dlfp/pages/wiki.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010-2011 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from weboob.tools.parsers.lxmlparser import select, SelectElementException + +from .index import DLFPPage + +class WikiEditPage(DLFPPage): + def get_body(self): + try: + return select(self.document.getroot(), 'textarea#wiki_page_wiki_body', 1).text + except SelectElementException: + return '' + + def _is_wiki_form(self, form): + return form.attrs.get('class', '') in ('new_wiki_page', 'edit_wiki_page') + + def post_content(self, title, body, message): + self.browser.select_form(predicate=self._is_wiki_form) + self.browser.set_all_readonly(False) + + if title is not None: + self.browser['wiki_page[title]'] = title + self.browser['commit'] = 'Créer' + else: + self.browser['commit'] = 'Mettre à jour' + self.browser['wiki_page[wiki_body]'] = body + if message is not None: + self.browser['wiki_page[message]'] = message + + self.browser.submit() + + def post_preview(self, body): + self.browser.select_form(predicate=self._is_wiki_form) + self.browser['wiki_page[wiki_body]'] = body + self.browser.submit() + + def get_preview_html(self): + body = select(self.document.getroot(), 'article.wikipage div.content', 1) + return self.browser.parser.tostring(body) diff --git a/weboob/backends/dlfp/tools.py b/weboob/backends/dlfp/tools.py index 912759ef..06d1ff07 100644 --- a/weboob/backends/dlfp/tools.py +++ b/weboob/backends/dlfp/tools.py @@ -19,10 +19,10 @@ import re RSSID_RE = re.compile('tag:.*:(\w)\w+/(\d+)') -ID2URL_RE = re.compile('^(\w)([\w\-_]*)\.([^\.]+)$') +ID2URL_RE = re.compile('^(\w)([\w\-_]*)\.([^ \.]+)$') URL2ID_DIARY_RE = re.compile('.*/users/([\w\-_]+)/journaux/([^\.]+)') URL2ID_NEWSPAPER_RE = re.compile('.*/news/(.+)') -URL2ID_WIKI_RE = re.compile('.*/wiki/(.+)') +URL2ID_WIKI_RE = re.compile('.*/wiki/([^ /]+)') URL2ID_FORUM_RE = re.compile('.*/forums/([\w\-_]+)/posts/([^\.]+)') def rssid(entry):