add Issue.fields attribute to support custom fields
This commit is contained in:
parent
370c8ec0e6
commit
02f40ccf2c
4 changed files with 54 additions and 4 deletions
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
||||
|
|
|
|||
|
|
@ -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'):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue