X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=overlays%2Fbugwarrior%2Fmantisbt.patch;fp=overlays%2Fbugwarrior%2Fmantisbt.patch;h=0000000000000000000000000000000000000000;hb=1a64deeb894dc95e2645a75771732c6cc53a79ad;hp=85e5af1eb115f58953a3c57099f2183fd707bed5;hpb=fa25ffd4583cc362075cd5e1b4130f33306103f0;p=perso%2FImmae%2FConfig%2FNix.git diff --git a/overlays/bugwarrior/mantisbt.patch b/overlays/bugwarrior/mantisbt.patch deleted file mode 100644 index 85e5af1..0000000 --- a/overlays/bugwarrior/mantisbt.patch +++ /dev/null @@ -1,379 +0,0 @@ -diff --git a/bugwarrior/services/mantisbt.py b/bugwarrior/services/mantisbt.py -new file mode 100644 -index 0000000..e54af0d ---- /dev/null -+++ b/bugwarrior/services/mantisbt.py -@@ -0,0 +1,361 @@ -+from builtins import filter -+import re -+import six -+ -+import requests -+from jinja2 import Template -+ -+from bugwarrior.config import asbool, aslist, die -+from bugwarrior.services import IssueService, Issue, ServiceClient -+ -+import logging -+log = logging.getLogger(__name__) -+ -+ -+class MantisbtClient(ServiceClient): -+ def __init__(self, host, token): -+ self.host = host -+ self.session = requests.Session() -+ self.session.headers['Authorization'] = token -+ -+ def _api_url(self, path, **context): -+ """ Build the full url to the API endpoint """ -+ baseurl = "https://{}/api/rest".format(self.host) -+ return baseurl + path.format(**context) -+ -+ def get_user(self): -+ return self.json_response(self.session.get(self._api_url("/users/me"))) -+ -+ def get_projects(self): -+ return self._getter(self._api_url("/projects"), subkey="projects") -+ -+ def get_issues(self): -+ url = self._api_url("/issues?page_size=50") -+ return self._getter(url, page_size=50, subkey="issues") -+ -+ def get_assigned_issues(self): -+ """ Returns all issues assigned to authenticated user. -+ """ -+ url = self._api_url("/issues?page_size=50&filter_id=assigned") -+ return self._getter(url, page_size=50, subkey="issues") -+ -+ def get_monitored_issues(self): -+ """ Returns all issues monitored by authenticated user. -+ """ -+ url = self._api_url("/issues?page_size=50&filter_id=monitored") -+ return self._getter(url, page_size=50, subkey="issues") -+ -+ def get_reported_issues(self): -+ """ Returns all issues reported by authenticated user. -+ """ -+ url = self._api_url("/issues?page_size=50&filter_id=reported") -+ return self._getter(url, page_size=50, subkey="issues") -+ -+ def _getter(self, url, page_size=None, subkey=None): -+ """ Pagination utility. Obnoxious. """ -+ -+ results = [] -+ link = dict(next=url) -+ page_number = 1 -+ -+ while 'next' in link: -+ if page_size is not None: -+ response = self.session.get(link['next'] + "&page=" + str(page_number)) -+ else: -+ response = self.session.get(link['next']) -+ -+ json_res = self.json_response(response) -+ -+ if subkey is not None: -+ json_res = json_res[subkey] -+ -+ results += json_res -+ -+ if page_size is not None and len(json_res) == page_size: -+ page_number += 1 -+ else: -+ break -+ -+ return results -+ -+class MantisbtIssue(Issue): -+ TITLE = 'mantisbttitle' -+ BODY = 'mantisbtbody' -+ CREATED_AT = 'mantisbtcreatedon' -+ UPDATED_AT = 'mantisbtupdatedat' -+ CLOSED_AT = 'mantisbtclosedon' -+ URL = 'mantisbturl' -+ PROJECT = 'mantisbtproject' -+ NUMBER = 'mantisbtnumber' -+ USER = 'mantisbtuser' -+ CATEGORY = 'mantisbtcategory' -+ STATE = 'mantisbtstate' -+ -+ UDAS = { -+ TITLE: { -+ 'type': 'string', -+ 'label': 'Mantisbt Title', -+ }, -+ BODY: { -+ 'type': 'string', -+ 'label': 'Mantisbt Body', -+ }, -+ CREATED_AT: { -+ 'type': 'date', -+ 'label': 'Mantisbt Created', -+ }, -+ UPDATED_AT: { -+ 'type': 'date', -+ 'label': 'Mantisbt Updated', -+ }, -+ CLOSED_AT: { -+ 'type': 'date', -+ 'label': 'Mantisbt Closed', -+ }, -+ PROJECT: { -+ 'type': 'string', -+ 'label': 'Mantisbt Project', -+ }, -+ URL: { -+ 'type': 'string', -+ 'label': 'Mantisbt URL', -+ }, -+ NUMBER: { -+ 'type': 'numeric', -+ 'label': 'Mantisbt Issue #', -+ }, -+ USER: { -+ 'type': 'string', -+ 'label': 'Mantisbt User', -+ }, -+ CATEGORY: { -+ 'type': 'string', -+ 'label': 'Mantisbt Category', -+ }, -+ STATE: { -+ 'type': 'string', -+ 'label': 'Mantisbt State', -+ } -+ } -+ UNIQUE_KEY = (URL, NUMBER, ) -+ -+ def _normalize_tag(self, label): -+ return re.sub(r'[^a-zA-Z0-9]', '_', label) -+ -+ def to_taskwarrior(self): -+ body = self.record.get('description') -+ if body: -+ body = body.replace('\r\n', '\n') -+ -+ created = self.parse_date(self.record.get('created_at')) -+ updated = self.parse_date(self.record.get('updated_at')) -+ closed_date = None -+ if self.record["status"]["name"] in ["closed", "resolved"]: -+ for history in self.record.get("history", []): -+ if history.get("field", {}).get("name", "") == "status"\ -+ and history.get("new_value", {}).get("name", "") in ["closed", "resolved"]: -+ closed_date = history["created_at"] -+ closed = self.parse_date(closed_date) -+ -+ return { -+ 'project': self.record['project']['name'], -+ 'priority': self.origin['default_priority'], -+ 'annotations': self.get_annotations(), -+ 'tags': self.get_tags(), -+ 'entry': created, -+ 'end': closed, -+ -+ self.TITLE: self.record.get('summary'), -+ self.BODY: body, -+ self.CREATED_AT: created, -+ self.UPDATED_AT: updated, -+ self.CLOSED_AT: closed, -+ self.URL: self.get_url(), -+ self.PROJECT: self.record['project'].get('name'), -+ self.NUMBER: self.record['id'], -+ self.USER: self.record['reporter'].get('name'), -+ self.CATEGORY: self.record['category'].get('name'), -+ self.STATE: self.record['status'].get('label'), -+ } -+ -+ def get_url(self): -+ return "https://{}view.php?id={}".format(self.extra['host'], self.record["id"]) -+ -+ def get_annotations(self): -+ annotations = [] -+ -+ context = self.record.copy() -+ annotation_template = Template(self.origin['annotation_template']) -+ -+ for annotation_dict in self.record.get('notes', []): -+ context.update({ -+ 'text': annotation_dict['text'], -+ 'date': annotation_dict['created_at'], -+ 'author': annotation_dict['reporter'].get('name', 'unknown'), -+ 'view': annotation_dict['view_state']['label'], -+ }) -+ annotations.append( -+ annotation_template.render(context) -+ ) -+ return annotations -+ -+ def get_tags(self): -+ tags = [] -+ -+ context = self.record.copy() -+ tag_template = Template(self.origin['tag_template']) -+ -+ for tag_dict in self.record.get('tags', []): -+ context.update({ -+ 'tag': self._normalize_tag(tag_dict['name']) -+ }) -+ tags.append( -+ tag_template.render(context) -+ ) -+ -+ return tags -+ -+ def get_default_description(self): -+ return self.build_default_description( -+ title=self.record['summary'], -+ url=self.get_processed_url(self.get_url()), -+ number=self.record['id'], -+ ) -+ -+ -+class MantisbtService(IssueService): -+ ISSUE_CLASS = MantisbtIssue -+ CONFIG_PREFIX = 'mantisbt' -+ -+ def __init__(self, *args, **kw): -+ super(MantisbtService, self).__init__(*args, **kw) -+ -+ self.host = self.config.get('host', 'www.mantisbt.org/bugs/') -+ -+ token = self.get_password('token') -+ -+ self.client = MantisbtClient(self.host, token) -+ self.user = None -+ -+ self.exclude_projects = self.config.get('exclude_projects', [], aslist) -+ self.include_projects = self.config.get('include_projects', [], aslist) -+ -+ self.involved_issues = self.config.get( -+ 'involved_issues', default=True, to_type=asbool -+ ) -+ self.assigned_issues = self.config.get( -+ 'assigned_issues', default=False, to_type=asbool -+ ) -+ self.monitored_issues = self.config.get( -+ 'monitored_issues', default=False, to_type=asbool -+ ) -+ self.reported_issues = self.config.get( -+ 'reported_issues', default=False, to_type=asbool -+ ) -+ self.tag_template = self.config.get( -+ 'tag_template', default='{{tag}}', to_type=six.text_type -+ ) -+ self.annotation_template = self.config.get( -+ 'annotation_template', default='{{date}} {{author}} ({{view}}): {{text}}', to_type=six.text_type -+ ) -+ -+ def get_service_metadata(self): -+ return { -+ 'tag_template': self.tag_template, -+ 'annotation_template': self.annotation_template, -+ } -+ -+ def filter_involved_issues(self, issue): -+ _, issue = issue -+ user = self.client.get_user() -+ uid = user["id"] -+ if issue["reporter"]["id"] != uid and \ -+ issue.get("handler", {}).get("id") != uid and \ -+ all([ x.get("user", {}).get("id") != uid for x in issue.get("history", [])]) and \ -+ all([ x.get("user", {}).get("id") != uid for x in issue.get("monitors", [])]): -+ return False -+ return self.filter_project_name(issue["project"]["name"]) -+ -+ def filter_issues(self, issue): -+ _, issue = issue -+ return self.filter_project_name(issue["project"]["name"]) -+ -+ def filter_project_name(self, name): -+ if self.exclude_projects: -+ if name in self.exclude_projects: -+ return False -+ -+ if self.include_projects: -+ if name in self.include_projects: -+ return True -+ else: -+ return False -+ -+ return True -+ -+ @staticmethod -+ def get_keyring_service(service_config): -+ host = service_config.get('host', 'www.mantisbt.org/bugs/') -+ username = service_config.get('username', default='nousername') -+ return "mantisbt://{username}@{host}".format(username=username, -+ host=host) -+ -+ @staticmethod -+ def to_issue_dict(issues): -+ return { i['id']: i for i in issues } -+ -+ def get_owner(self, issue): -+ return issue.get("handler", {}).get("name") -+ -+ def get_author(self, issue): -+ return issue.get("reporter", {}).get("name") -+ -+ def issues(self): -+ issues = {} -+ is_limited = self.assigned_issues or self.monitored_issues or self.reported_issues -+ -+ if self.assigned_issues: -+ issues.update( -+ filter(self.filter_issues, self.to_issue_dict(self.client.get_assigned_issues()).items()) -+ ) -+ if self.monitored_issues: -+ issues.update( -+ filter(self.filter_issues, self.to_issue_dict(self.client.get_monitored_issues()).items()) -+ ) -+ if self.reported_issues: -+ issues.update( -+ filter(self.filter_issues, self.to_issue_dict(self.client.get_reported_issues()).items()) -+ ) -+ -+ if not is_limited: -+ all_issues = self.to_issue_dict(self.client.get_issues()) -+ if self.involved_issues: -+ issues.update( -+ filter(self.filter_involved_issues, all_issues.items()) -+ ) -+ else: -+ issues.update( -+ filter(self.filter_issues, all_issues.items()) -+ ) -+ -+ log.debug(" Found %i issues.", len(issues)) -+ if not is_limited: -+ issues = list(filter(self.include, issues.values())) -+ else: -+ issues = list(issues.values()) -+ log.debug(" Pruned down to %i issues.", len(issues)) -+ -+ for issue in issues: -+ issue_obj = self.get_issue_for_record(issue) -+ extra = { -+ 'host': self.host -+ } -+ issue_obj.update_extra(extra) -+ yield issue_obj -+ -+ @classmethod -+ def validate_config(cls, service_config, target): -+ if 'token' not in service_config: -+ die("[%s] has no 'mantisbt.token'" % target) -+ -+ super(MantisbtService, cls).validate_config(service_config, target) -diff --git a/setup.py b/setup.py -index d6d957a..665e36e 100644 ---- a/setup.py -+++ b/setup.py -@@ -80,6 +80,7 @@ setup(name='bugwarrior', - activecollab2=bugwarrior.services.activecollab2:ActiveCollab2Service - activecollab=bugwarrior.services.activecollab:ActiveCollabService - jira=bugwarrior.services.jira:JiraService -+ mantisbt=bugwarrior.services.mantisbt:MantisbtService - megaplan=bugwarrior.services.megaplan:MegaplanService - phabricator=bugwarrior.services.phab:PhabricatorService - versionone=bugwarrior.services.versionone:VersionOneService