From 8d32b1b0f30715f1ee6e6d134d2ae5d9a83a1276 Mon Sep 17 00:00:00 2001 From: Lukas Brabec Date: Sep 04 2020 05:45:22 +0000 Subject: Bug proposal/rejection status as SVG endpoint This change adds a new endpoint /api/v0/bugimg/. It returns svg image with current info what the bug is proposed as from blockerbugs app. The image can be included in the initial description of discussion issue. This way, we get fresh info from blockerbugs app without updating the issue itself. --- diff --git a/blockerbugs/config.py b/blockerbugs/config.py index fc1b318..5dba7f1 100644 --- a/blockerbugs/config.py +++ b/blockerbugs/config.py @@ -47,6 +47,8 @@ class Config(object): BEHIND_PROXY = False FEDMENU_URL = "" FEDMENU_DATA_URL = "" + BLOCKERBUGS_URL = "https://qa.fedoraproject.org/blockerbugs/" + BLOCKERBUGS_API = "{}api/v0/".format(BLOCKERBUGS_URL) PAGURE_URL = "https://stg.pagure.io/" PAGURE_API = "https://stg.pagure.io/api/0/" PAGURE_REPO = "fedoraqa-test" @@ -58,13 +60,14 @@ class Config(object): PAGURE_DISCUSSION_TITLE = "$bugid $summary" PAGURE_DISCUSSION_CONTENT = '''\ Bug details: ** $bug_url ** - +Information from [BlockerBugs App]({}): +![$bugid]($bug_img) #### Current vote summary $vote_summary To learn how to vote, see: $pagure_url$pagure_repo -''' +'''.format(BLOCKERBUGS_URL) class ProductionConfig(Config): diff --git a/blockerbugs/controllers/api/api.py b/blockerbugs/controllers/api/api.py index f6a0bf1..6abf83d 100644 --- a/blockerbugs/controllers/api/api.py +++ b/blockerbugs/controllers/api/api.py @@ -31,7 +31,7 @@ from blockerbugs.models.release import Release from blockerbugs.models.bug import Bug from blockerbugs.util import pagure_bot from . import errors -from .utils import get_or_404, JsonResponse, check_signature +from .utils import get_or_404, JsonResponse, SVGResponse, check_signature api_v0 = Blueprint('api', __name__, url_prefix='/api/v0') @@ -143,3 +143,53 @@ def pagure_webhook(): msg = 'Unable to parse issue id from received message' app.logger.debug(msg) return JsonResponse({'msg': msg}) + + +def _svg_response_text(info_all): + svg_template = ''\ + '{info_lines}'\ + '' + info_line_template = '{info}' + + # height of each line is 17px, text is rendered at y offset 13px (4px bellow as padding) + # y_offset of nth line is 13 * (n + 1) + 4 * n = 13*n + 13 + 4*n = 17*n + 13 + info_lines = [info_line_template.format(y_offset=17 * index + 13, + info=info) for index, info in enumerate(info_all)] + return svg_template.format(total_height=17 * len(info_all), info_lines="".join(info_lines)) + + +def _get_bugtypes(bug): + bugtypes = [] + if bug.proposed_blocker: + bugtypes.append("Proposed Blocker") + if bug.proposed_fe: + bugtypes.append("Proposed FE") + if bug.rejected_blocker: + bugtypes.append("Rejected Blocker") + if bug.rejected_fe: + bugtypes.append("Rejected FE") + if bug.accepted_blocker: + bugtypes.append("Accepted Blocker") + if bug.accepted_0day: + bugtypes.append("Accepted 0day") + if bug.accepted_prevrel: + bugtypes.append("Accepted Previous release") + if bug.accepted_fe: + bugtypes.append("Accepted FE") + return bugtypes + +_UNKNOWN_BUG_SVG_TEXT = _svg_response_text(["unknown bug"]) + +@api_v0.route('/bugimg/') +def bug_image(bug_id): + bugs = Bug.query.filter_by(bugid=bug_id).all() + if not bugs: + return SVGResponse(_UNKNOWN_BUG_SVG_TEXT) + else: + info_all = [] + for bug in bugs: + milestone_info = "%s: " % bug.milestone.name + bugtypes = _get_bugtypes(bug) + info_all.append(milestone_info + ", ".join(bugtypes)) + + return SVGResponse(_svg_response_text(info_all)) diff --git a/blockerbugs/controllers/api/utils.py b/blockerbugs/controllers/api/utils.py index e302cb9..65a1916 100644 --- a/blockerbugs/controllers/api/utils.py +++ b/blockerbugs/controllers/api/utils.py @@ -75,6 +75,15 @@ class JsonResponse(Response): super(JsonResponse, self).__init__(data, *args, **kwargs) +class SVGResponse(Response): + default_mimetype = 'image/svg+xml' + + def __init__(self, response=None, *args, **kwargs): + if response is None: + response = "" + super(SVGResponse, self).__init__(response, *args, **kwargs) + + def json_loads(data): try: return json.loads(data) diff --git a/blockerbugs/util/pagure_interface.py b/blockerbugs/util/pagure_interface.py index 42bbefe..3327a89 100644 --- a/blockerbugs/util/pagure_interface.py +++ b/blockerbugs/util/pagure_interface.py @@ -14,6 +14,8 @@ def create_bug_discussion(bug): bugid=bug.bugid, summary=bug.summary) content = Template(app.config['PAGURE_DISCUSSION_CONTENT']).safe_substitute( + bugid=bug.bugid, + bug_img=app.config['BLOCKERBUGS_API'] + "bugimg/%s" % bug.bugid, bug_url=bug.url, vote_summary='Nobody voted yet.', pagure_url=app.config['PAGURE_URL'], @@ -33,6 +35,8 @@ def update_issue(issue_id, vote_summary): bugid=bug.bugid, summary=bug.summary) content = Template(app.config['PAGURE_DISCUSSION_CONTENT']).safe_substitute( + bugid=bug.bugid, + bug_img=app.config['BLOCKERBUGS_API'] + "bugimg/%s" % bug.bugid, bug_url=bug_url, vote_summary=vote_summary, pagure_url=app.config['PAGURE_URL'], diff --git a/conf/settings.py.example b/conf/settings.py.example index ac0e815..b8044c1 100644 --- a/conf/settings.py.example +++ b/conf/settings.py.example @@ -23,3 +23,4 @@ PAGURE_REPO_TOKEN = "YOUR SECRET API TOKEN FROM PROJECT SETTINGS" PAGURE_BOT_USERNAME = 'blockerbot' SHOW_DB_URI = False BEHIND_PROXY = False +BLOCKERBUGS_API = "https://qa.fedoraproject.org/blockerbugs/api/v0/" diff --git a/testing/test_api.py b/testing/test_api.py index 51035bd..f602a21 100644 --- a/testing/test_api.py +++ b/testing/test_api.py @@ -10,11 +10,13 @@ from mock import patch from blockerbugs import db from blockerbugs import app +from blockerbugs.models.bug import Bug from blockerbugs.models.build import Build from blockerbugs.models.userinfo import UserInfo from testing.test_controllers import add_release, add_milestone, \ add_bug, add_update from blockerbugs.controllers.api import errors +from blockerbugs.controllers.api.api import _get_bugtypes, _UNKNOWN_BUG_SVG_TEXT class TestRestAPI(object): @@ -140,3 +142,24 @@ class TestRestAPI(object): assert resp.status_code == httplib.OK data = json.loads(resp.data) assert data['name'] == self.milestone.name + + def test_get_bugimg(self): + url = '/api/v0/bugimg/9002' + resp = self.client.get(url) + assert resp.status_code == httplib.OK + data = str(resp.data) + + bug2 = db.session.query(Bug).filter_by(bugid = 9002).first() + + assert self.milestone.name in data + for bugtype in _get_bugtypes(bug2): + assert bugtype in data + + def test_get_bugimg_wrong_bugid(self): + url = '/api/v0/bugimg/90210' + resp = self.client.get(url) + assert resp.status_code == httplib.OK + data = str(resp.data) + + assert self.milestone.name not in data + assert _UNKNOWN_BUG_SVG_TEXT in data