From a05e6b7914c81e5a81f94ff63bb6225259ecb4f6 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Dec 07 2018 15:19:15 +0000 Subject: [PATCH 1/3] Allow filtering the issue list by the close status Relates to https://pagure.io/pagure/issue/1749 Signed-off-by: Pierre-Yves Chibon --- diff --git a/pagure/templates/issues.html b/pagure/templates/issues.html index aa72da1..600615f 100644 --- a/pagure/templates/issues.html +++ b/pagure/templates/issues.html @@ -216,7 +216,7 @@ username=username, namespace=repo.namespace, repo=repo.name ) }}" method="GET"> - +
@@ -321,6 +321,21 @@
+
+ +
+ +
+
+ +
+
+ Date: Dec 07 2018 15:19:15 +0000 Subject: [PATCH 2/3] Allow searching the content of the comments on an issue tracker Using ``content:`` one can now search all the comments on the issue tracker for that keyword. This works but it slow and thus should not be abused, so it's in purpose not being proposed prominently to the users. Fixes https://pagure.io/pagure/issue/1749 Signed-off-by: Pierre-Yves Chibon --- diff --git a/doc/usage/tips_tricks.rst b/doc/usage/tips_tricks.rst index fdfcf35..ecada60 100644 --- a/doc/usage/tips_tricks.rst +++ b/doc/usage/tips_tricks.rst @@ -105,3 +105,16 @@ Examples: ~~~~~~~~~ https://pagure.io/SSSD/sssd/issues?status=Open&search_pattern=review%3ATrue https://pagure.io/pagure/issues?status=Open&search_pattern=tags%3Aeasyfix + + +Search the comments of issues +----------------------------- + +One can search all the comments made on an issue tracker using +``content:`` in the search field. This is going to search all the +comments (including the descriptions) of all the tickets and thus can be quite +slow on large project. This is why this feature isn't being pushed much forward. + +Examples: +~~~~~~~~~ +https://pagure.io/pagure/issues?status=Open&search_pattern=content%3Aeasyfix diff --git a/pagure/lib/query.py b/pagure/lib/query.py index 529e5ef..eec9a55 100644 --- a/pagure/lib/query.py +++ b/pagure/lib/query.py @@ -2766,6 +2766,7 @@ def search_issues( offset=None, limit=None, search_pattern=None, + search_content=None, custom_search=None, updated_after=None, no_milestones=None, @@ -2820,6 +2821,8 @@ def search_issues( :type count: boolean :kwarg search_pattern: a string to search in issues title :type search_pattern: str or None + :kwarg search_content: a string to search in the issues comments + :type search_content: str or None :kwarg custom_search: a dictionary of key/values to be used when searching issues with a custom key constraint :type custom_search: dict or None @@ -3009,6 +3012,19 @@ def search_issues( sqlalchemy.or_((const for const in constraints)) ) + if search_content is not None: + query = query.filter( + sqlalchemy.or_( + model.Issue.content.ilike("%%%s%%" % search_content), + sqlalchemy.and_( + model.Issue.uid == model.IssueComment.issue_uid, + model.IssueComment.comment.ilike( + "%%%s%%" % search_content + ), + ), + ) + ) + query = session.query(model.Issue).filter( model.Issue.uid.in_(query.subquery()) ) diff --git a/pagure/ui/issues.py b/pagure/ui/issues.py index 93857c1..63de12b 100644 --- a/pagure/ui/issues.py +++ b/pagure/ui/issues.py @@ -492,9 +492,7 @@ def view_issues(repo, username=None, namespace=None): tags = [tag.strip() for tag in tags if tag.strip()] assignee = flask.request.args.get("assignee", None) author = flask.request.args.get("author", None) - search_pattern = flask.request.args.get("search_pattern", None) - if search_pattern == "": - search_pattern = None + search_pattern = flask.request.args.get("search_pattern") or None milestones = flask.request.args.getlist("milestone", None) order = flask.request.args.get("order", "desc") order_key = flask.request.args.get("order_key", "date_created") @@ -519,6 +517,7 @@ def view_issues(repo, username=None, namespace=None): "assignee": assignee, "author": author, "milestones": milestones, + "search_content": None, } no_stone = None @@ -531,6 +530,10 @@ def view_issues(repo, username=None, namespace=None): search_pattern ) + if "content" in extra_fields: + extra_fields["search_content"] = extra_fields["content"] + del (extra_fields["content"]) + for field in fields: if field in extra_fields: fields[field] = extra_fields[field] From 2a241807f7747cea6e6194dcc2d9457dc4ddeba9 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Dec 07 2018 15:19:15 +0000 Subject: [PATCH 3/3] Fix searching comments and description - with tests Signed-off-by: Pierre-Yves Chibon --- diff --git a/pagure/lib/query.py b/pagure/lib/query.py index eec9a55..59b6c20 100644 --- a/pagure/lib/query.py +++ b/pagure/lib/query.py @@ -3013,7 +3013,9 @@ def search_issues( ) if search_content is not None: - query = query.filter( + query = query.outerjoin( + model.IssueComment + ).filter( sqlalchemy.or_( model.Issue.content.ilike("%%%s%%" % search_content), sqlalchemy.and_( diff --git a/tests/test_pagure_flask_ui_issues.py b/tests/test_pagure_flask_ui_issues.py index 8a60fcf..52891c0 100644 --- a/tests/test_pagure_flask_ui_issues.py +++ b/tests/test_pagure_flask_ui_issues.py @@ -695,6 +695,15 @@ class PagureFlaskIssuestests(tests.Modeltests): self.session.commit() self.assertEqual(msg.title, 'Tést íssüé with milestone') + # Add a comment to that ticket + pagure.lib.query.add_issue_comment( + session=self.session, + issue=msg, + comment='How about nóã!', + user='foo', + ) + self.session.commit() + msg = pagure.lib.query.new_issue( session=self.session, repo=repo, @@ -776,6 +785,26 @@ class PagureFlaskIssuestests(tests.Modeltests): self.assertIn('Issues - test - Pagure', output_text) self.assertIn('0 Open & Closed Issues', output_text) + # Content search - description + output = self.app.get( + '/test/issues?status=all&search_pattern=content:work') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + 'Issues - test - Pagure', + output_text) + self.assertIn('1 Open & Closed Issues', output_text) + + # Content search - comment + output = self.app.get( + '/test/issues?status=all&search_pattern=content:nóã') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + 'Issues - test - Pagure', + output_text) + self.assertIn('1 Open & Closed Issues', output_text) + # Custom key searching output = self.app.get( '/test/issues?status=all&search_pattern=test1:firstissue')