Accepting request 837239 from devel:tools:scm

- Backport various fixes from upstream
  + Patch: 0001-Display-real-line-numbers-on-pull-request-s-diff-vie.patch
  + Patch: 0002-Show-the-assignee-s-avatar-on-the-board.patch
  + Patch: 0003-Allow-setting-a-status-as-closing-even-if-the-projec.patch
  + Patch: 0004-Include-the-assignee-in-the-list-of-people-notified-.patch
  + Patch: 0005-Introduce-the-collaborator_project_groups-mapping.patch
  + Patch: 0006-When-a-file-a-detected-as-a-binary-file-return-the-r.patch
  + Patch: 0007-Remove-fenced-code-block-when-checking-mention.patch
  + Patch: 0008-Add-support-for-using-cchardet-to-detect-files-encod.patch
  + Patch: 0009-Add-support-for-disabling-user-registration.patch
- Remove mandatory dependency on systemd to ease containerization

OBS-URL: https://build.opensuse.org/request/show/837239
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/pagure?expand=0&rev=19
This commit is contained in:
Dominique Leuenberger 2020-09-25 14:35:34 +00:00 committed by Git OBS Bridge
commit 028f8f9ec9
11 changed files with 1249 additions and 1 deletions

View File

@ -0,0 +1,194 @@
From f48278682d9552670b7d5cb9e99a7e0a74bdd689 Mon Sep 17 00:00:00 2001
From: Julen Landa Alustiza <jlanda@fedoraproject.org>
Date: Fri, 7 Aug 2020 12:35:32 +0200
Subject: [PATCH 1/9] Display real line numbers on pull request's diff view
Fixes #724
---
pagure/templates/_repo_renderdiff.html | 1 -
pagure/ui/filters.py | 101 ++++++++++---------------
tests/test_pagure_flask_ui_fork.py | 24 +++++-
3 files changed, 64 insertions(+), 62 deletions(-)
diff --git a/pagure/templates/_repo_renderdiff.html b/pagure/templates/_repo_renderdiff.html
index a0922169..aa9a062e 100644
--- a/pagure/templates/_repo_renderdiff.html
+++ b/pagure/templates/_repo_renderdiff.html
@@ -164,7 +164,6 @@
commit=patchstats["new_id"],
prequest=pull_request,
index=loop.index,
- isprdiff=True,
tree_id=diff_commits[0].tree.id)}}
</div>
{% endautoescape %}
diff --git a/pagure/ui/filters.py b/pagure/ui/filters.py
index 73799ed7..98b2741f 100644
--- a/pagure/ui/filters.py
+++ b/pagure/ui/filters.py
@@ -149,38 +149,33 @@ def format_loc(
for key in comments:
comments[key] = sorted(comments[key], key=lambda obj: obj.date_created)
- if not index:
- index = ""
+ if isinstance(filename, str) and six.PY2:
+ filename = filename.decode("UTF-8")
cnt = 1
for line in loc.split("\n"):
- if filename and commit:
- if isinstance(filename, str) and six.PY2:
- filename = filename.decode("UTF-8")
-
- if isprdiff and (
- line.startswith("@@")
- or line.startswith("+")
- or line.startswith("-")
- ):
- if line.startswith("@@"):
- output.append(
- '<tr class="stretch-table-column bg-light"\
- id="c-%(commit)s-%(cnt_lbl)s">'
- % ({"cnt_lbl": cnt, "commit": commit})
- )
- elif line.startswith("+"):
- output.append(
- '<tr class="stretch-table-column alert-success" \
- id="c-%(commit)s-%(cnt_lbl)s">'
- % ({"cnt_lbl": cnt, "commit": commit})
- )
- elif line.startswith("-"):
- output.append(
- '<tr class="stretch-table-column alert-danger" \
- id="c-%(commit)s-%(cnt_lbl)s">'
- % ({"cnt_lbl": cnt, "commit": commit})
- )
+ if line.startswith("@@"):
+ output.append(
+ '<tr class="stretch-table-column bg-light"\
+ id="c-%(commit)s-%(cnt_lbl)s">'
+ % ({"cnt_lbl": cnt, "commit": commit})
+ )
+ output.append(
+ '<td class="cell1"></td><td class="prc border-right"></td>'
+ )
+ else:
+ if line.startswith("+"):
+ output.append(
+ '<tr class="stretch-table-column alert-success" \
+ id="c-%(commit)s-%(cnt_lbl)s">'
+ % ({"cnt_lbl": cnt, "commit": commit})
+ )
+ elif line.startswith("-"):
+ output.append(
+ '<tr class="stretch-table-column alert-danger" \
+ id="c-%(commit)s-%(cnt_lbl)s">'
+ % ({"cnt_lbl": cnt, "commit": commit})
+ )
else:
output.append(
'<tr id="c-%(commit)s-%(cnt_lbl)s">'
@@ -211,13 +206,6 @@ def format_loc(
}
)
)
- else:
- output.append(
- '<tr><td class="cell1">'
- '<a id="%(cnt)s" href="#%(cnt)s" data-line-number='
- '"%(cnt_lbl)s"></a></td>'
- % ({"cnt": "%s_%s" % (index, cnt), "cnt_lbl": cnt})
- )
cnt += 1
if not line:
@@ -254,29 +242,24 @@ def format_loc(
+ 'title="Open changed file"></span></a>'
)
- if isprdiff and (
- line.startswith("@@")
- or line.startswith("+")
- or line.startswith("-")
- ):
- if line.startswith("@@"):
- output.append(
- '<td class="cell2 stretch-table-column">\
- <pre class="text-muted"><code>%s</code></pre></td>'
- % line
- )
- elif line.startswith("+"):
- output.append(
- '<td class="cell2 stretch-table-column">\
- <pre class="alert-success"><code>%s</code></pre></td>'
- % escape(line)
- )
- elif line.startswith("-"):
- output.append(
- '<td class="cell2 stretch-table-column">\
- <pre class="alert-danger"><code>%s</code></pre></td>'
- % escape(line)
- )
+ if line.startswith("@@"):
+ output.append(
+ '<td class="cell2 stretch-table-column">\
+ <pre class="text-muted"><code>%s</code></pre></td>'
+ % line
+ )
+ elif line.startswith("+"):
+ output.append(
+ '<td class="cell2 stretch-table-column">\
+ <pre class="alert-success"><code>%s</code></pre></td>'
+ % escape(line)
+ )
+ elif line.startswith("-"):
+ output.append(
+ '<td class="cell2 stretch-table-column">\
+ <pre class="alert-danger"><code>%s</code></pre></td>'
+ % escape(line)
+ )
else:
output.append(
'<td class="cell2"><pre><code>%s</code></pre></td>'
diff --git a/tests/test_pagure_flask_ui_fork.py b/tests/test_pagure_flask_ui_fork.py
index 21ecd7df..8e8dce1c 100644
--- a/tests/test_pagure_flask_ui_fork.py
+++ b/tests/test_pagure_flask_ui_fork.py
@@ -302,11 +302,31 @@ class PagureFlaskForktests(tests.Modeltests):
)
self.assertIn(
- '<span class="btn btn-success btn-sm font-weight-bold disabled opacity-100">+3</span>',
+ '<span class="btn btn-success btn-sm font-weight-bold disabled'
+ ' opacity-100">+3</span>',
output_text,
)
self.assertIn(
- '<span class="btn btn-danger btn-sm font-weight-bold disabled opacity-100">-1</span>',
+ '<span class="btn btn-danger btn-sm font-weight-bold disabled '
+ 'opacity-100">-1</span>',
+ output_text,
+ )
+
+ # Test if hunk headline is rendered without line numbers
+ self.assertIn(
+ '<td class="cell1"></td><td class="prc border-right"></td>\n<td '
+ 'class="cell2 stretch-table-column"> <pre class='
+ '"text-muted"><code>@@ -1,2 +1,4 @@',
+ output_text,
+ )
+ # Tests if line number 1 is displayed
+ self.assertNotIn(
+ '<td class="cell1"><a id="_1__1" href="#_1__1" data-line-number="1" data-file-number="1"></a></td>',
+ output_text,
+ )
+ # Test if line number 2 is displayed
+ self.assertIn(
+ '<td class="cell1"><a id="_1__2" href="#_1__2" data-line-number="2" data-file-number="1"></a></td>',
output_text,
)
--
2.26.2

View File

@ -0,0 +1,33 @@
From d3fb1c32746580bb109ac21ff349a655a01c46f0 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Wed, 12 Aug 2020 20:47:22 +0200
Subject: [PATCH 2/9] Show the assignee's avatar on the board
If the ticket shown in the board is assigned to someone, show this
person's avatar. This helps not only seeing what is in progress or
blocked but also who is working on what or being blocked.
Fixes https://pagure.io/pagure/issue/4959
Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>
---
pagure/templates/board.html | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pagure/templates/board.html b/pagure/templates/board.html
index 26509ae0..46a7eb65 100644
--- a/pagure/templates/board.html
+++ b/pagure/templates/board.html
@@ -65,6 +65,9 @@
{% elif bissue.issue.status == 'Closed' %}
<span class="fa fa-fw text-danger fa-exclamation-circle pt-1 icon_id"></span>
<span class="text-danger font-weight-bold id_txt">#{{ bissue.issue.id }}</span>
+ {% endif %}
+ {% if bissue.issue.assignee %}
+ - {{ bissue.issue.assignee.username | avatar(size=20) | safe}}
{% endif %}
- {{ bissue.issue.title | truncate(80, False, '...') }}
</a>
--
2.26.2

View File

@ -0,0 +1,128 @@
From 9fd32d4d948fc4231eee68e8044b844060db140c Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Wed, 12 Aug 2020 20:56:18 +0200
Subject: [PATCH 3/9] Allow setting a status as closing even if the project has
no close_status
When determining if a status "closes" tickets or not, we should first
check if it was set to and only if it wasn't then check if there was a
close_status set for it. Otherwise the logic wasn't correctly interpreted.
Fixes https://pagure.io/pagure/issue/4958
Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>
---
pagure/api/boards.py | 4 +-
tests/test_pagure_flask_api_boards.py | 81 +++++++++++++++++++++++++++
2 files changed, 84 insertions(+), 1 deletion(-)
diff --git a/pagure/api/boards.py b/pagure/api/boards.py
index e42f7cb6..669fd457 100644
--- a/pagure/api/boards.py
+++ b/pagure/api/boards.py
@@ -510,7 +510,9 @@ def api_board_status(repo, board_name, username=None, namespace=None):
try:
close_status = data[name].get("close_status") or None
- close = data[name].get("close") or True if close_status else False
+ close = data[name].get("close") or (
+ True if close_status else False
+ )
if close_status not in repo.close_status:
close_status = None
diff --git a/tests/test_pagure_flask_api_boards.py b/tests/test_pagure_flask_api_boards.py
index ef125878..67199703 100644
--- a/tests/test_pagure_flask_api_boards.py
+++ b/tests/test_pagure_flask_api_boards.py
@@ -801,6 +801,87 @@ class PagureFlaskApiBoardsWithBoardtests(tests.SimplePagureTest):
},
)
+ def test_api_board_api_board_status_no_close_status(self):
+ headers = {
+ "Authorization": "token aaabbbcccddd",
+ "Content-Type": "application/json",
+ }
+
+ data = json.dumps(
+ {
+ "Backlog": {
+ "close": False,
+ "close_status": None,
+ "bg_color": "#FFB300",
+ "default": True,
+ "rank": 1,
+ },
+ "Triaged": {
+ "close": False,
+ "close_status": None,
+ "bg_color": "#ca0dcd",
+ "default": False,
+ "rank": 2,
+ },
+ "Done": {
+ "close": True,
+ "close_status": None,
+ "bg_color": "#34d240",
+ "default": False,
+ "rank": 4,
+ },
+ " ": {
+ "close": True,
+ "close_status": None,
+ "bg_color": "#34d240",
+ "default": False,
+ "rank": 5,
+ },
+ }
+ )
+ output = self.app.post(
+ "/api/0/test/boards/dev/status", headers=headers, data=data
+ )
+ self.assertEqual(output.status_code, 200)
+ data = json.loads(output.get_data(as_text=True))
+ self.assertDictEqual(
+ data,
+ {
+ "board": {
+ "active": True,
+ "name": "dev",
+ "status": [
+ {
+ "bg_color": "#FFB300",
+ "close": False,
+ "close_status": None,
+ "default": True,
+ "name": "Backlog",
+ },
+ {
+ "bg_color": "#ca0dcd",
+ "close": False,
+ "close_status": None,
+ "default": False,
+ "name": "Triaged",
+ },
+ {
+ "name": "Done",
+ "close": True,
+ "close_status": None,
+ "default": False,
+ "bg_color": "#34d240",
+ },
+ ],
+ "tag": {
+ "tag": "dev",
+ "tag_color": "DeepBlueSky",
+ "tag_description": "",
+ },
+ }
+ },
+ )
+
def test_api_board_api_board_status_adding_removing(self):
headers = {
"Authorization": "token aaabbbcccddd",
--
2.26.2

View File

@ -0,0 +1,36 @@
From 1e129038cf63f619fd5b69f92057cb29c53a83d3 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Wed, 12 Aug 2020 21:19:22 +0200
Subject: [PATCH 4/9] Include the assignee in the list of people notified on a
ticket/PR
We always include the assignee in the notifications (even on private
tickets), but so far we did not show them in the list of subscriber.
With this commit, this oversight is now fixed.
Fixes https://pagure.io/pagure/issue/4957
Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>
---
pagure/lib/query.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/pagure/lib/query.py b/pagure/lib/query.py
index 8ee4df6c..498148df 100644
--- a/pagure/lib/query.py
+++ b/pagure/lib/query.py
@@ -4957,6 +4957,10 @@ def get_watch_list(session, obj):
# Add the user of the project
users.add(obj.project.user.username)
+ # Add the assignee if there is one
+ if obj.assignee:
+ users.add(obj.assignee.username)
+
# Add the regular contributors
for contributor in obj.project.users:
users.add(contributor.username)
--
2.26.2

View File

@ -0,0 +1,104 @@
From d91182e9bd01582c3ba1671a758038819943fb9b Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Tue, 18 Aug 2020 13:33:21 +0200
Subject: [PATCH 5/9] Introduce the collaborator_project_groups mapping
We need two mappings on a regular basis. One linking a project to its
group of collaborator and pointing to the PagureGroup objects directly.
This is used for example to retrieve the list of collaborator groups.
The one mapping is between a project and the corresponding ProjectGroup
for collaborators which is where the "branches" that the group is
restricted to is stored.
So we now have both mappings available and we need to be careful to use
the proper one, but pagure will quickly indicate (ie: crash) if one
uses the wrong one and tries to access either the group name or the
branches attribute.
Fixes https://pagure.io/fedora-infrastructure/issue/9247
Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>
---
pagure/lib/model.py | 10 ++++++++++
pagure/utils.py | 2 +-
tests/test_pagure_flask_api_project.py | 23 ++++++++++++++++++++++-
3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/pagure/lib/model.py b/pagure/lib/model.py
index 325a5452..4eea9f58 100644
--- a/pagure/lib/model.py
+++ b/pagure/lib/model.py
@@ -487,6 +487,16 @@ class Project(BASE):
)
collaborator_groups = relation(
+ "PagureGroup",
+ secondary="projects_groups",
+ primaryjoin="projects.c.id==projects_groups.c.project_id",
+ secondaryjoin="and_(pagure_group.c.id==projects_groups.c.group_id,\
+ projects_groups.c.access=='collaborator')",
+ order_by="PagureGroup.group_name.asc()",
+ viewonly=True,
+ )
+
+ collaborator_project_groups = relation(
"ProjectGroup",
primaryjoin="and_(projects.c.id==projects_groups.c.project_id,\
projects_groups.c.access=='collaborator')",
diff --git a/pagure/utils.py b/pagure/utils.py
index 24a0ce4d..915ba499 100644
--- a/pagure/utils.py
+++ b/pagure/utils.py
@@ -311,7 +311,7 @@ def is_repo_collaborator(repo_obj, refname, username=None, session=None):
return True
# If they are in a group that has commit access -> maybe
- for project_group in repo_obj.collaborator_groups:
+ for project_group in repo_obj.collaborator_project_groups:
if project_group.group.group_name in usergroups:
# if branch is None when the user tries to read,
# so we'll allow that
diff --git a/tests/test_pagure_flask_api_project.py b/tests/test_pagure_flask_api_project.py
index 3c364be2..51dd8e9f 100644
--- a/tests/test_pagure_flask_api_project.py
+++ b/tests/test_pagure_flask_api_project.py
@@ -1010,6 +1010,27 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
)
self.session.commit()
+ # Add a collaborator group
+ msg = pagure.lib.query.add_group(
+ self.session,
+ group_name="some_group",
+ display_name="Some Group",
+ description=None,
+ group_type="bar",
+ user="pingou",
+ is_admin=False,
+ blacklist=[],
+ )
+ pagure.lib.query.add_group_to_project(
+ session=self.session,
+ project=project,
+ new_group="some_group",
+ user="pingou",
+ access="collaborator",
+ branches="features/*",
+ )
+ self.session.commit()
+
# Existing project
output = self.app.get("/api/0/test")
self.assertEqual(output.status_code, 200)
@@ -1019,7 +1040,7 @@ class PagureFlaskApiProjecttests(tests.Modeltests):
expected_data = {
"access_groups": {
"admin": [],
- "collaborator": [],
+ "collaborator": ["some_group"],
"commit": [],
"ticket": [],
},
--
2.26.2

View File

@ -0,0 +1,219 @@
From 3f65d123faa3a1fcd0b93921e5d42fe659b79fa7 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Wed, 12 Aug 2020 21:33:07 +0200
Subject: [PATCH 6/9] When a file a detected as a binary file, return the raw
file
Basically, with the code until now, if an user was trying to view
a binary file in the UI, it was then prompted to download the file
(as pagure doesn't know how to display binary file), but the file
the users were downloading wasn't the raw file but rather the html
page that would contain the file.
Not ideal.
So with this commit we're now just saying: if the file is binary and
we can't render it, just return the raw file to the user and let
them deal with it.
Fixes https://pagure.io/pagure/issue/4907
Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>
---
pagure/ui/repo.py | 8 +++-
tests/test_pagure_flask_ui_fork.py | 18 ++-------
tests/test_pagure_flask_ui_repo.py | 25 ++++---------
tests/test_pagure_flask_ui_repo_view_file.py | 39 +++++++++-----------
4 files changed, 35 insertions(+), 55 deletions(-)
diff --git a/pagure/ui/repo.py b/pagure/ui/repo.py
index b6aacc8e..06afb71d 100644
--- a/pagure/ui/repo.py
+++ b/pagure/ui/repo.py
@@ -639,7 +639,13 @@ def view_file(repo, identifier, filename, username=None, namespace=None):
output_type = "tree"
if output_type == "binary":
- headers[str("Content-Disposition")] = "attachment"
+ return view_raw_file(
+ repo,
+ identifier,
+ filename=filename,
+ username=username,
+ namespace=namespace,
+ )
return flask.Response(
flask.stream_with_context(
diff --git a/tests/test_pagure_flask_ui_fork.py b/tests/test_pagure_flask_ui_fork.py
index 8e8dce1c..1bff134f 100644
--- a/tests/test_pagure_flask_ui_fork.py
+++ b/tests/test_pagure_flask_ui_fork.py
@@ -4676,10 +4676,7 @@ More information</textarea>
# Check fork-edit doesn't show for binary files
output = self.app.get("/test/blob/master/f/test.jpg")
self.assertEqual(output.status_code, 200)
- self.assertNotIn(
- "Fork and Edit\n </button>\n",
- output.get_data(as_text=True),
- )
+ self.assertNotIn(b"<html", output.data)
# Check for edit panel
output = self.app.post(
@@ -4737,8 +4734,7 @@ More information</textarea>
)
self.assertEqual(output.status_code, 400)
self.assertIn(
- "<p>Cannot edit binary files</p>",
- output.get_data(as_text=True),
+ b"<p>Cannot edit binary files</p>", output.data,
)
# Check fork-edit shows when user is not logged in
@@ -4764,10 +4760,7 @@ More information</textarea>
# Check fork-edit doesn't show for binary
output = self.app.get("/test/blob/master/f/test.jpg")
self.assertEqual(output.status_code, 200)
- self.assertNotIn(
- "Edit in your fork\n </button>\n",
- output.get_data(as_text=True),
- )
+ self.assertNotIn(b"<html", output.data)
@patch("pagure.lib.notify.send_email", MagicMock(return_value=True))
def test_fork_edit_file_namespace(self):
@@ -4865,10 +4858,7 @@ More information</textarea>
"/somenamespace/test3/blob/master/f/test.jpg"
)
self.assertEqual(output.status_code, 200)
- self.assertNotIn(
- "Fork and Edit\n </button>\n",
- output.get_data(as_text=True),
- )
+ self.assertNotIn(b"<html", output.data)
# Check for edit panel
output = self.app.post(
diff --git a/tests/test_pagure_flask_ui_repo.py b/tests/test_pagure_flask_ui_repo.py
index 27bf6e65..b4322e7d 100644
--- a/tests/test_pagure_flask_ui_repo.py
+++ b/tests/test_pagure_flask_ui_repo.py
@@ -2592,12 +2592,7 @@ class PagureFlaskRepotests(tests.Modeltests):
# View what's supposed to be an image
output = self.app.get("/test/blob/master/f/test.jpg")
self.assertEqual(output.status_code, 200)
- output_text = output.get_data(as_text=True)
- self.assertIn("Binary files cannot be rendered.<br/>", output_text)
- self.assertIn(
- '<a href="/test/raw/master/f/test.jpg">view the raw version',
- output_text,
- )
+ self.assertNotIn(b"<html", output.data)
# View by commit id
repo = pygit2.Repository(os.path.join(self.path, "repos", "test.git"))
@@ -2605,23 +2600,17 @@ class PagureFlaskRepotests(tests.Modeltests):
output = self.app.get("/test/blob/%s/f/test.jpg" % commit.oid.hex)
self.assertEqual(output.status_code, 200)
- output_text = output.get_data(as_text=True)
- self.assertIn("Binary files cannot be rendered.<br/>", output_text)
- self.assertIn('/f/test.jpg">view the raw version', output_text)
+ self.assertNotIn(b"<html", output.data)
# View by image name -- somehow we support this
- output = self.app.get("/test/blob/sources/f/test.jpg")
+ output = self.app.get("/test/blob/master/f/test.jpg")
self.assertEqual(output.status_code, 200)
- output_text = output.get_data(as_text=True)
- self.assertIn("Binary files cannot be rendered.<br/>", output_text)
- self.assertIn('/f/test.jpg">view the raw version', output_text)
+ self.assertNotIn(b"<html", output.data)
# View binary file
- output = self.app.get("/test/blob/sources/f/test_binary")
+ output = self.app.get("/test/blob/master/f/test_binary")
self.assertEqual(output.status_code, 200)
- output_text = output.get_data(as_text=True)
- self.assertIn('/f/test_binary">view the raw version', output_text)
- self.assertIn("Binary files cannot be rendered.<br/>", output_text)
+ self.assertNotIn(b"<html", output.data)
# View folder
output = self.app.get("/test/blob/master/f/folder1")
@@ -2748,7 +2737,7 @@ class PagureFlaskRepotests(tests.Modeltests):
output = self.app.get("/test/blob/master/f/sources")
self.assertEqual(output.status_code, 200)
output_text = output.get_data(as_text=True)
- self.assertIn("Binary files cannot be rendered.<br/>", output_text)
+ self.assertEqual("foo\n bar", output_text)
def test_view_raw_file(self):
""" Test the view_raw_file endpoint. """
diff --git a/tests/test_pagure_flask_ui_repo_view_file.py b/tests/test_pagure_flask_ui_repo_view_file.py
index 16a1ce18..effa06b6 100644
--- a/tests/test_pagure_flask_ui_repo_view_file.py
+++ b/tests/test_pagure_flask_ui_repo_view_file.py
@@ -135,12 +135,7 @@ class PagureFlaskRepoViewFiletests(LocalBasetests):
# View what's supposed to be an image
output = self.app.get("/test/blob/master/f/test.jpg")
self.assertEqual(output.status_code, 200)
- output_text = output.get_data(as_text=True)
- self.assertIn("Binary files cannot be rendered.<br/>", output_text)
- self.assertIn(
- '<a href="/test/raw/master/f/test.jpg">view the raw version',
- output_text,
- )
+ self.assertNotIn(b"<html", output.data)
def test_view_file_by_commit(self):
""" Test the view_file in a specific commit. """
@@ -151,29 +146,29 @@ class PagureFlaskRepoViewFiletests(LocalBasetests):
output = self.app.get("/test/blob/%s/f/test.jpg" % commit.oid.hex)
self.assertEqual(output.status_code, 200)
- output_text = output.get_data(as_text=True)
- self.assertIn("Binary files cannot be rendered.<br/>", output_text)
- self.assertIn('/f/test.jpg">view the raw version', output_text)
+ self.assertNotIn(b"<html", output.data)
- def test_view_file_by_name(self):
+ def test_view_file_invalid_branch(self):
""" Test the view_file via a image name. """
-
- # View by image name -- somehow we support this
output = self.app.get("/test/blob/sources/f/test.jpg")
- self.assertEqual(output.status_code, 200)
- output_text = output.get_data(as_text=True)
- self.assertIn("Binary files cannot be rendered.<br/>", output_text)
- self.assertIn('/f/test.jpg">view the raw version', output_text)
+ self.assertEqual(output.status_code, 404)
- def test_view_file_binary_file2(self):
+ def test_view_file_invalid_branch2(self):
""" Test the view_file with a binary file (2). """
-
- # View binary file
output = self.app.get("/test/blob/sources/f/test_binary")
+ self.assertEqual(output.status_code, 404)
+
+ def test_view_file_invalid_branch(self):
+ """ Test the view_file via a image name. """
+ output = self.app.get("/test/blob/master/f/test.jpg")
self.assertEqual(output.status_code, 200)
- output_text = output.get_data(as_text=True)
- self.assertIn('/f/test_binary">view the raw version', output_text)
- self.assertTrue("Binary files cannot be rendered.<br/>" in output_text)
+ self.assertNotIn(b"<html", output.data)
+
+ def test_view_file_invalid_branch2(self):
+ """ Test the view_file with a binary file (2). """
+ output = self.app.get("/test/blob/master/f/test_binary")
+ self.assertEqual(output.status_code, 200)
+ self.assertNotIn(b"<html", output.data)
def test_view_file_for_folder(self):
""" Test the view_file with a folder. """
--
2.26.2

View File

@ -0,0 +1,86 @@
From e921f23f8135d3e6667d532e06504f520b8c0109 Mon Sep 17 00:00:00 2001
From: Michael Scherer <misc@redhat.com>
Date: Thu, 3 Sep 2020 16:44:20 +0200
Subject: [PATCH 7/9] Remove fenced code block when checking mention
Fix bug #4978
We have to remove code using the '~~~~' markup since
this result in incorrect trigger, especially on private
ticket.
---
pagure/lib/notify.py | 6 +++++-
tests/test_pagure_lib_notify.py | 26 ++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/pagure/lib/notify.py b/pagure/lib/notify.py
index 0c124db9..02c277c0 100644
--- a/pagure/lib/notify.py
+++ b/pagure/lib/notify.py
@@ -35,6 +35,7 @@ import pagure.lib.query
import pagure.lib.tasks_services
from pagure.config import config as pagure_config
from pagure.pfmarkdown import MENTION_RE
+from markdown.extensions.fenced_code import FencedBlockPreprocessor
_log = logging.getLogger(__name__)
@@ -234,7 +235,10 @@ def _add_mentioned_users(emails, comment):
""" Check the comment to see if an user is mentioned in it and if
so add this user to the list of people to notify.
"""
- for username in re.findall(MENTION_RE, comment):
+ filtered_comment = re.sub(
+ FencedBlockPreprocessor.FENCED_BLOCK_RE, "", comment
+ )
+ for username in re.findall(MENTION_RE, filtered_comment):
user = pagure.lib.query.search_user(flask.g.session, username=username)
if user:
emails.add(user.default_email)
diff --git a/tests/test_pagure_lib_notify.py b/tests/test_pagure_lib_notify.py
index 8d31cb70..78af57af 100644
--- a/tests/test_pagure_lib_notify.py
+++ b/tests/test_pagure_lib_notify.py
@@ -25,6 +25,7 @@ import pagure.lib.model
import pagure.lib.notify
import pagure.lib.query
import tests
+import munch
class PagureLibNotifytests(tests.Modeltests):
@@ -543,6 +544,31 @@ RW1haWwgY29udGVudA==
"""
self.assertEqual(email.as_string(), exp)
+ def test_notification_mention(self):
+ g = munch.Munch()
+ g.session = self.session
+ with patch("flask.g", g):
+
+ def _check_mention(comment, exp):
+ emails = set([])
+ emails = pagure.lib.notify._add_mentioned_users(
+ emails, comment
+ )
+
+ self.assertEqual(emails, exp)
+
+ exp = set(["bar@pingou.com"])
+ comment = "I think we should ask @pingou how to pronounce pagure"
+ _check_mention(comment, exp)
+
+ exp = set([])
+ comment = """Let me quote him:
+~~~~
+ @pingou> Pagure is pronounced 'pa-gure', not 'pagu-re'
+~~~~
+"""
+ _check_mention(comment, exp)
+
if __name__ == "__main__":
unittest.main(verbosity=2)
--
2.26.2

View File

@ -0,0 +1,284 @@
From a8b2e001d6f4d2e4683aa65d6331b971f8e2ce33 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Mon, 14 Sep 2020 16:03:31 +0200
Subject: [PATCH 8/9] Add support for using cchardet to detect files' encoding
cchardet is a much faster version of the chardet library that can
be used to automatically detect the encoding of a file.
Since this library is only available on python3, we're making it
an optional dependency for now.
Fixes https://pagure.io/pagure/issue/4977
Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>
---
pagure/lib/encoding_utils.py | 12 ++++-
tests/test_pagure_flask_ui_repo.py | 58 ++++++++++++++++++++-----
tests/test_pagure_lib_encoding_utils.py | 40 ++++++++++++-----
tests/test_pagure_lib_mimetype.py | 28 ++++++++++--
4 files changed, 111 insertions(+), 27 deletions(-)
diff --git a/pagure/lib/encoding_utils.py b/pagure/lib/encoding_utils.py
index 66f7dced..304e7d84 100644
--- a/pagure/lib/encoding_utils.py
+++ b/pagure/lib/encoding_utils.py
@@ -15,7 +15,12 @@ from __future__ import unicode_literals, division, absolute_import
from collections import namedtuple
import logging
-from chardet import universaldetector, __version__ as ch_version
+try:
+ import cchardet
+ from cchardet import __version__ as ch_version
+except ImportError:
+ cchardet = None
+ from chardet import universaldetector, __version__ as ch_version
from pagure.exceptions import PagureEncodingException
@@ -44,7 +49,10 @@ def detect_encodings(data):
# We can't use ``chardet.detect`` because we want to dig in the internals
# of the detector to bias the utf-8 result.
- detector = universaldetector.UniversalDetector()
+ if cchardet is not None:
+ detector = cchardet.UniversalDetector()
+ else:
+ detector = universaldetector.UniversalDetector()
detector.reset()
detector.feed(data)
result = detector.close()
diff --git a/tests/test_pagure_flask_ui_repo.py b/tests/test_pagure_flask_ui_repo.py
index b4322e7d..e816e7f7 100644
--- a/tests/test_pagure_flask_ui_repo.py
+++ b/tests/test_pagure_flask_ui_repo.py
@@ -20,6 +20,12 @@ import tempfile
import time
import os
+cchardet = None
+try:
+ import cchardet
+except ImportError:
+ pass
+
import pygit2
import six
from mock import ANY, patch, MagicMock
@@ -2763,9 +2769,16 @@ class PagureFlaskRepotests(tests.Modeltests):
output = self.app.get("/test/raw/master")
self.assertEqual(output.status_code, 200)
output_text = output.get_data(as_text=True)
- self.assertEqual(
- output.headers["Content-Type"].lower(), "text/plain; charset=ascii"
- )
+ if cchardet is not None:
+ self.assertEqual(
+ output.headers["Content-Type"].lower(),
+ "text/plain; charset=utf-8",
+ )
+ else:
+ self.assertEqual(
+ output.headers["Content-Type"].lower(),
+ "text/plain; charset=ascii",
+ )
self.assertIn(":Author: Pierre-Yves Chibon", output_text)
# Add some more content to the repo
@@ -2784,9 +2797,16 @@ class PagureFlaskRepotests(tests.Modeltests):
# View in a branch
output = self.app.get("/test/raw/master/f/sources")
- self.assertEqual(
- output.headers["Content-Type"].lower(), "text/plain; charset=ascii"
- )
+ if cchardet is not None:
+ self.assertEqual(
+ output.headers["Content-Type"].lower(),
+ "text/plain; charset=utf-8",
+ )
+ else:
+ self.assertEqual(
+ output.headers["Content-Type"].lower(),
+ "text/plain; charset=ascii",
+ )
self.assertEqual(output.status_code, 200)
output_text = output.get_data(as_text=True)
self.assertIn("foo\n bar", output_text)
@@ -2837,9 +2857,16 @@ class PagureFlaskRepotests(tests.Modeltests):
output = self.app.get("/test/raw/master")
self.assertEqual(output.status_code, 200)
output_text = output.get_data(as_text=True)
- self.assertEqual(
- output.headers["Content-Type"].lower(), "text/plain; charset=ascii"
- )
+ if cchardet is not None:
+ self.assertEqual(
+ output.headers["Content-Type"].lower(),
+ "text/plain; charset=utf-8",
+ )
+ else:
+ self.assertEqual(
+ output.headers["Content-Type"].lower(),
+ "text/plain; charset=ascii",
+ )
self.assertTrue(
output_text.startswith("diff --git a/test_binary b/test_binary\n")
)
@@ -2877,9 +2904,16 @@ class PagureFlaskRepotests(tests.Modeltests):
output = self.app.get("/fork/pingou/test3/raw/master/f/sources")
self.assertEqual(output.status_code, 200)
output_text = output.get_data(as_text=True)
- self.assertEqual(
- output.headers["Content-Type"].lower(), "text/plain; charset=ascii"
- )
+ if cchardet is not None:
+ self.assertEqual(
+ output.headers["Content-Type"].lower(),
+ "text/plain; charset=utf-8",
+ )
+ else:
+ self.assertEqual(
+ output.headers["Content-Type"].lower(),
+ "text/plain; charset=ascii",
+ )
self.assertIn("foo\n bar", output_text)
def test_view_commit(self):
diff --git a/tests/test_pagure_lib_encoding_utils.py b/tests/test_pagure_lib_encoding_utils.py
index ccc8825f..aff7d8ba 100644
--- a/tests/test_pagure_lib_encoding_utils.py
+++ b/tests/test_pagure_lib_encoding_utils.py
@@ -5,11 +5,18 @@ Tests for :module:`pagure.lib.encoding_utils`.
from __future__ import unicode_literals, absolute_import
-import chardet
import os
import unittest
import sys
+cchardet = None
+try:
+ import cchardet
+except ImportError:
+ pass
+
+import chardet
+
sys.path.insert(
0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
)
@@ -24,7 +31,10 @@ class TestGuessEncoding(unittest.TestCase):
"""
data = "Twas bryllyg, and the slythy toves did gyre and gymble"
result = encoding_utils.guess_encoding(data.encode("ascii"))
- self.assertEqual(result, "ascii")
+ if cchardet is not None:
+ self.assertEqual(result, "utf-8")
+ else:
+ self.assertEqual(result, "ascii")
def test_guess_encoding_favor_utf_8(self):
"""
@@ -56,17 +66,24 @@ class TestGuessEncodings(unittest.TestCase):
chardet_result = chardet.detect(data)
if chardet.__version__[0] == "3":
# The first three have different confidence values
+ if cchardet is not None:
+ expexted_list = ["utf-8"]
+ # The last one in the list (which apparently has only one)
+ self.assertEqual(result[-1].encoding, "utf-8")
+ else:
+ expexted_list = ["utf-8", "ISO-8859-9", "ISO-8859-1"]
+ # This is the one with the least confidence
+ self.assertEqual(result[-1].encoding, "windows-1255")
self.assertListEqual(
- [encoding.encoding for encoding in result][:3],
- ["utf-8", "ISO-8859-9", "ISO-8859-1"],
+ [encoding.encoding for encoding in result][:3], expexted_list
)
- # This is the one with the least confidence
- self.assertEqual(result[-1].encoding, "windows-1255")
+
# The values in the middle of the list all have the same confidence
# value and can't be sorted reliably: use sets.
- self.assertEqual(
- set([encoding.encoding for encoding in result]),
- set(
+ if cchardet is not None:
+ expected_list = sorted(["utf-8"])
+ else:
+ expected_list = sorted(
[
"utf-8",
"ISO-8859-9",
@@ -89,7 +106,10 @@ class TestGuessEncodings(unittest.TestCase):
"windows-1251",
"windows-1255",
]
- ),
+ )
+ self.assertListEqual(
+ sorted(set([encoding.encoding for encoding in result])),
+ expected_list,
)
self.assertEqual(chardet_result["encoding"], "ISO-8859-9")
else:
diff --git a/tests/test_pagure_lib_mimetype.py b/tests/test_pagure_lib_mimetype.py
index d5947bee..8c2f4a31 100644
--- a/tests/test_pagure_lib_mimetype.py
+++ b/tests/test_pagure_lib_mimetype.py
@@ -9,6 +9,12 @@ import os
import unittest
import sys
+cchardet = None
+try:
+ import cchardet
+except ImportError:
+ pass
+
from pagure.lib import mimetype
sys.path.insert(
@@ -20,8 +26,18 @@ class TestMIMEType(unittest.TestCase):
def test_guess_type(self):
dataset = [
("hello.html", None, "text/html", None),
- ("hello.html", b"#!", "text/html", "ascii"),
- ("hello", b"#!", "text/plain", "ascii"),
+ (
+ "hello.html",
+ b"#!",
+ "text/html",
+ "ascii" if cchardet is None else "utf-8",
+ ),
+ (
+ "hello",
+ b"#!",
+ "text/plain",
+ "ascii" if cchardet is None else "utf-8",
+ ),
("hello.jpg", None, "image/jpeg", None),
("hello.jpg", b"#!", "image/jpeg", None),
("hello.jpg", b"\0", "image/jpeg", None),
@@ -49,7 +65,13 @@ class TestMIMEType(unittest.TestCase):
def test_get_normal_headers(self):
dataset = [
- ("hello", b"#!", "text/plain; charset=ascii"),
+ (
+ "hello",
+ b"#!",
+ "text/plain; charset=ascii"
+ if cchardet is None
+ else "text/plain; charset=utf-8",
+ ),
("hello.jpg", None, "image/jpeg"),
("hello.jpg", b"#!", "image/jpeg"),
("hello.jpg", b"\0", "image/jpeg"),
--
2.26.2

View File

@ -0,0 +1,134 @@
From 8e23c79fb64d4dd4e6f17f809d7e629840f7e91c Mon Sep 17 00:00:00 2001
From: Neal Gompa <ngompa13@gmail.com>
Date: Thu, 24 Sep 2020 06:40:06 -0400
Subject: [PATCH 9/9] Add support for disabling user registration
For public/private Pagure instances where it is intended to be used
by a single user, having the ability to turn off user registration
prevents confusion and closes an avenue of potential denial of service
attacks.
Signed-off-by: Neal Gompa <ngompa13@gmail.com>
---
doc/configuration.rst | 13 +++++++++++++
pagure/default_config.py | 3 +++
pagure/templates/login/login.html | 2 ++
pagure/ui/login.py | 3 +++
tests/test_pagure_flask_ui_login.py | 24 ++++++++++++++++++++++++
5 files changed, 45 insertions(+)
diff --git a/doc/configuration.rst b/doc/configuration.rst
index 735e378c..2ea7a66d 100644
--- a/doc/configuration.rst
+++ b/doc/configuration.rst
@@ -1117,6 +1117,7 @@ Valid options are ``fas``, ``openid``, ``oidc``, or ``local``.
the configuration options starting with ``OIDC_`` (see below) to be provided.
* ``local`` causes pagure to use the local pagure database for user management.
+ User registration can be disabled with the ALLOW_USER_REGISTRATION configuration key.
Defaults to: ``local``.
@@ -1784,6 +1785,18 @@ If turned off, users are managed outside of pagure.
Defaults to: ``True``
+ALLOW_USER_REGISTRATION
+~~~~~~~~~~~~~~~~~~~~~~~
+
+This configuration key can be used to turn on or off user registration
+(that is, the ability for users to create an account) in this pagure instance.
+If turned off, user accounts cannot be created through the UI or API.
+Currently, this key only applies to pagure instances configured with the ``local``
+authentication backend and has no effect with the other authentication backends.
+
+Defaults to: ``True``
+
+
SESSION_COOKIE_NAME
~~~~~~~~~~~~~~~~~~~
diff --git a/pagure/default_config.py b/pagure/default_config.py
index 045f2704..df0cd6b0 100644
--- a/pagure/default_config.py
+++ b/pagure/default_config.py
@@ -78,6 +78,9 @@ ENABLE_GROUP_MNGT = True
# Enables / Disables private projects
PRIVATE_PROJECTS = True
+# Enable / Disable user registration (local auth only)
+ALLOW_USER_REGISTRATION = True
+
# Enable / Disable deleting branches in the UI
ALLOW_DELETE_BRANCH = True
diff --git a/pagure/templates/login/login.html b/pagure/templates/login/login.html
index a65b10ae..e209c400 100644
--- a/pagure/templates/login/login.html
+++ b/pagure/templates/login/login.html
@@ -18,11 +18,13 @@
<input class="btn btn-primary btn-block mt-4" type="submit" value="Login">
{{ form.csrf_token }}
</form>
+ {% if config.get('ALLOW_USER_REGISTRATION', True) %}
<div>
<a class="btn btn-link btn-block" href="{{url_for('ui_ns.new_user') }}">
Create a new account
</a>
</div>
+ {% endif %}
</div>
</div>
</div>
diff --git a/pagure/ui/login.py b/pagure/ui/login.py
index 1a0dbd24..7da94a37 100644
--- a/pagure/ui/login.py
+++ b/pagure/ui/login.py
@@ -38,6 +38,9 @@ _log = logging.getLogger(__name__)
def new_user():
""" Create a new user.
"""
+ if not pagure.config.config.get("ALLOW_USER_REGISTRATION", True):
+ flask.flash("User registration is disabled.", "error")
+ return flask.redirect(flask.url_for("auth_login"))
form = forms.NewUserForm()
if form.validate_on_submit():
diff --git a/tests/test_pagure_flask_ui_login.py b/tests/test_pagure_flask_ui_login.py
index f11a2b22..8a1d16c7 100644
--- a/tests/test_pagure_flask_ui_login.py
+++ b/tests/test_pagure_flask_ui_login.py
@@ -149,6 +149,30 @@ class PagureFlaskLogintests(tests.SimplePagureTest):
items = pagure.lib.query.search_user(self.session)
self.assertEqual(3, len(items))
+ @patch.dict("pagure.config.config", {"PAGURE_AUTH": "local"})
+ @patch.dict("pagure.config.config", {"ALLOW_USER_REGISTRATION": False})
+ @patch("pagure.lib.notify.send_email", MagicMock(return_value=True))
+ def test_new_user_disabled(self):
+ """ Test the disabling of the new_user endpoint. """
+
+ # Check before:
+ items = pagure.lib.query.search_user(self.session)
+ self.assertEqual(2, len(items))
+
+ # Attempt to access the new user page
+ output = self.app.get("/user/new", follow_redirects=True)
+ self.assertEqual(output.status_code, 200)
+ self.assertIn(
+ "<title>Login - Pagure</title>", output.get_data(as_text=True)
+ )
+ self.assertIn(
+ "User registration is disabled.", output.get_data(as_text=True)
+ )
+
+ # Check after:
+ items = pagure.lib.query.search_user(self.session)
+ self.assertEqual(2, len(items))
+
@patch.dict("pagure.config.config", {"PAGURE_AUTH": "local"})
@patch.dict("pagure.config.config", {"CHECK_SESSION_IP": False})
def test_do_login(self):
--
2.26.2

View File

@ -1,3 +1,18 @@
-------------------------------------------------------------------
Thu Sep 24 22:57:42 UTC 2020 - Neal Gompa <ngompa13@gmail.com>
- Backport various fixes from upstream
+ Patch: 0001-Display-real-line-numbers-on-pull-request-s-diff-vie.patch
+ Patch: 0002-Show-the-assignee-s-avatar-on-the-board.patch
+ Patch: 0003-Allow-setting-a-status-as-closing-even-if-the-projec.patch
+ Patch: 0004-Include-the-assignee-in-the-list-of-people-notified-.patch
+ Patch: 0005-Introduce-the-collaborator_project_groups-mapping.patch
+ Patch: 0006-When-a-file-a-detected-as-a-binary-file-return-the-r.patch
+ Patch: 0007-Remove-fenced-code-block-when-checking-mention.patch
+ Patch: 0008-Add-support-for-using-cchardet-to-detect-files-encod.patch
+ Patch: 0009-Add-support-for-disabling-user-registration.patch
- Remove mandatory dependency on systemd to ease containerization
-------------------------------------------------------------------
Sun Aug 30 14:25:21 UTC 2020 - Neal Gompa <ngompa13@gmail.com>

View File

@ -41,6 +41,18 @@ Source1: https://raw.githubusercontent.com/fedora-infra/python-fedora
Source10: pagure-README.SUSE
# Backports from upstream
Patch0001: 0001-Display-real-line-numbers-on-pull-request-s-diff-vie.patch
Patch0002: 0002-Show-the-assignee-s-avatar-on-the-board.patch
Patch0003: 0003-Allow-setting-a-status-as-closing-even-if-the-projec.patch
Patch0004: 0004-Include-the-assignee-in-the-list-of-people-notified-.patch
Patch0005: 0005-Introduce-the-collaborator_project_groups-mapping.patch
Patch0006: 0006-When-a-file-a-detected-as-a-binary-file-return-the-r.patch
Patch0007: 0007-Remove-fenced-code-block-when-checking-mention.patch
Patch0008: 0008-Add-support-for-using-cchardet-to-detect-files-encod.patch
Patch0009: 0009-Add-support-for-disabling-user-registration.patch
# SUSE-specific fixes
## Change the defaults in the example config to match packaging
Patch1000: pagure-5.0-default-example-cfg.patch
@ -122,6 +134,9 @@ Requires: python3-dbm
Requires: python3-kitchen
Requires: python3-requests
# We want to use cchardet whenever it's available
Recommends: python3-cchardet
# If using PostgreSQL, the correct driver should be installed
Recommends: (python3-psycopg2 if postgresql-server)
@ -137,7 +152,7 @@ Recommends: (%{name}-web-nginx if nginx)
# The default theme is required
Requires: %{name}-theme-default
%{?systemd_requires}
%{?systemd_ordering}
# We use the git tools for some actions due to deficiencies in libgit2 and pygit2
Requires: git-core