Пример #1
0
class VicSecCardModule(Module, CapBank):
    NAME = 'vicseccard'
    MAINTAINER = u'Oleg Plakhotniuk'
    EMAIL = '*****@*****.**'
    VERSION = '1.3'
    LICENSE = 'AGPLv3+'
    DESCRIPTION = u'Victoria\'s Secret Angel Card'
    CONFIG = BackendConfig(
        ValueBackendPassword('username', label='User name', masked=False),
        ValueBackendPassword('password', label='Password'))
    BROWSER = VicSecCard

    def create_default_browser(self):
        return self.create_browser(self.config['username'].get(),
                                   self.config['password'].get())

    def iter_accounts(self):
        return self.browser.iter_accounts()

    def get_account(self, id_):
        return self.browser.get_account(id_)

    def iter_history(self, account):
        return self.browser.iter_history(account)
Пример #2
0
class MyFonciaModule(Module, CapDocument):
    NAME = 'myfoncia'
    DESCRIPTION = u'Foncia billing capabilities'
    MAINTAINER = u'Phyks (Lucas Verney)'
    EMAIL = '*****@*****.**'
    LICENSE = 'LGPLv3+'
    VERSION = '2.1'
    CONFIG = BackendConfig(
        Value(
            'login',
            label='Email address or Foncia ID'
        ),
        ValueBackendPassword(
            'password',
            label='Password'
        )
    )
    BROWSER = MyFonciaBrowser

    def create_default_browser(self):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get())

    def iter_subscription(self):
        return self.browser.get_subscriptions()

    def iter_documents(self, subscription):
        if isinstance(subscription, Subscription):
            subscription_id = subscription.id
        else:
            subscription_id = subscription
        return self.browser.get_documents(subscription_id)

    def get_document(self, bill):
        return find_object(
            self.iter_documents(bill.split("#")[0]),
            id=bill,
            error=DocumentNotFound
        )

    def download_document(self, bill):
        if not isinstance(bill, Bill):
            bill = self.get_document(bill)

        if not bill.url:
            return None

        return self.browser.open(bill.url).content
Пример #3
0
class MetalarchivesModule(Module, CapBands):
    NAME = 'metalarchives'
    DESCRIPTION = 'Metal Archives: Encyclopedia Metallum'
    MAINTAINER = 'qdef'
    EMAIL = '*****@*****.**'
    LICENSE = 'AGPLv3+'
    VERSION = '1.4'
    BROWSER = MetalarchivesBrowser

    CONFIG = BackendConfig(
        Value('login', label='Metal archives ID'),
        ValueBackendPassword('password', label='Metal archives password'))

    #Login credentials
    def create_default_browser(self, *args, **kwargs):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get(), *args,
                                   **kwargs)

    # Method to search for a band pattern:
    def iter_band_search(self, pattern):
        self.bands = list(self.browser.iter_band_search(pattern))
        # In case the city search returns no results:
        if not self.bands:
            raise BandNotFound('Sorry, no result matched your query.')
        return self.bands

    # Get the discography of a band:
    def get_albums(self, id):
        return self.browser.get_albums(id)

    # Method to retrieve the weather data for one specific city:
    def get_info(self, id):
        return self.browser.get_info(id)

    # Method to retrieve you favorite bands:
    def get_favorites(self):
        return self.browser.get_favorites()

    def suggestions(self):
        return self.browser.suggestions(self.get_bands())

    def get_bands(self):
        bands = list(self.get_favorites())
        band_ids = []
        for band in bands:
            band_ids.append(band.id)
        return band_ids
Пример #4
0
class TrainlineModule(Module, CapDocument):
    NAME = 'trainline'
    DESCRIPTION = u'trainline website'
    MAINTAINER = u'Edouard Lambert'
    EMAIL = '*****@*****.**'
    LICENSE = 'AGPLv3+'
    VERSION = '1.4'
    CONFIG = BackendConfig(
        Value('login', label='Adresse email'),
        ValueBackendPassword('password', label='Mot de passe'))

    BROWSER = TrainlineBrowser

    def create_default_browser(self):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get())

    def iter_subscription(self):
        return self.browser.get_subscription_list()

    def get_subscription(self, _id):
        return find_object(self.iter_subscription(),
                           id=_id,
                           error=SubscriptionNotFound)

    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)

    def iter_documents(self, subscription):
        if not isinstance(subscription, Subscription):
            subscription = self.get_subscription(subscription)
        return self.browser.iter_documents(subscription)

    def download_document(self, document):
        if not isinstance(document, Document):
            document = self.get_document(document)
        if document._url is NotAvailable:
            return

        return self.browser.open(document._url, headers={
            'Authorization': ''
        }).content
Пример #5
0
class MyFonciaModule(Module, CapDocument):
    NAME = 'myfoncia'
    DESCRIPTION = u'Foncia billing capabilities'
    MAINTAINER = u'Phyks (Lucas Verney)'
    EMAIL = '*****@*****.**'
    LICENSE = 'AGPLv3+'
    VERSION = '1.4'
    CONFIG = BackendConfig(
        Value(
            'login',
            label='Email address or Foncia ID'
        ),
        ValueBackendPassword(
            'password',
            label='Password'
        )
    )
    BROWSER = MyFonciaBrowser

    def create_default_browser(self):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get())

    def iter_subscription(self):
        return self.browser.get_subscriptions()

    def iter_documents(self, subscription):
        return self.browser.get_documents(subscription)

    def get_document(self, bill):
        try:
            return next(
                document
                for document in self.iter_documents(bill.split("#")[0])
                if document.id == bill
            )
        except StopIteration:
            raise DocumentNotFound

    def download_document(self, bill):
        if not isinstance(bill, Bill):
            bill = self.get_document(bill)

        if not bill.url:
            return None

        return self.browser.open(bill.url).content
Пример #6
0
class BouyguesModule(Module, CapMessages, CapMessagesPost, CapBill):
    NAME = 'bouygues'
    MAINTAINER = u'Bezleputh'
    EMAIL = '*****@*****.**'
    VERSION = '1.1'
    DESCRIPTION = u'Bouygues Télécom French mobile phone provider'
    LICENSE = 'AGPLv3+'
    CONFIG = BackendConfig(Value('login', label='Login/Phone number'),
                           ValueBackendPassword('password', label='Password'))
    BROWSER = BouyguesBrowser

    def create_default_browser(self):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get())

    def post_message(self, message):
        if not message.content.strip():
            raise CantSendMessage(u'Message content is empty.')
        self.browser.post_message(message)

    def iter_subscription(self):
        return self.browser.get_subscription_list()

    def get_subscription(self, _id):
        return find_object(self.iter_subscription(),
                           id=_id,
                           error=SubscriptionNotFound)

    def get_bill(self, _id):
        subid = _id.split('.')[0]
        subscription = self.get_subscription(subid)

        return find_object(self.iter_bills(subscription),
                           id=_id,
                           error=BillNotFound)

    def iter_bills(self, subscription):
        if not isinstance(subscription, Subscription):
            subscription = self.get_subscription(subscription)
        return self.browser.iter_bills(subscription)

    def download_bill(self, bill):
        if not isinstance(bill, Bill):
            bill = self.get_bill(bill)
        return self.browser.open(
            'http://www.bouyguestelecom.fr/mon-compte/suiviconso/index/facturepdf?id=%s'
            % bill._id_bill).content
Пример #7
0
class EdfModule(Module, CapDocument, CapProfile):
    NAME = 'edf'
    DESCRIPTION = u'EDF'
    MAINTAINER = u'Edouard Lambert'
    EMAIL = '*****@*****.**'
    LICENSE = 'LGPLv3+'
    VERSION = '1.6'
    CONFIG = BackendConfig(Value('login', label='E-mail ou Identifiant'),
                           ValueBackendPassword('password', label='Mot de passe'),
                           Value('website', label='Type de compte', default='par',
                                 choices={'par': 'Particulier', 'pro': 'Entreprise'}),
                           Value('otp', label='Entrez le code reçu par SMS', required=False))

    accepted_document_types = (DocumentTypes.BILL,)

    def create_default_browser(self):
        browsers = {'pro': EdfproBrowser, 'par': EdfBrowser}
        self.BROWSER = browsers[self.config['website'].get()]

        return self.create_browser(self.config)

    def iter_subscription(self):
        return self.browser.get_subscription_list()

    def get_subscription(self, _id):
        return find_object(self.iter_subscription(), id=_id, error=SubscriptionNotFound)

    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)

    def iter_documents(self, subscription):
        if not isinstance(subscription, Subscription):
            subscription = self.get_subscription(subscription)
        return self.browser.iter_documents(subscription)

    def download_document(self, document):
        if not isinstance(document, Document):
            document = self.get_document(document)
        return self.browser.download_document(document)

    def get_profile(self):
        return self.browser.get_profile()
Пример #8
0
class OvhModule(Module, CapDocument):
    NAME = 'ovh'
    DESCRIPTION = u'Ovh'
    MAINTAINER = u'Vincent Paredes'
    EMAIL = '*****@*****.**'
    LICENSE = 'LGPLv3+'
    VERSION = '1.6'
    CONFIG = BackendConfig(
        Value('login', label='Account ID'),
        ValueBackendPassword('password', label='Password'),
        Value('pin_code', label='Code PIN / Email', required=False,
              default=''))

    BROWSER = OvhBrowser

    accepted_document_types = (DocumentTypes.BILL, )

    def create_default_browser(self):
        return self.create_browser(self.config)

    def iter_subscription(self):
        return self.browser.get_subscription_list()

    def get_subscription(self, _id):
        return find_object(self.iter_subscription(),
                           id=_id,
                           error=SubscriptionNotFound)

    def get_document(self, _id):
        subid = _id.split('.')[0]
        subscription = self.get_subscription(subid)

        return find_object(self.iter_documents(subscription),
                           id=_id,
                           error=DocumentNotFound)

    def iter_documents(self, subscription):
        if not isinstance(subscription, Subscription):
            subscription = self.get_subscription(subscription)
        return self.browser.iter_documents(subscription)

    def download_document(self, bill):
        if not isinstance(bill, Bill):
            bill = self.get_document(bill)
        return self.browser.open(bill.url).content
Пример #9
0
class BouyguesModule(Module, CapMessages, CapMessagesPost, CapDocument):
    NAME = 'bouygues'
    MAINTAINER = u'Bezleputh'
    EMAIL = '*****@*****.**'
    VERSION = '1.4'
    DESCRIPTION = u'Bouygues Télécom French mobile phone provider'
    LICENSE = 'AGPLv3+'
    CONFIG = BackendConfig(Value('login', label='Login/Phone number'),
                           ValueBackendPassword('password', label='Password'))
    BROWSER = BouyguesBrowser

    def create_default_browser(self):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get())

    def post_message(self, message):
        if not message.content.strip():
            raise CantSendMessage(u'Message content is empty.')
        self.browser.post_message(message)

    def iter_subscription(self):
        return self.browser.get_subscription_list()

    def get_subscription(self, _id):
        return find_object(self.iter_subscription(),
                           id=_id,
                           error=SubscriptionNotFound)

    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)

    def iter_documents(self, subscription):
        if not isinstance(subscription, Subscription):
            subscription = self.get_subscription(subscription)
        return self.browser.iter_documents(subscription)

    def download_document(self, document):
        if not isinstance(document, Document):
            document = self.get_document(document)
        return self.browser.open(document.url).content
Пример #10
0
class FreeModule(Module, CapDocument, CapProfile):
    NAME = 'free'
    DESCRIPTION = u'free website'
    MAINTAINER = u'Edouard Lambert'
    EMAIL = '*****@*****.**'
    LICENSE = 'LGPLv3+'
    VERSION = '2.1'
    CONFIG = BackendConfig(Value('login', label='Identifiant'),
                           ValueBackendPassword('password', label='Mot de passe'))

    BROWSER = FreeBrowser

    accepted_document_types = (DocumentTypes.BILL,)

    def create_default_browser(self):
        return self.create_browser(self.config['login'].get(), self.config['password'].get())

    def iter_subscription(self):
        return self.browser.get_subscription_list()

    def get_subscription(self, _id):
        return find_object(self.iter_subscription(), id=_id, error=SubscriptionNotFound)

    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)

    def iter_documents(self, subscription):
        if not isinstance(subscription, Subscription):
            subscription = self.get_subscription(subscription)
        return self.browser.iter_documents(subscription)

    def download_document(self, document):
        if not isinstance(document, Document):
            document = self.get_document(document)
        if document.url is NotAvailable:
            return
        return self.browser.open(document.url).content

    def get_profile(self):
        return self.browser.get_profile()
Пример #11
0
class MediawikiModule(Module, CapContent):
    NAME = 'mediawiki'
    MAINTAINER = u'Clément Schreiner'
    EMAIL = '*****@*****.**'
    VERSION = '1.1'
    LICENSE = 'AGPLv3+'
    DESCRIPTION = 'Wikis running MediaWiki, like Wikipedia'
    CONFIG = BackendConfig(Value('url',      label='URL of the Mediawiki website', default='http://en.wikipedia.org/', regexp='https?://.*'),
                           Value('apiurl',   label='URL of the Mediawiki website\'s API', default='http://en.wikipedia.org/w/api.php', regexp='https?://.*'),
                           Value('username', label='Login', default=''),
                           ValueBackendPassword('password', label='Password', default=''))

    BROWSER = MediawikiBrowser

    def create_default_browser(self):
        username = self.config['username'].get()
        if len(username) > 0:
            password = self.config['password'].get()
        else:
            password = None
        return self.create_browser(self.config['url'].get(),
                                   self.config['apiurl'].get(),
                                   username, password)

    def get_content(self, _id, revision=None):
        _id = _id.replace(' ', '_')
        content = Content(_id)
        page = _id
        rev = revision.id if revision else None
        with self.browser:
            data = self.browser.get_wiki_source(page, rev)

        content.content = data
        return content

    def iter_revisions(self, _id):
        return self.browser.iter_wiki_revisions(_id)

    def push_content(self, content, message=None, minor=False):
        self.browser.set_wiki_source(content, message, minor)

    def get_content_preview(self, content):
        return self.browser.get_wiki_preview(content)
Пример #12
0
class AnticaptchaModule(Module, CapCaptchaSolver):
    NAME = 'anticaptcha'
    DESCRIPTION = 'Anti-Captcha website'
    MAINTAINER = 'Vincent A'
    EMAIL = '*****@*****.**'
    LICENSE = 'AGPLv3+'
    VERSION = '1.6'

    CONFIG = BackendConfig(
        ValueBackendPassword('api_key', label='API key', regexp='^[0-9a-f]+$'),
        # TODO support proxy option
    )

    BROWSER = AnticaptchaBrowser

    def create_default_browser(self):
        return self.create_browser(self.config['api_key'].get(), None)

    def create_job(self, job):
        if isinstance(job, ImageCaptchaJob):
            job.id = self.browser.post_image(job.image)
        elif isinstance(job, RecaptchaJob):
            job.id = self.browser.post_recaptcha(job.site_url, job.site_key)
        elif isinstance(job, RecaptchaV3Job):
            job.id = self.browser.post_gcaptchav3(job.site_url, job.site_key,
                                                  job.action)
        elif isinstance(job, NocaptchaJob):
            job.id = self.browser.post_nocaptcha(job.site_url, job.site_key)
        elif isinstance(job, FuncaptchaJob):
            job.id = self.browser.post_funcaptcha(job.site_url, job.site_key,
                                                  job.sub_domain)
        else:
            raise NotImplementedError()

    def poll_job(self, job):
        return self.browser.poll(job)

    def report_wrong_solution(self, job):
        if isinstance(job, ImageCaptchaJob):
            self.browser.report_wrong(job)

    def get_balance(self):
        return self.browser.get_balance()
Пример #13
0
class LdlcModule(Module, CapBill):
    NAME = 'ldlc'
    DESCRIPTION = u'ldlc website'
    MAINTAINER = u'Vincent Paredes'
    EMAIL = '*****@*****.**'
    LICENSE = 'AGPLv3+'
    VERSION = '1.2'
    CONFIG = BackendConfig(Value('login', label='Email'),
                       ValueBackendPassword('password', label='Password'),
                       Value('website', label='Site web', default='part',
                                                 choices={'pro': 'Professionnels',
                                                     'part': 'Particuliers'}))


    BROWSER = LdlcBrowser

    def create_default_browser(self):
        return self.create_browser(self.config['website'].get(),
                                   self.config['login'].get(),
                                   self.config['password'].get())

    def iter_subscription(self):
        return self.browser.get_subscription_list()

    def get_subscription(self, _id):
        return find_object(self.iter_subscription(), id=_id, error=SubscriptionNotFound)

    def get_bill(self, _id):
        subid = _id.split('_')[0]
        subscription = self.get_subscription(subid)

        return find_object(self.iter_bills(subscription), id=_id, error=BillNotFound)

    def iter_bills(self, subscription):
        if not isinstance(subscription, Subscription):
            subscription = self.get_subscription(subscription)
        return self.browser.iter_bills(subscription)

    def download_bill(self, bill):
        if not isinstance(bill, Bill):
            bill = self.get_bill(bill)
        return self.browser.open(bill._url).content
Пример #14
0
class Number26Module(Module, CapBank):
    NAME = 'n26'
    DESCRIPTION = u'Bank N26'
    MAINTAINER = u'Benjamin Bouvier'
    EMAIL = '*****@*****.**'
    LICENSE = 'LGPLv3+'
    VERSION = '2.1'

    BROWSER = Number26Browser

    CONFIG = BackendConfig(
                 Value('login', label='Email', regexp='.+'),
                 ValueBackendPassword('password', label='Password'),
                 ValueTransient('otp'),
                 ValueTransient('request_information')
             )

    STORAGE = {'categories': {}}

    def get_categories(self):
        categories = self.storage.get("categories", None)
        if categories is None:
            categories = self.browser.get_categories()
            self.storage.set("categories", categories)
        return categories

    def create_default_browser(self):
        return self.create_browser(self.config)

    def iter_accounts(self):
        return self.browser.get_accounts()

    def get_account(self, id):
        return self.browser.get_account(id)

    def iter_history(self, account):
        categories = self.get_categories()
        return self.browser.get_transactions(categories)

    def iter_coming(self, account):
        categories = self.get_categories()
        return self.browser.get_coming(categories)
Пример #15
0
class OvhModule(Module, CapBill):
    NAME = 'ovh'
    DESCRIPTION = u'ovh website'
    MAINTAINER = u'Vincent Paredes'
    EMAIL = '*****@*****.**'
    LICENSE = 'AGPLv3+'
    VERSION = '1.2'
    CONFIG = BackendConfig(Value('login', label='Account ID'),
                           ValueBackendPassword('password', label='Password'))

    BROWSER = OvhBrowser

    def create_default_browser(self):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get())

    def iter_subscription(self):
        return self.browser.get_subscription_list()

    def get_subscription(self, _id):
        return find_object(self.iter_subscription(),
                           id=_id,
                           error=SubscriptionNotFound)

    def get_bill(self, _id):
        subid = _id.split('.')[0]
        subscription = self.get_subscription(subid)

        return find_object(self.iter_bills(subscription),
                           id=_id,
                           error=BillNotFound)

    def iter_bills(self, subscription):
        if not isinstance(subscription, Subscription):
            subscription = self.get_subscription(subscription)
        return self.browser.iter_bills(subscription)

    def download_bill(self, bill):
        if not isinstance(bill, Bill):
            bill = self.get_bill(bill)
        return self.browser.open(bill._url).content
Пример #16
0
class MetalarchivesModule(Module, CapBands):
    NAME = 'metalarchives'
    DESCRIPTION = 'Metal Archives: Encyclopedia Metallum'
    MAINTAINER = 'Quentin Defenouillère'
    EMAIL = '*****@*****.**'
    LICENSE = 'LGPLv3+'
    VERSION = '2.1'
    BROWSER = MetalArchivesBrowser

    CONFIG = BackendConfig(
        Value('login', label='Metal archives ID'),
        ValueBackendPassword('password', label='Metal archives password'))

    def create_default_browser(self, *args, **kwargs):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get(), *args,
                                   **kwargs)

    # Method to search for a band pattern:
    def iter_band_search(self, pattern):
        bands_list = list(self.browser.iter_band_search(pattern))
        # In case the band search returns no results:
        if not bands_list:
            raise BandNotFound('No band result matched your search query.')
        return bands_list

    # Method to retrieve a band's discography:
    def get_albums(self, id):
        return self.browser.get_albums(id)

    # Method to retrieve a band's information:
    def get_info(self, id):
        return self.browser.get_info(id)

    # Method to retrieve your favorite bands:
    def get_favorites(self):
        return self.browser.get_favorites()

    def suggestions(self):
        favorite_bands = [band.id for band in list(self.get_favorites())]
        return self.browser.suggestions(favorite_bands)
Пример #17
0
class ChampslibresModule(Module, CapBook):
    NAME = 'champslibres'
    MAINTAINER = u'Florent Fourcot'
    EMAIL = '*****@*****.**'
    VERSION = '1.1'
    DESCRIPTION = 'Champs Libres (Rennes) Library'
    LICENSE = 'AGPLv3+'
    CONFIG = BackendConfig(
        Value('login', label='Account ID', regexp='^\d{1,15}|$'),
        ValueBackendPassword('password', label='Password of account'),
    )
    BROWSER = ChampslibresBrowser

    def create_default_browser(self):
        browser = self.create_browser(self.config['login'].get(),
                                      self.config['password'].get())
        # we have to force the login before to lauch any actions
        browser.login()
        return browser

    def get_rented(self):
        for book in self.browser.get_rented_books_list():
            yield book

    def get_booked(self):
        raise NotImplementedError()

    def renew_book(self, id):
        return self.browser.renew(id)

    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()
Пример #18
0
class BouyguesBackend(BaseBackend, ICapMessages, ICapMessagesPost):
    NAME = 'bouygues'
    MAINTAINER = u'Christophe Benz'
    EMAIL = '*****@*****.**'
    VERSION = '0.h'
    DESCRIPTION = u'Bouygues Télécom French mobile phone provider'
    LICENSE = 'AGPLv3+'
    CONFIG = BackendConfig(Value('login', label='Login'),
                           ValueBackendPassword('password', label='Password'))
    BROWSER = BouyguesBrowser
    ACCOUNT_REGISTER_PROPERTIES = None

    def create_default_browser(self):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get())

    def post_message(self, message):
        if not message.content.strip():
            raise CantSendMessage(u'Message content is empty.')
        with self.browser:
            self.browser.post_message(message)
Пример #19
0
class EnsapModule(Module, CapDocument):
    NAME = 'ensap'
    DESCRIPTION = u'ensap website'
    MAINTAINER = u'Juliette Fourcot'
    EMAIL = '*****@*****.**'
    LICENSE = 'LGPLv3+'
    VERSION = '1.6'

    BROWSER = EnsapBrowser
    CONFIG = BackendConfig(
        Value('login', label='User ID', regexp='[0-9]{15}', required=True),
        ValueBackendPassword('password', label='Password'))

    def create_default_browser(self):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get())

    def get_document(self, _id):
        return find_object(self.iter_documents(None),
                           id=_id,
                           error=DocumentNotFound)

    def get_subscription(self, _id):
        return find_object(self.browser.iter_subscription(),
                           id=_id,
                           error=SubscriptionNotFound)

    def iter_documents(self, subscription):
        if isinstance(subscription, basestring):
            subscription = self.get_subscription(subscription)
        return self.browser.iter_documents(subscription)

    def iter_subscription(self):
        return self.browser.iter_subscription()

    def download_document(self, doc):
        if not isinstance(doc, Document):
            doc = self.get_document(doc)
        return self.browser.open(doc.url).content
Пример #20
0
class WellsFargoModule(Module, CapBank):
    NAME = 'wellsfargo'
    MAINTAINER = u'Oleg Plakhotniuk'
    EMAIL = '*****@*****.**'
    VERSION = '1.1'
    LICENSE = 'AGPLv3+'
    DESCRIPTION = u'Wells Fargo'
    CONFIG = BackendConfig(
        ValueBackendPassword('login', label='Username', masked=False),
        ValueBackendPassword('password', label='Password'),
        ValueBackendPassword('question1', label='Question 1', masked=False),
        ValueBackendPassword('answer1', label='Answer 1', masked=False),
        ValueBackendPassword('question2', label='Question 2', masked=False),
        ValueBackendPassword('answer2', label='Answer 2', masked=False),
        ValueBackendPassword('question3', label='Question 3', masked=False),
        ValueBackendPassword('answer3', label='Answer 3', masked=False))
    BROWSER = WellsFargo

    def create_default_browser(self):
        return self.create_browser(username=self.config['login'].get(),
                                   password=self.config['password'].get(),
                                   question1=self.config['question1'].get(),
                                   answer1=self.config['answer1'].get(),
                                   question2=self.config['question2'].get(),
                                   answer2=self.config['answer2'].get(),
                                   question3=self.config['question3'].get(),
                                   answer3=self.config['answer3'].get())

    def iter_accounts(self):
        return self.browser.iter_accounts()

    def get_account(self, id_):
        return self.browser.get_account(id_)

    def iter_history(self, account):
        return self.browser.iter_history(account)
Пример #21
0
class AloesModule(Module, CapBook):
    NAME = 'opacwebaloes'
    MAINTAINER = u'Jeremy Monnet'
    EMAIL = '*****@*****.**'
    VERSION = '1.3'
    DESCRIPTION = 'Aloes Library software'
    LICENSE = 'AGPLv3+'
    CONFIG = BackendConfig(
        Value('login', label='Account ID', regexp='^\d{1,8}\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 iter_rented(self):
        for book in self.browser.get_rented_books_list():
            yield book

    def iter_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()
Пример #22
0
class T411Module(Module, CapTorrent):
    NAME = 't411'
    MAINTAINER = u'Julien Veyssier'
    EMAIL = '*****@*****.**'
    VERSION = '1.2'
    DESCRIPTION = 'T411 BitTorrent tracker'
    LICENSE = 'AGPLv3+'
    CONFIG = BackendConfig(Value('username', label='Username'),
                           ValueBackendPassword('password', label='Password'))
    BROWSER = T411Browser

    def create_default_browser(self):
        return self.create_browser(self.config['username'].get(),
                                   self.config['password'].get())

    def get_torrent(self, id):
        return self.browser.get_torrent(id)

    def get_torrent_file(self, id):
        torrent = self.browser.get_torrent(id)
        if not torrent:
            return None

        resp = self.browser.open(torrent.url)
        return resp.content

    def iter_torrents(self, pattern):
        return self.browser.iter_torrents(quote_plus(pattern.encode('utf-8')))

    def fill_torrent(self, torrent, fields):
        if 'description' in fields or 'files' in fields:
            torrent = self.browser.get_torrent(torrent.id, torrent)
        return torrent

    OBJECTS = {
        Torrent: fill_torrent
    }
Пример #23
0
class BibliothequesparisModule(Module, CapBook):
    NAME = 'bibliothequesparis'
    DESCRIPTION = u'Bibliotheques de Paris'
    MAINTAINER = u'Vincent A'
    EMAIL = '*****@*****.**'
    LICENSE = 'AGPLv3+'
    VERSION = '1.3'

    BROWSER = BibliothequesparisBrowser

    CONFIG = BackendConfig(
        Value('login', label='Library card number'),
        ValueBackendPassword('password', label='Password (usually birthdate)'),
    )

    def create_default_browser(self, *args, **kwargs):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get(), *args,
                                   **kwargs)

    def iter_rented(self):
        return self.browser.get_loans()

    def get_book(self, _id):
        raise NotImplementedError()

    def iter_booked(self):
        raise NotImplementedError()

    def iter_books(self):
        raise NotImplementedError()

    def renew_book(self, _id):
        return self.browser.do_renew(_id)

    def search_books(self, _string):
        raise NotImplementedError()
Пример #24
0
class Fakebankv3Module(Module, CapBank):
    NAME = 'fakebankv3'
    DESCRIPTION = 'fakebankv3 website'
    MAINTAINER = 'baadjis'
    EMAIL = '*****@*****.**'
    LICENSE = 'LGPLv3+'
    VERSION = '1.6'
    CONFIG = BackendConfig(
        Value('login', label='Username'),
        ValueBackendPassword('password', label='code', regexp='\d+'))
    BROWSER = Fakebankv3Browser

    def create_default_browser(self):
        print(self.config['login'].get())
        print(self.config['password'].get())

        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get())

    def iter_accounts(self):
        return self.browser.iter_accounts_list()

    def iter_history(self, id):
        return self.browser.iter_history(id)
Пример #25
0
class NefModule(Module, CapBankTransfer):
    NAME = 'nef'
    DESCRIPTION = 'La Nef'
    MAINTAINER = 'Damien Cassou'
    EMAIL = '*****@*****.**'
    LICENSE = 'LGPLv3+'
    VERSION = '1.6'

    BROWSER = NefBrowser

    CONFIG = BackendConfig(ValueBackendPassword('login', label='username', regexp='.+'),
                           ValueBackendPassword('password', label='Password'))

    def create_default_browser(self):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get())

    # CapBank
    def iter_accounts(self):
        """
        Iter accounts.

        :rtype: iter[:class:`Account`]
        """
        return self.browser.iter_accounts_list()

    def iter_coming(self, account):
        """
        Iter coming transactions on a specific account.

        :param account: account to get coming transactions
        :type account: :class:`Account`
        :rtype: iter[:class:`Transaction`]
        :raises: :class:`AccountNotFound`
        """
        return []

    def iter_history(self, account):
        """
        Iter history of transactions on a specific account.

        :param account: account to get history
        :type account: :class:`Account`
        :rtype: iter[:class:`Transaction`]
        :raises: :class:`AccountNotFound`
        """
        return self.browser.iter_transactions_list(account)

    def iter_resources(self, objs, split_path):
        """
        Iter resources.

        Default implementation of this method is to return on top-level
        all accounts (by calling :func:`iter_accounts`).

        :param objs: type of objects to get
        :type objs: tuple[:class:`BaseObject`]
        :param split_path: path to discover
        :type split_path: :class:`list`
        :rtype: iter[:class:`BaseObject`]
        """
        if Account in objs:
            self._restrict_level(split_path)

            return self.iter_accounts()

    # CapBankTransfer
    def iter_transfer_recipients(self, account):
        """
        Iter recipients availables for a transfer from a specific account.

        :param account: account which initiate the transfer
        :type account: :class:`Account`
        :rtype: iter[:class:`Recipient`]
        :raises: :class:`AccountNotFound`
        """
        return self.browser.iter_recipients_list()

    def init_transfer(self, transfer, **params):
        """
        Initiate a transfer.

        :param :class:`Transfer`
        :rtype: :class:`Transfer`
        :raises: :class:`TransferError`
        """
        raise NotImplementedError()

    def execute_transfer(self, transfer, **params):
        """
        Execute a transfer.

        :param :class:`Transfer`
        :rtype: :class:`Transfer`
        :raises: :class:`TransferError`
        """
        raise NotImplementedError()
Пример #26
0
class CaisseEpargneModule(Module, CapBankTransferAddRecipient, CapContact,
                          CapProfile):
    NAME = 'caissedepargne'
    MAINTAINER = u'Romain Bignon'
    EMAIL = '*****@*****.**'
    VERSION = '1.3'
    DESCRIPTION = u'Caisse d\'Épargne'
    LICENSE = 'AGPLv3+'
    BROWSER = CaisseEpargne
    website_choices = OrderedDict([
        (k, u'%s (%s)' % (v, k))
        for k, v in sorted({
            'www.caisse-epargne.fr': u'Caisse d\'Épargne',
            'www.banquebcp.fr': u'Banque BCP',
        }.iteritems(),
                           key=lambda k_v: (k_v[1], k_v[0]))
    ])
    CONFIG = BackendConfig(
        Value('website',
              label='Banque',
              choices=website_choices,
              default='www.caisse-epargne.fr'),
        ValueBackendPassword('login', label='Identifiant client',
                             masked=False),
        ValueBackendPassword('password', label='Code personnel', regexp='\d+'),
        Value('nuser', label='User ID (optional)', default=''))

    def create_default_browser(self):
        return self.create_browser(nuser=self.config['nuser'].get(),
                                   username=self.config['login'].get(),
                                   password=self.config['password'].get(),
                                   domain=self.config['website'].get())

    def iter_accounts(self):
        for account in self.browser.get_accounts_list():
            yield account
        for account in self.browser.get_loans_list():
            yield account

    def get_account(self, _id):
        account = self.browser.get_account(_id)

        if account:
            return account
        else:
            raise AccountNotFound()

    def iter_history(self, account):
        return self.browser.get_history(account)

    def iter_coming(self, account):
        return self.browser.get_coming(account)

    def iter_investment(self, account):
        return self.browser.get_investment(account)

    def iter_contacts(self):
        return self.browser.get_advisor()

    def get_profile(self):
        return self.browser.get_profile()

    def iter_transfer_recipients(self, origin_account):
        if not isinstance(origin_account, Account):
            origin_account = find_object(self.iter_accounts(),
                                         id=origin_account,
                                         error=AccountNotFound)
        return self.browser.iter_recipients(origin_account)

    def init_transfer(self, transfer, **params):
        self.logger.info('Going to do a new transfer')
        transfer.label = ' '.join(
            w for w in re.sub('[^0-9a-zA-Z/\-\?:\(\)\.,\'\+ ]+', '',
                              transfer.label).split()).upper()
        if transfer.account_iban:
            account = find_object(self.iter_accounts(),
                                  iban=transfer.account_iban,
                                  error=AccountNotFound)
        else:
            account = find_object(self.iter_accounts(),
                                  id=transfer.account_id,
                                  error=AccountNotFound)

        if transfer.recipient_iban:
            recipient = find_object(self.iter_transfer_recipients(account.id),
                                    iban=transfer.recipient_iban,
                                    error=RecipientNotFound)
        else:
            recipient = find_object(self.iter_transfer_recipients(account.id),
                                    id=transfer.recipient_id,
                                    error=RecipientNotFound)

        return self.browser.init_transfer(account, recipient, transfer)

    def execute_transfer(self, transfer, **params):
        return self.browser.execute_transfer(transfer)

    def new_recipient(self, recipient, **params):
        #recipient.label = ' '.join(w for w in re.sub('[^0-9a-zA-Z:\/\-\?\(\)\.,\'\+ ]+', '', recipient.label).split())
        return self.browser.new_recipient(recipient, **params)
Пример #27
0
class CmbModule(Module, CapBank):
    NAME = 'cmb'
    MAINTAINER = u'Johann Broudin'
    EMAIL = '*****@*****.**'
    VERSION = '1.1'
    LICENSE = 'AGPLv3+'
    DESCRIPTION = u'Crédit Mutuel de Bretagne'
    CONFIG = BackendConfig(
        ValueBackendPassword('login', label='Identifiant', masked=False),
        ValueBackendPassword('password', label='Mot de passe', masked=True))
    LABEL_PATTERNS = [
        (  # card
            compile('^CARTE (?P<text>.*)'), Transaction.TYPE_CARD, '%(text)s'),
        (  # order
            compile('^PRLV (?P<text>.*)'), Transaction.TYPE_ORDER, '%(text)s'),
        (  # withdrawal
            compile('^RET DAB (?P<text>.*)'), Transaction.TYPE_WITHDRAWAL,
            '%(text)s'),
        (  # loan payment
            compile('^ECH (?P<text>.*)'), Transaction.TYPE_LOAN_PAYMENT,
            '%(text)s'),
        (  # transfer
            compile('^VIR (?P<text>.*)'), Transaction.TYPE_TRANSFER,
            '%(text)s'),
        (  # payback
            compile('^ANN (?P<text>.*)'), Transaction.TYPE_PAYBACK,
            '%(text)s'),
        (  # bank
            compile('^F (?P<text>.*)'), Transaction.TYPE_BANK, '%(text)s'),
        (  # deposit
            compile('^VRST (?P<text>.*)'), Transaction.TYPE_DEPOSIT,
            '%(text)s')
    ]

    BROWSER = Browser
    islogged = False

    def login(self):
        data = {
            'codeEspace': 'NO',
            'codeEFS': '01',
            'codeSi': '001',
            'noPersonne': self.config['login'].get(),
            'motDePasse': self.config['password'].get()
        }

        try:
            self.browser.open(
                "https://www.cmb.fr/domiweb/servlet/Identification",
                allow_redirects=False,
                data=data)
            self.browser.open(
                "https://www.cmb.fr/domiweb/prive/particulier/releve/0-releve.act"
            )
        except BrowserHTTPError:
            raise BrowserIncorrectPassword()
        else:
            self.islogged = True

    def iter_accounts(self):
        if not self.islogged:
            self.login()

        data = self.browser.open(
            "https://www.cmb.fr/domiweb/prive/particulier/releve/0-releve.act"
        ).content
        parser = etree.HTMLParser()
        tree = etree.parse(StringIO(data), parser)

        table = tree.xpath('/html/body/table')
        if len(table) == 0:
            title = tree.xpath('/html/head/title')[0].text
            if title == u"Utilisateur non identifié":
                self.login()
                data = self.browser.open(
                    "https://www.cmb.fr/domiweb/prive/particulier/releve/0-releve.act"
                ).content

                parser = etree.HTMLParser()
                tree = etree.parse(StringIO(data), parser)
                table = tree.xpath('/html/body/table')
                if len(table) == 0:
                    raise ParseError()
            else:
                raise ParseError()

        for tr in tree.xpath('/html/body//table[contains(@class, "Tb")]/tr'):
            if tr.get('class',
                      None) not in ('LnTit', 'LnTot', 'LnMnTiers', None):
                account = Account()
                td = tr.xpath('td')

                a = td[1].xpath('a')
                account.label = unicode(a[0].text).strip()
                href = a[0].get('href')
                m = match(r"javascript:releve\((.*),'(.*)','(.*)'\)", href)
                if not m:
                    continue
                account.id = unicode(m.group(1) + m.group(2) + m.group(3))
                account._cmbvaleur = m.group(1)
                account._cmbvaleur2 = m.group(2)
                account._cmbtype = m.group(3)

                balance = u''.join([txt.strip() for txt in td[2].itertext()])
                balance = balance.replace(',', '.').replace(u"\xa0", '')
                account.balance = Decimal(balance)

                span = td[4].xpath('a/span')
                if len(span):
                    coming = span[0].text.replace(' ', '').replace(',', '.')
                    coming = coming.replace(u"\xa0", '')
                    account.coming = Decimal(coming)
                else:
                    account.coming = NotAvailable

                yield account

    def get_account(self, _id):
        for account in self.iter_accounts():
            if account.id == _id:
                return account

        raise AccountNotFound()

    def iter_history(self, account):
        if not self.islogged:
            self.login()

        page = "https://www.cmb.fr/domiweb/prive/particulier/releve/"
        if account._cmbtype == 'D':
            page += "10-releve.act"
        else:
            page += "2-releve.act"
        page += "?noPageReleve=1&indiceCompte="
        page += account._cmbvaleur
        page += "&typeCompte="
        page += account._cmbvaleur2
        page += "&deviseOrigineEcran=EUR"

        data = self.browser.open(page).content
        parser = etree.HTMLParser()
        tree = etree.parse(StringIO(data), parser)

        tables = tree.xpath('/html/body/table')
        if len(tables) == 0:
            title = tree.xpath('/html/head/title')[0].text
            if title == u"Utilisateur non identifié":
                self.login()
                data = self.browser.open(page).content

                parser = etree.HTMLParser()
                tree = etree.parse(StringIO(data), parser)
                tables = tree.xpath('/html/body/table')
                if len(tables) == 0:
                    raise ParseError()
            else:
                raise ParseError()

        i = 0

        for table in tables:
            if table.get('id') != "tableMouvements":
                continue
            for tr in table.getiterator('tr'):
                if (tr.get('class') != 'LnTit' and tr.get('class') != 'LnTot'):
                    operation = Transaction(i)
                    td = tr.xpath('td')

                    div = td[1].xpath('div')
                    d = div[0].text.split('/')
                    operation.date = date(*reversed([int(x) for x in d]))

                    div = td[2].xpath('div')
                    label = div[0].xpath('a')[0].text.replace('\n', '')
                    operation.raw = unicode(' '.join(label.split()))
                    for pattern, _type, _label in self.LABEL_PATTERNS:
                        mm = pattern.match(operation.raw)
                        if mm:
                            operation.type = _type
                            operation.label = sub('[ ]+', ' ', _label %
                                                  mm.groupdict()).strip()
                            break

                    amount = td[3].text
                    if amount.count(',') != 1:
                        amount = td[4].text
                        amount = amount.replace(',', '.').replace(u'\xa0', '')
                        operation.amount = Decimal(amount)
                    else:
                        amount = amount.replace(',', '.').replace(u'\xa0', '')
                        operation.amount = -Decimal(amount)

                    i += 1
                    yield operation
Пример #28
0
class AferModule(Module, CapBank):
    NAME = 'afer'
    DESCRIPTION = u'afer website'
    MAINTAINER = u'James GALT'
    EMAIL = '*****@*****.**'
    LICENSE = 'AGPLv3+'
    VERSION = '1.2'

    BROWSER = AferBrowser
    CONFIG = BackendConfig(
        ValueBackendPassword('login',
                             label='Username',
                             regexp='[A-z]\d+',
                             masked=False),
        ValueBackendPassword('password', label=u"mdp", regexp='\d+'))

    def create_default_browser(self):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get())

    def get_account(self, id):
        """
        Get an account from its ID.

        :param id: ID of the account
        :type id: :class:`str`
        :rtype: :class:`Account`
        :raises: :class:`AccountNotFound`
        """
        return find_object(self.iter_accounts(), id=id, error=AccountNotFound)

    def iter_accounts(self):
        """
        Iter accounts.

        :rtype: iter[:class:`Account`]
        """
        return self.browser.iter_accounts()

    def iter_coming(self, account):
        """
        Iter coming transactions on a specific account.

        :param account: account to get coming transactions
        :type account: :class:`Account`
        :rtype: iter[:class:`Transaction`]
        :raises: :class:`AccountNotFound`
        """
        raise NotImplementedError()

    def iter_history(self, account):
        """
        Iter history of transactions on a specific account.

        :param account: account to get history
        :type account: :class:`Account`
        :rtype: iter[:class:`Transaction`]
        :raises: :class:`AccountNotFound`
        """
        return self.browser.iter_history(account)

    def iter_investment(self, account):
        """
        Iter investment of a market account

        :param account: account to get investments
        :type account: :class:`Account`
        :rtype: iter[:class:`Investment`]
        :raises: :class:`AccountNotFound`
        """
        return self.browser.iter_investments(account)

    def iter_transfer_recipients(self, account):
        """
        Iter recipients availables for a transfer from a specific account.

        :param account: account which initiate the transfer
        :type account: :class:`Account`
        :rtype: iter[:class:`Recipient`]
        :raises: :class:`AccountNotFound`
        """
        raise NotImplementedError()

    def transfer(self, account, recipient, amount, reason):
        """
        Make a transfer from an account to a recipient.

        :param account: account to take money
        :type account: :class:`Account`
        :param recipient: account to send money
        :type recipient: :class:`Recipient`
        :param amount: amount
        :type amount: :class:`decimal.Decimal`
        :param reason: reason of transfer
        :type reason: :class:`unicode`
        :rtype: :class:`Transfer`
        :raises: :class:`AccountNotFound`, :class:`TransferError`
        """
        raise NotImplementedError()
Пример #29
0
class INGBackend(BaseBackend, ICapBank, ICapBill):
    NAME = 'ing'
    MAINTAINER = u'Florent Fourcot'
    EMAIL = '*****@*****.**'
    VERSION = '0.h'
    LICENSE = 'AGPLv3+'
    DESCRIPTION = 'ING Direct French bank website'
    CONFIG = BackendConfig(
        ValueBackendPassword('login', label='Account ID', masked=False),
        ValueBackendPassword('password', label='Password',
                             regexp='^(\d{6}|)$'),
        ValueBackendPassword('birthday',
                             label='Birthday',
                             regexp='^(\d{8}|)$',
                             masked=False))
    BROWSER = Ing

    def create_default_browser(self):
        return self.create_browser(self.config['login'].get(),
                                   self.config['password'].get(),
                                   birthday=self.config['birthday'].get())

    def iter_resources(self, objs, split_path):
        if Account in objs:
            self._restrict_level(split_path)
            return self.iter_accounts()
        if Subscription in objs:
            self._restrict_level(split_path)
            return self.iter_subscription()

    def iter_accounts(self):
        for account in self.browser.get_accounts_list():
            yield account

    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.id):
                yield history

    def iter_transfer_recipients(self, account):
        with self.browser:
            if not isinstance(account, Account):
                account = self.get_account(account)
            for recipient in self.browser.get_recipients(account):
                yield recipient

    def transfer(self, account, recipient, amount, reason):
        with self.browser:
            if not isinstance(account, Account):
                account = self.get_account(account)
            if not isinstance(recipient, Recipient):
                # Remove weboob identifier prefix (LA-, CC-...)
                if "-" in recipient:
                    recipient = recipient.split('-')[1]
            return self.browser.transfer(account, recipient, amount, reason)

    def iter_investment(self, account):
        with self.browser:
            if not isinstance(account, Account):
                account = self.get_account(account)
            for investment in self.browser.get_investments(account):
                yield investment

    def iter_subscription(self):
        for subscription in self.browser.get_subscriptions():
            yield subscription

    def get_subscription(self, _id):
        for subscription in self.browser.get_subscriptions():
            if subscription.id == _id:
                return subscription
        raise SubscriptionNotFound()

    def get_bill(self, id):
        subscription = self.get_subscription(id.split('-')[0])
        for bill in self.browser.get_bills(subscription):
            if bill.id == id:
                return bill
        raise BillNotFound()

    def iter_bills(self, subscription):
        if not isinstance(subscription, Subscription):
            subscription = self.get_subscription(subscription)
        return self.browser.get_bills(subscription)

    def download_bill(self, bill):
        if not isinstance(bill, Bill):
            bill = self.get_bill(bill)
        self.browser.predownload(bill)
        with self.browser:
            return self.browser.readurl("https://secure.ingdirect.fr" +
                                        bill._url)
Пример #30
0
class jcvelauxModule(Module, CapGauge):
    NAME = 'jcvelaux'
    DESCRIPTION = ('City bike renting availability information.\nCities: %s' %
                   ', '.join(CITIES))
    MAINTAINER = 'Herve Werner'
    EMAIL = '*****@*****.**'
    VERSION = '1.4'
    LICENSE = 'AGPLv3'

    BROWSER = VelibBrowser

    CONFIG = BackendConfig(Value('city', label='City', default='Paris',
                                 choices=CITIES + ("ALL",)),
                           ValueBackendPassword('api_key', label='Optional API key',
                                                default='', noprompt=True))

    def __init__(self, *a, **kw):
        super(jcvelauxModule, self).__init__(*a, **kw)
        self.cities = None

    def create_default_browser(self):
        api_key = self.config['api_key'].get()
        return self.create_browser(api_key)

    def _make_gauge(self, info):
        gauge = Gauge(info['id'])
        gauge.name = info['name']
        gauge.city = info['city']
        gauge.object = 'bikes'
        return gauge

    def _make_sensor(self, sensor_type, info, gauge):
        id = '%s.%s' % (sensor_type, gauge.id)
        sensor = BikeSensor(id)
        sensor.gaugeid = gauge.id
        sensor.name = SENSOR_TYPES[sensor_type]
        sensor.address = '%s' % info['address']
        sensor.longitude = info['longitude']
        sensor.latitude = info['latitude']
        sensor.history = []
        return sensor

    def _make_measure(self, sensor_type, info, gauge):
        id = '%s.%s' % (sensor_type, gauge.id)

        measure = BikeMeasure(id)
        measure.date = info['last_update']
        measure.level = float(info[sensor_type])
        return measure

    def _parse_gauge(self, info):
        gauge = self._make_gauge(info)
        gauge.sensors = []

        for type in SENSOR_TYPES:
            sensor = self._make_sensor(type, info, gauge)
            measure = self._make_measure(type, info, gauge)
            sensor.lastvalue = measure
            gauge.sensors.append(sensor)

        return gauge

    def _contract(self):
        contract = self.config.get('city').get()
        if contract.lower() == 'all':
            contract = None
        return contract

    def iter_gauges(self, pattern=None):
        if pattern is None:
            for jgauge in self.browser.get_station_list(contract=self._contract()):
                yield self._parse_gauge(jgauge)
        else:
            lowpattern = pattern.lower()
            for jgauge in self.browser.get_station_list(contract=self._contract()):
                gauge = self._parse_gauge(jgauge)
                if lowpattern in gauge.name.lower() or lowpattern in gauge.city.lower():
                    yield gauge

    def iter_sensors(self, gauge, pattern=None):
        if not isinstance(gauge, Gauge):
            gauge = self._get_gauge_by_id(gauge)
            if gauge is None:
                raise SensorNotFound()

        if pattern is None:
            for sensor in gauge.sensors:
                yield sensor
        else:
            lowpattern = pattern.lower()
            for sensor in gauge.sensors:
                if lowpattern in sensor.name.lower():
                    yield sensor

    def get_last_measure(self, sensor):
        if not isinstance(sensor, GaugeSensor):
            sensor = self._get_sensor_by_id(sensor)
        if sensor is None:
            raise SensorNotFound()
        return sensor.lastvalue

    def _fetch_cities(self):
        if self.cities:
            return

        self.cities = {}
        jcontract = self.browser.get_contracts_list()
        for jcontract in jcontract:
            for city in jcontract['cities']:
                self.cities[city.lower()] = jcontract['name']

    def _get_gauge_by_id(self, id):
        jgauge = self.browser.get_station_infos(id)
        if jgauge:
            return self._parse_gauge(jgauge)
        else:
            return None

    def _get_sensor_by_id(self, id):
        try:
            sensor_name, gauge_name, contract = id.split('.')
        except ValueError:
            raise UserError('Expected format NAME.ID.CITY for sensor: %r' % id)

        gauge = self._get_gauge_by_id('%s.%s' % (gauge_name, contract))
        if not gauge:
            raise SensorNotFound()
        for sensor in gauge.sensors:
            if sensor.id.lower() == id.lower():
                return sensor