The new woob repository is here: https://gitlab.com/woob/woob. This gitlab will be removed soon.

The new woob repository is here: https://gitlab.com/woob/woob. This gitlab will be removed soon.

Commit 7ba2f44a authored by Florian Duguet's avatar Florian Duguet Committed by Romain Bignon

[orange] remove CapMessage and port to python 3

Closes: https://git.weboob.org/weboob/devel/issues/152
parent 26d03d81
# -*- coding: utf-8 -*-
# Copyright(C) 2012-2014 Vincent Paredes
#
# 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 __future__ import unicode_literals
from weboob.browser import LoginBrowser, URL, need_login
from weboob.exceptions import BrowserIncorrectPassword
from .pages import LoginPage, BillsPage
from .pages.bills import SubscriptionsPage, BillsApiPage, ContractsPage
from .pages.profile import ProfilePage
from weboob.browser.exceptions import ClientError, ServerError
__all__ = ['OrangeBillBrowser']
class OrangeBillBrowser(LoginBrowser):
BASEURL = 'https://espaceclientv3.orange.fr/'
loginpage = URL('https://login.orange.fr/\?service=sosh&return_url=https://www.sosh.fr/',
'https://login.orange.fr/front/login', LoginPage)
contracts = URL('https://espaceclientpro.orange.fr/api/contracts\?page=1&nbcontractsbypage=15', ContractsPage)
subscriptions = URL(r'https://espaceclientv3.orange.fr/js/necfe.php\?zonetype=bandeau&idPage=gt-home-page', SubscriptionsPage)
billspage = URL('https://m.espaceclientv3.orange.fr/\?page=factures-archives',
'https://.*.espaceclientv3.orange.fr/\?page=factures-archives',
'https://espaceclientv3.orange.fr/\?page=factures-archives',
'https://espaceclientv3.orange.fr/\?page=facture-telecharger',
'https://espaceclientv3.orange.fr/maf.php',
'https://espaceclientv3.orange.fr/\?idContrat=(?P<subid>.*)&page=factures-historique',
'https://espaceclientv3.orange.fr/\?page=factures-historique&idContrat=(?P<subid>.*)',
BillsPage)
bills_api = URL('https://espaceclientpro.orange.fr/api/contract/(?P<subid>\d+)/bills\?count=(?P<count>)',
BillsApiPage)
doc_api = URL('https://espaceclientpro.orange.fr/api/contract/(?P<subid>\d+)/bill/(?P<dir>.*)/(?P<fact_type>.*)/\?(?P<billparams>)')
profile = URL('/\?page=profil-infosPerso', ProfilePage)
def do_login(self):
assert isinstance(self.username, basestring)
assert isinstance(self.password, basestring)
try:
self.loginpage.stay_or_go().login(self.username, self.password)
except ClientError as error:
if error.response.status_code == 401:
raise BrowserIncorrectPassword()
raise
def get_nb_remaining_free_sms(self):
raise NotImplementedError()
def post_message(self, message, sender):
raise NotImplementedError()
@need_login
def get_subscription_list(self):
profile = self.profile.go().get_profile()
# this only works when there are pro subs.
nb_sub = 0
try:
for sub in self.contracts.go().iter_subscriptions():
sub.subscriber = profile.name
yield sub
nb_sub = self.page.doc['totalContracts']
# assert pagination is not needed
assert nb_sub < 15
except ServerError:
pass
if nb_sub > 0:
return
# if nb_sub is 0, we continue, because we can get them in next url
self.location('https://espaceclientv3.orange.fr/?page=gt-home-page&sosh')
self.subscriptions.go()
for sub in self.page.iter_subscription():
sub.subscriber = profile.name
yield sub
@need_login
def iter_documents(self, subscription):
documents = []
if subscription._is_pro:
for d in self.bills_api.go(subid=subscription.id, count=72).get_bills(subid=subscription.id):
documents.append(d)
# check pagination for this subscription
assert len(documents) != 72
else:
self.billspage.go(subid=subscription.id)
for b in self.page.get_bills(subid=subscription.id):
documents.append(b)
return iter(documents)
@need_login
def get_profile(self):
return self.profile.go().get_profile()
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2011 Vincent Paredes
#
# 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 .login import LoginPage
from .bills import BillsPage
__all__ = ['LoginPage', 'BillsPage']
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2011 Vincent Paredes
#
# 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.browser.pages import HTMLPage
class LoginPage(HTMLPage):
def login(self, username, password):
json_data = {
'forcePwd': False,
'login': username,
'mem': True,
}
self.browser.location('https://login.orange.fr/front/login', json=json_data)
json_data = {
'login': username,
'password': password,
}
self.browser.location('https://login.orange.fr/front/password', json=json_data)
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2011 Nicolas Duhamel
# Copyright(C) 2012-2014 Vincent Paredes
#
# This file is part of weboob.
#
......@@ -17,52 +17,101 @@
# 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 __future__ import unicode_literals
#~ from .pages.compose import ClosePage, ComposePage, ConfirmPage, SentPage
#~ from .pages.login import LoginPage
from weboob.browser import LoginBrowser, URL, need_login
from weboob.exceptions import BrowserIncorrectPassword
from .pages import LoginPage, BillsPage
from .pages.bills import SubscriptionsPage, BillsApiPage, ContractsPage
from .pages.profile import ProfilePage
from weboob.browser.exceptions import ClientError, ServerError
from weboob.tools.compat import basestring
from .pages import LoginPage, ComposePage, ConfirmPage
from weboob.deprecated.browser import Browser, BrowserIncorrectPassword
__all__ = ['OrangeBillBrowser']
__all__ = ['OrangeBrowser']
class OrangeBillBrowser(LoginBrowser):
BASEURL = 'https://espaceclientv3.orange.fr/'
loginpage = URL('https://login.orange.fr/\?service=sosh&return_url=https://www.sosh.fr/',
'https://login.orange.fr/front/login', LoginPage)
class OrangeBrowser(Browser):
DOMAIN = 'orange.fr'
PAGES = {
'http://id.orange.fr/auth_user/bin/auth_user.cgi.*': LoginPage,
'http://id.orange.fr/auth_user/bin/auth0user.cgi.*': LoginPage,
'https://id.orange.fr/auth_user/bin/auth_user.cgi.*': LoginPage,
'https://id.orange.fr/auth_user/bin/auth0user.cgi.*': LoginPage,
'https://authweb.orange.fr/auth_user/bin/auth_user.cgi.*': LoginPage,
'https://authweb.orange.fr/auth_user/bin/auth0user.cgi.*': LoginPage,
'http://smsmms1.orange.fr/./Sms/sms_write.php.*' : ComposePage,
'http://smsmms1.orange.fr/./Sms/sms_write.php?command=send' : ConfirmPage,
'https://smsmms1.orange.fr/./Sms/sms_write.php.*' : ComposePage,
'https://smsmms1.orange.fr/./Sms/sms_write.php?command=send' : ConfirmPage,
}
contracts = URL('https://espaceclientpro.orange.fr/api/contracts\?page=1&nbcontractsbypage=15', ContractsPage)
def get_nb_remaining_free_sms(self):
self.location("http://smsmms1.orange.fr/M/Sms/sms_write.php")
return self.page.get_nb_remaining_free_sms()
subscriptions = URL(r'https://espaceclientv3.orange.fr/js/necfe.php\?zonetype=bandeau&idPage=gt-home-page', SubscriptionsPage)
billspage = URL('https://m.espaceclientv3.orange.fr/\?page=factures-archives',
'https://.*.espaceclientv3.orange.fr/\?page=factures-archives',
'https://espaceclientv3.orange.fr/\?page=factures-archives',
'https://espaceclientv3.orange.fr/\?page=facture-telecharger',
'https://espaceclientv3.orange.fr/maf.php',
'https://espaceclientv3.orange.fr/\?idContrat=(?P<subid>.*)&page=factures-historique',
'https://espaceclientv3.orange.fr/\?page=factures-historique&idContrat=(?P<subid>.*)',
BillsPage)
bills_api = URL('https://espaceclientpro.orange.fr/api/contract/(?P<subid>\d+)/bills\?count=(?P<count>)',
BillsApiPage)
def home(self):
self.location("http://smsmms1.orange.fr/M/Sms/sms_write.php")
doc_api = URL('https://espaceclientpro.orange.fr/api/contract/(?P<subid>\d+)/bill/(?P<dir>.*)/(?P<fact_type>.*)/\?(?P<billparams>)')
profile = URL('/\?page=profil-infosPerso', ProfilePage)
def is_logged(self):
self.location("http://smsmms1.orange.fr/M/Sms/sms_write.php", no_login=True)
return not self.is_on_page(LoginPage)
def do_login(self):
assert isinstance(self.username, basestring)
assert isinstance(self.password, basestring)
def login(self):
if not self.is_on_page(LoginPage):
self.location('https://authweb.orange.fr/auth_user/bin/auth_user.cgi?url=http://www.orange.fr', no_login=True)
self.page.login(self.username, self.password)
if not self.is_logged():
raise BrowserIncorrectPassword()
try:
self.loginpage.stay_or_go().login(self.username, self.password)
except ClientError as error:
if error.response.status_code == 401:
raise BrowserIncorrectPassword()
raise
def get_nb_remaining_free_sms(self):
raise NotImplementedError()
def post_message(self, message, sender):
if not self.is_on_page(ComposePage):
self.home()
self.page.post_message(message, sender)
raise NotImplementedError()
@need_login
def get_subscription_list(self):
profile = self.profile.go().get_profile()
# this only works when there are pro subs.
nb_sub = 0
try:
for sub in self.contracts.go().iter_subscriptions():
sub.subscriber = profile.name
yield sub
nb_sub = self.page.doc['totalContracts']
# assert pagination is not needed
assert nb_sub < 15
except ServerError:
pass
if nb_sub > 0:
return
# if nb_sub is 0, we continue, because we can get them in next url
self.location('https://espaceclientv3.orange.fr/?page=gt-home-page&sosh')
self.subscriptions.go()
for sub in self.page.iter_subscription():
sub.subscriber = profile.name
yield sub
@need_login
def iter_documents(self, subscription):
documents = []
if subscription._is_pro:
for d in self.bills_api.go(subid=subscription.id, count=72).get_bills(subid=subscription.id):
documents.append(d)
# check pagination for this subscription
assert len(documents) != 72
else:
self.billspage.go(subid=subscription.id)
for b in self.page.get_bills(subid=subscription.id):
documents.append(b)
return iter(documents)
@need_login
def get_profile(self):
return self.profile.go().get_profile()
......@@ -19,53 +19,29 @@
from weboob.capabilities.bill import CapDocument, Subscription, Document, SubscriptionNotFound, DocumentNotFound
from weboob.capabilities.messages import CantSendMessage, CapMessages, CapMessagesPost
from weboob.capabilities.base import find_object, NotAvailable
from weboob.capabilities.account import CapAccount, StatusField
from weboob.capabilities.account import CapAccount
from weboob.capabilities.profile import CapProfile
from weboob.tools.backend import Module, BackendConfig
from weboob.tools.value import ValueBackendPassword, Value
from .browser import OrangeBrowser
from .bill.browser import OrangeBillBrowser
from .browser import OrangeBillBrowser
__all__ = ['OrangeModule']
# We need to have a switcher, CapMessages use a browser1 and
# CapDocument use a browser2
# This will be remove when CapMessages use a browser2
def browser_switcher(b):
def set_browser(func):
def func_wrapper(*args, **kwargs):
self = args[0]
if self._browser is None or type(self._browser) != b:
self.BROWSER = b
try:
self._browser = self._browsers[b]
except KeyError:
self._browsers[b] = self.create_default_browser()
self._browser = self._browsers[b]
return func(*args, **kwargs)
return func_wrapper
return set_browser
class OrangeModule(Module, CapAccount, CapMessages, CapMessagesPost, CapDocument, CapProfile):
class OrangeModule(Module, CapAccount, CapDocument, CapProfile):
NAME = 'orange'
MAINTAINER = u'Lucas Nussbaum'
EMAIL = 'lucas@lucas-nussbaum.net'
MAINTAINER = 'Florian Duguet'
EMAIL = 'florian.duguet@budget-insight.com'
VERSION = '1.4'
DESCRIPTION = 'Orange French mobile phone provider'
LICENSE = 'AGPLv3+'
CONFIG = BackendConfig(Value('login', label='Login'),
ValueBackendPassword('password', label='Password'),
Value('phonenumber', label='Phone number', default='')
)
ACCOUNT_REGISTER_PROPERTIES = None
ValueBackendPassword('password', label='Password'))
BROWSER = OrangeBillBrowser
def __init__(self, *args, **kwargs):
self._browsers = dict()
super(OrangeModule, self).__init__(*args, **kwargs)
......@@ -73,38 +49,22 @@ def __init__(self, *args, **kwargs):
def create_default_browser(self):
return self.create_browser(self.config['login'].get(), self.config['password'].get())
@browser_switcher(OrangeBrowser)
def get_account_status(self):
return (StatusField('nb_remaining_free_sms', 'Number of remaining free SMS',
self.browser.get_nb_remaining_free_sms()),)
@browser_switcher(OrangeBrowser)
def post_message(self, message):
if not message.content.strip():
raise CantSendMessage(u'Message content is empty.')
self.browser.post_message(message, self.config['phonenumber'].get())
@browser_switcher(OrangeBillBrowser)
def iter_subscription(self):
return self.browser.get_subscription_list()
@browser_switcher(OrangeBillBrowser)
def get_subscription(self, _id):
return find_object(self.iter_subscription(), id=_id, error=SubscriptionNotFound)
@browser_switcher(OrangeBillBrowser)
def get_document(self, _id):
subid = _id.rsplit('_', 1)[0]
subscription = self.get_subscription(subid)
return find_object(self.iter_documents(subscription), id=_id, error=DocumentNotFound)
@browser_switcher(OrangeBillBrowser)
def iter_documents(self, subscription):
if not isinstance(subscription, Subscription):
subscription = self.get_subscription(subscription)
return self.browser.iter_documents(subscription)
@browser_switcher(OrangeBillBrowser)
def download_document(self, document):
if not isinstance(document, Document):
document = self.get_document(document)
......@@ -112,6 +72,5 @@ def download_document(self, document):
return
return self.browser.open(document.url).content
@browser_switcher(OrangeBillBrowser)
def get_profile(self):
return self.browser.get_profile()
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2011 Nicolas Duhamel
# Copyright(C) 2010-2011 Vincent Paredes
#
# This file is part of weboob.
#
......@@ -18,6 +18,6 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
from .login import LoginPage
from .compose import ComposePage, ConfirmPage
from .bills import BillsPage
__all__ = ['LoginPage', 'ComposePage', 'ConfirmPage']
__all__ = ['LoginPage', 'BillsPage']
......@@ -20,7 +20,7 @@
from __future__ import unicode_literals
import re
import HTMLParser
from html.parser import HTMLParser
from weboob.browser.pages import HTMLPage, LoggedPage, JsonPage
from weboob.capabilities.bill import Subscription
......@@ -49,14 +49,13 @@ class item(ItemElement):
obj_date = Date(Dict('dueDate'), parse_func=parse_french_date, default=NotAvailable)
obj_price = CleanDecimal(Dict('amountIncludingTax'))
obj_type = "bill"
obj_format = "pdf"
obj_format = 'pdf'
def obj_label(self):
return "Facture du %s" % Field('date')(self)
return 'Facture du %s' % Field('date')(self)
def obj_id(self):
return "%s_%s" % (Env('subid')(self), Field('date')(self).strftime('%d%m%Y'))
return '%s_%s' % (Env('subid')(self), Field('date')(self).strftime('%d%m%Y'))
def get_params(self):
params = {'billid': Dict('id')(self), 'billDate': Dict('dueDate')(self)}
......@@ -71,11 +70,11 @@ class get_bills(TableElement):
item_xpath = '//table[has-class("table-hover")]/div/div/tr | //table[has-class("table-hover")]/div/tr'
head_xpath = '//table[has-class("table-hover")]/thead/tr/th'
col_date = u'Date'
col_amount = [u'Montant TTC', u'Montant']
col_ht = u'Montant HT'
col_url = u'Télécharger'
col_infos = u'Infos paiement'
col_date = 'Date'
col_amount = ['Montant TTC', 'Montant']
col_ht = 'Montant HT'
col_url = 'Télécharger'
col_infos = 'Infos paiement'
class item(ItemElement):
klass = Bill
......@@ -109,7 +108,7 @@ def obj_currency(self):
def obj_url(self):
if Field('_url_base')(self):
# URL won't work if HTML is not unescape
return HTMLParser.HTMLParser().unescape(str(Field('_url_base')(self)))
return HTMLParser().unescape(str(Field('_url_base')(self)))
else :
return Link(TableCell(Field('_cell')(self))(self)[0].xpath('./a'), default=NotAvailable)(self)
......@@ -117,7 +116,7 @@ def obj_url(self):
def obj_label(self):
if Field('_label_base')(self):
return HTMLParser.HTMLParser().unescape(str(Field('_label_base')(self)))
return HTMLParser().unescape(str(Field('_label_base')(self)))
else:
return CleanText(TableCell(Field('_cell')(self))(self)[0].xpath('.//span[@class="ec_visually_hidden"]'))(self)
......
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2011 Nicolas Duhamel
#
# 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/>.
import re
from weboob.capabilities.messages import CantSendMessage
from weboob.deprecated.browser import Page
class ConfirmPage(Page):
def on_loaded(self):
pass
class ComposePage(Page):
phone_regex = re.compile('^(\+33|0033|0)(6|7)(\d{8})$')
def on_loaded(self):
# Deal with bad encoding... for ie6...
response = self.browser.response()
response.set_data(response.get_data().decode('utf-8', 'ignore'))
self.browser.set_response(response)
def get_nb_remaining_free_sms(self):
return "0"
def post_message(self, message, sender):
receiver = message.thread.id
if self.phone_regex.match(receiver) is None:
raise CantSendMessage(u'Invalid receiver: %s' % receiver)
listetel = ",," + receiver
#Fill the form
self.browser.select_form(name="formulaire")
self.browser.new_control("hidden", "autorize", {'value': ''})
self.browser.set_all_readonly(False)
self.browser["corpsms"] = message.content.encode('utf-8')
self.browser["pays"] = "33"
self.browser["listetel"] = listetel
self.browser["reply"] = "2"
self.browser["typesms"] = "2"
self.browser["produit"] = "1000"
self.browser["destToKeep"] = listetel
self.browser["NUMTEL"] = sender
self.browser["autorize"] = "1"
self.browser["msg"] = message.content.encode('utf-8')
self.browser.submit()
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2011 Nicolas Duhamel
# Copyright(C) 2010-2011 Vincent Paredes
#
# This file is part of weboob.
#
......@@ -17,36 +17,21 @@
# 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 Page
from weboob.tools.compat import urlencode
class LoginPage(Page):
def on_loaded(self):
pass
from weboob.browser.pages import HTMLPage
def login(self, user, pwd):
post_data = {"credential" : str(user),
"password" : str(pwd),
"save_user": "false",
"save_pwd" : "false",
"save_TC" : "true",
"action" : "valider",
"usertype" : "",
"service" : "",
"url" : "http://www.orange.fr",
"case" : "",
"origin" : "", }
post_data = urlencode(post_data)
self.browser.addheaders = [('Referer', 'http://id.orange.fr/auth_user/template/auth0user/htm/vide.html'),
("Content-Type" , 'application/x-www-form-urlencoded') ]
class LoginPage(HTMLPage):
def login(self, username, password):
json_data = {
'forcePwd': False,
'login': username,
'mem': True,
}
self.browser.location('https://login.orange.fr/front/login', json=json_data)
self.browser.open(self.browser.geturl(), data=post_data)
#~ print "LOGIN!!!"
#~ self.browser.select_form(predicate=lambda form: "id" in form.attrs and form.attrs["id"] == "authentication_form" )
#~ user_control = self.browser.find_control(id="user_credential")
#~ user_control.value = user
#~ pwd_control = self.browser.find_control(id="user_password")
#~ pwd_control.value = pwd
#~ self.browser.submit()
json_data = {
'login': username,
'password': password,
}
self.browser.location('https://login.orange.fr/front/password', json=json_data)
......@@ -101,6 +101,7 @@ nectarine
nova
oney
opensubtitles
orange
ouifm
pap
pariskiwi
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment