diff --git a/weboob/backends/phpbb/backend.py b/weboob/backends/phpbb/backend.py index c1279aa9..42ac3a2a 100644 --- a/weboob/backends/phpbb/backend.py +++ b/weboob/backends/phpbb/backend.py @@ -24,10 +24,10 @@ from weboob.tools.backend import BaseBackend, BackendConfig from weboob.tools.newsfeed import Newsfeed from weboob.tools.value import Value, ValueInt, ValueBackendPassword from weboob.tools.misc import limit -from weboob.capabilities.messages import ICapMessages, ICapMessagesPost, Message, Thread +from weboob.capabilities.messages import ICapMessages, ICapMessagesPost, Message, Thread, CantSendMessage from .browser import PhpBB -from .tools import rssid, url2id, id2url +from .tools import rssid, url2id, id2url, id2topic __all__ = ['PhpBBBackend'] @@ -87,9 +87,9 @@ class PhpBBBackend(BaseBackend, ICapMessages, ICapMessagesPost): thread = id id = thread.id - thread_id = url2id(id) or id + thread_id = url2id(id, nopost=True) or id try: - last_seen_id = self.storage.get('seen', default={})[url2id(thread_id)] + last_seen_id = self.storage.get('seen', default={})[id2topic(thread_id)] except KeyError: last_seen_id = 0 @@ -135,11 +135,10 @@ class PhpBBBackend(BaseBackend, ICapMessages, ICapMessagesPost): url = self.browser.get_root_feed_url() for article in Newsfeed(url, rssid).iter_entries(): id = url2id(article.link) - thread_id, message_id = [int(v) for v in id.split('.')] - thread = Thread(thread_id) + thread = None try: - last_seen_id = self.storage.get('seen', default={})[thread.id] + last_seen_id = self.storage.get('seen', default={})[id2topic(id)] except KeyError: last_seen_id = 0 @@ -148,6 +147,8 @@ class PhpBBBackend(BaseBackend, ICapMessages, ICapMessagesPost): if self.config['thread_unread_messages'].get() > 0: iterator = limit(iterator, self.config['thread_unread_messages'].get()) for post in iterator: + if not thread: + thread = Thread('%s.%s' % (post.forum_id, post.topic_id)) message = self._post2message(thread, post) if child: @@ -163,12 +164,12 @@ class PhpBBBackend(BaseBackend, ICapMessages, ICapMessagesPost): def set_message_read(self, message): try: - last_seen_id = self.storage.get('seen', default={})[message.thread.id] + last_seen_id = self.storage.get('seen', default={})[id2topic(message.thread.id)] except KeyError: last_seen_id = 0 if message.id > last_seen_id: - self.storage.set('seen', int(message.thread.id), message.id) + self.storage.set('seen', id2topic(message.thread.id), message.id) self.storage.save() def fill_thread(self, thread, fields): @@ -178,8 +179,20 @@ class PhpBBBackend(BaseBackend, ICapMessages, ICapMessagesPost): def post_message(self, message): assert message.thread + forum = 0 + topic = 0 + if message.thread: + try: + if '.' in message.thread.id: + forum, topic = [int(i) for i in message.thread.id.split('.', 1)] + else: + forum = int(message.thread.id) + except ValueError: + raise CantSendMessage('Thread ID must be in form "FORUM_ID[.TOPIC_ID]".') + with self.browser: - return self.browser.post_answer(message.thread.id if message.thread else 0, + return self.browser.post_answer(forum, + topic, message.title, message.content) diff --git a/weboob/backends/phpbb/browser.py b/weboob/backends/phpbb/browser.py index 5356ac9b..9cc2f728 100644 --- a/weboob/backends/phpbb/browser.py +++ b/weboob/backends/phpbb/browser.py @@ -18,6 +18,7 @@ # along with weboob. If not, see . +import re import urllib from urlparse import urlsplit @@ -28,6 +29,10 @@ from .pages.index import LoginPage from .pages.forum import ForumPage, TopicPage, PostingPage from .tools import id2url, url2id + +__all__ = ['PhpBB'] + + # Browser class PhpBB(BaseBrowser): PAGES = {'https?://.*/index.php': ForumPage, @@ -93,7 +98,7 @@ class PhpBB(BaseBrowser): parent = 0 while 1: for post in self.page.iter_posts(): - if post.id >= stop_id: + if stop_id and post.id >= stop_id: return post.parent = parent @@ -145,11 +150,39 @@ class PhpBB(BaseBrowser): return post - def post_answer(self, topic, title, content): - if topic == 0: - raise CantSendMessage('Unable to create new topic for now') + def get_forums(self): + self.home() + return dict(self.page.iter_all_forums()) + + def post_answer(self, forum_id, topic_id, title, content): + if topic_id == 0: + if not forum_id: + forums = self.get_forums() + forums_prompt = 'Forums list:\n%s' % ('\n'.join(['\t- %s' % f for f in forums.itervalues()])) + m = re.match('\[(.*)\] (.*)', title or '') + if not m: + raise CantSendMessage('Please enter a title formatted like that:\n\t"[FORUM] SUBJECT"\n\n%s' % forums_prompt) + + forum_id = None + for k,v in forums.iteritems(): + if v.lower() == m.group(1).lower(): + forum_id = k + break + + if not forum_id: + raise CantSendMessage('Forum "%s" not found.\n\n%s' % (m.group(1), forums_prompt)) + + self.location('%s/posting.php?mode=post&f=%d' % (self.BASEPATH, forum_id)) + + assert self.is_on_page(PostingPage) + self.page.post(title, content) + + assert self.is_on_page(PostingPage) + error = self.page.get_error_message() + if error: + raise CantSendMessage(u'Unable to send message: %s' % error) else: - self.location('%s/%s' % (self.BASEPATH, id2url(topic))) + self.location('%s/%s' % (self.BASEPATH, id2url(topic_id))) assert self.is_on_page(TopicPage) self.page.go_reply() @@ -158,7 +191,7 @@ class PhpBB(BaseBrowser): # Don't send title because it isn't needed in real use case # and with monboob title is something like: # Re: [Forum Name] Re: Topic Name - if title is not None and title.startswith('Re: '): + if title is not None and title.startswith('Re:'): title = None self.page.post(title, content) diff --git a/weboob/backends/phpbb/pages/forum.py b/weboob/backends/phpbb/pages/forum.py index 744edfb6..647d747e 100644 --- a/weboob/backends/phpbb/pages/forum.py +++ b/weboob/backends/phpbb/pages/forum.py @@ -67,10 +67,19 @@ class ForumPage(PhpBBPage): link.nb_messages = int(li.cssselect('dd.posts')[0].text.strip()) + 1 yield link + def iter_all_forums(self): + for option in self.parser.select(self.document.getroot(), 'select#f', 1).findall('option'): + value = int(option.attrib['value']) + if value < 0 or not option.text: + continue + + yield value, option.text.strip(u'ยป \xa0\n\r') + class Post(object): - def __init__(self, topic, id): + def __init__(self, forum_id, topic_id, id): self.id = int(id) - self.topic = topic + self.forum_id = forum_id + self.topic_id = topic_id self.title = u'' self.author = u'' self.date = None @@ -85,9 +94,14 @@ class TopicPage(PhpBBPage): self.cur_page = int(strongs[0].text.strip()) self.tot_pages = int(strongs[1].text.strip()) - v = urlsplit(self.url) + try: + url = self.parser.select(self.document.getroot(), 'h2 a', 1).attrib['href'] + except BrokenPageError, e: + url = self.url + v = urlsplit(url) args = parse_qs(v.query) self.topic_id = int(args['t'][0]) + self.forum_id = int(args['f'][0]) if 'f' in args else 0 self.forum_title = u'' nav = self.parser.select(self.document.getroot(), 'li.icon-home') @@ -143,15 +157,15 @@ class TopicPage(PhpBBPage): profile = div.cssselect('dl.postprofile')[0] id = div.attrib['id'][1:] - post = Post(self.topic_id, id) + post = Post(self.forum_id, self.topic_id, id) - title = u'' title_tags = body.cssselect('h3 a') if len(title_tags) == 0: title_tags = self.document.getroot().cssselect('h2 a') if len(title_tags) == 0: + title = u'' self.logger.warning('Unable to parse title') - elif title_tags[0].text: + else: title = title_tags[0].text.strip() post.title = self.forum_title + title diff --git a/weboob/backends/phpbb/tools.py b/weboob/backends/phpbb/tools.py index 8813a5b7..292bf18b 100644 --- a/weboob/backends/phpbb/tools.py +++ b/weboob/backends/phpbb/tools.py @@ -24,13 +24,19 @@ from urlparse import urlsplit, parse_qs from weboob.tools.misc import local2utc -def url2id(url): +def url2id(url, nopost=False): v = urlsplit(url) pagename = v.path.split('/')[-1] args = parse_qs(v.query) + if pagename == 'viewforum.php': + return '%d' % int(args['f'][0]) if pagename == 'viewtopic.php': - s = '%d' % int(args['t'][0]) - if 'p' in args: + if 'f' in args: + s = '%d' % int(args['f'][0]) + else: + s = '0' + s += '.%d' % int(args['t'][0]) + if 'p' in args and not nopost: s += '.%d' % int(args['p'][0]) return s @@ -39,11 +45,20 @@ def url2id(url): def id2url(id): v = id.split('.') if len(v) == 1: - return 'viewtopic.php?t=%d' % int(v[0]) + return 'viewforum.php?f=%d' % int(v[0]) if len(v) == 2: - return 'viewtopic.php?t=%d&p=%d#p%d' % (int(v[0]), - int(v[1]), - int(v[1])) + return 'viewtopic.php?f=%d&t=%d' % (int(v[0]), int(v[1])) + if len(v) == 3: + return 'viewtopic.php?f=%d&t=%d&p=%d#p%d' % (int(v[0]), + int(v[1]), + int(v[2]), + int(v[2])) + +def id2topic(id): + try: + return int(id.split('.')[1]) + except IndexError: + return None def rssid(id): return id