def test_add(self): u = Url('https://foob.ar/some/where/some/thing') a = Url('http://foob.it/') rel = Url('../../rville') self.assertEqual(a, u + a) self.assertEqual(u, a + u) self.assertEqual(Url('https://foob.ar/some/rville'), u + rel) self.assertEqual(u, rel + u)
def test_init(self): flavours = self.url_flavours() for f in flavours: msg = reduce(lambda a, b: a + b[0], f, '') urlstr = reduce(lambda a, b: a + b[1][0], f, '') tests = reduce(lambda a, b: a + b[1][1], f, tuple()) url = Url(urlstr) for tname, predicate in tests: self.assertTrue(predicate(url), msg=msg + ": " + tname) copy = Url(str(url)) self.assertEqual(str(copy), str(url), msg="copy is not identical")
def test_path_append(self): u = Url(host='foo.com', scheme='http') u.path.append('foo') u.path.append('bar') self.assertTrue(str(u), 'http://foo.com/foo/bar') u = Url(host='foo.com', scheme='http') u.path.append('foo/bar') self.assertEqual(len(u.path), 2) self.assertEqual(u.path[0], 'foo') self.assertEqual(u.path[1], 'bar') self.assertTrue(str(u), 'http://foo.com/foo/bar')
def test_netloc(self): u=Url() self.assertTrue(u) u.username = '******' u.password = '******' u.host = 'foob.ar' self.assertEqual('toto:[email protected]', u.netloc) self.assertEqual(None, u.port) u.netloc = 'toto.com' self.assertEqual(None, u.username) self.assertEqual(None, u.password) self.assertEqual('toto.com', u.host) self.assertEqual(None, u.port)
def handle_starttag(self, tag, attrs): tag = tag.lower() if tag == 'a': href = self.__get_attr('href', attrs) url = Url(href, default_netloc=self.domain, default_path=self.current.path) if self.__sameDomain(url.netloc) and url.scheme == self.scheme: req = GetRequest(url) if req not in self.requests: self.requests.append(req) elif tag == 'img': src = self.__get_attr('src', attrs) for ext in self.config.AllowedExtensions: if re.match(".+\.%s.*" % ext, src): url = Url(src, default_netloc=self.domain, default_path=self.current.path) if self.__sameDomain( url.netloc) and url.scheme == self.scheme: req = GetRequest(url) if req not in self.requests: self.requests.append(req) break elif tag == 'frame' or tag == 'iframe': src = self.__get_attr('src', attrs) url = Url(src, default_netloc=self.domain, default_path=self.current.path) if self.__sameDomain(url.netloc) and url.scheme == self.scheme: req = GetRequest(url) if req not in self.requests: self.requests.append(req) elif tag == 'form': self.form = {} self.form['data'] = {} self.form['action'] = self.__get_attr('action', attrs, self.current.path) self.form['method'] = self.__get_attr('method', attrs, 'get').lower() elif self.form != None: if tag == 'input': name = self.__get_attr('name', attrs) value = self.__get_attr('value', attrs) self.form['data'][name] = value elif tag == 'select': self.form['data'][self.__get_attr('name', attrs)] = ''
def get_user(self, username): endpoint = Url(self.base_url) endpoint.path.append('users') endpoint.path.append(username) request = Request('GET', endpoint) response = self.user_agent.request(request) if response.is_success: return json.loads(response.content) else: raise Exception(response.status_line)
def handle_starttag(self, tag, attrs): tag = tag.lower() if tag == 'a': href = self.__get_attr('href', attrs) url = Url(href, default_netloc=self.domain, default_path=self.current.path) if self.__sameDomain(url.netloc) and url.scheme == self.scheme: req = GetRequest(url) if req not in self.requests: self.requests.append(req) elif tag == 'frame' or tag == 'iframe': src = self.__get_attr('src', attrs) url = Url(src, default_netloc=self.domain, default_path=self.current.path) if self.__sameDomain(url.netloc) and url.scheme == self.scheme: req = GetRequest(url) if req not in self.requests: self.requests.append(req) elif tag == 'form': self.form = {} self.form['data'] = {} self.form['action'] = self.__get_attr('action', attrs, self.current.path) self.form['method'] = self.__get_attr('method', attrs, 'get').lower() elif self.form != None: if tag == 'input': name = self.__get_attr('name', attrs) value = self.__get_attr('value', attrs) if value == "": value = self.__auto_input_form(name) self.form['data'][name] = value elif tag == 'select': #name = self.__get_attr('name', attrs) auto select!!! #print self.__get_attr('value', attrs) self.form['data'][self.__get_attr('name', attrs)] = ''
def handle_endtag(self, tag): tag = tag.lower() if tag == 'form' and self.form != None: if self.form['method'] == 'get': link = self.form['action'] + "?" + urlencode(self.form['data']) url = Url(link, default_netloc=self.domain) if self.__sameDomain(url.netloc) and url.scheme == self.scheme: req = GetRequest(url) if req not in self.requests: self.requests.append(req) elif self.form['method'] == 'post': link = self.form['action'] url = Url(link, default_netloc=self.domain, default_path=self.current.path) if self.__sameDomain(url.netloc) and url.scheme == self.scheme: req = PostRequest(url) for name, value in self.form['data'].items(): req.addField(name, value) if req not in self.requests: self.requests.append(req) self.form = None
def test_netloc(self): u = Url() self.assertTrue(u) u.username = '******' u.password = '******' u.host = 'foob.ar' self.assertEqual('toto:[email protected]', u.netloc) self.assertEqual(None, u.port) u.netloc = 'toto.com' self.assertEqual(None, u.username) self.assertEqual(None, u.password) self.assertEqual('toto.com', u.host) self.assertEqual(None, u.port)
def parse(self, request): if g.O['file-ext'] != None: (root, ext) = os.path.splitext(request.url.path) if ext[1:] not in g.O['file-ext'] and ext != '': self.parsed.append(request) return if g.O['depth'] != None: if len(request.url.path.split('/')) + 1 > g.O['depth']: self.parsed.append(request) return try: response = request.fetch() response = re.sub("href\s*=\s*([^\"'\s>]+)", r'href="\1"', response) response = re.sub("src\s*=\s*([^\"'\s>]+)", r'src="\1"', response) response = re.sub("action\s*=\s*([^\"'\s>]+)", r'action="\1"', response) response = re.sub("method\s*=\s*([^\"'\s>]+)", r'method="\1"', response) response = re.sub("name\s*=\s*([^\"'\s>]+)", r'name="\1"', response) response = re.sub("value\s*=\s*([^\"'\s>]+)", r'value="\1"', response) self.current = request.url self.feed(response) self.close() except Exception as e: #print e pass finally: self.parsed.append(request) if request.redirect != None: url = Url(request.redirect, default_netloc=self.domain, default_path=self.root.path) self.parsed.append(GetRequest(url)) for req in self.requests: if req not in self.parsed: self.parse(req)
def search( self, # Search parameters client_id=None, contact_id=None, invoice_number=None, status=None, payment_type=None, from_date=None, to_date=None, label=None, intro=None, note=None, tags=None, article_id=None, order_by=None, fetch_all=False, allow_empty_filter=False, keep_old_items=False, page=1, per_page=None): """ Fills the list with Invoice-objects If no search criteria given --> all invoices will returned (REALLY ALL!). :param client_id: ID of the client :param contact_id: ID of the contact :param invoice_number: invoice number :param status: Status (DRAFT, OPEN, PAID, OVERDUE, CANCELED). More than one statuses could be given as a comma separated list. Theses statuses will be logically OR-connected. :param payment_type: Payment Type (eg. CASH, BANK_TRANSFER, PAYPAL, ...). More than one payment type could be given as a comma separated list. Theses payment types will be logically OR-connected. You can find a overview of all payment types at API documentation of payments. :param from_date: (originaly: "from") Only show invoices since this date (format YYYY-MM-DD) :param to_date: (originaly: "to") Only show invoices up to this date (format YYYY-MM-DD) :param label: Free text search in label text :param intro: Free text search in introductory text :param note: Free text search in explanatory notes :param tags: Comma seperated list of tags :param article_id: ID of an article :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. So, all invoices will returned. !!! EVERY INVOICE !!! """ # Check empty filter if not allow_empty_filter: if not any([ client_id, contact_id, invoice_number, status, payment_type, from_date, to_date, label, intro, note, tags, article_id, ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path="/api/invoices") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if client_id: url.query["client_id"] = client_id if contact_id: url.query["contact_id"] = contact_id if invoice_number: url.query["invoice_number"] = invoice_number if status: url.query["status"] = status if payment_type: url.query["payment_type"] = payment_type if from_date: url.query["from"] = from_date if to_date: url.query["to"] = to_date if label: url.query["label"] = label if intro: url.query["intro"] = intro if note: url.query["note"] = note if tags: url.query["tags"] = tags if article_id: url.query["article_id"] = article_id # Fetch data response = self.conn.get(path=str(url)) # Parse XML invoices_etree = ET.fromstring(response.data) self.per_page = int(invoices_etree.attrib.get("per_page", "100")) self.total = int(invoices_etree.attrib.get("total", "0")) self.page = int(invoices_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int( bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all invoices for invoice_etree in invoices_etree: self.append(Invoice(conn=self.conn, invoice_etree=invoice_etree)) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters client_id=client_id, contact_id=contact_id, invoice_number=invoice_number, status=status, payment_type=payment_type, from_date=from_date, to_date=to_date, label=label, intro=intro, note=note, tags=tags, article_id=article_id, order_by=order_by, fetch_all=fetch_all, allow_empty_filter=allow_empty_filter, keep_old_items=True, page=page + 1, per_page=per_page)
def search( self, # Search parameters invoice_id = None, from_date = None, to_date = None, type = None, user_id = None, order_by = None, fetch_all = False, allow_empty_filter = False, keep_old_items = False, page = 1, per_page = None ): """ Fills the (internal) list with InvoicePayment-objects If no search criteria given --> all payments will returned (REALLY ALL!). :param invoice_id: ID of the invoice :param from_date: Original "from"; Only payments since this date :param to_date: Original "to"; Only payments up to this date :param type: Payment type (eg. CASH, BANK_TRANSFER, PAYPAL, ...). More than one payment type could be given as a comma separated list. Theses payment types will be logically OR-connected. :param user_id: ID of the user :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. All invoice-payments will returned. !!! EVERY !!! """ # Check empty filter if not allow_empty_filter: if not any([ invoice_id, from_date, to_date, type, user_id, ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path = "/api/invoice-payments") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if invoice_id: url.query["invoice_id"] = invoice_id if from_date: url.query["from"] = from_date if to_date: url.query["to"] = to_date if type: url.query["type"] = type if user_id: url.query["user_id"] = user_id # Fetch data response = self.conn.get(path = str(url)) if response.status != 200: # Check if "Unothorized" --> raise NotFoundError errors_etree = ET.fromstring(response.data) for error_etree in errors_etree: text = error_etree.text if text.lower() == "unauthorized": raise errors.NotFoundError( u"invoice_id: {invoice_id}".format(invoice_id = invoice_id) ) # Other Error raise errors.BillomatError(response.data) # No response (workaround for inconsistent gziped answer; DecodeError) try: if len(response.data) == 0: return except urllib3.exceptions.DecodeError: if response.headers.get("content-type", "").lower() != "application/xml": return else: raise # Parse XML payments_etree = ET.fromstring(response.data) self.per_page = int(payments_etree.attrib.get("per_page", "0")) self.total = int(payments_etree.attrib.get("total", "0")) self.page = int(payments_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int(bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all payments for payment_etree in payments_etree: self.append( InvoicePayment(conn = self.conn, payment_etree = payment_etree) ) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters invoice_id = invoice_id, from_date = from_date, to_date = to_date, type = type, user_id = user_id, order_by = order_by, fetch_all = fetch_all, allow_empty_filter = allow_empty_filter, keep_old_items = True, page = page + 1, per_page = per_page )
def test_path_unicode(self): u = Url(host='foo.com', scheme='http') u.path.append(unicode('/foo/bar/baz')) self.assertEqual(len(u.path), 4) self.assertEqual(str(u), 'http://foo.com/foo/bar/baz')
def search( self, # Search parameters name = None, client_number = None, email = None, first_name = None, last_name = None, country_code = None, note = None, invoice_id = None, tags = None, order_by = None, fetch_all = False, allow_empty_filter = False, keep_old_items = False, page = 1, per_page = None ): """ Fills the (internal) list with Client-objects If no search criteria given --> all clients will returned (REALLY ALL!). :param name: Company name :param client_number: Client number :param email: E-mail address :param first_name: First name of the contact person :param last_name: Last name of the contact person :param country_code: Country code as ISO 3166 Alpha-2 :param note: Note :param invoice_id: ID of an invoice of this client, multiple values seperated with comma :param tags: Comma seperated list of tags :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. All clients will returned. !!! EVERY CLIENT !!! """ # Check empty filter if not allow_empty_filter: if not any([ name, client_number, email, first_name, last_name, country_code, note, invoice_id, tags, ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path = "/api/clients") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if name: url.query["name"] = name if client_number: url.query["client_number"] = client_number if email: url.query["email"] = email if first_name: url.query["first_name"] = first_name if last_name: url.query["last_name"] = last_name if country_code: url.query["country_code"] = country_code if note: url.query["note"] = note if invoice_id: url.query["invoice_id"] = invoice_id if tags: url.query["tags"] = tags # Fetch data response = self.conn.get(path = str(url)) # Parse XML clients_etree = ET.fromstring(response.data) self.per_page = int(clients_etree.attrib.get("per_page", "0")) self.total = int(clients_etree.attrib.get("total", "0")) self.page = int(clients_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int(bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all clients for client_etree in clients_etree: self.append(Client(conn = self.conn, client_etree = client_etree)) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters name = name, client_number = client_number, email = email, first_name = first_name, last_name = last_name, country_code = country_code, note = note, invoice_id = invoice_id, tags = tags, order_by = order_by, fetch_all = fetch_all, allow_empty_filter = allow_empty_filter, keep_old_items = True, page = page + 1, per_page = per_page )
def search( self, # Search parameters reminder_id=None, order_by=None, fetch_all=False, allow_empty_filter=False, keep_old_items=False, page=1, per_page=None): """ Fills the (internal) list with ReminderTag-objects If no search criteria given --> all tags will returned (REALLY ALL!). :param reminder_id: Reminder ID :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. All reminder-tags will returned. !!! EVERY !!! """ # Check empty filter if not allow_empty_filter: if not any([ reminder_id, ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path="/api/reminder-tags") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if reminder_id: url.query["reminder_id"] = reminder_id # Fetch data response = self.conn.get(path=str(url)) if response.status != 200: # Check if "Unothorized" --> raise NotFoundError errors_etree = ET.fromstring(response.data) for error_etree in errors_etree: text = error_etree.text if text.lower() == "unauthorized": raise errors.NotFoundError( u"reminder_id: {reminder_id}".format( reminder_id=reminder_id)) # Other Error raise errors.BillomatError(response.data) # No response (workaround for inconsistent gziped answer; DecodeError) try: if len(response.data) == 0: return except urllib3.exceptions.DecodeError: if response.headers.get("content-type", "").lower() != "application/xml": return else: raise # Parse XML tags_etree = ET.fromstring(response.data) self.per_page = int(tags_etree.attrib.get("per_page", "0")) self.total = int(tags_etree.attrib.get("total", "0")) self.page = int(tags_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int( bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all tags for tag_etree in tags_etree: self.append(ReminderTag(conn=self.conn, tag_etree=tag_etree)) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters reminder_id=reminder_id, fetch_all=fetch_all, allow_empty_filter=allow_empty_filter, keep_old_items=True, page=page + 1, per_page=per_page)
def search( self, # Search parameters client_id=None, contact_id=None, name=None, payment_type=None, cycle=None, label=None, intro=None, note=None, tags=None, order_by=None, fetch_all=False, allow_empty_filter=False, keep_old_items=False, page=1, per_page=None): """ Fills the list with Recurring-objects If no search criteria given --> all recurrings will returned (REALLY ALL!). :param client_id: ID of the client :param contact_id: ID of the contact :param name: The Name of the recurring :param payment_type: Payment Type (eg. CASH, BANK_TRANSFER, PAYPAL, ...). More than one payment type could be given as a comma separated list. Theses payment types will be logically OR-connected. You can find a overview of all payment types at API documentation of payments. :param cycle: Interval (DAILY, WEEKLY, MONTHLY, YEARLY). :param label: Free text search in label text :param intro: Free text search in introductory text :param note: Free text search in explanatory notes :param tags: Comma seperated list of tags :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. So, all invoices will returned. !!! EVERY INVOICE !!! """ # Check empty filter if not allow_empty_filter: if not any([ client_id, contact_id, name, payment_type, cycle, label, intro, note, tags, ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path="/api/recurrings") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if client_id: url.query["client_id"] = client_id if contact_id: url.query["contact_id"] = contact_id if name: url.query["name"] = name if payment_type: url.query["payment_type"] = payment_type if cycle: url.query["cycle"] = cycle if label: url.query["label"] = label if intro: url.query["intro"] = intro if note: url.query["note"] = note if tags: url.query["tags"] = tags # Fetch data response = self.conn.get(path=str(url)) # Parse XML recurrings_etree = ET.fromstring(response.data) self.per_page = int(recurrings_etree.attrib.get("per_page", "100")) self.total = int(recurrings_etree.attrib.get("total", "0")) self.page = int(recurrings_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int( bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all recurrings for recurring_etree in recurrings_etree: self.append( Recurring(conn=self.conn, recurring_etree=recurring_etree)) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters client_id=client_id, contact_id=contact_id, name=name, payment_type=payment_type, cycle=cycle, label=label, intro=intro, note=note, tags=tags, order_by=order_by, fetch_all=fetch_all, allow_empty_filter=allow_empty_filter, keep_old_items=True, page=page + 1, per_page=per_page)
def search( self, # Search parameters order_by=None, fetch_all=False, keep_old_items=False, page=1, per_page=None): """ Fills the (internal) list with ReminderText-objects If no search criteria given --> all email templates will returned (REALLY ALL!). :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. """ # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path="/api/reminder-texts") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Fetch data response = self.conn.get(path=str(url)) # Parse XML reminder_texts_etree = ET.fromstring(response.data) self.per_page = int(reminder_texts_etree.attrib.get("per_page", "0")) self.total = int(reminder_texts_etree.attrib.get("total", "0")) self.page = int(reminder_texts_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int( bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all email templates for reminder_text_etree in reminder_texts_etree: self.append( ReminderText(conn=self.conn, reminder_text_etree=reminder_text_etree)) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search(order_by=order_by, fetch_all=fetch_all, keep_old_items=True, page=page + 1, per_page=per_page)
def search( self, # Search parameters name=None, client_number=None, email=None, first_name=None, last_name=None, country_code=None, note=None, invoice_id=None, tags=None, order_by=None, fetch_all=False, allow_empty_filter=False, keep_old_items=False, page=1, per_page=None): """ Fills the (internal) list with Client-objects If no search criteria given --> all clients will returned (REALLY ALL!). :param name: Company name :param client_number: Client number :param email: E-mail address :param first_name: First name of the contact person :param last_name: Last name of the contact person :param country_code: Country code as ISO 3166 Alpha-2 :param note: Note :param invoice_id: ID of an invoice of this client, multiple values seperated with comma :param tags: Comma seperated list of tags :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. All clients will returned. !!! EVERY CLIENT !!! """ # Check empty filter if not allow_empty_filter: if not any([ name, client_number, email, first_name, last_name, country_code, note, invoice_id, tags, ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path="/api/clients") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if name: url.query["name"] = name if client_number: url.query["client_number"] = client_number if email: url.query["email"] = email if first_name: url.query["first_name"] = first_name if last_name: url.query["last_name"] = last_name if country_code: url.query["country_code"] = country_code if note: url.query["note"] = note if invoice_id: url.query["invoice_id"] = invoice_id if tags: url.query["tags"] = tags # Fetch data response = self.conn.get(path=str(url)) # Parse XML clients_etree = ET.fromstring(response.data) self.per_page = int(clients_etree.attrib.get("per_page", "0")) self.total = int(clients_etree.attrib.get("total", "0")) self.page = int(clients_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int( bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all clients for client_etree in clients_etree: self.append(Client(conn=self.conn, client_etree=client_etree)) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters name=name, client_number=client_number, email=email, first_name=first_name, last_name=last_name, country_code=country_code, note=note, invoice_id=invoice_id, tags=tags, order_by=order_by, fetch_all=fetch_all, allow_empty_filter=allow_empty_filter, keep_old_items=True, page=page + 1, per_page=per_page)
def search( self, # Search parameters order_by = None, fetch_all = False, keep_old_items = False, page = 1, per_page = None ): """ Fills the (internal) list with ReminderText-objects If no search criteria given --> all email templates will returned (REALLY ALL!). :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. """ # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path = "/api/reminder-texts") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Fetch data response = self.conn.get(path = str(url)) # Parse XML reminder_texts_etree = ET.fromstring(response.data) self.per_page = int(reminder_texts_etree.attrib.get("per_page", "0")) self.total = int(reminder_texts_etree.attrib.get("total", "0")) self.page = int(reminder_texts_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int(bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all email templates for reminder_text_etree in reminder_texts_etree: self.append( ReminderText( conn = self.conn, reminder_text_etree = reminder_text_etree ) ) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( order_by = order_by, fetch_all = fetch_all, keep_old_items = True, page = page + 1, per_page = per_page )
def search( self, # Search parameters invoice_id = None, from_date = None, to_date = None, type = None, user_id = None, order_by = None, fetch_all = False, allow_empty_filter = False, keep_old_items = False, page = 1, per_page = None ): """ Fills the (internal) list with InvoicePayment-objects If no search criteria given --> all payments will returned (REALLY ALL!). :param invoice_id: ID of the invoice :param from_date: Original "from"; Only payments since this date :param to_date: Original "to"; Only payments up to this date :param type: Payment type (eg. CASH, BANK_TRANSFER, PAYPAL, ...). More than one payment type could be given as a comma separated list. Theses payment types will be logically OR-connected. :param user_id: ID of the user :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. All invoice-payments will returned. !!! EVERY !!! """ # Check empty filter if not allow_empty_filter: if not any([ invoice_id, from_date, to_date, type, user_id, ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path = "/api/invoice-payments") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if invoice_id: url.query["invoice_id"] = invoice_id if from_date: url.query["from"] = from_date if to_date: url.query["to"] = to_date if type: url.query["type"] = type if user_id: url.query["user_id"] = user_id # Fetch data response = self.conn.get(path = str(url)) if response.status != 200: # Check if "Unothorized" --> raise NotFoundError errors_etree = ET.fromstring(response.data) for error_etree in errors_etree: text = error_etree.text if text.lower() == "unauthorized": raise errors.NotFoundError( u"invoice_id: {invoice_id}".format(invoice_id = invoice_id) ) # Other Error raise errors.BillomatError(response.data) # No response (workaround for inconsistent gziped answer; DecodeError) try: if len(response.data) == 0: return except urllib3.exceptions.DecodeError: if response.headers.get("content-type", "").lower() != "application/xml": return else: raise # Parse XML payments_etree = ET.fromstring(response.data) self.per_page = int(payments_etree.attrib.get("per_page", "0")) self.total = int(payments_etree.attrib.get("total", "0")) self.page = int(payments_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int(bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all payments for payment_etree in payments_etree: self.append( InvoicePayment(conn = self.conn, payment_etree = payment_etree) ) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters invoice_id = invoice_id, from_date = from_date, to_date = to_date, type = type, user_id = user_id, order_by = order_by, fetch_all = fetch_all, allow_empty_filter = allow_empty_filter, keep_old_items = True, page = page + 1, per_page = per_page )
def search( self, # Search parameters client_id = None, client_property_id = None, value = None, order_by = None, fetch_all = False, allow_empty_filter = False, keep_old_items = False, page = 1, per_page = None ): """ Fills the (internal) list with ClientPropertyValue-objects If no search criteria given --> all properties will returned (REALLY ALL!). :param client_id: Client ID :param client_property_id: Client-Property-ID :param value: Value of the Client-Property :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. All client-properties will returned. !!! EVERY !!! """ # Check empty filter if not allow_empty_filter: if not any([ client_id, client_property_id, value ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path = "/api/client-property-values") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if client_id: url.query["client_id"] = client_id if client_property_id: url.query["client_property_id"] = client_property_id if value is not None: url.query["value"] = value # Fetch data response = self.conn.get(path = str(url)) if response.status != 200: # Check if "Unothorized" --> raise NoClientFoundError errors_etree = ET.fromstring(response.data) for error_etree in errors_etree: text = error_etree.text if text.lower() == "unauthorized": raise errors.NotFoundError( u"client_id: {client_id}".format(client_id = client_id) ) # Other Error raise errors.BillomatError(response.data) # No response (workaround for inconsistent gziped answer; DecodeError) try: if len(response.data) == 0: return except urllib3.exceptions.DecodeError: if response.headers.get("content-type", "").lower() != "application/xml": return else: raise # Parse XML properties_etree = ET.fromstring(response.data) self.per_page = int(properties_etree.attrib.get("per_page", "0")) self.total = int(properties_etree.attrib.get("total", "0")) self.page = int(properties_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int(bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all client-properties for property_etree in properties_etree: self.append( ClientProperty(conn = self.conn, property_etree = property_etree) ) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters client_id = client_id, client_property_id = client_property_id, value = value, fetch_all = fetch_all, allow_empty_filter = allow_empty_filter, keep_old_items = True, page = page + 1, per_page = per_page )
def search( self, # Search parameters article_number = None, title = None, description = None, currency_code = None, unit_id = None, tags = None, supplier_id = None, order_by = None, fetch_all = False, allow_empty_filter = False, keep_old_items = False, page = 1, per_page = None ): """ Fills the list with Article-objects If no search criteria given --> all articles will returned (REALLY ALL!). :param article_number: Article number :param title: Title :param description: Description :param currency_code: ISO code of the currency :param unit_id: ID of the chosen unit :param tags: Comma seperated list of tags :param supplier_id: ID of the chosen supplier :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. So, all articles will returned. !!! EVERY INVOICE !!! """ # Check empty filter if not allow_empty_filter: if not any([ article_number, title, description, currency_code, unit_id, tags, supplier_id, ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path = "/api/articles") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if article_number: url.query["article_number"] = article_number if title: url.query["title"] = title if description: url.query["description"] = description if currency_code: url.query["currency_code"] = currency_code if unit_id: url.query["unit_id"] = unit_id if tags: url.query["tags"] = tags if supplier_id: url.query["supplier_id"] = supplier_id # Fetch data response = self.conn.get(path = str(url)) # Parse XML articles_etree = ET.fromstring(response.data) self.per_page = int(articles_etree.attrib.get("per_page", "100")) self.total = int(articles_etree.attrib.get("total", "0")) self.page = int(articles_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int(bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all articles for article_etree in articles_etree: self.append(Article(conn = self.conn, article_etree = article_etree)) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters article_number = article_number, title = title, description = description, currency_code = currency_code, unit_id = unit_id, tags = tags, supplier_id = supplier_id, order_by = order_by, fetch_all = fetch_all, allow_empty_filter = allow_empty_filter, keep_old_items = True, page = page + 1, per_page = per_page )
def search( self, # Search parameters reminder_id = None, order_by = None, fetch_all = False, keep_old_items = False, page = 1, per_page = None ): """ Fills the list with ReminderItem-objects :param reminder_id: ID of the reminder (mandatory) :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. """ # Check empty param if not reminder_id: raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path = "/api/reminder-items") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameter url.query["reminder_id"] = reminder_id # Fetch data response = self.conn.get(path = str(url)) # Parse XML reminder_items_etree = ET.fromstring(response.data) self.per_page = int(reminder_items_etree.attrib.get("per_page", "100")) self.total = int(reminder_items_etree.attrib.get("total", "0")) self.page = int(reminder_items_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int(bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all items for reminder_item_etree in reminder_items_etree: self.append( ReminderItem(conn = self.conn, reminder_item_etree = reminder_item_etree) ) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters reminder_id = reminder_id, order_by = order_by, fetch_all = fetch_all, keep_old_items = True, page = page + 1, per_page = per_page )
def search( self, # Search parameters credit_note_id=None, order_by=None, fetch_all=False, keep_old_items=False, page=1, per_page=None, credit_note_ids=None): """ Fills the list with CreditNoteItem-objects :param credit_note_id: ID of the credit note (mandatory) or a list of IDs. If list with IDs given: The result contains the credit note items of many credit notes. Be careful: Too many credit note IDs can produce to large responses or to large SQL statements. My recommendation: 10-50 credit note IDs at one time. :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. """ # Check empty param if not credit_note_id: raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path=CreditNoteItem.base_path) url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameter if isinstance(credit_note_id, (list, tuple)): credit_note_id = ",".join(str(id) for id in set(credit_note_id)) url.query["credit_note_id"] = credit_note_id # Fetch data response = self.conn.get(path=str(url)) # Parse XML credit_note_items_etree = ET.fromstring(response.data) self.per_page = int( credit_note_items_etree.attrib.get("per_page", "100")) self.total = int(credit_note_items_etree.attrib.get("total", "0")) self.page = int(credit_note_items_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int( bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all items for credit_note_item_etree in credit_note_items_etree: self.append( CreditNoteItem(conn=self.conn, credit_note_item_etree=credit_note_item_etree)) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters credit_note_id=credit_note_id, order_by=order_by, fetch_all=fetch_all, keep_old_items=True, page=page + 1, per_page=per_page)
def search( self, # Search parameters client_id=None, order_by=None, fetch_all=False, keep_old_items=False, page=1, per_page=None): """ Fills the list with Contact-objects :param client_id: ID of the client (mandatory) :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. """ # Check empty param if not client_id: raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path="/api/contacts") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameter url.query["client_id"] = client_id # Fetch data response = self.conn.get(path=str(url)) # Parse XML contacts_etree = ET.fromstring(response.data) self.per_page = int(contacts_etree.attrib.get("per_page", "100")) self.total = int(contacts_etree.attrib.get("total", "0")) self.page = int(contacts_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int( bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all contacts for contact_etree in contacts_etree: self.append(Contact(conn=self.conn, contact_etree=contact_etree)) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters client_id=client_id, order_by=order_by, fetch_all=fetch_all, keep_old_items=True, page=page + 1, per_page=per_page)
def search( self, # Search parameters client_id = None, contact_id = None, invoice_number = None, status = None, payment_type = None, from_date = None, to_date = None, label = None, intro = None, note = None, tags = None, article_id = None, order_by = None, fetch_all = False, allow_empty_filter = False, keep_old_items = False, page = 1, per_page = None ): """ Fills the list with Invoice-objects If no search criteria given --> all invoices will returned (REALLY ALL!). :param client_id: ID of the client :param contact_id: ID of the contact :param invoice_number: invoice number :param status: Status (DRAFT, OPEN, PAID, OVERDUE, CANCELED). More than one statuses could be given as a comma separated list. Theses statuses will be logically OR-connected. :param payment_type: Payment Type (eg. CASH, BANK_TRANSFER, PAYPAL, ...). More than one payment type could be given as a comma separated list. Theses payment types will be logically OR-connected. You can find a overview of all payment types at API documentation of payments. :param from_date: (originaly: "from") Only show invoices since this date (format YYYY-MM-DD) :param to_date: (originaly: "to") Only show invoices up to this date (format YYYY-MM-DD) :param label: Free text search in label text :param intro: Free text search in introductory text :param note: Free text search in explanatory notes :param tags: Comma seperated list of tags :param article_id: ID of an article :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. So, all invoices will returned. !!! EVERY INVOICE !!! """ # Check empty filter if not allow_empty_filter: if not any([ client_id, contact_id, invoice_number, status, payment_type, from_date, to_date, label, intro, note, tags, article_id, ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path = "/api/invoices") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if client_id: url.query["client_id"] = client_id if contact_id: url.query["contact_id"] = contact_id if invoice_number: url.query["invoice_number"] = invoice_number if status: url.query["status"] = status if payment_type: url.query["payment_type"] = payment_type if from_date: url.query["from"] = from_date if to_date: url.query["to"] = to_date if label: url.query["label"] = label if intro: url.query["intro"] = intro if note: url.query["note"] = note if tags: url.query["tags"] = tags if article_id: url.query["article_id"] = article_id # Fetch data response = self.conn.get(path = str(url)) # Parse XML invoices_etree = ET.fromstring(response.data) self.per_page = int(invoices_etree.attrib.get("per_page", "100")) self.total = int(invoices_etree.attrib.get("total", "0")) self.page = int(invoices_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int(bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all invoices for invoice_etree in invoices_etree: self.append(Invoice(conn = self.conn, invoice_etree = invoice_etree)) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters client_id = client_id, contact_id = contact_id, invoice_number = invoice_number, status = status, payment_type = payment_type, from_date = from_date, to_date = to_date, label = label, intro = intro, note = note, tags = tags, article_id = article_id, order_by = order_by, fetch_all = fetch_all, allow_empty_filter = allow_empty_filter, keep_old_items = True, page = page + 1, per_page = per_page )
def test_final_slash(self): u = Url(host='foo.com', scheme='http') self.assertEqual(u, 'http://foo.com/') u = Url('http://foo.com') self.assertEqual(u, 'http://foo.com/')
def search( self, # Search parameters client_id = None, contact_id = None, name = None, payment_type = None, cycle = None, label = None, intro = None, note = None, tags = None, order_by = None, fetch_all = False, allow_empty_filter = False, keep_old_items = False, page = 1, per_page = None ): """ Fills the list with Recurring-objects If no search criteria given --> all recurrings will returned (REALLY ALL!). :param client_id: ID of the client :param contact_id: ID of the contact :param name: The Name of the recurring :param payment_type: Payment Type (eg. CASH, BANK_TRANSFER, PAYPAL, ...). More than one payment type could be given as a comma separated list. Theses payment types will be logically OR-connected. You can find a overview of all payment types at API documentation of payments. :param cycle: Interval (DAILY, WEEKLY, MONTHLY, YEARLY). :param label: Free text search in label text :param intro: Free text search in introductory text :param note: Free text search in explanatory notes :param tags: Comma seperated list of tags :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. So, all invoices will returned. !!! EVERY INVOICE !!! """ # Check empty filter if not allow_empty_filter: if not any([ client_id, contact_id, name, payment_type, cycle, label, intro, note, tags, ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path = "/api/recurrings") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if client_id: url.query["client_id"] = client_id if contact_id: url.query["contact_id"] = contact_id if name: url.query["name"] = name if payment_type: url.query["payment_type"] = payment_type if cycle: url.query["cycle"] = cycle if label: url.query["label"] = label if intro: url.query["intro"] = intro if note: url.query["note"] = note if tags: url.query["tags"] = tags # Fetch data response = self.conn.get(path = str(url)) # Parse XML recurrings_etree = ET.fromstring(response.data) self.per_page = int(recurrings_etree.attrib.get("per_page", "100")) self.total = int(recurrings_etree.attrib.get("total", "0")) self.page = int(recurrings_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int(bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all recurrings for recurring_etree in recurrings_etree: self.append(Recurring(conn = self.conn, recurring_etree = recurring_etree)) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters client_id = client_id, contact_id = contact_id, name = name, payment_type = payment_type, cycle = cycle, label = label, intro = intro, note = note, tags = tags, order_by = order_by, fetch_all = fetch_all, allow_empty_filter = allow_empty_filter, keep_old_items = True, page = page + 1, per_page = per_page )
class Worker(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): while 1: if task_queue.empty() == True: break task = task_queue.get() module[task['module']].exploit(task['request']) if __name__ == '__main__': target = Url("http://w") o = { "depth": 5, "ext": ['cgi', 'cfm', 'asp', 'aspx', 'jsp', 'php', 'htm', 'html', 'do'], } thread = 10 #module_list=["sqli","xss","lfi","ftp_login","ssh_login"] module_list = ["sqli", "xss"] module = {} ya = Crawler(target, o) ya.parse(GetRequest(target)) task_queue = Queue.Queue() for item in module_list: module[item] = __import__(item) for request in ya.requests:
def parse(self, request): # check for a valid extension if self.config.AllowedExtensions != None: (root, ext) = os.path.splitext(request.url.path) if ext[1:] not in self.config.AllowedExtensions and ext != '': self.ed.warning( "Skipping page with unallowed extension '%s' ." % request.url.path) self.parsed.append(request) return # check directory depth if self.config.MaxDirectoryDepth != None: if len(request.url.path.split( '/')) + 1 > self.config.MaxDirectoryDepth: self.ed.warning("Max directory depth exceeded '%s' ." % request.url.path) self.parsed.append(request) return # if enabled, delay the crawl process if self.config.CrawlDelayEnabled != None and self.config.CrawlDelayEnabled == True: self.ed.warning("Delaying crawling process of %d ms ..." % self.config.CrawlDelay) time.sleep(self.config.CrawlDelay / 1000.0) try: # set user-agent if specified if self.config.UserAgent != None: request.setHeader('User-Agent', self.config.UserAgent) # set proxy if specified if self.config.ProxyEnabled != None and self.config.ProxyEnabled == True: self.ed.status( "Setting request proxy to %s:%d ." % (self.config.ProxyServer, self.config.ProxyPort)) request.setProxy(self.config.ProxyServer, self.config.ProxyPort) response = request.fetch() # fix broken html response = re.sub("href\s*=\s*([^\"'\s>]+)", r'href="\1"', response) response = re.sub("src\s*=\s*([^\"'\s>]+)", r'src="\1"', response) response = re.sub("action\s*=\s*([^\"'\s>]+)", r'action="\1"', response) response = re.sub("method\s*=\s*([^\"'\s>]+)", r'method="\1"', response) response = re.sub("name\s*=\s*([^\"'\s>]+)", r'name="\1"', response) response = re.sub("value\s*=\s*([^\"'\s>]+)", r'value="\1"', response) response = BeautifulSoup(response).prettify() self.current = request.url self.ed.parsing(request.url) self.feed(response) self.close() # custom parsing pages = re.findall('window\.open\s*\(\s*[\'"]([^\'"]+)', response) if pages != None: for page in pages: url = Url(page, default_netloc=self.domain, default_path=self.root.path) if url.netloc == self.domain and url.scheme == self.scheme: req = GetRequest(url) if req not in self.requests: self.requests.append(req) except HTTPError as e: self.ed.warning("%s (%s)" % (request.url.get(), e)) except Exception as e: self.ed.warning(e) finally: self.parsed.append(request) if request.redirect != None: url = Url(request.redirect, default_netloc=self.domain, default_path=self.root.path) self.parsed.append(GetRequest(url)) for req in self.requests: if req not in self.parsed: self.parse(req)
def search( self, # Search parameters article_number=None, title=None, description=None, currency_code=None, unit_id=None, tags=None, supplier_id=None, order_by=None, fetch_all=False, allow_empty_filter=False, keep_old_items=False, page=1, per_page=None): """ Fills the list with Article-objects If no search criteria given --> all articles will returned (REALLY ALL!). :param article_number: Article number :param title: Title :param description: Description :param currency_code: ISO code of the currency :param unit_id: ID of the chosen unit :param tags: Comma seperated list of tags :param supplier_id: ID of the chosen supplier :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. :param allow_empty_filter: If `True`, every filter-parameter may be empty. So, all articles will returned. !!! EVERY INVOICE !!! """ # Check empty filter if not allow_empty_filter: if not any([ article_number, title, description, currency_code, unit_id, tags, supplier_id, ]): raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path="/api/articles") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameters if article_number: url.query["article_number"] = article_number if title: url.query["title"] = title if description: url.query["description"] = description if currency_code: url.query["currency_code"] = currency_code if unit_id: url.query["unit_id"] = unit_id if tags: url.query["tags"] = tags if supplier_id: url.query["supplier_id"] = supplier_id # Fetch data response = self.conn.get(path=str(url)) # Parse XML articles_etree = ET.fromstring(response.data) self.per_page = int(articles_etree.attrib.get("per_page", "100")) self.total = int(articles_etree.attrib.get("total", "0")) self.page = int(articles_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int( bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all articles for article_etree in articles_etree: self.append(Article(conn=self.conn, article_etree=article_etree)) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters article_number=article_number, title=title, description=description, currency_code=currency_code, unit_id=unit_id, tags=tags, supplier_id=supplier_id, order_by=order_by, fetch_all=fetch_all, allow_empty_filter=allow_empty_filter, keep_old_items=True, page=page + 1, per_page=per_page)
def search( self, # Search parameters invoice_id = None, order_by = None, fetch_all = False, keep_old_items = False, page = 1, per_page = None, invoice_ids = None ): """ Fills the list with InvoiceItem-objects :param invoice_id: ID of the invoice (mandatory) or a list of IDs. If list with IDs given: The result contains the invoice-items of many invoices. Be careful: Too many invoice IDs can produce to large responses or to large SQL statements. My recommendation: 10-50 invoice IDs at one time. :param order_by: Sortings consist of the name of the field and sort order: ASC for ascending resp. DESC for descending order. If no order is specified, ascending order (ASC) is used. Nested sort orders are possible. Please separate the sort orders by comma. """ # Check empty param if not invoice_id: raise errors.EmptyFilterError() # Empty the list if not keep_old_items: while True: try: self.pop() except IndexError: break # Url and system-parameters url = Url(path = "/api/invoice-items") url.query["page"] = page if per_page: url.query["per_page"] = per_page if order_by: url.query["order_by"] = order_by # Search parameter if isinstance(invoice_id, (list, tuple)): invoice_id = ",".join(str(id) for id in set(invoice_id)) url.query["invoice_id"] = invoice_id # Fetch data response = self.conn.get(path = str(url)) # Parse XML invoice_items_etree = ET.fromstring(response.data) self.per_page = int(invoice_items_etree.attrib.get("per_page", "100")) self.total = int(invoice_items_etree.attrib.get("total", "0")) self.page = int(invoice_items_etree.attrib.get("page", "1")) try: self.pages = (self.total // self.per_page) + int(bool(self.total % self.per_page)) except ZeroDivisionError: self.pages = 0 # Iterate over all items for invoice_item_etree in invoice_items_etree: self.append( InvoiceItem(conn = self.conn, invoice_item_etree = invoice_item_etree) ) # Fetch all if fetch_all and self.total > (self.page * self.per_page): self.search( # Search parameters invoice_id = invoice_id, order_by = order_by, fetch_all = fetch_all, keep_old_items = True, page = page + 1, per_page = per_page )