Commit 8531e80c authored by Romain Bignon's avatar Romain Bignon

Update of modules

parent 4bb66891
......@@ -36,7 +36,7 @@ class SevenFiftyGramsModule(Module, CapRecipe):
NAME = '750g'
MAINTAINER = u'Julien Veyssier'
EMAIL = 'julien.veyssier@aiur.fr'
VERSION = '1.4'
VERSION = '1.5'
DESCRIPTION = u'750g French recipe website'
LICENSE = 'AGPLv3+'
BROWSER = SevenFiftyGramsBrowser
......
......@@ -32,7 +32,7 @@ class AdeccoModule(Module, CapJob):
DESCRIPTION = u'adecco website'
MAINTAINER = u'Bezleputh'
EMAIL = 'carton_ben@yahoo.fr'
VERSION = '1.4'
VERSION = '1.5'
BROWSER = AdeccoBrowser
......
......@@ -36,7 +36,7 @@ class AferModule(Module, CapBankWealth):
MAINTAINER = u'James GALT'
EMAIL = 'jgalt@budget-insight.com'
LICENSE = 'AGPLv3+'
VERSION = '1.4'
VERSION = '1.5'
BROWSER = AferBrowser
CONFIG = BackendConfig(ValueBackendPassword('login', label='Username', regexp='[A-z]\d+', masked=False),
......
......@@ -34,7 +34,7 @@ class AgendaculturelModule(Module, CapCalendarEvent):
MAINTAINER = u'Bezleputh'
EMAIL = 'carton_ben@yahoo.fr'
LICENSE = 'AGPLv3+'
VERSION = '1.4'
VERSION = '1.5'
ASSOCIATED_CATEGORIES = [CATEGORIES.CONCERT, CATEGORIES.THEATRE, CATEGORIES.EXPO, CATEGORIES.AUTRE, CATEGORIES.FEST]
BROWSER = AgendaculturelBrowser
......
......@@ -35,7 +35,7 @@ class AgendadulibreModule(Module, CapCalendarEvent):
MAINTAINER = u'Bezleputh'
EMAIL = 'carton_ben@yahoo.fr'
LICENSE = 'AGPLv3+'
VERSION = '1.4'
VERSION = '1.5'
ASSOCIATED_CATEGORIES = [CATEGORIES.CONF]
BROWSER = AgendadulibreBrowser
......
......@@ -35,7 +35,7 @@ class AllocineModule(Module, CapCinema, CapVideo, CapCalendarEvent, CapCollectio
NAME = 'allocine'
MAINTAINER = u'Julien Veyssier'
EMAIL = 'julien.veyssier@aiur.fr'
VERSION = '1.4'
VERSION = '1.5'
DESCRIPTION = u'AlloCiné French cinema database service'
LICENSE = 'AGPLv3+'
BROWSER = AllocineBrowser
......
......@@ -31,7 +31,7 @@ class AllrecipesModule(Module, CapRecipe):
NAME = 'allrecipes'
MAINTAINER = u'Julien Veyssier'
EMAIL = 'julien.veyssier@aiur.fr'
VERSION = '1.4'
VERSION = '1.5'
DESCRIPTION = u'Allrecipes English recipe website'
LICENSE = 'AGPLv3+'
BROWSER = AllrecipesBrowser
......
......@@ -40,7 +40,7 @@ class AmazonModule(Module, CapDocument):
MAINTAINER = 'Théo Dorée'
EMAIL = 'tdoree@budget-insight.com'
LICENSE = 'AGPLv3+'
VERSION = '1.4'
VERSION = '1.5'
website_choices = OrderedDict([(k, u'%s (%s)' % (v, k)) for k, v in sorted({
'www.amazon.com': u'Amazon.com',
......
......@@ -31,7 +31,7 @@ class AmazonStoreCardModule(Module, CapBank):
NAME = 'amazonstorecard'
MAINTAINER = u'Oleg Plakhotniuk'
EMAIL = 'olegus8@gmail.com'
VERSION = '1.4'
VERSION = '1.5'
LICENSE = 'AGPLv3+'
DESCRIPTION = u'Amazon Store Card'
CONFIG = BackendConfig(
......
......@@ -32,7 +32,7 @@ class AmeliModule(Module, CapDocument):
DESCRIPTION = 'Ameli website: French Health Insurance'
MAINTAINER = 'Christophe Lampin'
EMAIL = 'weboob@lampin.net'
VERSION = '1.4'
VERSION = '1.5'
LICENSE = 'AGPLv3+'
BROWSER = AmeliBrowser
CONFIG = BackendConfig(ValueBackendPassword('login', label='Numero de SS', regexp=r'^\d{13}$', masked=False),
......
......@@ -29,7 +29,7 @@ class AmeliProModule(Module, CapDocument):
DESCRIPTION = u'Ameli website: French Health Insurance for Professionals'
MAINTAINER = u'Christophe Lampin'
EMAIL = 'weboob@lampin.net'
VERSION = '1.4'
VERSION = '1.5'
LICENSE = 'AGPLv3+'
BROWSER = AmeliProBrowser
CONFIG = BackendConfig(ValueBackendPassword('login',
......
......@@ -33,7 +33,7 @@ class AmericanExpressModule(Module, CapBank):
NAME = 'americanexpress'
MAINTAINER = u'Romain Bignon'
EMAIL = 'romain@weboob.org'
VERSION = '1.4'
VERSION = '1.5'
DESCRIPTION = u'American Express'
LICENSE = 'AGPLv3+'
CONFIG = BackendConfig(ValueBackendPassword('login', label='Code utilisateur', masked=False),
......
......@@ -34,7 +34,7 @@ class AmundiModule(Module, CapBankWealth):
MAINTAINER = u'James GALT'
EMAIL = 'james.galt.bi@gmail.com'
LICENSE = 'AGPLv3+'
VERSION = '1.4'
VERSION = '1.5'
CONFIG = BackendConfig(ValueBackendPassword('login', label='Identifiant', regexp=r'\d+', masked=False),
ValueBackendPassword('password', label=u"Mot de passe", regexp=r'\d+'),
Value('website', label='Type de compte', default='ee',
......
......@@ -36,7 +36,7 @@ class AnticaptchaModule(Module, CapCaptchaSolver):
MAINTAINER = 'Vincent A'
EMAIL = 'dev@indigo.re'
LICENSE = 'AGPLv3+'
VERSION = '1.4'
VERSION = '1.5'
CONFIG = BackendConfig(
ValueBackendPassword('api_key', label='API key', regexp='^[0-9a-f]+$'),
......
......@@ -34,7 +34,7 @@ class ApecModule(Module, CapJob):
DESCRIPTION = u'apec website'
MAINTAINER = u'Bezleputh'
EMAIL = 'carton_ben@yahoo.fr'
VERSION = '1.4'
VERSION = '1.5'
BROWSER = ApecBrowser
......
......@@ -18,57 +18,64 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
from weboob.deprecated.browser import Browser, BrowserIncorrectPassword
from weboob.browser import LoginBrowser, URL, need_login
from weboob.capabilities.base import find_object
from weboob.exceptions import BrowserIncorrectPassword
from .pages import LoginPage, AccountsPage, OperationsPage
from .pages import LoginPage, AccountsPage, InvestmentsPage, OperationsPage
__all__ = ['ApivieBrowser']
class ApivieBrowser(Browser):
PROTOCOL = 'https'
DOMAIN = 'www.apivie.fr'
ENCODING = None
class ApivieBrowser(LoginBrowser):
login = URL(r'/$',
r'/accueil$',
r'/perte.*',
LoginPage)
accounts = URL(r'/accueil-connect', AccountsPage)
investments = URL(r'/synthese-contrat.*', InvestmentsPage)
operations = URL(r'/historique-contrat.*', OperationsPage)
PAGES = {
'https?://www.apivie.fr/': LoginPage,
'https?://www.apivie.fr/accueil': LoginPage,
'https?://www.apivie.fr/perte.*': LoginPage,
'https?://www.apivie.fr/accueil-connect': AccountsPage,
'https?://www.apivie.fr/historique-contrat.*': OperationsPage,
}
def __init__(self, website, *args, **kwargs):
self.BASEURL = 'https://%s' % website
super(ApivieBrowser, self).__init__(*args, **kwargs)
def home(self):
self.location('https://www.apivie.fr/accueil-connect')
self.location('%s/accueil-connect' % self.BASEURL)
def login(self):
assert isinstance(self.username, basestring)
assert isinstance(self.password, basestring)
if not self.is_on_page(LoginPage):
self.location('/accueil', no_login=True)
def do_login(self):
if not self.login.is_here():
self.location('/accueil')
self.page.login(self.username, self.password)
if not self.is_logged():
if self.login.is_here() or self.page is None:
raise BrowserIncorrectPassword()
def is_logged(self):
return not self.is_on_page(LoginPage)
@need_login
def iter_accounts(self):
self.location('/accueil-connect')
return self.page.iter_accounts()
@need_login
def get_account(self, _id):
try:
return next(a for a in self.iter_accounts() if a.id == _id)
except StopIteration:
return None
return find_object(self.iter_accounts(), id=_id)
@need_login
def iter_investment(self, account):
self.location('/synthese-contrat', params={'contratId': account.id})
assert self.investments.is_here()
return self.page.iter_investment()
@need_login
def iter_history(self, account):
self.location(self.buildurl('/historique-contrat', contratId=account.id))
self.location('/historique-contrat', params={'contratId': account.id})
assert self.is_on_page(OperationsPage)
assert self.operations.is_here()
return self.page.iter_history()
@need_login
def get_subscription_list(self):
return []
......@@ -32,7 +32,7 @@ class ApivieModule(Module, CapBankWealth):
DESCRIPTION = u'Apivie'
MAINTAINER = u'Romain Bignon'
EMAIL = 'romain@weboob.org'
VERSION = '1.4'
VERSION = '1.5'
BROWSER = ApivieBrowser
......@@ -40,17 +40,18 @@ class ApivieModule(Module, CapBankWealth):
ValueBackendPassword('password', label='Mot de passe'))
def create_default_browser(self):
return self.create_browser(self.config['login'].get(),
return self.create_browser('www.apivie.fr',
self.config['login'].get(),
self.config['password'].get())
def iter_accounts(self):
with self.browser:
return self.browser.iter_accounts()
return self.browser.iter_accounts()
def get_account(self, _id):
with self.browser:
return self.browser.get_account(_id)
return self.browser.get_account(_id)
def iter_investment(self, account):
return self.browser.iter_investment(account)
def iter_history(self, account):
with self.browser:
return self.browser.iter_history(account)
return self.browser.iter_history(account)
......@@ -20,59 +20,101 @@
from decimal import Decimal
from weboob.capabilities.bank import Account
from weboob.deprecated.browser import Page
from weboob.capabilities.bank import Account, Investment
from weboob.capabilities.base import NotAvailable
from weboob.browser.pages import LoggedPage, HTMLPage
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
from weboob.browser.filters.standard import Date, CleanText
from weboob.browser.filters.html import Attr
class LoginPage(Page):
class LoginPage(HTMLPage):
def login(self, username, password):
self.browser.select_form(nr=0)
self.browser['_58_login'] = username.encode('utf-8')
self.browser['_58_password'] = password.encode('utf-8')
self.browser.submit(nologin=True)
form = self.get_form(nr=0)
form['_58_login'] = username.encode('utf-8')
form['_58_password'] = password.encode('utf-8')
return form.submit()
class AccountsPage(Page):
class AccountsPage(LoggedPage, HTMLPage):
TYPES = {u'APIVIE': Account.TYPE_LIFE_INSURANCE,
u'LINXEA ZEN CLIENT': Account.TYPE_LIFE_INSURANCE,
u'PERP': Account.TYPE_PERP
}
COL_LABEL = 0
COL_OWNER = 1
COL_ID = 2
COL_AMOUNT = 3
def iter_accounts(self):
for line in self.document.xpath('//table[@summary="informations contrat"]/tbody/tr'):
for line in self.doc.xpath('//table[@summary="informations contrat"]/tbody/tr'):
yield self._get_account(line)
def _get_account(self, line):
cleaner = CleanText().filter
tds = line.findall('td')
account = Account()
account.id = self.parser.tocleanstring(tds[self.COL_ID])
account.label = self.parser.tocleanstring(tds[self.COL_LABEL])
balance_str = self.parser.tocleanstring(tds[self.COL_AMOUNT])
account.id = cleaner(tds[self.COL_ID])
account.label = cleaner(tds[self.COL_LABEL])
tlabel = Attr('//a[contains(@class, "logo")]/img', 'alt')(self.doc).upper()
account.type = self.TYPES.get(tlabel, Account.TYPE_UNKNOWN)
balance_str = cleaner(tds[self.COL_AMOUNT])
account.balance = Decimal(FrenchTransaction.clean_amount(balance_str))
account.currency = account.get_currency(balance_str)
return account
class InvestmentsPage(LoggedPage, HTMLPage):
COL_LABEL = 0
COL_CODE = 1
COL_VALUATION = 2
COL_PORTFOLIO_SHARE = 3
def iter_investment(self):
cleaner = CleanText().filter
for line in self.doc.xpath('//div[@class="supportTable"]//table/tbody/tr'):
tds = line.findall('td')
if len(tds) < 4:
continue
inv = Investment()
if self.doc.xpath('//div[@id="table-evolution-contrat"]//table/tbody/tr[1]/td[1]'):
inv.vdate = Date(dayfirst=True).filter(CleanText().filter(
self.doc.xpath('//div[@id="table-evolution-contrat"]//table/tbody/tr[1]/td[1]')))
else:
inv.vdate = NotAvailable
inv.label = cleaner(tds[self.COL_LABEL])
inv.code = cleaner(tds[self.COL_CODE])
inv.valuation = Decimal(FrenchTransaction.clean_amount(
cleaner(tds[self.COL_VALUATION])))
inv.portfolio_share = Decimal(FrenchTransaction.clean_amount(
cleaner(tds[self.COL_PORTFOLIO_SHARE]))) / 100
yield inv
class Transaction(FrenchTransaction):
pass
class OperationsPage(Page):
class OperationsPage(LoggedPage, HTMLPage):
COL_DATE = 0
COL_LABEL = 1
COL_AMOUNT = 2
def iter_history(self):
for line in self.document.xpath('//table[@role="treegrid"]/tbody/tr'):
cleaner = CleanText().filter
for line in self.doc.xpath('//table[@role="treegrid"]/tbody/tr'):
tds = line.findall('td')
operation = Transaction()
date = self.parser.tocleanstring(tds[self.COL_DATE])
label = self.parser.tocleanstring(tds[self.COL_LABEL])
amount = self.parser.tocleanstring(tds[self.COL_AMOUNT])
date = cleaner(tds[self.COL_DATE])
label = cleaner(tds[self.COL_LABEL])
amount = cleaner(tds[self.COL_AMOUNT])
if len(amount) == 0:
continue
......
# -*- coding: utf-8 -*-
# Copyright(C) 2013 franek
#
# 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 <http://www.gnu.org/licenses/>.
from .module import ArretSurImagesModule
__all__ = ['ArretSurImagesModule']
# -*- coding: utf-8 -*-
# Copyright(C) 2013 franek
#
# 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 <http://www.gnu.org/licenses/>.
from weboob.deprecated.browser import Browser, BrowserIncorrectPassword
from weboob.deprecated.browser.decorators import id2url
from .pages import VideoPage, IndexPage, LoginPage, LoginRedirectPage
from .video import ArretSurImagesVideo
__all__ = ['ArretSurImagesBrowser']
class ArretSurImagesBrowser(Browser):
PROTOCOL = 'http'
DOMAIN = 'www.arretsurimages.net'
ENCODING = None
PAGES = {
'%s://%s/contenu.php\?id=.+' % (PROTOCOL, DOMAIN): VideoPage,
'%s://%s/emissions.php' % (PROTOCOL, DOMAIN): IndexPage,
'%s://%s/forum/login.php' % (PROTOCOL, DOMAIN): LoginPage,
'%s://%s/forum/index.php' % (PROTOCOL, DOMAIN): LoginRedirectPage,
}
def home(self):
self.location('http://www.arretsurimages.net')
def search_videos(self, pattern):
self.location(self.buildurl('/emissions.php'))
assert self.is_on_page(IndexPage)
return self.page.iter_videos(pattern)
@id2url(ArretSurImagesVideo.id2url)
def get_video(self, url, video=None):
self.login()
self.location(url)
return self.page.get_video(video)
def is_logged(self):
return not self.is_on_page(LoginPage)
def login(self):
if not self.is_on_page(LoginPage):
self.location('http://www.arretsurimages.net/forum/login.php', no_login=True)
self.page.login(self.username, self.password)
if not self.is_logged():
raise BrowserIncorrectPassword()
def latest_videos(self):
self.location(self.buildurl('/emissions.php'))
assert self.is_on_page(IndexPage)
return self.page.iter_videos()
# -*- coding: utf-8 -*-
# Copyright(C) 2013 franek
#
# 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 <http://www.gnu.org/licenses/>.
from weboob.capabilities.video import CapVideo, BaseVideo
from weboob.capabilities.collection import CapCollection, CollectionNotFound
from weboob.tools.backend import Module, BackendConfig
from weboob.tools.value import ValueBackendPassword
from .browser import ArretSurImagesBrowser
from .video import ArretSurImagesVideo
__all__ = ['ArretSurImagesModule']
class ArretSurImagesModule(Module, CapVideo, CapCollection):
NAME = 'arretsurimages'
DESCRIPTION = u'arretsurimages website'
MAINTAINER = u'franek'
EMAIL = 'franek@chicour.net'
VERSION = '1.4'
CONFIG = BackendConfig(ValueBackendPassword('login', label='email', masked=False),
ValueBackendPassword('password', label='Password'))
BROWSER = ArretSurImagesBrowser
def create_default_browser(self):
return self.create_browser(self.config['login'].get(), self.config['password'].get(), get_home=False)
def search_videos(self, pattern, sortby=CapVideo.SEARCH_RELEVANCE, nsfw=False):
with self.browser:
return self.browser.search_videos(pattern)
# raise UserError('Search does not work on ASI website, use ls latest command')
def get_video(self, _id):
if _id.startswith('http://') and not _id.startswith('http://www.arretsurimages.net'):
return None
with self.browser:
return self.browser.get_video(_id)
def fill_video(self, video, fields):
if fields != ['thumbnail']:
# if we don't want only the thumbnail, we probably want also every fields
with self.browser:
video = self.browser.get_video(ArretSurImagesVideo.id2url(video.id), video)