diff --git a/modules/redmine/browser.py b/modules/redmine/browser.py index 4aff057c..25de46be 100644 --- a/modules/redmine/browser.py +++ b/modules/redmine/browser.py @@ -20,6 +20,7 @@ from urlparse import urlsplit import urllib +import re import lxml.html from weboob.capabilities.bugtracker import IssueError @@ -152,6 +153,7 @@ class RedmineBrowser(BaseBrowser): ) for key, value in kwargs.iteritems(): if value: + value = self.page.get_value_from_label(self.METHODS[method]['value'] % key, value) data += ((self.METHODS[method]['value'] % key, value),) data += ((self.METHODS[method]['field'], key),) data += ((self.METHODS[method]['operator'] % key, '~'),) @@ -236,3 +238,20 @@ class RedmineBrowser(BaseBrowser): self.location('/projects') return self.page.iter_projects() + + def create_category(self, project, name, token): + data = {'issue_category[name]': name.encode('utf-8')} + headers = {'X-CSRF-Token': token, + 'X-Prototype-Version': '1.7', + 'X-Requested-With': 'XMLHttpRequest', + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*', + } + request = self.request_class(self.absurl(self.buildurl('%s/projects/%s/issue_categories' % (self.BASEPATH, project), **data)), + '', headers) + r = self.readurl(request) + + # Element.replace("issue_category_id", "\u003Cselect id=\"issue_category_id\" name=\"issue[category_id]\"\u003E\u003Coption\u003E\u003C/option\u003E\u003Coption value=\"28\"\u003Ebnporc\u003C/option\u003E\n\u003Coption value=\"31\"\u003Ebp\u003C/option\u003E\n\u003Coption value=\"30\"\u003Ecrag2r\u003C/option\u003E\n\u003Coption value=\"29\"\u003Ecragr\u003C/option\u003E\n\u003Coption value=\"27\"\u003Ei\u003C/option\u003E\n\u003Coption value=\"32\"\u003Elol\u003C/option\u003E\n\u003Coption value=\"33\" selected=\"selected\"\u003Elouiel\u003C/option\u003E\u003C/select\u003E"); + + m = re.search('''value=\\\\"(\d+)\\\\" selected''', r) + if m: + return m.group(1) diff --git a/modules/redmine/pages/issues.py b/modules/redmine/pages/issues.py index 20cd522f..8af239b4 100644 --- a/modules/redmine/pages/issues.py +++ b/modules/redmine/pages/issues.py @@ -18,6 +18,7 @@ # along with weboob. If not, see . +from mechanize import Item import re import datetime @@ -79,9 +80,14 @@ class BaseIssuePage(BasePage): def get_authenticity_token(self): tokens = self.parser.select(self.document.getroot(), 'input[name=authenticity_token]') if len(tokens) == 0: - raise IssueError("You doesn't have rights to remove this issue.") + tokens = self.document.xpath('//meta[@name="csrf-token"]') + if len(tokens) == 0: + raise IssueError("You don't have rights to remove this issue.") - token = tokens[0].attrib['value'] + try: + token = tokens[0].attrib['value'] + except KeyError: + token = tokens[0].attrib['content'] return token def get_errors(self): @@ -90,6 +96,12 @@ class BaseIssuePage(BasePage): errors.append(li.text.strip()) return ', '.join(errors) + def get_value_from_label(self, name, label): + for option in self.document.xpath('//select[@name="%s"]/option' % name): + if option.text.strip().lower() == label.lower(): + return option.attrib['value'] + return label + class IssuesPage(BaseIssuePage): PROJECT_FIELDS = {'members': 'values_assigned_to_id', @@ -151,6 +163,10 @@ class NewIssuePage(BaseIssuePage): 'statuses': 'issue_status_id', } + def get_project_name(self): + m = re.search('/projects/([^/]+)/', self.url) + return m.group(1) + def iter_custom_fields(self): for div in self.document.xpath('//form//input[starts-with(@id, "issue_custom_field")]'): label = self.document.xpath('//label[@for="%s"]' % div.attrib['id'])[0] @@ -184,7 +200,15 @@ class NewIssuePage(BaseIssuePage): if option.text and option.text.strip() == category: self.browser['issue[category_id]'] = [option.attrib['value']] return - self.logger.warning('Category "%s" not found' % category) + value = None + if len(self.document.xpath('//a[@title="New category"]')) > 0: + value = self.browser.create_category(self.get_project_name(), category, self.get_authenticity_token()) + if value: + control = self.browser.find_control('issue[category_id]') + Item(control, {'name': category, 'value': value}) + self.browser['issue[category_id]'] = [value] + else: + self.logger.warning('Category "%s" not found' % category) else: self.browser['issue[category_id]'] = ['']