add Issue.fields attribute to support custom fields

This commit is contained in:
Romain Bignon 2014-01-21 21:05:39 +01:00
commit 02f40ccf2c
4 changed files with 54 additions and 4 deletions

View file

@ -189,6 +189,9 @@ class RedmineBackend(BaseBackend, ICapContent, ICapBugTracker, ICapCollection):
issue.body = params['body']
issue.creation = params['created_on']
issue.updated = params['updated_on']
issue.fields = {}
for key, value in params['fields'].iteritems():
issue.fields[key] = value
issue.attachments = []
for a in params['attachments']:
attachment = Attachment(a['id'])
@ -220,12 +223,14 @@ class RedmineBackend(BaseBackend, ICapContent, ICapBugTracker, ICapCollection):
def create_issue(self, project):
try:
with self.browser:
r = self.browser.query_issues(project)
r = self.browser.get_project(project)
except BrowserHTTPNotFound:
return None
issue = Issue(0)
issue.project = self._build_project(r['project'])
issue.project = self._build_project(r)
with self.browser:
issue.fields = self.browser.get_custom_fields(project)
return issue
def post_issue(self, issue):
@ -237,6 +242,7 @@ class RedmineBackend(BaseBackend, ICapContent, ICapBugTracker, ICapCollection):
'category': issue.category,
'status': issue.status.id if issue.status else None,
'body': issue.body,
'fields': issue.fields,
}
with self.browser:
@ -291,7 +297,6 @@ class RedmineBackend(BaseBackend, ICapContent, ICapBugTracker, ICapCollection):
return self._build_project(params['project'])
def fill_issue(self, issue, fields):
# currently there isn't cases where an Issue is uncompleted.
return issue
return self.get_issue(issue)
OBJECTS = {Issue: fill_issue}

View file

@ -22,6 +22,7 @@ from urlparse import urlsplit
import urllib
import lxml.html
from weboob.capabilities.bugtracker import IssueError
from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword
from .pages.index import LoginPage, IndexPage, MyPage, ProjectsPage
@ -147,6 +148,12 @@ class RedmineBrowser(BaseBrowser):
'iter': self.page.iter_issues(),
}
def get_project(self, project):
self.location('/projects/%s/issues/new' % project)
assert self.is_on_page(NewIssuePage)
return self.page.get_project(project)
def get_issue(self, id):
self.location('/issues/%s' % id)
@ -165,12 +172,26 @@ class RedmineBrowser(BaseBrowser):
assert self.is_on_page(IssuePage)
self.page.fill_form(note=message)
def get_custom_fields(self, project):
self.location('/projects/%s/issues/new' % project)
assert self.is_on_page(NewIssuePage)
fields = {}
for key, div in self.page.iter_custom_fields():
fields[key] = div.attrib['value']
return fields
def create_issue(self, project, **kwargs):
self.location('/projects/%s/issues/new' % project)
assert self.is_on_page(NewIssuePage)
self.page.fill_form(**kwargs)
error = self.page.get_errors()
if len(error) > 0:
raise IssueError(error)
assert self.is_on_page(IssuePage)
return int(self.page.groups[0])

View file

@ -81,6 +81,12 @@ class BaseIssuePage(BasePage):
token = tokens[0].attrib['value']
return token
def get_errors(self):
errors = []
for li in self.document.xpath('//div[@id="errorExplanation"]//li'):
errors.append(li.text.strip())
return ', '.join(errors)
class IssuesPage(BaseIssuePage):
PROJECT_FIELDS = {'members': 'values_assigned_to_id',
@ -139,6 +145,11 @@ class NewIssuePage(BaseIssuePage):
'statuses': 'issue_status_id',
}
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]
yield label.text.strip(), div
def set_title(self, title):
self.browser['issue[subject]'] = title.encode('utf-8')
@ -178,6 +189,13 @@ class NewIssuePage(BaseIssuePage):
def set_note(self, message):
self.browser['notes'] = message.encode('utf-8')
def set_fields(self, fields):
for key, div in self.iter_custom_fields():
try:
self.browser[div.attrib['name']] = fields[key]
except KeyError:
continue
def fill_form(self, **kwargs):
self.browser.select_form(predicate=lambda form: form.attrs.get('id', '') == 'issue-form')
for key, value in kwargs.iteritems():
@ -230,6 +248,11 @@ class IssuePage(NewIssuePage):
params['category'] = self._parse_selection('issue_category_id')
params['version'] = self._parse_selection('issue_fixed_version_id')
params['fields'] = {}
for key, div in self.iter_custom_fields():
value = div.attrib['value']
params['fields'][key] = value
params['attachments'] = []
try:
for p in self.parser.select(content, 'div.attachments', 1).findall('p'):

View file

@ -206,6 +206,7 @@ class Issue(CapBaseObject):
category = StringField('Name of the category')
version = Field('Target version of this issue', Version)
status = Field('Status of this issue', Status)
fields = Field('Custom fields (key,value)', dict)
class Query(CapBaseObject):