Exemple #1
0
    def bcall_errors_handler(self, errors):
        """
        Handler for the CallErrors exception.
        """
        self.ind.set_status(appindicator.IndicatorStatus.ATTENTION)
        for backend, error, backtrace in errors.errors:
            notify = True
            if isinstance(error, BrowserIncorrectPassword):
                msg = 'invalid login/password.'
            elif isinstance(error, BrowserSSLError):
                msg = '/!\ SERVER CERTIFICATE IS INVALID /!\\'
            elif isinstance(error, BrowserForbidden):
                msg = unicode(error) or 'Forbidden'
            elif isinstance(error, BrowserUnavailable):
                msg = unicode(error)
                if not msg:
                    msg = 'website is unavailable.'
            elif isinstance(error, NotImplementedError):
                notify = False
            elif isinstance(error, UserError):
                msg = unicode(error)
            elif isinstance(error, MoreResultsAvailable):
                notify = False
            else:
                msg = unicode(error)

            if notify:
                Notify.Notification.new('<b>Error Boobank: %s</b>' % backend.name,
                                        msg,
                                        'notification-message-im').show()
Exemple #2
0
    def __init__(self, video, parent=None):
        super(Video, self).__init__(parent)
        self.ui = Ui_Video()
        self.ui.setupUi(self)

        self.video = video
        self.setWindowTitle("Video - %s" % video.title)
        self.ui.urlEdit.setText(video.url)
        self.ui.titleLabel.setText(video.title)
        self.ui.durationLabel.setText(unicode(video.duration))
        self.ui.authorLabel.setText(unicode(video.author))
        self.ui.dateLabel.setText(unicode(video.date))
        if video.rating_max:
            self.ui.ratingLabel.setText('%s / %s' % (video.rating, video.rating_max))
        else:
            self.ui.ratingLabel.setText('%s' % video.rating)

        self.mediaPlayer = QMediaPlayer()

        self.mediaPlayer.durationChanged.connect(self._setMax)
        self.mediaPlayer.seekableChanged.connect(self.ui.seekSlider.setEnabled)
        self.mediaPlayer.positionChanged.connect(self._slide)
        self.ui.seekSlider.valueChanged.connect(self.mediaPlayer.setPosition)

        mc = QMediaContent(QUrl(video.url))
        self.mediaPlayer.setMedia(mc)
        self.ui.videoPlayer.setMediaObject(self.mediaPlayer)
        self.mediaPlayer.play()
Exemple #3
0
 def get_account_status(self):
     return (
             StatusField(u'myname', u'My name', unicode(self.browser.get_my_name())),
             StatusField(u'score', u'Score', unicode(self.browser.score())),
             StatusField(u'avcharms', u'Available charms', unicode(self.browser.nb_available_charms())),
             StatusField(u'newvisits', u'New visits', unicode(self.browser.nb_new_visites())),
            )
Exemple #4
0
 def filter(self, el):
     try:
         el = el[0]
     except IndexError:
         return self.default_or_raise(XPathNotFound('Unable to find element %s' % self.selector))
     if el.tag == 'input':
         # checkboxes or radios
         if el.attrib.get('type') in ('radio', 'checkbox'):
             return 'checked' in el.attrib
         # regular text input
         elif el.attrib.get('type', '') in ('', 'text', 'email', 'search', 'tel', 'url'):
             try:
                 return unicode(el.attrib['value'])
             except KeyError:
                 return self.default_or_raise(AttributeNotFound('Element %s does not have attribute value' % el))
         # TODO handle html5 number, datetime, etc.
         else:
             raise UnrecognizedElement('Element %s is recognized' % el)
     elif el.tag == 'textarea':
         return unicode(el.text)
     elif el.tag == 'select':
         options = el.xpath('.//option[@selected]')
         # default is the first one
         if len(options) == 0:
             options = el.xpath('.//option[1]')
         return u'\n'.join([unicode(o.text) for o in options])
     else:
         raise UnrecognizedElement('Element %s is recognized' % el)
Exemple #5
0
    def unique_id(self, seen=None, account_id=None):
        """
        Get an unique ID for the transaction based on date, amount and raw.

        :param seen: if given, the method uses this dictionary as a cache to
                     prevent several transactions with the same values to have the same
                     unique ID.
        :type seen: :class:`dict`
        :param account_id: if given, add the account ID in data used to create
                           the unique ID. Can be useful if you want your ID to be unique across
                           several accounts.
        :type account_id: :class:`str`
        :returns: an unique ID encoded in 8 length hexadecimal string (for example ``'a64e1bc9'``)
        :rtype: :class:`str`
        """
        crc = crc32(unicode(self.date).encode('utf-8'))
        crc = crc32(unicode(self.amount).encode('utf-8'), crc)
        if not empty(self.raw):
            label = self.raw
        else:
            label = self.label

        crc = crc32(re.sub('[ ]+', ' ', label).encode("utf-8"), crc)

        if account_id is not None:
            crc = crc32(unicode(account_id).encode('utf-8'), crc)

        if seen is not None:
            while crc in seen:
                crc = crc32(b"*", crc)

            seen.add(crc)

        return "%08x" % (crc & 0xffffffff)
Exemple #6
0
 def create_transfer(self, account, recipient, transfer):
     transfer = Transfer()
     transfer.currency = FrenchTransaction.Currency('.//tr[td[contains(text(), "Montant")]]/td[not(@class)] | \
                                                     .//tr[th[contains(text(), "Montant")]]/td[not(@class)]')(self.doc)
     transfer.amount = CleanDecimal('.//tr[td[contains(text(), "Montant")]]/td[not(@class)] | \
                                     .//tr[th[contains(text(), "Montant")]]/td[not(@class)]', replace_dots=True)(self.doc)
     transfer.account_iban = account.iban
     if recipient.category == u'Externe':
         for word in Upper(CleanText(u'.//tr[th[contains(text(), "Compte à créditer")]]/td[not(@class)]'))(self.doc).split():
             if is_iban_valid(word):
                 transfer.recipient_iban = word
                 break
         else:
             raise TransferError('Unable to find IBAN (original was %s)' % recipient.iban)
     else:
         transfer.recipient_iban = recipient.iban
     transfer.account_id = unicode(account.id)
     transfer.recipient_id = unicode(recipient.id)
     transfer.exec_date = Date(CleanText('.//tr[th[contains(text(), "En date du")]]/td[not(@class)]'), dayfirst=True)(self.doc)
     transfer.label = (CleanText(u'.//tr[td[contains(text(), "Motif de l\'opération")]]/td[not(@class)]')(self.doc) or
                      CleanText(u'.//tr[td[contains(text(), "Libellé")]]/td[not(@class)]')(self.doc) or
                      CleanText(u'.//tr[th[contains(text(), "Libellé")]]/td[not(@class)]')(self.doc))
     transfer.account_label = account.label
     transfer.recipient_label = recipient.label
     transfer._account = account
     transfer._recipient = recipient
     transfer.account_balance = account.balance
     return transfer
Exemple #7
0
    def edit_issue(self, issue, edit=True):
        backend = self.weboob.get_backend(issue.backend)
        content = self.issue2text(issue, backend)
        while True:
            if self.stdin.isatty():
                content = self.acquire_input(content, {'vim': "-c 'set ft=mail'"})
                m = message_from_string(content.encode('utf-8'))
            else:
                m = message_from_file(self.stdin)

            try:
                email_to = self.text2issue(issue, m)
            except ValueError as e:
                if not self.stdin.isatty():
                    raise
                input("%s -- Press Enter to continue..." % unicode(e).encode("utf-8"))
                continue

            try:
                issue = backend.post_issue(issue)
                print('Issue %s %s' % (self.formatter.colored(issue.fullid, 'red', 'bold'),
                                       'updated' if edit else 'created'))
                if edit:
                    self.format(issue)
                elif email_to:
                    self.send_notification(email_to, issue)
                return 0
            except IssueError as e:
                if not self.stdin.isatty():
                    raise
                input("%s -- Press Enter to continue..." % unicode(e).encode("utf-8"))
Exemple #8
0
    def iter_persons(self, pattern):
        params = [('partner', self.PARTNER_KEY),
                  ('q', pattern),
                  ('format', 'json'),
                  ('filter', 'person')]

        jres = self.__do_request('search', params)
        if jres is None:
            return
        if 'person' not in jres['feed']:
            return
        for p in jres['feed']['person']:
            thumbnail_url = NotAvailable
            if 'picture' in p:
                thumbnail_url = unicode(p['picture']['href'])
            person = Person(p['code'], unicode(p['name']))
            desc = u''
            if 'birthDate' in p:
                desc += '(%s), ' % p['birthDate']
            if 'activity' in p:
                for a in p['activity']:
                    desc += '%s, ' % a['$']
            person.real_name = NotLoaded
            person.birth_place = NotLoaded
            person.birth_date = NotLoaded
            person.death_date = NotLoaded
            person.gender = NotLoaded
            person.nationality = NotLoaded
            person.short_biography = NotLoaded
            person.short_description = desc.strip(', ')
            person.roles = NotLoaded
            person.thumbnail_url = thumbnail_url
            yield person
Exemple #9
0
    def parse(self):
        self.url = '%s#%s' % (self.preurl, self.div.attrib['id'])
        self.title = unicode(self.div.find('h2').xpath('.//a[has-class("title")]')[0].text)
        try:
            a = self.div.find('p').xpath('.//a[@rel="author"]')[0]
        except IndexError:
            self.author = 'Anonyme'
            self.username = None
        else:
            self.author = unicode(a.text)
            self.username = unicode(a.attrib['href'].split('/')[2])
        self.date = datetime.strptime(self.div.find('p').xpath('.//time')[0].attrib['datetime'].split('+')[0],
                                      '%Y-%m-%dT%H:%M:%S')
        self.date = local2utc(self.date)

        content = self.div.find('div')
        try:
            signature = content.xpath('.//p[has-class("signature")]')[0]
        except IndexError:
            # No signature.
            pass
        else:
            content.remove(signature)
            self.signature = lxml.html.tostring(signature).decode('utf-8')
        self.body = lxml.html.tostring(content).decode('utf-8')

        self.score = int(self.div.find('p').xpath('.//span[has-class("score")]')[0].text)
        forms = self.div.find('footer').xpath('.//form[has-class("button_to")]')
        if len(forms) > 0:
            self.relevance_url = forms[0].attrib['action'].rstrip('for').rstrip('against')
            self.relevance_token = forms[0].xpath('.//input[@name="authenticity_token"]')[0].attrib['value']
Exemple #10
0
    def get_accounts_list(self):
        for table in self.doc.xpath('//div[@class="comptestabl"]/table'):
            try:
                account_type = self.ACCOUNT_TYPES[table.get('summary').lower()]
                if not account_type:
                    account_type = self.ACCOUNT_TYPES[table.xpath('./caption/text()')[0].strip().lower()]
            except (IndexError,KeyError):
                account_type = Account.TYPE_UNKNOWN
            for tr in table.xpath('./tbody/tr'):
                cols = tr.findall('td')

                link = cols[0].find('a')
                if link is None:
                    continue

                a = Account()
                a.type = account_type
                a.id = unicode(re.search('([A-Z\d]{4}[A-Z\d\*]{3}[A-Z\d]{4})', link.attrib['title']).group(1))
                a.label = unicode(link.attrib['title'].replace('%s ' % a.id, ''))
                tmp_balance = CleanText(None).filter(cols[1])
                a.currency = a.get_currency(tmp_balance)
                if not a.currency:
                    a.currency = u'EUR'
                a.balance = Decimal(Transaction.clean_amount(tmp_balance))
                a._has_cards = False
                a.url = urljoin(self.url, link.attrib['href'])
                yield a
Exemple #11
0
    def __init__(self, browser, url, tree):
        super(Article, self).__init__(browser)
        self.url = url
        self.id = url2id(self.url)

        if tree is None:
            return

        header = tree.find('header')
        self.title = u' — '.join([a.text for a in header.find('h1').xpath('.//a')])
        try:
            a = header.xpath('.//a[@rel="author"]')[0]
        except IndexError:
            self.author = 'Anonyme'
            self.username = None
        else:
            self.author = unicode(a.text)
            self.username = unicode(a.attrib['href'].split('/')[2])
        self.body = lxml.html.tostring(tree.xpath('.//div[has-class("content")]')[0]).decode('utf-8')
        try:
            self.date = datetime.strptime(header.xpath('.//time')[0].attrib['datetime'].split('+')[0],
                                          '%Y-%m-%dT%H:%M:%S')
            self.date = local2utc(self.date)
        except IndexError:
            pass
        for form in tree.find('footer').xpath('//form[has-class("button_to")]'):
            if form.attrib['action'].endswith('/for'):
                self.relevance_url = form.attrib['action'].rstrip('for').rstrip('against')
                self.relevance_token = form.xpath('.//input[@name="authenticity_token"]')[0].attrib['value']

        self.score = int(tree.xpath('.//div[has-class("figures")]//figure[has-class("score")]')[0].text)
Exemple #12
0
    def get_arte_cinema_categories(self, cat=[]):
        menu = self.videos_list.go(site=SITE.CINEMA.get('id'), lang=self.lang.get('site'),
                                   cat='').get_arte_cinema_menu()
        menuSplit = map(lambda x: x.split("/")[2:], menu)

        result = {}
        for record in menuSplit:
            here = result
            for item in record[:-1]:
                if item not in here:
                    here[item] = {}
                here = here[item]
            if "end" not in here:
                here["end"] = []
            here["end"].append(record[-1])

        cat = cat if not cat else cat[1:]

        if not cat and "end" in result:
            del result["end"]

        for el in cat:
            result = result.get(el)

        if "end" in result.keys():
            return self.page.iter_arte_cinema_categories(cat='/'.join(cat))
        else:
            categories = []
            for item in result.keys():
                if item == "programs":
                    continue
                categories.append(Collection([SITE.CINEMA.get('id'), unicode(item)], unicode(item)))
            return categories
Exemple #13
0
    def iter_investment(self):
        for tr in self.doc.xpath("//table/tbody/tr[starts-with(@class, 'net2g_asv_tableau_ligne_')]"):
            cells = tr.findall('td')
            inv = self.create_investment(cells)
            inv.label = unicode(cells[self.COL_LABEL].xpath('a/span')[0].text.strip())
            inv.description = unicode(cells[self.COL_LABEL].xpath('a//div/b[last()]')[0].tail)

            yield inv
Exemple #14
0
    def iter_investment(self):
        not_rounded_valuations = self.get_not_rounded_valuations()

        doc = self.browser.open('/brs/fisc/fisca10a.html').page.doc
        num_page = None

        try:
            num_page = int(CleanText('.')(doc.xpath(u'.//tr[contains(td[1], "Relevé des plus ou moins values latentes")]/td[2]')[0]).split('/')[1])
        except IndexError:
            pass

        docs = [doc]

        if num_page:
            for n in range(2, num_page + 1):
                docs.append(self.browser.open('%s%s' % ('/brs/fisc/fisca10a.html?action=12&numPage=', str(n))).page.doc)

        for doc in docs:
            # There are two different tables possible depending on the market account type.
            is_detailed = bool(doc.xpath(u'//span[contains(text(), "Années d\'acquisition")]'))
            tr_xpath = '//tr[@height and td[@colspan="6"]]' if is_detailed else '//tr[count(td)>5]'
            for tr in doc.xpath(tr_xpath):
                cells = tr.findall('td')

                inv = Investment()

                title_split = cells[self.COL_LABEL].xpath('.//span')[0].attrib['title'].split(' - ')
                inv.label = unicode(title_split[0])

                for code in title_split[1:]:
                    if is_isin_valid(code):
                        inv.code = unicode(code)
                        inv.code_type = Investment.CODE_TYPE_ISIN
                        break
                    else:
                        inv.code = NotAvailable
                        inv.code_type = NotAvailable

                if is_detailed:
                    inv.quantity = MyDecimal('.')(tr.xpath('./following-sibling::tr/td[2]')[0])
                    inv.unitprice = MyDecimal('.', replace_dots=True)(tr.xpath('./following-sibling::tr/td[3]')[1])
                    inv.unitvalue = MyDecimal('.', replace_dots=True)(tr.xpath('./following-sibling::tr/td[3]')[0])

                    try: # try to get not rounded value
                        inv.valuation = not_rounded_valuations[inv.label]
                    except KeyError: # ok.. take it from the page
                        inv.valuation = MyDecimal('.')(tr.xpath('./following-sibling::tr/td[4]')[0])

                    inv.diff = MyDecimal('.')(tr.xpath('./following-sibling::tr/td[5]')[0]) or \
                               MyDecimal('.')(tr.xpath('./following-sibling::tr/td[6]')[0])
                else:
                    inv.quantity = MyDecimal('.')(cells[self.COL_QUANTITY])
                    inv.diff = MyDecimal('.')(cells[self.COL_DIFF])
                    inv.unitprice = MyDecimal('.')(cells[self.COL_UNITPRICE].xpath('.//tr[1]/td[2]')[0])
                    inv.unitvalue = MyDecimal('.')(cells[self.COL_VALUATION].xpath('.//tr[1]/td[2]')[0])
                    inv.valuation = MyDecimal('.')(cells[self.COL_VALUATION].xpath('.//tr[2]/td[2]')[0])

                yield inv
Exemple #15
0
    def load_state(self, state):
        super(LCLBrowser, self).load_state(state)

        # lxml _ElementStringResult were put in the state, convert them to plain strs
        # TODO to remove at some point
        if self.contracts:
            self.contracts = [unicode(s) for s in self.contracts]
        if self.current_contract:
            self.current_contract = unicode(self.current_contract)
Exemple #16
0
 def get_emissions(self, basename):
     params = [('partner', self.PARTNER_KEY),
               ('format', 'json'),
               ('filter', 'acshow'),
               ]
     result = self.__do_request('termlist', params)
     if result is None:
         return
     for emission in result['feed']['term']:
         yield Collection([basename, unicode(emission['nameShort'])], unicode(emission['$']))
Exemple #17
0
 def iter_transactions(self):
     for li in self.doc.xpath('//section[@class="transactions"]//div/li'):
         date = li.xpath('p[@data-type="date"]//text()')[0].strip()
         label = li.xpath('p[@data-type="description"]//text()')[0].strip()
         amount = li.xpath('p[@data-type="amount"]//text()')[0].strip()
         t = Transaction()
         t.date = datetime.strptime(date, '%m/%d/%Y')
         t.rdate = datetime.strptime(date, '%m/%d/%Y')
         t.type = Transaction.TYPE_UNKNOWN
         t.raw = unicode(label)
         t.label = unicode(label)
         t.amount = -AmTr.decimal_amount(amount)
         yield t
Exemple #18
0
 def parse_video(self, _video, category):
     video = BaseVideo(u'%s#%s' % (_video['code'], category))
     video.title = unicode(_video['title'])
     video._video_code = unicode(_video['code'])
     video.ext = u'mp4'
     if 'runtime' in _video:
         video.duration = timedelta(seconds=int(_video['runtime']))
     if 'description' in _video:
         video.description = unicode(_video['description'])
     renditions = sorted(_video['rendition'],
                         key=lambda x: 'bandwidth' in x and x['bandwidth']['code'],
                         reverse=True)
     video.url = unicode(max(renditions, key=lambda x: 'bandwidth' in x)['href'])
     return video
Exemple #19
0
 def obj_url(self):
     links = XPath('//div[@id="download_links"]/div[@class="paragraph"]/div[has-class("share")]/a[@target="_blank"]/@href')(self)
     for link in links:
         ext = str(link).split('.')[-1]
         self.logger.debug("Link:%s Ext:%s", link, ext)
         if ext in ['mp4', 'webm']:
             return self.page.browser.BASEURL + unicode(link)
Exemple #20
0
 def iter_movies(self, pattern):
     res = self.open('http://www.imdb.com/xml/find?json=1&nr=1&tt=on', params={'q': pattern})
     jres = res.json()
     htmlparser = HTMLParser()
     for cat in ['title_popular', 'title_exact', 'title_approx']:
         if cat in jres:
             for m in jres[cat]:
                 tdesc = unicode(m['title_description'])
                 if '<a' in tdesc and '>' in tdesc:
                     short_description = u'%s %s' % (tdesc.split('<')[
                                                     0].strip(', '), tdesc.split('>')[1].split('<')[0])
                 else:
                     short_description = tdesc.strip(', ')
                 movie = Movie(m['id'], htmlparser.unescape(m['title']))
                 movie.other_titles = NotLoaded
                 movie.release_date = NotLoaded
                 movie.duration = NotLoaded
                 movie.short_description = htmlparser.unescape(short_description)
                 movie.pitch = NotLoaded
                 movie.country = NotLoaded
                 movie.note = NotLoaded
                 movie.roles = NotLoaded
                 movie.all_release_dates = NotLoaded
                 movie.thumbnail_url = NotLoaded
                 yield movie
Exemple #21
0
    def retrieve_index(self, browser, repo_path):
        """
        Retrieve the index file of this repository. It can use network
        if this is a remote repository.

        :param repo_path: path to save the downloaded index file.
        :type repo_path: str
        """
        if self.local:
            # Repository is local, open the file.
            filename = os.path.join(self.localurl2path(), self.INDEX)
            try:
                fp = open(filename, 'r')
            except IOError as e:
                # This local repository doesn't contain a built modules.list index.
                self.name = Repositories.url2filename(self.url)
                self.build_index(self.localurl2path(), filename)
                fp = open(filename, 'r')
        else:
            # This is a remote repository, download file
            try:
                fp = StringIO(browser.open(posixpath.join(self.url, self.INDEX)).text)
            except BrowserHTTPError as e:
                raise RepositoryUnavailable(unicode(e))

        self.parse_index(fp)

        if self.local:
            # Always rebuild index of a local repository.
            self.build_index(self.localurl2path(), filename)

        # Save the repository index in ~/.weboob/repositories/
        self.save(repo_path, private=True)
Exemple #22
0
    def load_backends(self, *args, **kwargs):
        while True:
            last_exc = None
            try:
                return Application.load_backends(self, *args, **kwargs)
            except VersionsMismatchError as e:
                msg = 'Versions of modules mismatch with version of weboob.'
            except ConfigError as e:
                msg = unicode(e)
                last_exc = e

            res = QMessageBox.question(None, 'Configuration error', u'%s\n\nDo you want to update repositories?' % msg, QMessageBox.Yes|QMessageBox.No)
            if res == QMessageBox.No:
                raise last_exc

            # Do not import it globally, it causes circular imports
            from .backendcfg import ProgressDialog
            pd = ProgressDialog('Update of repositories', "Cancel", 0, 100)
            pd.setWindowModality(Qt.WindowModal)
            try:
                self.weboob.update(pd)
            except ModuleInstallError as err:
                QMessageBox.critical(None, self.tr('Update error'),
                                     self.tr('Unable to update repositories: %s' % err),
                                     QMessageBox.Ok)
            pd.setValue(100)
            QMessageBox.information(None, self.tr('Update of repositories'),
                                    self.tr('Repositories updated!'), QMessageBox.Ok)
Exemple #23
0
    def do_cd(self, line):
        """
        cd [PATH]

        Follow a path.
        ".." is a special case and goes up one directory.
        "" is a special case and goes home.
        """
        if not len(line.strip()):
            self.working_path.home()
        elif line.strip() == '..':
            self.working_path.up()
        else:
            self.working_path.cd1(line)

            collections = []
            try:
                for res in self.do('get_collection', objs=self.COLLECTION_OBJECTS,
                                   split_path=self.working_path.get(),
                                   caps=CapCollection):
                    if res:
                        collections.append(res)
            except CallErrors as errors:
                self.bcall_errors_handler(errors, CollectionNotFound)

            if len(collections):
                # update the path from the collection if possible
                if len(collections) == 1:
                    self.working_path.split_path = collections[0].split_path
            else:
                print(u"Path: %s not found" % unicode(self.working_path), file=self.stderr)
                self.working_path.restore()
                return 1

        self._change_prompt()
Exemple #24
0
    def retrieve_keyring(self, browser, keyring_path, progress):
        # ignore local
        if self.local:
            return

        keyring = Keyring(keyring_path)
        # prevent previously signed repos from going unsigned
        if not self.signed and keyring.exists():
            raise RepositoryUnavailable('Previously signed repository can not go unsigned')
        if not self.signed:
            return

        if not keyring.exists() or self.key_update > keyring.version:
            # This is a remote repository, download file
            try:
                keyring_data = browser.open(posixpath.join(self.url, self.KEYRING)).content
                sig_data = browser.open(posixpath.join(self.url, self.KEYRING + '.sig')).content
            except BrowserHTTPError as e:
                raise RepositoryUnavailable(unicode(e))
            if keyring.exists():
                if not keyring.is_valid(keyring_data, sig_data):
                    raise InvalidSignature('the keyring itself')
                progress.progress(0.0, 'The keyring was updated (and validated by the previous one).')
            elif not progress.prompt('The repository %s isn\'t trusted yet.\nFingerprint of keyring is %s\nAre you sure you want to continue?' % (self.url, hashlib.sha1(keyring_data).hexdigest())):
                raise RepositoryUnavailable('Repository not trusted')
            keyring.save(keyring_data, self.key_update)
            progress.progress(0.0, str(keyring))
Exemple #25
0
    def update(self, progress=PrintProgress()):
        """
        Update repositories and install new packages versions.

        :param progress: observer object.
        :type progress: :class:`IProgress`
        """
        self.update_repositories(progress)

        to_update = []
        for name, info in self.get_all_modules_info().items():
            if not info.is_local() and info.is_installed():
                if self.versions.get(name) != info.version:
                    to_update.append(info)

        if len(to_update) == 0:
            progress.progress(1.0, 'All modules are up-to-date.')
            return

        class InstallProgress(PrintProgress):
            def __init__(self, n):
                self.n = n

            def progress(self, percent, message):
                progress.progress(float(self.n)/len(to_update) + 1.0/len(to_update)*percent, message)

        for n, info in enumerate(to_update):
            inst_progress = InstallProgress(n)
            try:
                self.install(info, inst_progress)
            except ModuleInstallError as e:
                inst_progress.progress(1.0, unicode(e))
Exemple #26
0
 def __init__(self, value):
     super(_QtValueStr, self).__init__()
     self._value = value
     if value.default:
         self.setText(unicode(value.default))
     if value.masked:
         self.setEchoMode(self.Password)
Exemple #27
0
    def __init__(self, movie, backend, parent=None):
        super(Movie, self).__init__(parent)
        self.parent = parent
        self.ui = Ui_Movie()
        self.ui.setupUi(self)
        langs = sorted(LANGUAGE_CONV.keys())
        for lang in langs:
            self.ui.langCombo.addItem(lang)

        self.ui.castingButton.clicked.connect(self.casting)
        self.ui.torrentButton.clicked.connect(self.searchTorrent)
        self.ui.subtitleButton.clicked.connect(self.searchSubtitle)
        self.ui.personsInCommonButton.clicked.connect(self.personsInCommon)

        self.movie = movie
        self.backend = backend
        self.ui.titleLabel.setText(movie.original_title)
        self.ui.durationLabel.setText(unicode(movie.duration))
        self.gotThumbnail()
        self.putReleases()

        self.ui.idEdit.setText(u'%s@%s' % (movie.id, backend.name))
        if not empty(movie.other_titles):
            self.ui.otherTitlesPlain.setPlainText('\n'.join(movie.other_titles))
        else:
            self.ui.otherTitlesPlain.parent().hide()
        if not empty(movie.genres):
            genres = u''
            for g in movie.genres:
                genres += '%s, ' % g
            genres = genres[:-2]
            self.ui.genresLabel.setText(genres)
        else:
            self.ui.genresLabel.parent().hide()
        if not empty(movie.release_date):
            self.ui.releaseDateLabel.setText(movie.release_date.strftime('%Y-%m-%d'))
        else:
            self.ui.releaseDateLabel.parent().hide()
        if not empty(movie.duration):
            self.ui.durationLabel.setText('%s min' % movie.duration)
        else:
            self.ui.durationLabel.parent().hide()
        if not empty(movie.pitch):
            self.ui.pitchPlain.setPlainText('%s' % movie.pitch)
        else:
            self.ui.pitchPlain.parent().hide()
        if not empty(movie.country):
            self.ui.countryLabel.setText('%s' % movie.country)
        else:
            self.ui.countryLabel.parent().hide()
        if not empty(movie.note):
            self.ui.noteLabel.setText('%s' % movie.note)
        else:
            self.ui.noteLabel.parent().hide()
        for role in movie.roles.keys():
            self.ui.castingCombo.addItem('%s' % role)

        self.ui.verticalLayout.setAlignment(Qt.AlignTop)
        self.ui.verticalLayout_2.setAlignment(Qt.AlignTop)
Exemple #28
0
    def get_loan_list(self):
        accounts = OrderedDict()

        # Old website
        for tr in self.doc.xpath('//table[@cellpadding="1"]/tr[not(@class) and td[a]]'):
            tds = tr.findall('td')

            account = Account()
            account.id = CleanText('./a')(tds[2]).split('-')[0].strip()
            account.label = CleanText('./a')(tds[2]).split('-')[-1].strip()
            account.type = Account.TYPE_LOAN
            account.balance = -CleanDecimal('./a', replace_dots=True)(tds[4])
            account.currency = account.get_currency(CleanText('./a')(tds[4]))
            accounts[account.id] = account

        if len(accounts) == 0:
            # New website
            for table in self.doc.xpath('//div[@class="panel"]'):
                title = table.getprevious()
                if title is None:
                    continue
                account_type = self.ACCOUNT_TYPES.get(CleanText('.')(title), Account.TYPE_UNKNOWN)
                for tr in table.xpath('./table/tbody/tr[contains(@id,"MM_SYNTHESE_CREDITS") and contains(@id,"IdTrGlobal")]'):
                    tds = tr.findall('td')
                    if len(tds) == 0 :
                        continue
                    for i in tds[0].xpath('.//a/strong'):
                        label = i.text.strip()
                        break
                    if len(tds) == 3 and Decimal(FrenchTransaction.clean_amount(CleanText('.')(tds[-2]))) and any(cls in Attr('.', 'id')(tr) for cls in ['dgImmo', 'dgConso']) == False:
                        # in case of Consumer credit or revolving credit, we substract avalaible amount with max amout
                        # to get what was spend
                        balance = Decimal(FrenchTransaction.clean_amount(CleanText('.')(tds[-2]))) - Decimal(FrenchTransaction.clean_amount(CleanText('.')(tds[-1])))
                    else:
                        balance = Decimal(FrenchTransaction.clean_amount(CleanText('.')(tds[-1])))
                    account = Loan()
                    account.id = label.split(' ')[-1]
                    account.label = unicode(label)
                    account.type = account_type
                    account.balance = -abs(balance)
                    account.currency = account.get_currency(CleanText('.')(tds[-1]))
                    account._card_links = []
                    if "immobiliers" in CleanText('.')(title):
                        xp = './/div[contains(@id, "IdDivDetail")]/table/tbody/tr[contains(@id, "%s")]/td'
                        account.maturity_date = Date(CleanText(xp % 'IdDerniereEcheance'), dayfirst=True, default=NotAvailable)(tr)
                        account.total_amount = CleanDecimal(CleanText(xp % 'IdCapitalEmprunte'), replace_dots=True, default=NotAvailable)(tr)
                        account.subscription_date = Date(CleanText(xp % 'IdDateOuverture'), dayfirst=True, default=NotAvailable)(tr)
                        account.next_payment_date = Date(CleanText(xp % 'IdDateProchaineEcheance'), dayfirst=True, default=NotAvailable)(tr)
                        account.rate = CleanDecimal(CleanText(xp % 'IdTaux'), replace_dots=True, default=NotAvailable)(tr)
                        account.next_payment_amount = CleanDecimal(CleanText(xp % 'IdMontantEcheance'), replace_dots=True, default=NotAvailable)(tr)
                    elif "renouvelables" in CleanText('.')(title):
                        self.go_loans_conso(tr)
                        d = self.browser.loans_conso()
                        if d:
                            account.total_amount = d['contrat']['creditMaxAutorise']
                            account.available_amount = d['situationCredit']['disponible']
                            account.next_payment_amount = d['situationCredit']['mensualiteEnCours']
                    accounts[account.id] = account
        return accounts.values()
Exemple #29
0
    def __init__(self, _id, title=NotLoaded, language=NotLoaded, contents=NotLoaded,
            public=NotLoaded, url=None):
        super(BasePaste, self).__init__(unicode(_id), url)

        self.title = title
        self.language = language
        self.contents = contents
        self.public = public
Exemple #30
0
 def dump(self, **kwargs):
     kwargs.pop('since_seconds', None)
     target = os.path.splitext(self.path)[0] + '.sql'
     with tempfile.NamedTemporaryFile(dir=os.path.dirname(self.path), delete=False) as f:
         for line in self.storage.iterdump():
             f.write(unicode(line).encode('utf-8'))
             f.write(b'\n')
     replace(f.name, target)
Exemple #31
0
 def get_account_status(self):
     return (StatusField(u'myname', u'My name', unicode(self.browser.my_name)),
             StatusField(u'credits', u'Credits', unicode(self.browser.credits)),
            )
Exemple #32
0
    def send_email(self, backend_name, mail):
        domain = self.config.get('domain')
        recipient = self.config.get('recipient')

        parent_message = mail.parent
        references = []
        while parent_message:
            references.append(u'<%s.%s@%s>' %
                              (backend_name, mail.parent.full_id, domain))
            parent_message = parent_message.parent
        subject = mail.title
        sender = u'"%s" <%s@%s>' % (mail.sender.replace('"', '""') if
                                    mail.sender else '', backend_name, domain)

        # assume that .date is an UTC datetime
        date = formatdate(time.mktime(utc2local(mail.date).timetuple()),
                          localtime=True)
        msg_id = u'<%s.%s@%s>' % (backend_name, mail.full_id, domain)

        if self.config.get('html') and mail.flags & mail.IS_HTML:
            body = mail.content
            content_type = 'html'
        else:
            if mail.flags & mail.IS_HTML:
                body = html2text(mail.content)
            else:
                body = mail.content
            content_type = 'plain'

        if body is None:
            body = ''

        if mail.signature:
            if self.config.get('html') and mail.flags & mail.IS_HTML:
                body += u'<p>-- <br />%s</p>' % mail.signature
            else:
                body += u'\n\n-- \n'
                if mail.flags & mail.IS_HTML:
                    body += html2text(mail.signature)
                else:
                    body += mail.signature

        # Header class is smart enough to try US-ASCII, then the charset we
        # provide, then fall back to UTF-8.
        header_charset = 'ISO-8859-1'

        # We must choose the body charset manually
        for body_charset in 'US-ASCII', 'ISO-8859-1', 'UTF-8':
            try:
                body.encode(body_charset)
            except UnicodeError:
                pass
            else:
                break

        # Split real name (which is optional) and email address parts
        sender_name, sender_addr = parseaddr(sender)
        recipient_name, recipient_addr = parseaddr(recipient)

        # We must always pass Unicode strings to Header, otherwise it will
        # use RFC 2047 encoding even on plain ASCII strings.
        sender_name = str(Header(unicode(sender_name), header_charset))
        recipient_name = str(Header(unicode(recipient_name), header_charset))

        # Make sure email addresses do not contain non-ASCII characters
        sender_addr = sender_addr.encode('ascii')
        recipient_addr = recipient_addr.encode('ascii')

        # Create the message ('plain' stands for Content-Type: text/plain)
        msg = MIMEText(body.encode(body_charset), content_type, body_charset)
        msg['From'] = formataddr((sender_name, sender_addr))
        msg['To'] = formataddr((recipient_name, recipient_addr))
        msg['Subject'] = Header(unicode(subject), header_charset)
        msg['Message-Id'] = msg_id
        msg['Date'] = date
        if references:
            msg['In-Reply-To'] = references[0]
            msg['References'] = u" ".join(reversed(references))

        self.logger.info('Send mail from <%s> to <%s>' % (sender, recipient))
        if len(self.config.get('pipe')) > 0:
            p = subprocess.Popen(self.config.get('pipe'),
                                 shell=True,
                                 stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.STDOUT)
            p.stdin.write(msg.as_string())
            p.stdin.close()
            if p.wait() != 0:
                self.logger.error('Unable to deliver mail: %s' %
                                  p.stdout.read().strip())
                return False
        else:
            # Send the message via SMTP to localhost:25
            try:
                smtp = SMTP(self.config.get('smtp'))
                smtp.sendmail(sender, recipient, msg.as_string())
            except Exception as e:
                self.logger.error('Unable to deliver mail: %s' % e)
                return False
            else:
                smtp.quit()

        return True
Exemple #33
0
def rebuild_rib(rib):
    rib = clean(rib)
    assert len(rib) >= 21
    key = find_rib_checksum(rib[:5], rib[5:10], rib[10:21])
    return unicode(rib[:21] + ('%02d' % key))
Exemple #34
0
    def __init__(self, movie, backend, parent=None):
        super(Movie, self).__init__(parent)
        self.parent = parent
        self.ui = Ui_Movie()
        self.ui.setupUi(self)
        langs = sorted(LANGUAGE_CONV.keys())
        for lang in langs:
            self.ui.langCombo.addItem(lang)

        self.ui.castingButton.clicked.connect(self.casting)
        self.ui.torrentButton.clicked.connect(self.searchTorrent)
        self.ui.subtitleButton.clicked.connect(self.searchSubtitle)
        self.ui.personsInCommonButton.clicked.connect(self.personsInCommon)

        self.movie = movie
        self.backend = backend
        self.ui.titleLabel.setText(movie.original_title)
        self.ui.durationLabel.setText(unicode(movie.duration))
        self.gotThumbnail()
        self.putReleases()

        self.ui.idEdit.setText(u'%s@%s' % (movie.id, backend.name))
        if not empty(movie.other_titles):
            self.ui.otherTitlesPlain.setPlainText('\n'.join(
                movie.other_titles))
        else:
            self.ui.otherTitlesPlain.parent().hide()
        if not empty(movie.genres):
            genres = u''
            for g in movie.genres:
                genres += '%s, ' % g
            genres = genres[:-2]
            self.ui.genresLabel.setText(genres)
        else:
            self.ui.genresLabel.parent().hide()
        if not empty(movie.release_date):
            self.ui.releaseDateLabel.setText(
                movie.release_date.strftime('%Y-%m-%d'))
        else:
            self.ui.releaseDateLabel.parent().hide()
        if not empty(movie.duration):
            self.ui.durationLabel.setText('%s min' % movie.duration)
        else:
            self.ui.durationLabel.parent().hide()
        if not empty(movie.pitch):
            self.ui.pitchPlain.setPlainText('%s' % movie.pitch)
        else:
            self.ui.pitchPlain.parent().hide()
        if not empty(movie.country):
            self.ui.countryLabel.setText('%s' % movie.country)
        else:
            self.ui.countryLabel.parent().hide()
        if not empty(movie.note):
            self.ui.noteLabel.setText('%s' % movie.note)
        else:
            self.ui.noteLabel.parent().hide()
        for role in movie.roles.keys():
            self.ui.castingCombo.addItem('%s' % role)

        self.ui.verticalLayout.setAlignment(Qt.AlignTop)
        self.ui.verticalLayout_2.setAlignment(Qt.AlignTop)
Exemple #35
0
 def __init__(self, backend_name, exception):
     super(WebNip.LoadError, self).__init__(unicode(exception))
     self.backend_name = backend_name
Exemple #36
0
 def __init__(self, id, name, value, url=None):
     super(Status, self).__init__(id, url)
     self.name = unicode(name)
     self.value = value
Exemple #37
0
    def run(self):

        now = datetime.datetime.now().strftime("%Y-%m-%d")

        if self.boomoney.options.force:
            from_date = self.date_min
        else:
            from_date = self.last_date

        if from_date >= now:
            self.boomoney.print(
                Style.BRIGHT +
                "%s (%s): Last import date is %s, no need to import again..." %
                (self.account, self.label, self.last_date) + Style.RESET_ALL)
            return

        boobank = self.boomoney.createBoobank(self.account)
        if boobank is None:
            with numMutex:
                self.boomoney.importIndex = self.boomoney.importIndex + 1
            return

        boobank.stderr = StringIO()
        boobank.stdout = boobank.stderr
        id, backend = self.account.split("@")
        module_name, foo = boobank.weboob.backends_config.get_backend(backend)
        moduleHandler = "%s.bat" % os.path.join(
            os.path.dirname(self.boomoney.getMoneyFile()), module_name)
        self.boomoney.logger.info("Starting history of %s (%s)..." %
                                  (self.account, self.label))

        MAX_RETRIES = 3
        count = 0
        found = False
        content = ''
        boobank.error = False
        while count <= MAX_RETRIES and not (found and not boobank.error):
            boobank.options.outfile = StringIO()
            boobank.error = False

            # executing history command
            boobank.onecmd("history " + self.account + " " + from_date)

            if count > 0:
                self.boomoney.logger.info(
                    "Retrying %s (%s)... %i/%i" %
                    (self.account, self.label, count, MAX_RETRIES))
            found = re.match(r'^OFXHEADER:100',
                             boobank.options.outfile.getvalue())
            if found and not boobank.error:
                content = boobank.options.outfile.getvalue()
            boobank.options.outfile.close()
            count = count + 1
        if content == '':
            # error occurred
            with numMutex:
                self.boomoney.importIndex = self.boomoney.importIndex + 1
                index = self.boomoney.importIndex
            self.boomoney.logger.error(
                "(%i/%i) %s (%s): %saborting after %i retries.%s" %
                (index, len(self.boomoney.threads), self.account, self.label,
                 Fore.RED + Style.BRIGHT, MAX_RETRIES, Style.RESET_ALL))
            return

        # postprocessing of the ofx content to match MSMoney expectations
        content = re.sub(r'<BALAMT>Not loaded', r'<BALAMT></BALAMT>', content)
        input = StringIO(content)
        output = StringIO()
        field = {}
        fields = ' '
        for line in input:
            if re.match(r'^OFXHEADER:100', line):
                inTransaction = False
            if re.match(r'^<STMTTRN>', line):
                inTransaction = True
            if not inTransaction:
                output.write(line)
            if re.match(r'^</STMTTRN>', line):
                # MSMoney expects CHECKNUM instead of NAME for CHECK transactions
                if "TRNTYPE" in field and field["TRNTYPE"] == "CHECK":
                    if "NAME" in field and unicode(field["NAME"]).isnumeric():
                        field["CHECKNUM"] = field["NAME"]
                        del field["NAME"]
                        fields = fields.replace(' NAME ', ' CHECKNUM ')

                # go through specific backend process if any
                IGNORE = False
                NEW = None
                origfields = fields
                origfield = field.copy()
                if os.path.exists(moduleHandler):
                    self.boomoney.logger.info("Calling backend handler %s..." %
                                              moduleHandler)
                    # apply the transformations, in the form
                    # field_NAME=...
                    # field_MEMO=...
                    # field=...

                    cmd = 'cmd /C '
                    for f in field:
                        value = field[f]
                        cmd = cmd + 'set field_%s=%s& ' % (f, value)

                    cmd = cmd + '"' + moduleHandler + '"'
                    result = subprocess.check_output(
                        cmd.encode(sys.stdout.encoding))

                    for line in re.split(r'[\r\n]+', result):
                        if not line == "":
                            f, value = line.split("=", 1)

                            if f == "IGNORE":
                                IGNORE = True
                            elif f == "NEW":
                                NEW = value
                            elif f.startswith('field_'):
                                f = re.sub(r'^field_', '', f)
                                if value == "":
                                    if f in field:
                                        del field[f]
                                    fields = re.sub(" " + f + " ", " ", fields)
                                else:
                                    field[f] = value
                                    if f not in fields.strip().split(" "):
                                        # MSMoney does not like when CHECKNUM is after MEMO
                                        if f == "CHECKNUM":
                                            fields = fields.replace(
                                                "MEMO", "CHECKNUM MEMO")
                                        else:
                                            fields = fields + f + " "

                if not IGNORE:
                    # dump transaction
                    self.dumpTransaction(output, fields, field)

                    if NEW is not None:
                        for n in NEW.strip().split(" "):
                            fields = origfields
                            field = origfield.copy()
                            field["FITID"] = origfield["FITID"] + "_" + n
                            for line in re.split(r'[\r\n]+', result):
                                if not line == "":
                                    f, value = line.split("=", 1)

                                    if f.startswith(n + '_field_'):
                                        f = re.sub(r'^.*_field_', '', f)
                                        field[f] = value
                                        if f not in fields.strip().split(" "):
                                            fields = fields + f + " "
                            # dump secondary transaction
                            self.dumpTransaction(output, fields, field)

                inTransaction = False
            if inTransaction:
                if re.match(r'^<STMTTRN>', line):
                    field = {}
                    fields = ' '
                else:
                    t = line.split(">", 1)
                    v = re.split(r'[\r\n]', t[1])
                    field[t[0][1:]] = v[0]
                    fields = fields + t[0][1:] + ' '

        ofxcontent = output.getvalue()
        stderrcontent = boobank.stderr.getvalue()
        input.close()
        output.close()
        boobank.stderr.close()

        if self.boomoney.options.display:
            self.boomoney.print(Style.BRIGHT + ofxcontent + Style.RESET_ALL)

        nbTransactions = ofxcontent.count('<STMTTRN>')

        # create ofx file
        fname = re.sub(r'[^\w@\. ]', '_', self.account + " " + self.label)
        ofxfile = os.path.join(self.boomoney.getDownloadsPath(),
                               fname + ".ofx")
        with open(ofxfile, "w") as ofx_file:
            ofx_file.write(
                re.sub(r'\r\n', r'\n', ofxcontent.encode(sys.stdout.encoding)))

        with numMutex:
            self.boomoney.write(stderrcontent)
            self.boomoney.importIndex = self.boomoney.importIndex + 1
            index = self.boomoney.importIndex
        if not (self.boomoney.options.noimport or nbTransactions == 0):
            self.boomoney.backupIfNeeded()
        with printMutex:
            if self.boomoney.options.noimport or nbTransactions == 0:
                if nbTransactions == 0:
                    print(Style.BRIGHT + '(%i/%i) %s (%s) (no transaction).' %
                          (index, len(self.boomoney.threads), self.account,
                           self.label) + Style.RESET_ALL)
                else:
                    print(Fore.GREEN + Style.BRIGHT +
                          '(%i/%i) %s (%s) (%i transaction(s)).' %
                          (index, len(self.boomoney.threads), self.account,
                           self.label, nbTransactions) + Style.RESET_ALL)
            else:
                # import into money
                print(
                    Fore.GREEN + Style.BRIGHT +
                    '(%i/%i) Importing "%s" into MSMoney (%i transaction(s))...'
                    % (index, len(self.boomoney.threads), ofxfile,
                       nbTransactions) + Style.RESET_ALL)
        if not self.boomoney.options.noimport:
            if nbTransactions > 0:
                subprocess.check_call('"%s" %s' % (os.path.join(
                    self.boomoney.getMoneyPath(), "mnyimprt.exe"), ofxfile))
            self.last_date = now
Exemple #38
0
    def fetch(self, which, modulename=None, login=None):
        """
        Wrapper to fetch data from the Weboob connector.

        This wrapper fetches the required data from Weboob and returns it. It
        handles the translation between Weboob exceptions and Kresus error
        codes stored in the JSON response.

        :param which: The type of data to fetch. Can be either ``accounts`` or
        ``operations``.

        :param modulename: The name of the module from which data should be
        fetched. Optional, if not provided all available backends are used.

        :param login: The login to further filter on the available backends.
        Optional, if not provided all matching backends are used.

        :returns: A dict of the fetched data, in a ``values`` keys. Errors are
        described under ``error_code``, ``error_short`` and ``error_content``
        keys.
        """
        results = {}
        try:
            results['values'] = []
            backends = self.get_backends(modulename, login)

            if which == 'accounts':
                fetch_function = self.get_accounts
            elif which == 'operations':
                fetch_function = self.get_operations
            else:
                raise Exception('Invalid fetch command.')

            for backend in backends:
                with backend:  # Acquire lock on backend
                    results['values'].extend(fetch_function(backend))

        except NoAccountsException:
            results['error_code'] = NO_ACCOUNTS
        except ModuleLoadError:
            results['error_code'] = UNKNOWN_MODULE
        except BrowserPasswordExpired:
            results['error_code'] = EXPIRED_PASSWORD
        except ActionNeeded as exc:
            # This `except` clause is not in alphabetic order and cannot be,
            # because BrowserPasswordExpired (above) inherits from it in
            # Weboob 1.4.
            results['error_code'] = ACTION_NEEDED
            results['error_content'] = unicode(exc)
        except BrowserIncorrectPassword:
            # This `except` clause is not in alphabetic order and cannot be,
            # because BrowserPasswordExpired (above) inherits from it in
            # Weboob 1.3.
            results['error_code'] = INVALID_PASSWORD
        except Module.ConfigError as exc:
            results['error_code'] = INVALID_PARAMETERS
            results['error_content'] = unicode(exc)
        except ConnectionError as exc:
            results['error_code'] = CONNECTION_ERROR
            results['error_content'] = unicode(exc)
        except Exception as exc:
            fail(GENERIC_EXCEPTION, 'Unknown error: %s.' % unicode(exc),
                 traceback.format_exc())
        return results
Exemple #39
0
 def filter(self, values):
     values = [unicode(v) for v in values if v]
     if not values and self.default is not _NO_DEFAULT:
         return self.default
     return self.pattern.join(values)
Exemple #40
0
 def read_text(self, pos):
     t = self._tok.tok(pos)
     # TODO: handle PDF encodings properly.
     return (pos+1, unicode(t.value(), errors='ignore')) \
         if t.is_text() else (pos, None)
Exemple #41
0
def main():
    """
    Guess what? It's the main function!
    """

    parser = argparse.ArgumentParser(
        description='Process CLI arguments for Kresus')

    parser.add_argument('command',
                        choices=['test', 'version', 'operations', 'accounts'],
                        help='The command to be executed by the script')
    parser.add_argument('--module', help="The weboob module name.")
    parser.add_argument('--login', help="The login for the access.")
    parser.add_argument('--password', help="The password for the access.")
    parser.add_argument('--field',
                        nargs=2,
                        action='append',
                        help="Custom fields. Can be set several times.",
                        metavar=('NAME', 'VALUE'))
    parser.add_argument('--debug',
                        action='store_true',
                        help="If set, the debug mode is activated.")
    parser.add_argument(
        '--update',
        action='store_true',
        help=("If set, the repositories will be updated prior to command "
              "accounts or operations."))

    # Parse command from standard input.
    options = parser.parse_args()

    # Handle logging
    is_prod = os.environ.get('NODE_ENV', 'production') == 'production'
    if options.debug:
        init_logging(logging.DEBUG, is_prod)
    else:
        init_logging(logging.WARNING, is_prod)

    kresus_dir = os.environ.get('KRESUS_DIR', None)
    if kresus_dir is None:
        fail(INTERNAL_ERROR,
             "KRESUS_DIR must be set to use the weboob cli tool.",
             traceback.format_exc())

    sources_list_content = None
    if ('WEBOOB_SOURCES_LIST' in os.environ
            and os.path.isfile(os.environ['WEBOOB_SOURCES_LIST'])):
        # Read the new content from the sources.list provided as env
        # variable.
        with io.open(os.environ['WEBOOB_SOURCES_LIST'],
                     encoding="utf-8") as fh:
            sources_list_content = fh.read().splitlines()

    # Build a Weboob connector.
    try:
        weboob_connector = Connector(
            weboob_data_path=os.path.join(kresus_dir, 'weboob-data'),
            fakemodules_path=os.path.join(kresus_dir, 'fakemodules'),
            sources_list_content=sources_list_content,
            is_prod=is_prod,
        )
    except ConnectionError as exc:
        fail(CONNECTION_ERROR, 'The connection seems down: %s' % unicode(exc),
             traceback.format_exc())
    except Exception as exc:
        fail(WEBOOB_NOT_INSTALLED,
             ('Is weboob installed? Unknown exception raised: %s.' %
              unicode(exc)), traceback.format_exc())

    # Handle the command and output the expected result on standard output, as
    # JSON encoded string.
    command = options.command
    if command == 'version':
        # Return Weboob version.
        obj = {'values': weboob_connector.version()}
        print(json.dumps(obj))
        sys.exit()

    if options.update:
        # Update Weboob modules.
        try:
            weboob_connector.update()
        except ConnectionError as exc:
            fail(CONNECTION_ERROR,
                 'Exception when updating weboob: %s.' % unicode(exc),
                 traceback.format_exc())
        except Exception as exc:
            fail(GENERIC_EXCEPTION,
                 'Exception when updating weboob: %s.' % unicode(exc),
                 traceback.format_exc())

    if command == 'test':
        # Do nothing, just check we arrived so far.
        print(json.dumps({}))
        sys.exit()

    if command in ['accounts', 'operations']:
        if not options.module:
            fail_unset_field('Module')

        if not options.login:
            fail_unset_field('Login')

        if not options.password:
            fail_unset_field('Password', error_type=NO_PASSWORD)

        # Format parameters for the Weboob connector.
        bank_module = options.module

        params = {
            'login': options.login,
            'password': options.password,
        }

        if options.field is not None:
            for name, value in options.field:
                if not name:
                    fail_unset_field('Name of custom field')
                if not value:
                    fail_unset_field('Value of custom field')
                params[name] = value

        # Create a Weboob backend, fetch data and delete the module.
        try:
            weboob_connector.create_backend(bank_module, params)
        except Module.ConfigError as exc:
            fail(INVALID_PARAMETERS, "Unable to load module %s." % bank_module,
                 traceback.format_exc())

        except ModuleLoadError as exc:
            fail(UNKNOWN_MODULE, "Unable to load module %s." % bank_module,
                 traceback.format_exc())

        content = weboob_connector.fetch(command)
        weboob_connector.delete_backend(bank_module, login=params['login'])

        # Output the fetched data as JSON.
        print(json.dumps(content, cls=WeboobEncoder))
        sys.exit()
Exemple #42
0
    def get_list(self):
        for table in self.has_accounts():
            tds = table.xpath('./tbody/tr')[0].findall('td')
            if len(tds) < 3:
                if tds[0].text_content() == u'Pr\xeat Personnel':

                    account = Account()
                    args = self.js2args(table.xpath('.//a')[0].attrib['onclick'])
                    account._args = args
                    account.label = CleanText().filter(tds[0].xpath('./ancestor::table[has-class("tableaux-pret-personnel")]/caption'))
                    account.id = account.label.split()[-1] + args['paramNumContrat']
                    loan_details = self.browser.open("/webapp/axabanque/jsp/panorama.faces",data=args)
                    # Need to go back on home page after open
                    self.browser.bank_accounts.open()
                    account.balance = -CleanDecimal().filter(loan_details.page.doc.xpath('//*[@id="table-detail"]/tbody/tr/td[7]/text()'))
                    account.currency = Currency().filter(loan_details.page.doc.xpath('//*[@id="table-detail"]/tbody/tr/td[7]/text()'))
                    account.type = Account.TYPE_LOAN
                    account._acctype = "bank"
                    account._hasinv = False
                    yield account

                continue

            boxes = table.xpath('./tbody//tr[not(.//strong[contains(text(), "Total")])]')
            foot = table.xpath('./tfoot//tr')

            for box in boxes:
                account = Account()
                account._url = None

                if len(box.xpath('.//a')) != 0 and 'onclick' in box.xpath('.//a')[0].attrib:
                    args = self.js2args(box.xpath('.//a')[0].attrib['onclick'])
                    account.label =  u'{0} {1}'.format(unicode(table.xpath('./caption')[0].text.strip()), unicode(box.xpath('.//a')[0].text.strip()))
                elif len(foot[0].xpath('.//a')) != 0 and 'onclick' in foot[0].xpath('.//a')[0].attrib:
                    args = self.js2args(foot[0].xpath('.//a')[0].attrib['onclick'])
                    account.label =  unicode(table.xpath('./caption')[0].text.strip())
                else:
                    continue

                self.logger.debug('Args: %r' % args)
                if 'paramNumCompte' not in args:
                    #The displaying of life insurances is very different from the other
                    if args.get('idPanorama:_idcl').split(":")[1] == 'tableaux-direct-solution-vie':
                        account_details = self.browser.open("#", data=args)
                        scripts = account_details.page.doc.xpath('//script[@type="text/javascript"]/text()')
                        script = filter(lambda x: "src" in x, scripts)[0]
                        iframe_url = re.search("src:(.*),", script).group()[6:-2]
                        account_details_iframe = self.browser.open(iframe_url, data=args)
                        account.id = account_details_iframe.page.doc.xpath('//span[contains(@id,"NumeroContrat")]/text()')[0]
                        account._url = iframe_url
                        account.type = account.TYPE_LIFE_INSURANCE
                        account.balance = MyDecimal().filter(account_details_iframe.page.doc.xpath('//span[contains(@id,"MontantEpargne")]/text()')[0])
                        account._acctype = "bank"
                    else:
                        try:
                            label = unicode(table.xpath('./caption')[0].text.strip())
                        except Exception:
                            label = 'Unable to determine'
                        self.logger.warning('Unable to get account ID for %r' % label)
                        continue

                if account.type != account.TYPE_LIFE_INSURANCE:
                    try:
                        account.id = args['paramNumCompte'] + args['paramNumContrat']
                        if 'Visa' in account.label:
                            card_id = re.search('(\d+)', box.xpath('./td[2]')[0].text.strip())
                            if card_id:
                                account.id += card_id.group(1)
                        if u'Valorisation' in account.label or u'Liquidités' in account.label:
                            account.id += args[next(k for k in args.keys() if "_idcl" in k)].split('Jsp')[-1]
                    except KeyError:
                        account.id = args['paramNumCompte']

                    try:
                        account.balance = Decimal(FrenchTransaction.clean_amount(self.parse_number(u''.join([txt.strip() for txt in box.cssselect("td.montant")[0].itertext()]))))
                    except InvalidOperation:
                        #The account doesn't have a amount
                        pass

                    for l in table.attrib['class'].split(' '):
                        if 'tableaux-comptes-' in l:
                            account_type_str = l[len('tableaux-comptes-'):].lower()
                            break
                    else:
                        account_type_str = ''
                    for pattern, type in self.ACCOUNT_TYPES.items():
                        if pattern in account_type_str or pattern in account.label.lower():
                            account.type = type
                            break
                    else:
                        account.type = Account.TYPE_UNKNOWN

                    types = [('Valorisation', Account.TYPE_MARKET),
                             ('Visa', Account.TYPE_CARD),
                            ]

                    for sub, t in types:
                        if sub in account.label:
                            account.type = t
                            break

                    account._url = self.doc.xpath('//form[contains(@action, "panorama")]/@action')[0]
                    account._acctype = "bank"

                currency_title = table.xpath('./thead//th[@class="montant"]')[0].text.strip()
                m = re.match('Montant \((\w+)\)', currency_title)
                if not m:
                    self.logger.warning('Unable to parse currency %r' % currency_title)
                else:
                    account.currency = account.get_currency(m.group(1))

                account._args = args
                account._hasinv = True if "Valorisation" in account.label else False

                yield account
Exemple #43
0
 def __str__(self):
     return unicode(self).encode('utf-8')
Exemple #44
0
    def get_movie(self, id):
        res = self.open(
            'http://www.omdbapi.com/?apikey=b7c56eb5&i=%s&plot=full' % id)
        if res is not None:
            jres = res.json()
        else:
            return None
        htmlparser = HTMLParser()

        title = NotAvailable
        duration = NotAvailable
        release_date = NotAvailable
        pitch = NotAvailable
        country = NotAvailable
        note = NotAvailable
        short_description = NotAvailable
        thumbnail_url = NotAvailable
        other_titles = []
        genres = []
        roles = {}

        if 'Title' not in jres:
            return
        title = htmlparser.unescape(unicode(jres['Title'].strip()))
        if 'Poster' in jres:
            thumbnail_url = unicode(jres['Poster'])
        if 'Director' in jres:
            short_description = unicode(jres['Director'])
        if 'Genre' in jres:
            for g in jres['Genre'].split(', '):
                genres.append(g)
        if 'Runtime' in jres:
            m = re.search('(\d+?) min', jres['Runtime'])
            if m:
                duration = int(m.group(1))
        if 'Released' in jres:
            released_string = str(jres['Released'])
            if released_string == 'N/A':
                release_date = NotAvailable
            else:
                months = {
                    'Jan': '01',
                    'Feb': '02',
                    'Mar': '03',
                    'Apr': '04',
                    'May': '05',
                    'Jun': '06',
                    'Jul': '07',
                    'Aug': '08',
                    'Sep': '09',
                    'Oct': '10',
                    'Nov': '11',
                    'Dec': '12',
                }
                for st in months:
                    released_string = released_string.replace(st, months[st])
                release_date = datetime.strptime(released_string, '%d %m %Y')
        if 'Country' in jres:
            country = u''
            for c in jres['Country'].split(', '):
                country += '%s, ' % c
            country = country[:-2]
        if 'Plot' in jres:
            pitch = unicode(jres['Plot'])
        if 'imdbRating' in jres and 'imdbVotes' in jres:
            note = u'%s/10 (%s votes)' % (jres['imdbRating'],
                                          jres['imdbVotes'])
        for r in ['Actors', 'Director', 'Writer']:
            if '%s' % r in jres.keys():
                roles['%s' % r] = [('N/A', e)
                                   for e in jres['%s' % r].split(', ')]

        movie = Movie(id, title)
        movie.other_titles = other_titles
        movie.release_date = release_date
        movie.duration = duration
        movie.genres = genres
        movie.pitch = pitch
        movie.country = country
        movie.note = note
        movie.roles = roles
        movie.short_description = short_description
        movie.all_release_dates = NotLoaded
        movie.thumbnail_url = thumbnail_url
        return movie
Exemple #45
0
 def iter_recipes(self, pattern):
     return self.browser.iter_recipes(
         strip_accents(unicode(pattern)).encode('utf-8'))
Exemple #46
0
 def decode_row(self, row, encoding):
     if encoding:
         return [unicode(cell, encoding) for cell in row]
     else:
         return row
Exemple #47
0
 def __init__(self, id, name, url=None):
     super(Version, self).__init__(id, url)
     self.name = unicode(name)
Exemple #48
0
 def tostring(self, element):
     if not isinstance(element, basestring):
         return unicode(element)
     return element
Exemple #49
0
 def __init__(self, id, name, url=None):
     super(Project, self).__init__(id, url)
     self.name = unicode(name)
Exemple #50
0
    sys.path.append(os.environ['WEBOOB_DIR'])

try:
    from weboob.capabilities.base import empty
    from weboob.core import Weboob
    from weboob.exceptions import (ActionNeeded, BrowserIncorrectPassword,
                                   BrowserPasswordExpired, NoAccountsException,
                                   ModuleInstallError, ModuleLoadError)
    from weboob.tools.backend import Module
    from weboob.tools.compat import unicode
    from weboob.tools.log import createColoredFormatter
    from weboob.tools.json import WeboobEncoder
except ImportError as exc:
    fail(WEBOOB_NOT_INSTALLED,
         ('Is weboob correctly installed? Unknown exception raised: %s.' %
          unicode(exc)), traceback.format_exc())


def init_logging(level, is_prod):
    """
    Initialize loggers.

    :param level: Minimal severity to log.
    :param is_prod: whether we're running in production or not.
    """
    root_logger = logging.getLogger()

    root_logger.setLevel(level)

    handler = logging.StreamHandler(sys.stderr)
    fmt = ('%(asctime)s:%(levelname)s:%(name)s:%(filename)s:'
Exemple #51
0
 def searchSubtitle(self):
     tosearch = unicode(self.movie.original_title)
     lang = self.ui.langCombo.currentText()
     desc = 'Search subtitles for "%s" (lang:%s)' % (tosearch, lang)
     self.parent.doAction(desc, self.parent.searchSubtitleAction,
                          [lang, tosearch])
Exemple #52
0
    def get_list(self):
        no_accounts_message = self.doc.xpath(u'//span/b[contains(text(),"Votre abonnement est clôturé. Veuillez contacter votre conseiller.")]/text()')
        if no_accounts_message:
            raise ActionNeeded(no_accounts_message[0])

        previous_checking_account = None
        # Several deposit accounts ('Compte à terme') have the same id and the same label
        # So a number is added to distinguish them
        previous_deposit_account = None
        deposit_count = 1
        for tr in self.doc.xpath('//table[has-class("datas")]//tr'):
            if tr.attrib.get('class', '') == 'entete':
                continue

            cols = tr.findall('td')

            a = Account()
            a.label = unicode(cols[self.COL_ID].xpath('.//span[@class="left-underline"] | .//span[@class="left"]/a')[0].text.strip())
            a.type = self.get_account_type(a.label)
            balance = CleanText('.')(cols[self.COL_BALANCE])
            if balance == '':
                continue
            a.balance = CleanDecimal(replace_dots=True).filter(balance)
            a.currency = a.get_currency(balance)
            if cols[self.COL_ID].find('a'):
                a._link, a._args = self.params_from_js(cols[self.COL_ID].find('a').attrib['href'])
            # There may be a href with 'javascript:NoDetail();'
            # The _link and _args should be None
            else:
                a._link, a._args = None, None
            a._acc_nb = cols[self.COL_ID].xpath('.//span[@class="right-underline"] | .//span[@class="right"]')[0].text.replace(' ', '').strip()

            a.id = a._acc_nb
            if hasattr(a, '_args') and a._args:
                if a._args['IndiceCompte'].isdigit():
                    a.id = '%s%s' % (a.id, a._args['IndiceCompte'])
                if a._args['Indiceclassement'].isdigit():
                    a.id = '%s%s' % (a.id, a._args['Indiceclassement'])

            # This account can be multiple life insurance accounts
            if (any(a.label.startswith(lab) for lab in ['ASS.VIE-BONS CAPI-SCPI-DIVERS', 'BONS CAPI-SCPI-DIVERS'])
                or (u'Aucun d\\351tail correspondant pour ce compte' in tr.xpath('.//a/@href')[0])
                    and 'COMPTE A TERME' not in tr.xpath('.//span[contains(@class, "left")]/text()')[0]):
                continue

            if a.type is Account.TYPE_CARD:
                a.coming = a.balance
                a.balance = Decimal('0.0')

                # Take the predecessiong checking account as parent
                if previous_checking_account:
                    a.parent = previous_checking_account
                else:
                    self.logger.warning('The card account %s has no parent account' % a.id)

            a._inv = True

            if a.type == Account.TYPE_CHECKING:
                previous_checking_account = a

            if previous_deposit_account and previous_deposit_account.id == a.id:
                a.id = a.id + '_%s' % deposit_count
                deposit_count += 1
                previous_deposit_account = a

            if a.type == Account.TYPE_DEPOSIT:
                previous_deposit_account = a

            yield a
Exemple #53
0
def rebuild_iban(iban):
    return unicode(iban[:2] + ('%02d' % find_iban_checksum(iban)) + iban[4:])
Exemple #54
0
 def get_iban(self):
     m = re.search(self.iban_regexp, self.parsed_text.decode('utf-8'))
     if m:
         return unicode(m.group(1))
     return None
Exemple #55
0
    def process_incoming_mail(self, msg):
        to = self.get_email_address_ident(msg, 'To')
        sender = msg.get('From')
        reply_to = self.get_email_address_ident(msg, 'In-Reply-To')

        title = msg.get('Subject')
        if title:
            new_title = u''
            for part in decode_header(title):
                if part[1]:
                    new_title += unicode(part[0], part[1])
                else:
                    new_title += unicode(part[0])
            title = new_title

        content = u''
        for part in msg.walk():
            if part.get_content_type() == 'text/plain':
                s = part.get_payload(decode=True)
                charsets = part.get_charsets() + msg.get_charsets()
                for charset in charsets:
                    try:
                        if charset is not None:
                            content += unicode(s, charset)
                        else:
                            content += unicode(s)
                    except UnicodeError as e:
                        self.logger.warning('Unicode error: %s' % e)
                        continue
                    except Exception as e:
                        self.logger.exception(e)
                        continue
                    else:
                        break

        if len(content) == 0:
            print('Unable to send an empty message', file=self.stderr)
            return 1

        # remove signature
        content = content.split(u'\n-- \n')[0]

        parent_id = None
        if reply_to is None:
            # This is a new message
            if '.' in to:
                backend_name, thread_id = to.split('.', 1)
            else:
                backend_name = to
                thread_id = None
        else:
            # This is a reply
            try:
                backend_name, id = reply_to.split('.', 1)
                thread_id, parent_id = id.rsplit('.', 1)
            except ValueError:
                print(
                    'In-Reply-To header might be in form <backend.thread_id.message_id>',
                    file=self.stderr)
                return 1

            # Default use the To header field to know the backend to use.
            if to and backend_name != to:
                backend_name = to

        try:
            backend = self.weboob.backend_instances[backend_name]
        except KeyError:
            print('Backend %s not found' % backend_name, file=self.stderr)
            return 1

        if not backend.has_caps(CapMessagesPost):
            print('The backend %s does not implement CapMessagesPost' %
                  backend_name,
                  file=self.stderr)
            return 1

        thread = Thread(thread_id)
        message = Message(
            thread,
            0,
            title=title,
            sender=sender,
            receivers=[to],
            parent=Message(thread, parent_id) if parent_id else None,
            content=content)
        try:
            backend.post_message(message)
        except Exception as e:
            content = u'Unable to send message to %s:\n' % thread_id
            content += u'\n\t%s\n' % to_unicode(e)
            if logging.root.level <= logging.DEBUG:
                content += u'\n%s\n' % to_unicode(get_backtrace(e))
            self.send_email(
                backend.name,
                Message(
                    thread,
                    0,
                    title='Unable to send message',
                    sender='Monboob',
                    parent=Message(thread, parent_id) if parent_id else None,
                    content=content))
Exemple #56
0
 def get_iban(self):
     try:
         return unicode(self.doc.xpath('.//td[@width="315"]/font')[0].text.replace(' ', '').strip())
     except AttributeError:
         return NotAvailable
Exemple #57
0
    def get_list(self):
        for table in self.has_accounts():
            tds = table.xpath('./tbody/tr')[0].findall('td')
            if len(tds) < 3:
                if tds[0].text_content() == 'Prêt Personnel':

                    account = Account()
                    args = self.js2args(
                        table.xpath('.//a')[0].attrib['onclick'])
                    account._args = args
                    account.label = CleanText().filter(tds[0].xpath(
                        './ancestor::table[has-class("tableaux-pret-personnel")]/caption'
                    ))
                    account.id = account.label.split(
                    )[-1] + args['paramNumContrat']
                    account.number = account.id
                    loan_details = self.browser.open(
                        '/webapp/axabanque/jsp/panorama.faces', data=args).page
                    # Need to go back on home page after open
                    self.browser.bank_accounts.open()
                    account.balance = loan_details.get_loan_balance()
                    account.currency = loan_details.get_loan_currency()
                    account.ownership = loan_details.get_loan_ownership()
                    # Skip loans without any balance (already fully reimbursed)
                    if empty(account.balance):
                        continue
                    account.type = Account.TYPE_LOAN
                    account._acctype = "bank"
                    account._hasinv = False
                    account._is_debit_card = False
                    yield account

                continue

            boxes = table.xpath(
                './tbody//tr[not(.//strong[contains(text(), "Total")])]')
            foot = table.xpath('./tfoot//tr')

            for box in boxes:
                account = Account()
                account._url = None

                if len(box.xpath('.//a')) != 0 and 'onclick' in box.xpath(
                        './/a')[0].attrib:
                    args = self.js2args(box.xpath('.//a')[0].attrib['onclick'])
                    account.label = '%s %s' % (
                        table.xpath('./caption')[0].text.strip(),
                        box.xpath('.//a')[0].text.strip())
                elif len(foot[0].xpath('.//a')) != 0 and 'onclick' in foot[
                        0].xpath('.//a')[0].attrib:
                    args = self.js2args(
                        foot[0].xpath('.//a')[0].attrib['onclick'])
                    account.label = table.xpath('./caption')[0].text.strip()
                    # Adding 'Valorisation' to the account label in order to differentiate it
                    # from the card and checking account associate to the './caption'
                    if 'Valorisation' not in account.label and len(
                            box.xpath(
                                './td[contains(text(), "Valorisation")]')):
                        account.label = '%s Valorisation Titres' % CleanText(
                            './caption')(table)
                else:
                    continue

                self.logger.debug('Args: %r' % args)
                if 'paramNumCompte' not in args:
                    # The displaying of life insurances is very different from the other
                    if args.get('idPanorama:_idcl').split(
                            ":")[1] == 'tableaux-direct-solution-vie':
                        account_details = self.browser.open("#", data=args)
                        scripts = account_details.page.doc.xpath(
                            '//script[@type="text/javascript"]/text()')
                        script = list(filter(lambda x: "src" in x, scripts))[0]
                        iframe_url = re.search("src:(.*),",
                                               script).group()[6:-2]
                        account_details_iframe = self.browser.open(iframe_url,
                                                                   data=args)
                        account.id = CleanText(
                            '//span[contains(@id,"NumeroContrat")]/text()')(
                                account_details_iframe.page.doc)
                        account.number = account.id
                        account._url = iframe_url
                        account.type = account.TYPE_LIFE_INSURANCE
                        account.balance = MyDecimal(
                            '//span[contains(@id,"MontantEpargne")]/text()')(
                                account_details_iframe.page.doc)
                        account._acctype = "bank"
                        account._is_debit_card = False
                    else:
                        try:
                            label = unicode(
                                table.xpath('./caption')[0].text.strip())
                        except Exception:
                            label = 'Unable to determine'
                        self.logger.warning('Unable to get account ID for %r' %
                                            label)
                        continue

                if account.type != account.TYPE_LIFE_INSURANCE:
                    # get accounts type
                    account_type_str = ''
                    for l in table.attrib['class'].split(' '):
                        if 'tableaux-comptes-' in l:
                            account_type_str = l[len('tableaux-comptes-'
                                                     ):].lower()
                            break

                    account.type = Account.TYPE_UNKNOWN
                    for pattern, type in self.ACCOUNT_TYPES.items():
                        if pattern in account_type_str or pattern in account.label.lower(
                        ):
                            account.type = type
                            break

                    # get accounts id
                    account.id = args['paramNumCompte'] + args.get(
                        'paramNumContrat', '')

                    if 'Visa' in account.label:
                        account.number = Regexp(
                            CleanText('./td[contains(@class,"libelle")]',
                                      replace=[(' ', ''), ('x', 'X')]),
                            r'(X{12}\d{4})')(box)
                        account.id += Regexp(
                            CleanText('./td[contains(@class,"libelle")]'),
                            r'(\d+)')(box)

                    if 'Valorisation' in account.label or 'Liquidités' in account.label:
                        account.id += args[next(
                            k for k in args.keys()
                            if '_idcl' in k)].split('Jsp')[-1]
                        account.number = account.id

                    # get accounts balance
                    try:
                        balance_value = CleanText(
                            './/td[has-class("montant")]')(box)

                        # skip debit card
                        # some cards don't have information in balance tab, skip them
                        if balance_value == 'Débit immédiat' or balance_value == '':
                            account._is_debit_card = True
                        else:
                            account._is_debit_card = False

                        account.balance = Decimal(
                            FrenchTransaction.clean_amount(
                                self.parse_number(balance_value)))
                        if account.type == Account.TYPE_CARD:
                            account.coming = account.balance
                            account.balance = Decimal(0)

                    except InvalidOperation:
                        # The account doesn't have a amount
                        pass

                    account._url = self.doc.xpath(
                        '//form[contains(@action, "panorama")]/@action')[0]
                    account._acctype = "bank"
                    account._owner = CleanText('./td[has-class("libelle")]')(
                        box)

                # get accounts currency
                currency_title = table.xpath(
                    './thead//th[@class="montant"]')[0].text.strip()
                m = re.match('Montant \((\w+)\)', currency_title)
                if not m:
                    self.logger.warning('Unable to parse currency %r' %
                                        currency_title)
                else:
                    account.currency = account.get_currency(m.group(1))

                account._args = args
                account._hasinv = True if "Valorisation" in account.label else False

                yield account
Exemple #58
0
 def iter_recipes(self, pattern):
     # the search form does that so the url is clean of special chars
     # we go directly on search results by the url so we strip it too
     return self.browser.iter_recipes(strip_accents(unicode(pattern)))
Exemple #59
0
    def bcall_error_handler(self, backend, error, backtrace):
        """
        Handler for an exception inside the CallErrors exception.

        This method can be overrided to support more exceptions types.
        """
        if isinstance(error, BrowserQuestion):
            for field in error.fields:
                v = self.ask(field)
                if v:
                    backend.config[field.id].set(v)
        if isinstance(error, CaptchaQuestion):
            print(u'Warning(%s): Captcha has been found on login page' %
                  backend.name,
                  file=self.stderr)
        elif isinstance(error, BrowserIncorrectPassword):
            msg = unicode(error)
            if not msg:
                msg = 'invalid login/password.'
            print('Error(%s): %s' % (backend.name, msg), file=self.stderr)
            if self.ask('Do you want to reconfigure this backend?',
                        default=True):
                self.unload_backends(names=[backend.name])
                self.edit_backend(backend.name)
                self.load_backends(names=[backend.name])
        elif isinstance(error, BrowserSSLError):
            print(u'FATAL(%s): ' % backend.name + self.BOLD +
                  '/!\ SERVER CERTIFICATE IS INVALID /!\\' + self.NC,
                  file=self.stderr)
        elif isinstance(error, BrowserHTTPSDowngrade):
            print(u'FATAL(%s): ' % backend.name +
                  'Downgrade from HTTPS to HTTP')
        elif isinstance(error, BrowserForbidden):
            msg = unicode(error)
            print(u'Error(%s): %s' % (backend.name, msg or 'Forbidden'),
                  file=self.stderr)
        elif isinstance(error, BrowserUnavailable):
            msg = unicode(error)
            print(u'Error(%s): %s' %
                  (backend.name, msg or 'Website is unavailable.'),
                  file=self.stderr)
        elif isinstance(error, ActionNeeded):
            msg = unicode(error)
            print(u'Error(%s): Action needed on website: %s' %
                  (backend.name, msg),
                  file=self.stderr)
        elif isinstance(error, NotImplementedError):
            print(
                u'Error(%s): this feature is not supported yet by this backend.'
                % backend.name,
                file=self.stderr)
            print(
                u'      %s   To help the maintainer of this backend implement this feature,'
                % (' ' * len(backend.name)),
                file=self.stderr)
            print(u'      %s   please contact us on the project mailing list' %
                  (' ' * len(backend.name)),
                  file=self.stderr)
        elif isinstance(error, TransferInvalidAmount):
            print(u'Error(%s): %s' % (backend.name, to_unicode(error)
                                      or 'The transfer amount is invalid'),
                  file=self.stderr)
        elif isinstance(error, TransferInvalidLabel):
            print(u'Error(%s): %s' % (backend.name, to_unicode(error)
                                      or 'The transfer label is invalid'),
                  file=self.stderr)
        elif isinstance(error, TransferInvalidEmitter):
            print(u'Error(%s): %s' % (backend.name, to_unicode(error)
                                      or 'The transfer emitter is invalid'),
                  file=self.stderr)
        elif isinstance(error, TransferInvalidRecipient):
            print(u'Error(%s): %s' % (backend.name, to_unicode(error)
                                      or 'The transfer recipient is invalid'),
                  file=self.stderr)
        elif isinstance(error, TransferInvalidDate):
            print(u'Error(%s): %s' %
                  (backend.name, to_unicode(error)
                   or 'The transfer execution date is invalid'),
                  file=self.stderr)
        elif isinstance(error, UserError):
            print(u'Error(%s): %s' % (backend.name, to_unicode(error)),
                  file=self.stderr)
        elif isinstance(error, MoreResultsAvailable):
            print(u'Hint: There are more results for backend %s' %
                  (backend.name),
                  file=self.stderr)
        elif isinstance(error, NoAccountsException):
            print(u'Error(%s): %s' % (backend.name, to_unicode(error)
                                      or 'No account on this backend'),
                  file=self.stderr)
        else:
            print(u'Bug(%s): %s' % (backend.name, to_unicode(error)),
                  file=self.stderr)

            minfo = self.weboob.repositories.get_module_info(backend.NAME)
            if minfo and not minfo.is_local():
                if self.options.auto_update:
                    self.weboob.repositories.update_repositories(
                        ConsoleProgress(self))

                    # minfo of the new available module
                    minfo = self.weboob.repositories.get_module_info(
                        backend.NAME)
                    if minfo and minfo.version > self.weboob.repositories.versions.get(minfo.name) and \
                       self.ask('A new version of %s is available. Do you want to install it?' % minfo.name, default=True) and \
                       self.install_module(minfo):
                        print(
                            'New version of module %s has been installed. Retry to call the command.'
                            % minfo.name)
                        return
                else:
                    print(
                        '(If --auto-update is passed on the command-line, new versions of the module will be checked automatically)'
                    )

            if logging.root.level <= logging.DEBUG:
                print(backtrace, file=self.stderr)
            else:
                return True
Exemple #60
0
    def parse_transaction(self, transaction, account):
        trans = []
        # Add secondary transactions on label condition.
        for t in transaction['secondaryTransactions']:
            if t['transactionDescription'][
                    'description'] == u'Virement à partir de':
                trans.extend(self.parse_transaction(t, account))
        if 'transactionStatus' in transaction and transaction[
                'transactionStatus'] in [
                    u'Créé', u'Annulé', u'Suspendu', u'Mis à jour', u'Actif',
                    u'Payé', u'En attente', u'Rejeté', u'Expiré', u'Created',
                    u'Brouillon', u'Paid', u'Pending', u'Canceled',
                    u'Suspended'
                ]:
            return []
        for pattern in [u'Commande à', u'Offre de remboursement', u'Bill to']:
            if 'description' not in transaction[
                    'transactionDescription'] or transaction[
                        'transactionDescription']['description'].startswith(
                            pattern):
                return []

        t = FrenchTransaction(transaction['transactionId'])
        # Those are not really transactions.
        if 'grossAmount' not in transaction or not 'currency' in transaction['grossAmount'] \
                or transaction['transactionDescription']['description'].startswith("Conversion de devise"):
            return []
        original_currency = unicode(transaction['grossAmount']['currency'])
        if not original_currency == account.currency:
            if original_currency in self.browser.account_currencies:
                return []
            cc = [tr['grossAmount']['amountUnformatted'] for tr in transaction['secondaryTransactions'] \
                 if account.currency == tr['grossAmount']['currency'] \
                  and (int(tr['grossAmount']['amountUnformatted']) < 0) == (int(transaction['grossAmount']['amountUnformatted']) < 0) \
                  and tr['transactionDescription']['description'].startswith('Conversion de devise')]
            if not cc:
                return []
            assert len(cc) == 1
            t.original_amount = Decimal(
                str(transaction['netAmount']['amountUnformatted']))
            t.original_currency = original_currency
            t.amount = Decimal(str(cc[0]))
        else:
            t.amount = Decimal(
                str(transaction['netAmount']['amountUnformatted']))
        date = parse_french_date(transaction['transactionTime'])
        raw = "%s %s" % (transaction['transactionDescription']['description'],
                         transaction['transactionDescription']['name'])
        if raw == "Transfert de Compte bancaire":
            t.type = FrenchTransaction.TYPE_TRANSFER
        if raw == u'Annulation des frais de PayPal':
            return []

        # Dougs told us that commission should always be netAmount minus grossAmount
        grossAmount = Decimal(
            str(transaction['grossAmount']['amountUnformatted']))
        t.commission = Decimal(
            str(transaction['feeAmount']['amountUnformatted']))
        if t.commission:
            if original_currency == account.currency:
                assert abs(t.amount - grossAmount) == abs(t.commission)
                t.commission = t.amount - grossAmount
            else:
                t.commission = (t.commission * t.amount /
                                t.original_amount).quantize(
                                    Decimal('.01'), rounding=ROUND_DOWN)

        t.parse(date=date, raw=raw)
        trans.append(t)
        return trans