diff --git a/modules/poivy/__init__.py b/modules/poivy/__init__.py index 9fccbea1..ab467ddb 100644 --- a/modules/poivy/__init__.py +++ b/modules/poivy/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2013 Florent Fourcot +# Copyright(C) 2013-2014 Florent Fourcot # # This file is part of weboob. # diff --git a/modules/poivy/backend.py b/modules/poivy/backend.py index fe376441..fd618948 100644 --- a/modules/poivy/backend.py +++ b/modules/poivy/backend.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2013 Florent Fourcot +# Copyright(C) 2013-2014 Florent Fourcot # # This file is part of weboob. # @@ -52,17 +52,14 @@ class PoivyBackend(BaseBackend, ICapBill): yield subscription def get_subscription(self, _id): - with self.browser: - subscription = self.browser.get_subscription(_id) + subscription = self.browser.get_subscription(_id) if subscription: return subscription else: raise SubscriptionNotFound() def iter_bills_history(self, subscription): - with self.browser: - for history in self.browser.get_history(): - yield history + return self.browser.get_history() # No details on the website def get_details(self, subscription): @@ -75,5 +72,5 @@ class PoivyBackend(BaseBackend, ICapBill): balance.id = "%s-balance" % subscription.id balance.price = subscription._balance balance.label = u"Balance %s" % subscription.id - balance.currency = 'EUR' + balance.currency = u'EUR' return balance diff --git a/modules/poivy/browser.py b/modules/poivy/browser.py index a0767260..339a5534 100644 --- a/modules/poivy/browser.py +++ b/modules/poivy/browser.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2013 Fourcot Florent +# Copyright(C) 2013-2014 Fourcot Florent # # This file is part of weboob. # @@ -18,75 +18,55 @@ # along with weboob. If not, see . -from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword, BrowserBanned +from weboob.tools.browser2 import LoginBrowser, URL, need_login from .pages import HomePage, LoginPage, HistoryPage, BillsPage, ErrorPage __all__ = ['PoivyBrowser'] -class PoivyBrowser(BaseBrowser): - DOMAIN = 'www.poivy.com' - PROTOCOL = 'https' - ENCODING = None # refer to the HTML encoding - PAGES = {'.*login': LoginPage, - '.*buy_credit.*': HomePage, - '.*/recent_calls': HistoryPage, - '.*purchases': BillsPage, - '.*warning.*': ErrorPage - } +class PoivyBrowser(LoginBrowser): + BASEURL = 'https://www.poivy.com' - def __init__(self, *args, **kwargs): - BaseBrowser.__init__(self, *args, **kwargs) + login = URL('/login', LoginPage) + homepage = URL('/buy_credit.*', HomePage) + history = URL('/recent_calls', HistoryPage) + bills = URL('/purchases', BillsPage) + warning = URL('/warning.*', ErrorPage) - def home(self): - self.location('/login') - - def is_logged(self): - return not self.is_on_page(LoginPage) - - def login(self): + def do_login(self): assert isinstance(self.username, basestring) assert isinstance(self.password, basestring) - if not self.is_on_page(LoginPage): - self.location('/login') + self.login.stay_or_go() if not self.page.login(self.username, self.password): raise BrowserBanned('Too many connections from you IP address: captcha enabled') - if self.is_on_page(LoginPage) or self.is_on_page(ErrorPage): + if self.login.is_here() or self.warning.is_here(): raise BrowserIncorrectPassword() + @need_login def get_subscription_list(self): - if not self.is_on_page(HomePage): - self.location('/buy_credit') + return self.homepage.stay_or_go().get_list() - return self.page.get_list() - - def get_subscription(self, id): - assert isinstance(id, basestring) - - l = self.get_subscription_list() - for a in l: - if a.id == id: + def _find_id_list(self, mylist, _id): + for a in mylist: + if a.id == _id: return a - return None + @need_login + def get_subscription(self, _id): + return self._find_id_list(self.get_subscription_list(), _id) + + @need_login def get_history(self): - if not self.is_on_page(HistoryPage): - self.location('/recent_calls') - return self.page.get_calls() + return self.history.stay_or_go().get_calls() + @need_login def iter_bills(self, parentid): - if not self.is_on_page(BillsPage): - self.location('/purchases') - return self.page.date_bills() + return self.bills.stay_or_go().get_bills() + @need_login def get_bill(self, id): - assert isinstance(id, basestring) - - l = self.iter_bills(id) - for a in l: - if a.id == id: - return a + return self._find_id_list(self.iter_bills(), _id) diff --git a/modules/poivy/pages.py b/modules/poivy/pages.py index 2e916bb5..21d0b916 100644 --- a/modules/poivy/pages.py +++ b/modules/poivy/pages.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2013 Florent Fourcot +# Copyright(C) 2013-2014 Florent Fourcot # # This file is part of weboob. # @@ -17,7 +17,8 @@ # You should have received a copy of the GNU Affero General Public License # along with weboob. If not, see . -from weboob.tools.browser import BasePage +from weboob.tools.browser2.page import HTMLPage, LoggedPage, method, ListElement, ItemElement +from weboob.tools.browser2.filters import Env, CleanText, CleanDecimal, Field, Attr, Filter, Time, Date from weboob.capabilities.bill import Subscription, Detail from decimal import Decimal, InvalidOperation from datetime import datetime, date, time @@ -27,15 +28,11 @@ import re __all__ = ['LoginPage', 'HomePage', 'HistoryPage', 'BillsPage', 'ErrorPage'] -class ErrorPage(BasePage): - def on_loaded(self): +class ErrorPage(HTMLPage): pass -class LoginPage(BasePage): - def on_loaded(self): - pass - +class LoginPage(HTMLPage): def _predicate_form(self, form): try: return form.attrs['class'] == "form-detail" @@ -43,73 +40,78 @@ class LoginPage(BasePage): return False def login(self, login, password): - captcha = self.document.xpath('//label[@class="label_captcha_input"]') + captcha = self.doc.xpath('//label[@class="label_captcha_input"]') if len(captcha) > 0: return False - form_newsletter = self.document.xpath('//form[@id="newsletter_form"]')[0] - hidden_input = form_newsletter.xpath('./input[@type="hidden"]')[0] - hidden_id = hidden_input.attrib["value"] - hidden_name = hidden_input.attrib["name"] + xpath_hidden = '//form[@id="newsletter_form"]/input[@type="hidden"]' + hidden_id = Attr(xpath_hidden, "value")(self.doc) + hidden_name = Attr(xpath_hidden, "name")(self.doc) - # Form without name - self.browser.select_form(predicate=self._predicate_form) - self.browser.set_all_readonly(False) - self.browser['login[username]'] = login.encode('iso-8859-1') - self.browser['login[password]'] = password.encode('iso-8859-1') - self.browser[hidden_name] = hidden_id - self.browser.submit(nologin=True) + form = self.get_form(xpath="//form[@class='form-detail']") + form['login[username]'] = login.encode('iso-8859-1') + form['login[password]'] = password.encode('iso-8859-1') + form[hidden_name] = hidden_id + form.submit() return True -class HomePage(BasePage): - def on_loaded(self): - pass +class Insert2(Filter): + """ + Insert two Filters inside a string + """ + def __init__(self, selector, selector2, string): + super(Insert2, self).__init__(selector) + self.string = string + self.selector2 = selector2 - def get_list(self): - spanabo = self.document.xpath('//span[@class="welcome-text"]/b')[0] - owner = spanabo.text_content() - credit = self.document.xpath('//span[@class="balance"]')[0].text_content() + def __call__(self, item): + value = self.selector(item) + value2 = self.selector2(item) + return self.filter(value, value2) - subscription = Subscription(owner) - subscription.label = u"Poivy - %s - %s" % (owner, credit) - subscription._balance = Decimal(re.sub(u'[^\d\-\.]', '', credit)) - - return [subscription] + def filter(self, txt, txt2): + return self.string % (txt, txt2) -class HistoryPage(BasePage): - months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] +class HomePage(LoggedPage, HTMLPage): - def on_loaded(self): - pass + @method + class get_list(ListElement): + item_xpath = '.' - def get_calls(self): - table = self.document.xpath('//table/tbody')[0] - for tr in table.xpath('tr'): - tds = tr.xpath('td') + class item(ItemElement): + klass = Subscription - rawdate = tds[0].text_content() - splitdate = rawdate.split('-') - month_no = self.months.index(splitdate[1]) + 1 - mydate = date(int(splitdate[2]), month_no, int(splitdate[0])) - - rawtime = tds[1].text_content() - mytime = time(*[int(x) for x in rawtime.split(":")]) - - price = re.sub(u'[^\d\-\.]', '', tds[6].text) - detail = Detail() - detail.datetime = datetime.combine(mydate, mytime) - detail.label = u"%s from %s to %s - %s" % (tds[2].text, tds[3].text, tds[4].text, tds[5].text) - try: - detail.price = Decimal(price) - except InvalidOperation: - detail.price = Decimal(0) # free calls - detail.currency = 'EUR' - - yield detail + obj_id = CleanText('//span[@class="welcome-text"]/b') + obj__balance = CleanDecimal(CleanText('//span[@class="balance"]'), replace_dots=False) + obj_label = Insert2(Field('id'), Field('_balance'), u"Poivy - %s - %s €") -class BillsPage(BasePage): - def on_loaded(self): - pass +class HistoryPage(LoggedPage, HTMLPage): + + @method + class get_calls(ListElement): + item_xpath = '//table/tbody/tr' + + class item(ItemElement): + klass = Detail + + obj_datetime = Env('datetime') + obj_price = CleanDecimal('td[7]', replace_dots=False) + obj_currency = u'EUR' + obj_label = Env('label') + + def parse(self, el): + tds = el.xpath('td') + + mydate = Date(CleanText('td[1]'))(el) + mytime = Time(CleanText('td[2]'))(el) + + self.env['datetime'] = datetime.combine(mydate, mytime) + self.env['label'] = u"%s from %s to %s - %s" % (tds[2].text, tds[3].text, tds[4].text, tds[5].text) + + +#TODO +class BillsPage(HTMLPage): + pass