diff --git a/modules/paypal/__init__.py b/modules/paypal/__init__.py new file mode 100644 index 00000000..3a773e7f --- /dev/null +++ b/modules/paypal/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 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 .backend import PaypalBackend + +__all__ = ['PaypalBackend'] diff --git a/modules/paypal/backend.py b/modules/paypal/backend.py new file mode 100644 index 00000000..fa6ec03e --- /dev/null +++ b/modules/paypal/backend.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 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 . + + +# python2.5 compatibility +from __future__ import with_statement + +from weboob.capabilities.bank import ICapBank, AccountNotFound +from weboob.tools.backend import BaseBackend, BackendConfig +from weboob.tools.value import ValueBackendPassword + +from .browser import Paypal + + +__all__ = ['PaypalBackend'] + + +class PaypalBackend(BaseBackend, ICapBank): + NAME = 'paypal' + MAINTAINER = u'Laurent Bachelier' + EMAIL = 'laurent@bachelier.name' + VERSION = '0.f' + LICENSE = 'AGPLv3+' + DESCRIPTION = u'PayPal money transfer website' + CONFIG = BackendConfig(ValueBackendPassword('login', label='E-mail', masked=False), + ValueBackendPassword('password', label='Password')) + BROWSER = Paypal + + def create_default_browser(self): + return self.create_browser(self.config['login'].get(), + self.config['password'].get()) + + def iter_accounts(self): + yield self.get_account(u"1") + + def get_account(self, _id): + with self.browser: + account = self.browser.get_account(_id) + if account: + return account + else: + raise AccountNotFound() + + def iter_history(self, account): + with self.browser: + for history in self.browser.get_history(account): + yield history diff --git a/modules/paypal/browser.py b/modules/paypal/browser.py new file mode 100644 index 00000000..630e0674 --- /dev/null +++ b/modules/paypal/browser.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 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.browser import BaseBrowser, BrowserIncorrectPassword +from .pages import LoginPage, AccountPage + + +__all__ = ['Paypal'] + + +class Paypal(BaseBrowser): + DOMAIN = 'www.paypal.com' + PROTOCOL = 'https' + # CERTHASH = '74429081f489cb723a82171a94350913d42727053fc86cf5bf5c3d65d39ec449' + ENCODING = None # refer to the HTML encoding + PAGES = { + '/cgi-bin/\?cmd=_login-run$': LoginPage, + '/cgi-bin/\?cmd=_login-submit.+$': LoginPage, # wrong login + '/cgi-bin/webscr\?cmd=_account&nav=0.0$': AccountPage, + } + + def home(self): + self.location('https://' + self.DOMAIN + '/en/cgi-bin/?cmd=_login-run') + + def is_logged(self): + # TODO Does not handle disconnect mid-session + return not self.is_on_page(LoginPage) + + def login(self): + assert isinstance(self.username, basestring) + assert isinstance(self.password, basestring) + + if not self.is_on_page(LoginPage): + self.location('https://' + self.DOMAIN + '/en/cgi-bin/?cmd=_login-run') + + self.page.login(self.username, self.password) + + if self.is_on_page(LoginPage): + raise BrowserIncorrectPassword() + + def get_account(self, _id): + if _id != u"1": + return None + + if not self.is_on_page(AccountPage): + self.location('/en/cgi-bin/webscr?cmd=_account&nav=0.0') + + return self.page.get_account() + + def get_history(self, account): + raise NotImplementedError() + + def transfer(self, from_id, to_id, amount, reason=None): + raise NotImplementedError() diff --git a/modules/paypal/pages.py b/modules/paypal/pages.py new file mode 100644 index 00000000..d232fe8f --- /dev/null +++ b/modules/paypal/pages.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 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 decimal import Decimal + +from weboob.tools.browser import BasePage +from weboob.capabilities.bank import Account +from weboob.tools.capabilities.bank.transactions import FrenchTransaction + +__all__ = ['LoginPage', 'AccountPage'] + + +class LoginPage(BasePage): + def login(self, login, password): + self.browser.select_form(name='login_form') + self.browser['login_email'] = login + self.browser['login_password'] = password + self.browser.submit(nologin=True) + + +class AccountPage(BasePage): + def get_account(self): + account = Account() + account.id = u"1" + account.label = unicode(self.browser.username) + account.type = Account.TYPE_CHECKING + + balance = self.document.xpath('//div[@id="main"]')[0] \ + .xpath('.//div[@class="col first"]//h3/span[@class="balance"]')[0] \ + .balance.text_content().strip() + account.balance = Decimal(FrenchTransaction.clean_amount(balance)) + account.currency = account.get_currency(balance) + + return account