diff --git a/modules/sprunge/__init__.py b/modules/sprunge/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..70131fe90d425a4d648577ce952f3f139d3c91ca --- /dev/null +++ b/modules/sprunge/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2017 Laurent Bachelier +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + +from .module import SprungeModule + +__all__ = ['SprungeModule'] diff --git a/modules/sprunge/browser.py b/modules/sprunge/browser.py new file mode 100644 index 0000000000000000000000000000000000000000..d03a5076815c9a3915473ecdd73f019da71ac66e --- /dev/null +++ b/modules/sprunge/browser.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2017 Laurent Bachelier +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + +from weboob.browser.browsers import PagesBrowser +from weboob.browser.elements import ItemElement, method +from weboob.browser.filters.standard import BrowserURL, Env, Field +from weboob.browser.pages import HTMLPage +from weboob.browser.url import URL +from weboob.capabilities.base import NotAvailable +from weboob.capabilities.paste import BasePaste, PasteNotFound + + +class SprungePaste(BasePaste): + # all pastes are private + public = False + + # TODO perhaps move this logic elsewhere, remove this and id2url from capability + # (page_url is required by pastoob) + @property + def page_url(self): + return self.url + + +class PastePage(HTMLPage): + @method + class fill_paste(ItemElement): + klass = SprungePaste + + obj_id = Env('id') + obj_title = NotAvailable + + def obj_contents(self): + text = self.page.response.text + # Sprunge seems to add a newline to our original text + if text.endswith(u'\n'): + text = text[:-1] + return text + + obj_url = BrowserURL('paste', id=Field('id')) + + def validate(self, obj): + if obj.contents == u'%s not found.' % obj.id: + raise PasteNotFound() + return True + + +class SprungeBrowser(PagesBrowser): + BASEURL = 'http://sprunge.us/' + + paste = URL(r'(?P\w+)', PastePage) + post = URL(r'$') + + @paste.id2url + def get_paste(self, url): + url = self.absurl(url, base=True) + m = self.paste.match(url) + if m: + return SprungePaste(m.groupdict()['id']) + + def fill_paste(self, paste): + """ + Get as much as information possible from the paste page + """ + return self.paste.stay_or_go(id=paste.id).fill_paste(paste) + + def post_paste(self, paste): + url = self.post.open(data={'sprunge': paste.contents}).text.strip() + self.location(url) + return self.page.fill_paste(paste) diff --git a/modules/sprunge/favicon.png b/modules/sprunge/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..45a7a136028855f4170a634094f6465fd3e7d1bd Binary files /dev/null and b/modules/sprunge/favicon.png differ diff --git a/modules/sprunge/module.py b/modules/sprunge/module.py new file mode 100644 index 0000000000000000000000000000000000000000..d8788f29abe8dfec9f0e0e5c924ae175e024e6b9 --- /dev/null +++ b/modules/sprunge/module.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2017 Laurent Bachelier +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + + +from weboob.tools.backend import Module +from weboob.tools.capabilities.paste import BasePasteModule + +from .browser import SprungeBrowser, SprungePaste + + +class SprungeModule(Module, BasePasteModule): + NAME = 'sprunge' + MAINTAINER = u'Laurent Bachelier' + EMAIL = 'laurent@bachelier.name' + VERSION = '1.4' + DESCRIPTION = u'Sprunge text sharing tool' + LICENSE = 'AGPLv3+' + BROWSER = SprungeBrowser + + EXPIRATIONS = { + False: 'f', + } + + def new_paste(self, *args, **kwargs): + return SprungePaste(*args, **kwargs) + + def can_post(self, contents, title=None, public=None, max_age=None): + if public is True: + return 0 + if max_age is not None: + if self.get_closest_expiration(max_age) is None: + return 0 + if not title: + return 2 + return 1 + + def get_paste(self, _id): + return self.browser.get_paste(_id) + + def fill_paste(self, paste, fields): + self.browser.fill_paste(paste) + return paste + + def post_paste(self, paste, max_age=None): + self.browser.post_paste(paste) + + OBJECTS = {SprungePaste: fill_paste} diff --git a/modules/sprunge/test.py b/modules/sprunge/test.py new file mode 100644 index 0000000000000000000000000000000000000000..07c0831bb118ab65c2ab99ce1fe33989faaa8abe --- /dev/null +++ b/modules/sprunge/test.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2017 Laurent Bachelier +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + + +from weboob.capabilities.base import NotAvailable +from weboob.capabilities.paste import PasteNotFound +from weboob.tools.test import BackendTest + + +class SprungeTest(BackendTest): + MODULE = 'sprunge' + + def _get_paste(self, _id): + # html method + p = self.backend.get_paste(_id) + self.backend.fillobj(p, ['title']) + assert p.title is NotAvailable + assert p.page_url.startswith('http://sprunge.us/') + assert p.public is False + + def test_post(self): + p = self.backend.new_paste(None, contents=u'Weboob Test héhéhé') + self.backend.post_paste(p, max_age=False) + assert p.id + self.backend.fill_paste(p, ['title']) + assert p.title is NotAvailable + assert p.id in p.page_url + assert p.public is False + + # test all get methods from the Paste we just created + self._get_paste(p.id) + + # same but from the full URL + self._get_paste('http://sprunge.us/%s' % p.id) + + def test_notfound(self): + for _id in ('ab', + 'http://sprunge.us/ab'): + # html method + p = self.backend.get_paste(_id) + self.assertRaises(PasteNotFound, self.backend.fillobj, p, ['title']) + + # raw method + p = self.backend.get_paste(_id) + self.assertRaises(PasteNotFound, self.backend.fillobj, p, ['contents']) + + def test_checkurl(self): + # call with an URL we can't handle with this backend + assert self.backend.get_paste('http://pastebin.com/nJG9ZFG8') is None + + def test_can_post(self): + assert 2 == self.backend.can_post(u'hello', public=False) + assert 1 == self.backend.can_post(u'hello', public=False, title=u'hello') + assert 1 == self.backend.can_post(u'hello', title=u'hello') + assert 0 == self.backend.can_post(u'hello', public=True) + assert 0 == self.backend.can_post(u'hello', public=False, max_age=3600*24)