Commit 24ab5516 authored by jems's avatar jems Committed by Romain Bignon

add library capability and backend and application for archimede software...

add library capability and backend and application for archimede software aloes http://www.archimed.fr/aloes/presentation-et-avantages-12.htmlSigned-off-by: default avatarjems <jems@ldjm.fr>
Signed-off-by: Romain Bignon's avatarRomain Bignon <romain@symlink.me>
parent 2fbb21db
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2011 Jeremy Monnet
#
# 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 .backend import AloesBackend
__all__ = ['AloesBackend']
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2012 Jeremy Monnet
#
# 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 with_statement
from weboob.capabilities.library import ICapBook
from weboob.tools.backend import BaseBackend, BackendConfig
from weboob.tools.value import ValueBackendPassword, Value
from .browser import AloesBrowser
__all__ = ['AloesBackend']
class AloesBackend(BaseBackend, ICapBook):
NAME = 'opacwebaloes'
MAINTAINER = u'Jeremy Monnet'
EMAIL = 'jmonnet@gmail.com'
VERSION = '0.b'
DESCRIPTION = 'Aloes Library software'
LICENSE = 'AGPLv3+'
CONFIG = BackendConfig(Value('login', label='Account ID', regexp='^\d{1,6}\w$'),
ValueBackendPassword('password', label='Password of account'),
Value('baseurl', label='Base URL')
)
BROWSER = AloesBrowser
def create_default_browser(self):
return self.create_browser(self.config['baseurl'].get(),
self.config['login'].get(),
self.config['password'].get())
def get_rented(self):
for book in self.browser.get_rented_books_list():
yield book
def get_booked(self):
for book in self.browser.get_booked_books_list():
yield book
def iter_books(self):
for book in self.get_booked():
yield book
for book in self.get_rented():
yield book
def get_book(self, _id):
raise NotImplementedError()
def search_books(self, _string):
raise NotImplementedError()
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2012 Jeremy Monnet
#
# 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.tools.browser import BaseBrowser, BrowserIncorrectPassword
from .pages import LoginPage, HomePage, RentedPage, HistoryPage, BookedPage
__all__ = ['AloesBrowser']
# Browser
class AloesBrowser(BaseBrowser):
PROTOCOL = 'http'
ENCODING = 'utf-8'
USER_AGENT = BaseBrowser.USER_AGENTS['desktop_firefox']
#DEBUG_HTTP = True
DEBUG_HTTP = False
PAGES = {
'http://.*/index.aspx': LoginPage,
'http://.*/index.aspx\?IdPage=1': HomePage,
'http://.*/index.aspx\?IdPage=45': RentedPage,
'http://.*/index.aspx\?IdPage=429': HistoryPage,
'http://.*/index.aspx\?IdPage=44': BookedPage
}
def __init__(self, baseurl, *args, **kwargs):
self.BASEURL=baseurl
BaseBrowser.__init__(self, *args, **kwargs)
def is_logged(self):
return self.page \
and not self.page.document.getroot().xpath('//input[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl08_ctl00_TextSaisie")]')
#return True
def login(self):
assert isinstance(self.username, basestring)
assert isinstance(self.password, basestring)
if not self.is_on_page(HomePage):
self.location('%s://%s/index.aspx' \
% (self.PROTOCOL, self.BASEURL),
no_login=True)
if not self.page.login(self.username, self.password) or \
not self.is_logged() or \
(self.is_on_page(LoginPage) and self.page.is_error()) :
raise BrowserIncorrectPassword()
def get_rented_books_list(self):
if not self.is_on_page(RentedPage):
self.location('%s://%s/index.aspx?IdPage=45' \
% (self.PROTOCOL, self.BASEURL)
)
return self.page.get_list()
def get_booked_books_list(self):
if not self.is_on_page(BookedPage):
self.location('%s://%s/index.aspx?IdPage=44' \
% (self.PROTOCOL, self.BASEURL))
return self.page.get_list()
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2012 Jeremy Monnet
#
# 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 datetime import date
from weboob.capabilities.library import Book
from weboob.tools.browser import BasePage, BrowserUnavailable
from weboob.tools.mech import ClientForm
class SkipPage(BasePage):
pass
class HomePage(BasePage):
pass
def txt2date(s):
return date(*reversed([int(x) for x in s.split(' ')[-1].split('/')]))
class RentedPage(BasePage):
# TODO, table limited to 20 items, need to use pagination
def get_list(self):
for book in self.iter_books('//tr[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl07_COMPTE_PRET_1_1_GrillePrets_ctl00__")]', 1):
book.late = False
yield book
for book in self.iter_books('//tr[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl08_COMPTE_RETARD_0_1_GrilleRetards_ctl00__")]', 0):
book.late = True
yield book
def iter_books(self, el, start):
for tr in self.document.getroot().xpath(el):
book = Book(tr[start].text)
book.name = tr[start+3].text
book.author = tr[start+4].text
book.date = txt2date(tr[start+5].text)
yield book
class HistoryPage(BasePage):
pass
class BookedPage(BasePage):
# TODO, table limited to 20 items, need to use pagination
def get_list(self):
for tr in self.document.getroot().xpath('//tr[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl09_COMPTE_INFOS_0_GrilleInfos_ctl00__0")]'):
username=tr[1].text+"_"+tr[0].text
for i, tr in enumerate(self.document.getroot().xpath('//tr[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl10_COMPTE_RESA_1_1_GrilleResas_ctl00__")]')):
book = Book('%s%d' % (username, i))
# if all the books booked are available, there are only 7 columns.
# if (at least ?) one book is still not available, yous can cancel, and the first column does contain the checkbox. So 8 columns.
if (len(tr) == 7):
start = 2
if (len(tr) == 8):
start = 3
book.name = tr[start].text
book.author = tr[start+1].text
book.date = txt2date(tr[start+3].text)
book.late = False
yield book
class LoginPage(BasePage):
def login(self, login, passwd):
self.browser.select_form(predicate=lambda x: x.attrs.get('id','')=='aspnetForm')
self.browser.form.set_all_readonly(False)
self.browser['ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$TextSaisie'] = login
self.browser['ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$TextPass'] = passwd
self.browser['ctl00_ScriptManager1_TSM']="%3B%3BSystem.Web.Extensions%2C%20Version%3D1.0.61025.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3D31bf3856ad364e35%3Afr-FR%3A1f0f78f9-0731-4ae9-b308-56936732ccb8%3Aea597d4b%3Ab25378d2%3BTelerik.Web.UI%2C%20Version%3D2009.3.1314.20%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3D121fae78165ba3d4%3Afr-FR%3Aec1048f9-7413-49ac-913a-b3b534cde186%3A16e4e7cd%3Aed16cbdc%3Af7645509%3A24ee1bba%3A19620875%3A874f8ea2%3A33108d14%3Abd8f85e4"
self.browser.controls.append(ClientForm.TextControl('text', 'RadAJAXControlID', {'value': ''}))
self.browser['RadAJAXControlID']="ctl00_ContentPlaceHolder1_ctl00_ctl04_ctl00_RadAjaxPanelConnexion"
self.browser.controls.append(ClientForm.TextControl('text', 'ctl00$ScriptManager1', {'value': ''}))
self.browser['ctl00$ScriptManager1']="ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$RadAjaxPanelConnexionPanel|"
self.browser.controls.append(ClientForm.TextControl('text', '__EVENTTARGET', {'value': ''}))
self.browser.controls.append(ClientForm.TextControl('text', '__EVENTARGUMENT', {'value': ''}))
self.browser.controls.append(ClientForm.TextControl('text', 'ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$btnImgConnexion.x', {'value': ''}))
self.browser['ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$btnImgConnexion.x']="76"
self.browser.controls.append(ClientForm.TextControl('text', 'ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$btnImgConnexion.y', {'value': ''}))
self.browser['ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$btnImgConnexion.y']="10"
try:
self.browser.submit()
except BrowserUnavailable:
# Login is not valid
return False
return True
def is_error(self):
for text in self.document.find('body').itertext():
text=text.strip()
# Login seems valid, but password does not
needle='Echec lors de l\'authentification'
if text.startswith(needle.decode('utf-8')):
return True
return False
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2011 Jeremy Monnet
#
# 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.tools.test import BackendTest
class AloestTest(BackendTest):
BACKEND = 'aloes'
def test_aloes(self):
pass
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: ft=python et softtabstop=4 cinoptions=4 shiftwidth=4 ts=4 ai
# Copyright(C) 2012 Jeremy Monnet
#
# 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.applications.boobooks import Boobooks
if __name__ == '__main__':
Boobooks.run()
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2011 Jérémy Monnet
#
# 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 .boobooks import Boobooks
__all__ = ['Boobooks']
# -*- coding: utf-8 -*-
# Copyright(C) 2009-2012 Jeremy Monnet
#
# 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.library import ICapBook, Book
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.formatters.iformatter import IFormatter
__all__ = ['Boobooks']
class RentedListFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'date', 'author', 'name', 'late')
RED = ''
count = 0
def flush(self):
self.count = 0
def format_dict(self, item):
self.count += 1
if self.interactive:
backend = item['id'].split('@', 1)[1]
id = '#%d (%s)' % (self.count, backend)
else:
id = item['id']
s = u'%s%s%s %s — %s (%s)' % (self.BOLD, id, self.NC, item['author'], item['name'], item['date'])
if item['late']:
s += u' %sLATE!%s' % (self.RED, self.NC)
return s
class Boobooks(ReplApplication):
APPNAME = 'boobooks'
VERSION = '0.b'
COPYRIGHT = 'Copyright(C) 2012 Jeremy Monnet'
CAPS = ICapBook
DESCRIPTION = "Console application allowing to list your books rented or booked at the library, " \
"book and search new ones, get your booking history (if available)."
EXTRA_FORMATTERS = {'rented_list': RentedListFormatter,
}
DEFAULT_FORMATTER = 'table'
COMMANDS_FORMATTERS = {'ls': 'rented_list',
'list': 'rented_list',
}
COLLECTION_OBJECTS = (Book, )
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2012 Jeremy Monnet
#
# 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 datetime import datetime, date
from .collection import ICapCollection, CollectionNotFound
from .base import CapBaseObject
__all__ = ['ICapBook', 'Book']
class Book(CapBaseObject):
def __init__(self, id):
CapBaseObject.__init__(self, id)
self.add_field('name', basestring)
self.add_field('author', basestring)
self.add_field('location', basestring)
self.add_field('date', (datetime, date)) # which may be the due date
self.add_field('late', bool)
class ICapBook(ICapCollection):
def iter_resources(self, objs, split_path):
if Book in objs:
if len(split_path) > 0:
raise CollectionNotFound(split_path)
return self.iter_books()
def iter_books(self, pattern):
raise NotImplementedError()
def get_book(self, _id):
raise NotImplementedError()
def get_booked(self, _id):
raise NotImplementedError()
def get_rented(self, _id):
raise NotImplementedError()
def search_books(self, _string):
raise NotImplementedError()
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