From 4ef386a97d4e3e3de6a5f019688b5faa7f637912 Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Mar 03 2017 15:00:57 +0000
Subject: [PATCH 1/9] issue.py: Allow user with ticket access to edit custom fields


Signed-off-by: Vivek Anand <vivekanand1101@gmail.com>

---

diff --git a/pagure/templates/issue.html b/pagure/templates/issue.html
index 7e6338c..d668bb2 100644
--- a/pagure/templates/issue.html
+++ b/pagure/templates/issue.html
@@ -410,7 +410,7 @@
         <a class="btn btn-secondary issue-custom-form edit_custom_toggle">
           cancel
         </a>
-        {% if authenticated and g.repo_admin %}
+        {% if authenticated and g.repo_user %}
           <a class="btn btn-secondary issue-custom-display edit_custom_toggle">
             Edit Metadata
           </a>

From c7f8ebe22729740fd8b0d0934a65a6a27ca447c5 Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Mar 03 2017 15:00:57 +0000
Subject: [PATCH 2/9] issue: allow user with ticket access to edit metadata


Signed-off-by: Vivek Anand <vivekanand1101@gmail.com>

---

diff --git a/pagure/templates/issue.html b/pagure/templates/issue.html
index d668bb2..4526e98 100644
--- a/pagure/templates/issue.html
+++ b/pagure/templates/issue.html
@@ -295,7 +295,7 @@
               {% endif %}
             </div>
           </fieldset>
-          {% if authenticated and g.repo_admin %}
+          {% if authenticated and g.repo_user %}
             {{ render_bootstrap_field(form.milestone,
               formclass="issue-metadata-form") }}
           {% endif%}

From fd247536b8a2b561a070aa13dfcce8ee9082b469 Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Mar 03 2017 15:00:57 +0000
Subject: [PATCH 3/9] issue: repo users to change from public to private


They shouldn't be able to do the other way round, since
both GET and POST is blocked if the user is not a committer

---

diff --git a/pagure/templates/issue.html b/pagure/templates/issue.html
index 4526e98..98fb0fe 100644
--- a/pagure/templates/issue.html
+++ b/pagure/templates/issue.html
@@ -307,7 +307,7 @@
             <label><strong class="red-icon">Private</strong></label>
           </fieldset>
           {% endif %}
-          {% if authenticated and g.repo_admin %}
+          {% if authenticated and g.repo_user %}
             {{ render_bootstrap_field(form.private,
               formclass="issue-metadata-form") }}
           {% endif%}

From d83b03e365cd12dc3d0277fd7ee917713bdd6646 Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Mar 03 2017 15:00:57 +0000
Subject: [PATCH 4/9] Unit test: View issue when user has not access level in repo


Signed-off-by: Vivek Anand <vivekanand1101@gmail.com>

---

diff --git a/tests/test_pagure_flask_ui_issues.py b/tests/test_pagure_flask_ui_issues.py
index 14b1d66..58fbc65 100644
--- a/tests/test_pagure_flask_ui_issues.py
+++ b/tests/test_pagure_flask_ui_issues.py
@@ -603,6 +603,258 @@ class PagureFlaskIssuestests(tests.Modeltests):
 
     @patch('pagure.lib.git.update_git')
     @patch('pagure.lib.notify.send_email')
+    def test_view_issue_no_access(self, p_send_email, p_ugt):
+        """ Test the view_issue endpoint. when a user has no access on repo """
+        p_send_email.return_value = True
+        p_ugt.return_value = True
+
+        output = self.app.get('/foo/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        tests.create_projects(self.session)
+        tests.create_projects_git(
+            os.path.join(self.path), bare=True)
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        # Create issues to play with
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None
+        )
+
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Add milestone
+        repo.milestones = {'77': None}
+        self.session.add(repo)
+        issue = pagure.lib.search_issues(
+            self.session,
+            repo=repo,
+            issueid=1
+        )
+
+        pagure.lib.edit_issue(
+            self.session,
+            issue,
+            pagure.APP.config.get('TICKETS_FOLDER'),
+            user='pingou',
+            milestone='77'
+        )
+        self.session.add(repo)
+        self.session.add(issue)
+
+        msg = pagure.lib.set_custom_key_fields(
+            self.session,
+            project=repo,
+            fields=['abc', 'xyz'],
+            types=['boolean', 'boolean'],
+            data=[None, None],
+        )
+        self.assertEqual(msg, 'List of custom fields updated')
+        self.session.add(repo)
+
+        msg = pagure.lib.set_custom_key_value(
+            self.session,
+            issue=issue,
+            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
+            value=1
+        )
+        self.session.add(issue)
+        self.session.commit()
+
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 200)
+        # Not authentified = No edit
+        self.assertNotIn(
+            '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
+            'title="Edit this issue">',
+            output.data)
+        self.assertTrue(
+            '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
+            'Login</a>\n            to comment on this ticket.'
+            in output.data)
+
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+            # Not author nor admin = No edit
+            self.assertNotIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertNotIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+            self.assertNotIn('title="Delete this ticket">', output.data)
+
+            # no edit metadata
+            self.assertNotIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+            self.assertFalse(
+                '<a href="/login/">Login</a> to comment on this ticket.'
+                in output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+            # but can't edit them
+            self.assertNotIn(
+                '<select class="form-control c-select" id="milestone" '
+                ' name="milestone"><option value=""></option><option '
+                'selected value="77">77</option></select>',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can't edit depends on
+            self.assertNotIn(
+                '<input class="form-control" id="depends" type="text"\n\
+                                placeholder="issue depending" name="depends"\n\
+                                value="" />',
+                output.data)
+
+            # no toggle option for custom fields
+            self.assertNotIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # no checkbox for private
+            self.assertNotIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        user.username = 'foo'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+            self.assertNotIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertNotIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+            self.assertNotIn('title="Delete this ticket">', output.data)
+
+            csrf_token = output.data.split(
+                'name="csrf_token" type="hidden" value="')[1].split('">')[0]
+
+            # no edit metadata
+            self.assertNotIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+            self.assertFalse(
+                '<a href="/login/">Login</a> to comment on this ticket.'
+                in output.data)
+
+            # no toggle option for custom fields
+            self.assertNotIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # can't see the custom field as a checkbox
+            self.assertNotIn(
+                '<input type="checkbox"                   '
+                'class="form-control" name="abc" id="abc"checked/>',
+                output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+
+            # but can't edit them
+            self.assertNotIn(
+                '<select class="form-control c-select" id="milestone" '
+                ' name="milestone"><option value=""></option><option '
+                'selected value="77">77</option></select>',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can't edit depends on
+            self.assertNotIn(
+                '<input class="form-control" id="depends" type="text"\n\
+                                placeholder="issue depending" name="depends"\n\
+                                value="" />',
+                output.data)
+
+            # no checkbox for private
+            self.assertNotIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        # Create private issue
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=True,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Not logged in
+        output = self.app.get('/test/issue/2')
+        self.assertEqual(output.status_code, 403)
+
+        # Wrong user
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 403)
+
+        # reporter
+        user.username = 'pingou'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 200)
+            self.assertIn(
+                '<title>Issue #2: Test issue - test - Pagure</title>',
+                output.data)
+            self.assertIn(
+                '<span class="oi red-icon" data-glyph="lock-locked" '
+                'title="Private issue"></span>', output.data)
+            self.assertIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/2/edit" title="Edit this issue">',
+                output.data)
+
+
+    @patch('pagure.lib.git.update_git')
+    @patch('pagure.lib.notify.send_email')
     def test_view_issue_non_ascii_milestone(self, p_send_email, p_ugt):
         """ Test the view_issue endpoint with non-ascii milestone. """
         p_send_email.return_value = True

From e0020ef61af75c33009bf19060b106dde1534db8 Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Mar 03 2017 15:00:57 +0000
Subject: [PATCH 5/9] Unit test: view issue endpoint when user has ticket access


Signed-off-by: Vivek Anand <vivekanand1101@gmail.com>

---

diff --git a/tests/test_pagure_flask_ui_issues.py b/tests/test_pagure_flask_ui_issues.py
index 58fbc65..a4b5f80 100644
--- a/tests/test_pagure_flask_ui_issues.py
+++ b/tests/test_pagure_flask_ui_issues.py
@@ -852,6 +852,268 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 'href="/test/issue/2/edit" title="Edit this issue">',
                 output.data)
 
+    @patch('pagure.lib.git.update_git')
+    @patch('pagure.lib.notify.send_email')
+    def test_view_issue_ticket_access(self, p_send_email, p_ugt):
+        """ Test the view_issue endpoint. when a user has ticket access on repo """
+        p_send_email.return_value = True
+        p_ugt.return_value = True
+
+        output = self.app.get('/foo/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        tests.create_projects(self.session)
+        tests.create_projects_git(
+            os.path.join(self.path), bare=True)
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        # Create issues to play with
+        repo = pagure.lib.get_project(self.session, 'test')
+
+        # Add user 'foo' with ticket access on repo
+        msg = pagure.lib.add_user_to_project(
+            self.session,
+            repo,
+            new_user='foo',
+            user='pingou',
+            access='ticket',
+        )
+        self.assertEqual(msg, 'User added')
+        self.session.commit()
+
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None
+        )
+
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Add milestone
+        repo.milestones = {'77': None}
+        self.session.add(repo)
+        issue = pagure.lib.search_issues(
+            self.session,
+            repo=repo,
+            issueid=1
+        )
+
+        pagure.lib.edit_issue(
+            self.session,
+            issue,
+            pagure.APP.config.get('TICKETS_FOLDER'),
+            user='pingou',
+            milestone='77'
+        )
+        self.session.add(repo)
+        self.session.add(issue)
+
+        msg = pagure.lib.set_custom_key_fields(
+            self.session,
+            project=repo,
+            fields=['abc', 'xyz'],
+            types=['boolean', 'boolean'],
+            data=[None, None],
+        )
+        self.assertEqual(msg, 'List of custom fields updated')
+        self.session.add(repo)
+
+        msg = pagure.lib.set_custom_key_value(
+            self.session,
+            issue=issue,
+            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
+            value=1
+        )
+        self.session.add(issue)
+        self.session.commit()
+
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 200)
+        # Not authentified = No edit
+        self.assertNotIn(
+            '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
+            'title="Edit this issue">',
+            output.data)
+        self.assertTrue(
+            '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
+            'Login</a>\n            to comment on this ticket.'
+            in output.data)
+
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+            # Not author nor admin = No edit
+            self.assertNotIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertNotIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+            self.assertNotIn('title="Delete this ticket">', output.data)
+
+            # no edit metadata
+            self.assertNotIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+            self.assertFalse(
+                '<a href="/login/">Login</a> to comment on this ticket.'
+                in output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+            # but can't edit them
+            self.assertNotIn(
+                '<select class="form-control c-select" id="milestone" '
+                ' name="milestone"><option value=""></option><option '
+                'selected value="77">77</option></select>',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can't edit depends on
+            self.assertNotIn(
+                '<input class="form-control" id="depends" type="text"\n\
+                                placeholder="issue depending" name="depends"\n\
+                                value="" />',
+                output.data)
+
+            # no toggle option for custom fields
+            self.assertNotIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # no checkbox for private
+            self.assertNotIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        user.username = 'foo'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+
+            # the user can't edit the issue
+            self.assertNotIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertNotIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+
+            # the user still can't delete the ticket
+            self.assertNotIn('title="Delete this ticket">', output.data)
+
+            csrf_token = output.data.split(
+                'name="csrf_token" type="hidden" value="')[1].split('">')[0]
+
+            # the user can do the following things
+            # edit metadata
+            self.assertIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+
+            # toggle option for custom fields
+            self.assertIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+
+            # can edit them
+            self.assertNotIn(
+                '<select class="form-control c-select" id="milestone" '
+                ' name="milestone"><option value=""></option><option '
+                'selected value="77">77</option></select>',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can edit depends on
+            self.assertIn(
+                '<input class="form-control" id="depends" type="text"'
+                '\n                placeholder="issue depending" name="depends"\n',
+                output.data)
+
+            # the user should be able to do public -> private
+            # the other way round won't be possible since GET and POST
+            # to this endpoint for this user will be blocked
+
+            # checkbox for private
+            self.assertIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        # Create private issue
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=True,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Not logged in
+        output = self.app.get('/test/issue/2')
+        self.assertEqual(output.status_code, 403)
+
+        # Wrong user
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 403)
+
+        # reporter
+        user.username = 'pingou'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 200)
+            self.assertIn(
+                '<title>Issue #2: Test issue - test - Pagure</title>',
+                output.data)
+            self.assertIn(
+                '<span class="oi red-icon" data-glyph="lock-locked" '
+                'title="Private issue"></span>', output.data)
+            self.assertIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/2/edit" title="Edit this issue">',
+                output.data)
 
     @patch('pagure.lib.git.update_git')
     @patch('pagure.lib.notify.send_email')

From 2c3c0bb42b18ea7a835fd7947b27bcc50f124fde Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Mar 03 2017 15:00:57 +0000
Subject: [PATCH 6/9] Unit test: view issue when user has commit access in repo


Signed-off-by: Vivek Anand <vivekanand1101@gmail.com>

---

diff --git a/tests/test_pagure_flask_ui_issues.py b/tests/test_pagure_flask_ui_issues.py
index a4b5f80..19b2485 100644
--- a/tests/test_pagure_flask_ui_issues.py
+++ b/tests/test_pagure_flask_ui_issues.py
@@ -1117,6 +1117,269 @@ class PagureFlaskIssuestests(tests.Modeltests):
 
     @patch('pagure.lib.git.update_git')
     @patch('pagure.lib.notify.send_email')
+    def test_view_issue_commit_access(self, p_send_email, p_ugt):
+        """ Test the view_issue endpoint. when a user has commit access on repo """
+        p_send_email.return_value = True
+        p_ugt.return_value = True
+
+        output = self.app.get('/foo/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        tests.create_projects(self.session)
+        tests.create_projects_git(
+            os.path.join(self.path), bare=True)
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        # Create issues to play with
+        repo = pagure.lib.get_project(self.session, 'test')
+
+        # Add user 'foo' with ticket access on repo
+        msg = pagure.lib.add_user_to_project(
+            self.session,
+            repo,
+            new_user='foo',
+            user='pingou',
+            access='commit',
+        )
+        self.assertEqual(msg, 'User added')
+        self.session.commit()
+
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None
+        )
+
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Add milestone
+        repo.milestones = {'77': None}
+        self.session.add(repo)
+        issue = pagure.lib.search_issues(
+            self.session,
+            repo=repo,
+            issueid=1
+        )
+
+        pagure.lib.edit_issue(
+            self.session,
+            issue,
+            pagure.APP.config.get('TICKETS_FOLDER'),
+            user='pingou',
+            milestone='77'
+        )
+        self.session.add(repo)
+        self.session.add(issue)
+
+        msg = pagure.lib.set_custom_key_fields(
+            self.session,
+            project=repo,
+            fields=['abc', 'xyz'],
+            types=['boolean', 'boolean'],
+            data=[None, None],
+        )
+        self.assertEqual(msg, 'List of custom fields updated')
+        self.session.add(repo)
+
+        msg = pagure.lib.set_custom_key_value(
+            self.session,
+            issue=issue,
+            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
+            value=1
+        )
+        self.session.add(issue)
+        self.session.commit()
+
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 200)
+        # Not authentified = No edit
+        self.assertNotIn(
+            '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
+            'title="Edit this issue">',
+            output.data)
+        self.assertTrue(
+            '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
+            'Login</a>\n            to comment on this ticket.'
+            in output.data)
+
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+            # Not author nor admin = No edit
+            self.assertNotIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertNotIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+            self.assertNotIn('title="Delete this ticket">', output.data)
+
+            # no edit metadata
+            self.assertNotIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+            self.assertFalse(
+                '<a href="/login/">Login</a> to comment on this ticket.'
+                in output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+            # but can't edit them
+            self.assertNotIn(
+                '<select class="form-control c-select" id="milestone" '
+                ' name="milestone"><option value=""></option><option '
+                'selected value="77">77</option></select>',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can't edit depends on
+            self.assertNotIn(
+                '<input class="form-control" id="depends" type="text"\n\
+                                placeholder="issue depending" name="depends"\n\
+                                value="" />',
+                output.data)
+
+            # no toggle option for custom fields
+            self.assertNotIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # no checkbox for private
+            self.assertNotIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        user.username = 'foo'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+
+            # the user can't edit the issue
+            self.assertNotIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertNotIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+
+            # the user still can't delete the ticket
+            self.assertNotIn('title="Delete this ticket">', output.data)
+
+            csrf_token = output.data.split(
+                'name="csrf_token" type="hidden" value="')[1].split('">')[0]
+
+            # the user can do the following things
+            # edit metadata
+            self.assertIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+
+            # toggle option for custom fields
+            self.assertIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+
+            # can edit them
+            self.assertNotIn(
+                '<select class="form-control c-select" id="milestone" '
+                ' name="milestone"><option value=""></option><option '
+                'selected value="77">77</option></select>',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can edit depends on
+            self.assertIn(
+                '<input class="form-control" id="depends" type="text"'
+                '\n                placeholder="issue depending" name="depends"\n',
+                output.data)
+
+            # the user should be able to do public -> private
+            # the other way round won't be possible since GET and POST
+            # to this endpoint for this user will be blocked
+
+            # checkbox for private
+            self.assertIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        # Create private issue
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=True,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Not logged in
+        output = self.app.get('/test/issue/2')
+        self.assertEqual(output.status_code, 403)
+
+        # Wrong user
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 403)
+
+        # reporter
+        user.username = 'pingou'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 200)
+            self.assertIn(
+                '<title>Issue #2: Test issue - test - Pagure</title>',
+                output.data)
+            self.assertIn(
+                '<span class="oi red-icon" data-glyph="lock-locked" '
+                'title="Private issue"></span>', output.data)
+            self.assertIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/2/edit" title="Edit this issue">',
+                output.data)
+
+    @patch('pagure.lib.git.update_git')
+    @patch('pagure.lib.notify.send_email')
     def test_view_issue_non_ascii_milestone(self, p_send_email, p_ugt):
         """ Test the view_issue endpoint with non-ascii milestone. """
         p_send_email.return_value = True

From 9c6c9c61e3bb694b1d5558264614c86bca1c4b3e Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Mar 03 2017 15:00:57 +0000
Subject: [PATCH 7/9] Unit test: view issue when the user has admin access


Signed-off-by: Vivek Anand <vivekanand1101@gmail.com>

---

diff --git a/tests/test_pagure_flask_ui_issues.py b/tests/test_pagure_flask_ui_issues.py
index 19b2485..70e94a0 100644
--- a/tests/test_pagure_flask_ui_issues.py
+++ b/tests/test_pagure_flask_ui_issues.py
@@ -1380,6 +1380,269 @@ class PagureFlaskIssuestests(tests.Modeltests):
 
     @patch('pagure.lib.git.update_git')
     @patch('pagure.lib.notify.send_email')
+    def test_view_issue_admin_access(self, p_send_email, p_ugt):
+        """ Test the view_issue endpoint. when a user has admin access on repo """
+        p_send_email.return_value = True
+        p_ugt.return_value = True
+
+        output = self.app.get('/foo/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        tests.create_projects(self.session)
+        tests.create_projects_git(
+            os.path.join(self.path), bare=True)
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        # Create issues to play with
+        repo = pagure.lib.get_project(self.session, 'test')
+
+        # Add user 'foo' with ticket access on repo
+        msg = pagure.lib.add_user_to_project(
+            self.session,
+            repo,
+            new_user='foo',
+            user='pingou',
+            access='admin',
+        )
+        self.assertEqual(msg, 'User added')
+        self.session.commit()
+
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None
+        )
+
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Add milestone
+        repo.milestones = {'77': None}
+        self.session.add(repo)
+        issue = pagure.lib.search_issues(
+            self.session,
+            repo=repo,
+            issueid=1
+        )
+
+        pagure.lib.edit_issue(
+            self.session,
+            issue,
+            pagure.APP.config.get('TICKETS_FOLDER'),
+            user='pingou',
+            milestone='77'
+        )
+        self.session.add(repo)
+        self.session.add(issue)
+
+        msg = pagure.lib.set_custom_key_fields(
+            self.session,
+            project=repo,
+            fields=['abc', 'xyz'],
+            types=['boolean', 'boolean'],
+            data=[None, None],
+        )
+        self.assertEqual(msg, 'List of custom fields updated')
+        self.session.add(repo)
+
+        msg = pagure.lib.set_custom_key_value(
+            self.session,
+            issue=issue,
+            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
+            value=1
+        )
+        self.session.add(issue)
+        self.session.commit()
+
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 200)
+        # Not authentified = No edit
+        self.assertNotIn(
+            '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
+            'title="Edit this issue">',
+            output.data)
+        self.assertTrue(
+            '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
+            'Login</a>\n            to comment on this ticket.'
+            in output.data)
+
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+            # Not author nor admin = No edit
+            self.assertNotIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertNotIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+            self.assertNotIn('title="Delete this ticket">', output.data)
+
+            # no edit metadata
+            self.assertNotIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+            self.assertFalse(
+                '<a href="/login/">Login</a> to comment on this ticket.'
+                in output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+            # but can't edit them
+            self.assertNotIn(
+                '<select class="form-control c-select" id="milestone" '
+                ' name="milestone"><option value=""></option><option '
+                'selected value="77">77</option></select>',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can't edit depends on
+            self.assertNotIn(
+                '<input class="form-control" id="depends" type="text"\n\
+                                placeholder="issue depending" name="depends"\n\
+                                value="" />',
+                output.data)
+
+            # no toggle option for custom fields
+            self.assertNotIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # no checkbox for private
+            self.assertNotIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        user.username = 'foo'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+
+            # the user can edit the issue
+            self.assertIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+
+            # the user still can delete the ticket
+            self.assertIn('title="Delete this ticket">', output.data)
+
+            csrf_token = output.data.split(
+                'name="csrf_token" type="hidden" value="')[1].split('">')[0]
+
+            # the user can do the following things
+            # edit metadata
+            self.assertIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+
+            # toggle option for custom fields
+            self.assertIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+
+            # can edit them
+            self.assertNotIn(
+                '<select class="form-control c-select" id="milestone" '
+                ' name="milestone"><option value=""></option><option '
+                'selected value="77">77</option></select>',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can edit depends on
+            self.assertIn(
+                '<input class="form-control" id="depends" type="text"'
+                '\n                placeholder="issue depending" name="depends"\n',
+                output.data)
+
+            # the user should be able to do public -> private
+            # the other way round won't be possible since GET and POST
+            # to this endpoint for this user will be blocked
+
+            # checkbox for private
+            self.assertIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        # Create private issue
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=True,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Not logged in
+        output = self.app.get('/test/issue/2')
+        self.assertEqual(output.status_code, 403)
+
+        # Wrong user
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 403)
+
+        # reporter
+        user.username = 'pingou'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 200)
+            self.assertIn(
+                '<title>Issue #2: Test issue - test - Pagure</title>',
+                output.data)
+            self.assertIn(
+                '<span class="oi red-icon" data-glyph="lock-locked" '
+                'title="Private issue"></span>', output.data)
+            self.assertIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/2/edit" title="Edit this issue">',
+                output.data)
+
+    @patch('pagure.lib.git.update_git')
+    @patch('pagure.lib.notify.send_email')
     def test_view_issue_non_ascii_milestone(self, p_send_email, p_ugt):
         """ Test the view_issue endpoint with non-ascii milestone. """
         p_send_email.return_value = True

From a9a56cbbeb13f2e4fe1516aaa0d119fcdcfdbed9 Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Mar 03 2017 15:00:57 +0000
Subject: [PATCH 8/9] Unit tests: Fix broken conditions for issues


This commit brings a couple of changes:
1. The committer should be able to edit or delete an issue (thanks
to unit tests)
2. The condition for checking "altering" milestone was broken which
wasn't caught because it was inside self.assertNotIn

---

diff --git a/pagure/templates/_formhelper.html b/pagure/templates/_formhelper.html
index 33af8dc..fbdea6e 100644
--- a/pagure/templates/_formhelper.html
+++ b/pagure/templates/_formhelper.html
@@ -186,7 +186,7 @@
           <span class="oi" data-glyph="share-boxed"></span>
         </a>
       {% endif %}
-      {% if g.repo_admin or (
+      {% if g.repo_committer or (
         g.fas_user and g.fas_user.username == comment.user.username) %}
       <a class="btn btn-primary btn-sm" href="{{
           url_for('edit_issue',
@@ -197,7 +197,7 @@
           }}" title="Edit this issue">
       <span class="oi" data-glyph="pencil"></span></a>
       {% endif %}
-      {% if g.repo_admin %}
+      {% if g.repo_committer %}
         <button class="btn btn-danger btn-sm" type="submit" id="closeticket"
             title="Delete this ticket">
           <span class="oi" data-glyph="trash"></span>
diff --git a/tests/test_pagure_flask_ui_issues.py b/tests/test_pagure_flask_ui_issues.py
index 70e94a0..aba7b47 100644
--- a/tests/test_pagure_flask_ui_issues.py
+++ b/tests/test_pagure_flask_ui_issues.py
@@ -1049,10 +1049,10 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 output.data)
 
             # can edit them
-            self.assertNotIn(
+            self.assertIn(
                 '<select class="form-control c-select" id="milestone" '
-                ' name="milestone"><option value=""></option><option '
-                'selected value="77">77</option></select>',
+                'name="milestone"><option value=""></option><option selected '
+                'value="77">77</option></select>\n      <div>\n',
                 output.data)
 
             # can view depends on
@@ -1275,17 +1275,17 @@ class PagureFlaskIssuestests(tests.Modeltests):
             output = self.app.get('/test/issue/1')
             self.assertEqual(output.status_code, 200)
 
-            # the user can't edit the issue
-            self.assertNotIn(
+            # the user can edit the issue
+            self.assertIn(
                 '<a class="btn btn-primary btn-sm" '
                 'href="/test/issue/1/edit" title="Edit this issue">',
                 output.data)
-            self.assertNotIn(
+            self.assertIn(
                 '<button class="btn btn-danger btn-sm" type="submit"',
                 output.data)
 
-            # the user still can't delete the ticket
-            self.assertNotIn('title="Delete this ticket">', output.data)
+            # the user can delete the ticket
+            self.assertIn('title="Delete this ticket">', output.data)
 
             csrf_token = output.data.split(
                 'name="csrf_token" type="hidden" value="')[1].split('">')[0]
@@ -1312,12 +1312,11 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 output.data)
 
             # can edit them
-            self.assertNotIn(
+            self.assertIn(
                 '<select class="form-control c-select" id="milestone" '
-                ' name="milestone"><option value=""></option><option '
-                'selected value="77">77</option></select>',
+                'name="milestone"><option value=""></option><option selected '
+                'value="77">77</option></select>\n      <div>\n',
                 output.data)
-
             # can view depends on
             self.assertIn(
                 '<label><strong>Depends on</strong></label>',
@@ -1575,10 +1574,10 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 output.data)
 
             # can edit them
-            self.assertNotIn(
+            self.assertIn(
                 '<select class="form-control c-select" id="milestone" '
-                ' name="milestone"><option value=""></option><option '
-                'selected value="77">77</option></select>',
+                'name="milestone"><option value=""></option><option selected '
+                'value="77">77</option></select>\n      <div>\n',
                 output.data)
 
             # can view depends on

From 6f20f848f4165d86c48aa28cc89f4cfa646c3cfd Mon Sep 17 00:00:00 2001
From: Vivek Anand <vivekanand1101@gmail.com>
Date: Mar 03 2017 15:05:41 +0000
Subject: [PATCH 9/9] Unit tests: Move ACL related tests for view_issue endpoint in another file


Signed-off-by: Vivek Anand <vivekanand1101@gmail.com>

---

diff --git a/tests/test_pagure_flask_ui_issues.py b/tests/test_pagure_flask_ui_issues.py
index aba7b47..14b1d66 100644
--- a/tests/test_pagure_flask_ui_issues.py
+++ b/tests/test_pagure_flask_ui_issues.py
@@ -603,1045 +603,6 @@ class PagureFlaskIssuestests(tests.Modeltests):
 
     @patch('pagure.lib.git.update_git')
     @patch('pagure.lib.notify.send_email')
-    def test_view_issue_no_access(self, p_send_email, p_ugt):
-        """ Test the view_issue endpoint. when a user has no access on repo """
-        p_send_email.return_value = True
-        p_ugt.return_value = True
-
-        output = self.app.get('/foo/issue/1')
-        self.assertEqual(output.status_code, 404)
-
-        tests.create_projects(self.session)
-        tests.create_projects_git(
-            os.path.join(self.path), bare=True)
-
-        output = self.app.get('/test/issue/1')
-        self.assertEqual(output.status_code, 404)
-
-        # Create issues to play with
-        repo = pagure.lib.get_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
-            session=self.session,
-            repo=repo,
-            title='Test issue',
-            content='We should work on this',
-            user='pingou',
-            ticketfolder=None
-        )
-
-        self.session.commit()
-        self.assertEqual(msg.title, 'Test issue')
-
-        # Add milestone
-        repo.milestones = {'77': None}
-        self.session.add(repo)
-        issue = pagure.lib.search_issues(
-            self.session,
-            repo=repo,
-            issueid=1
-        )
-
-        pagure.lib.edit_issue(
-            self.session,
-            issue,
-            pagure.APP.config.get('TICKETS_FOLDER'),
-            user='pingou',
-            milestone='77'
-        )
-        self.session.add(repo)
-        self.session.add(issue)
-
-        msg = pagure.lib.set_custom_key_fields(
-            self.session,
-            project=repo,
-            fields=['abc', 'xyz'],
-            types=['boolean', 'boolean'],
-            data=[None, None],
-        )
-        self.assertEqual(msg, 'List of custom fields updated')
-        self.session.add(repo)
-
-        msg = pagure.lib.set_custom_key_value(
-            self.session,
-            issue=issue,
-            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
-            value=1
-        )
-        self.session.add(issue)
-        self.session.commit()
-
-
-        output = self.app.get('/test/issue/1')
-        self.assertEqual(output.status_code, 200)
-        # Not authentified = No edit
-        self.assertNotIn(
-            '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
-            'title="Edit this issue">',
-            output.data)
-        self.assertTrue(
-            '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
-            'Login</a>\n            to comment on this ticket.'
-            in output.data)
-
-        user = tests.FakeUser()
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/1')
-            self.assertEqual(output.status_code, 200)
-            # Not author nor admin = No edit
-            self.assertNotIn(
-                '<a class="btn btn-primary btn-sm" '
-                'href="/test/issue/1/edit" title="Edit this issue">',
-                output.data)
-            self.assertNotIn(
-                '<button class="btn btn-danger btn-sm" type="submit"',
-                output.data)
-            self.assertNotIn('title="Delete this ticket">', output.data)
-
-            # no edit metadata
-            self.assertNotIn(
-                '<a class="btn btn-secondary issue-metadata-display'
-                ' editmetadatatoggle">',
-                output.data)
-            self.assertFalse(
-                '<a href="/login/">Login</a> to comment on this ticket.'
-                in output.data)
-
-            # can view the milestone
-            self.assertIn(
-                '<label><strong>Milestone</strong></label>',
-                output.data)
-            self.assertIn(
-                '<span >77</span>',
-                output.data)
-            # but can't edit them
-            self.assertNotIn(
-                '<select class="form-control c-select" id="milestone" '
-                ' name="milestone"><option value=""></option><option '
-                'selected value="77">77</option></select>',
-                output.data)
-
-            # can view depends on
-            self.assertIn(
-                '<label><strong>Depends on</strong></label>',
-                output.data)
-
-            # can't edit depends on
-            self.assertNotIn(
-                '<input class="form-control" id="depends" type="text"\n\
-                                placeholder="issue depending" name="depends"\n\
-                                value="" />',
-                output.data)
-
-            # no toggle option for custom fields
-            self.assertNotIn(
-                '<a class="btn btn-secondary '
-                'issue-custom-display edit_custom_toggle">',
-                output.data)
-
-            # no checkbox for private
-            self.assertNotIn(
-                '<input id="private" name="private" type="checkbox" value="y">',
-                output.data)
-
-        user.username = 'foo'
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/1')
-            self.assertEqual(output.status_code, 200)
-            self.assertNotIn(
-                '<a class="btn btn-primary btn-sm" '
-                'href="/test/issue/1/edit" title="Edit this issue">',
-                output.data)
-            self.assertNotIn(
-                '<button class="btn btn-danger btn-sm" type="submit"',
-                output.data)
-            self.assertNotIn('title="Delete this ticket">', output.data)
-
-            csrf_token = output.data.split(
-                'name="csrf_token" type="hidden" value="')[1].split('">')[0]
-
-            # no edit metadata
-            self.assertNotIn(
-                '<a class="btn btn-secondary issue-metadata-display'
-                ' editmetadatatoggle">',
-                output.data)
-            self.assertFalse(
-                '<a href="/login/">Login</a> to comment on this ticket.'
-                in output.data)
-
-            # no toggle option for custom fields
-            self.assertNotIn(
-                '<a class="btn btn-secondary '
-                'issue-custom-display edit_custom_toggle">',
-                output.data)
-
-            # can't see the custom field as a checkbox
-            self.assertNotIn(
-                '<input type="checkbox"                   '
-                'class="form-control" name="abc" id="abc"checked/>',
-                output.data)
-
-            # can view the milestone
-            self.assertIn(
-                '<label><strong>Milestone</strong></label>',
-                output.data)
-            self.assertIn(
-                '<span >77</span>',
-                output.data)
-
-            # but can't edit them
-            self.assertNotIn(
-                '<select class="form-control c-select" id="milestone" '
-                ' name="milestone"><option value=""></option><option '
-                'selected value="77">77</option></select>',
-                output.data)
-
-            # can view depends on
-            self.assertIn(
-                '<label><strong>Depends on</strong></label>',
-                output.data)
-
-            # can't edit depends on
-            self.assertNotIn(
-                '<input class="form-control" id="depends" type="text"\n\
-                                placeholder="issue depending" name="depends"\n\
-                                value="" />',
-                output.data)
-
-            # no checkbox for private
-            self.assertNotIn(
-                '<input id="private" name="private" type="checkbox" value="y">',
-                output.data)
-
-        # Create private issue
-        repo = pagure.lib.get_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
-            session=self.session,
-            repo=repo,
-            title='Test issue',
-            content='We should work on this',
-            user='pingou',
-            ticketfolder=None,
-            private=True,
-        )
-        self.session.commit()
-        self.assertEqual(msg.title, 'Test issue')
-
-        # Not logged in
-        output = self.app.get('/test/issue/2')
-        self.assertEqual(output.status_code, 403)
-
-        # Wrong user
-        user = tests.FakeUser()
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/2')
-            self.assertEqual(output.status_code, 403)
-
-        # reporter
-        user.username = 'pingou'
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/2')
-            self.assertEqual(output.status_code, 200)
-            self.assertIn(
-                '<title>Issue #2: Test issue - test - Pagure</title>',
-                output.data)
-            self.assertIn(
-                '<span class="oi red-icon" data-glyph="lock-locked" '
-                'title="Private issue"></span>', output.data)
-            self.assertIn(
-                '<a class="btn btn-primary btn-sm" '
-                'href="/test/issue/2/edit" title="Edit this issue">',
-                output.data)
-
-    @patch('pagure.lib.git.update_git')
-    @patch('pagure.lib.notify.send_email')
-    def test_view_issue_ticket_access(self, p_send_email, p_ugt):
-        """ Test the view_issue endpoint. when a user has ticket access on repo """
-        p_send_email.return_value = True
-        p_ugt.return_value = True
-
-        output = self.app.get('/foo/issue/1')
-        self.assertEqual(output.status_code, 404)
-
-        tests.create_projects(self.session)
-        tests.create_projects_git(
-            os.path.join(self.path), bare=True)
-
-        output = self.app.get('/test/issue/1')
-        self.assertEqual(output.status_code, 404)
-
-        # Create issues to play with
-        repo = pagure.lib.get_project(self.session, 'test')
-
-        # Add user 'foo' with ticket access on repo
-        msg = pagure.lib.add_user_to_project(
-            self.session,
-            repo,
-            new_user='foo',
-            user='pingou',
-            access='ticket',
-        )
-        self.assertEqual(msg, 'User added')
-        self.session.commit()
-
-        repo = pagure.lib.get_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
-            session=self.session,
-            repo=repo,
-            title='Test issue',
-            content='We should work on this',
-            user='pingou',
-            ticketfolder=None
-        )
-
-        self.session.commit()
-        self.assertEqual(msg.title, 'Test issue')
-
-        # Add milestone
-        repo.milestones = {'77': None}
-        self.session.add(repo)
-        issue = pagure.lib.search_issues(
-            self.session,
-            repo=repo,
-            issueid=1
-        )
-
-        pagure.lib.edit_issue(
-            self.session,
-            issue,
-            pagure.APP.config.get('TICKETS_FOLDER'),
-            user='pingou',
-            milestone='77'
-        )
-        self.session.add(repo)
-        self.session.add(issue)
-
-        msg = pagure.lib.set_custom_key_fields(
-            self.session,
-            project=repo,
-            fields=['abc', 'xyz'],
-            types=['boolean', 'boolean'],
-            data=[None, None],
-        )
-        self.assertEqual(msg, 'List of custom fields updated')
-        self.session.add(repo)
-
-        msg = pagure.lib.set_custom_key_value(
-            self.session,
-            issue=issue,
-            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
-            value=1
-        )
-        self.session.add(issue)
-        self.session.commit()
-
-
-        output = self.app.get('/test/issue/1')
-        self.assertEqual(output.status_code, 200)
-        # Not authentified = No edit
-        self.assertNotIn(
-            '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
-            'title="Edit this issue">',
-            output.data)
-        self.assertTrue(
-            '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
-            'Login</a>\n            to comment on this ticket.'
-            in output.data)
-
-        user = tests.FakeUser()
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/1')
-            self.assertEqual(output.status_code, 200)
-            # Not author nor admin = No edit
-            self.assertNotIn(
-                '<a class="btn btn-primary btn-sm" '
-                'href="/test/issue/1/edit" title="Edit this issue">',
-                output.data)
-            self.assertNotIn(
-                '<button class="btn btn-danger btn-sm" type="submit"',
-                output.data)
-            self.assertNotIn('title="Delete this ticket">', output.data)
-
-            # no edit metadata
-            self.assertNotIn(
-                '<a class="btn btn-secondary issue-metadata-display'
-                ' editmetadatatoggle">',
-                output.data)
-            self.assertFalse(
-                '<a href="/login/">Login</a> to comment on this ticket.'
-                in output.data)
-
-            # can view the milestone
-            self.assertIn(
-                '<label><strong>Milestone</strong></label>',
-                output.data)
-            self.assertIn(
-                '<span >77</span>',
-                output.data)
-            # but can't edit them
-            self.assertNotIn(
-                '<select class="form-control c-select" id="milestone" '
-                ' name="milestone"><option value=""></option><option '
-                'selected value="77">77</option></select>',
-                output.data)
-
-            # can view depends on
-            self.assertIn(
-                '<label><strong>Depends on</strong></label>',
-                output.data)
-
-            # can't edit depends on
-            self.assertNotIn(
-                '<input class="form-control" id="depends" type="text"\n\
-                                placeholder="issue depending" name="depends"\n\
-                                value="" />',
-                output.data)
-
-            # no toggle option for custom fields
-            self.assertNotIn(
-                '<a class="btn btn-secondary '
-                'issue-custom-display edit_custom_toggle">',
-                output.data)
-
-            # no checkbox for private
-            self.assertNotIn(
-                '<input id="private" name="private" type="checkbox" value="y">',
-                output.data)
-
-        user.username = 'foo'
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/1')
-            self.assertEqual(output.status_code, 200)
-
-            # the user can't edit the issue
-            self.assertNotIn(
-                '<a class="btn btn-primary btn-sm" '
-                'href="/test/issue/1/edit" title="Edit this issue">',
-                output.data)
-            self.assertNotIn(
-                '<button class="btn btn-danger btn-sm" type="submit"',
-                output.data)
-
-            # the user still can't delete the ticket
-            self.assertNotIn('title="Delete this ticket">', output.data)
-
-            csrf_token = output.data.split(
-                'name="csrf_token" type="hidden" value="')[1].split('">')[0]
-
-            # the user can do the following things
-            # edit metadata
-            self.assertIn(
-                '<a class="btn btn-secondary issue-metadata-display'
-                ' editmetadatatoggle">',
-                output.data)
-
-            # toggle option for custom fields
-            self.assertIn(
-                '<a class="btn btn-secondary '
-                'issue-custom-display edit_custom_toggle">',
-                output.data)
-
-            # can view the milestone
-            self.assertIn(
-                '<label><strong>Milestone</strong></label>',
-                output.data)
-            self.assertIn(
-                '<span >77</span>',
-                output.data)
-
-            # can edit them
-            self.assertIn(
-                '<select class="form-control c-select" id="milestone" '
-                'name="milestone"><option value=""></option><option selected '
-                'value="77">77</option></select>\n      <div>\n',
-                output.data)
-
-            # can view depends on
-            self.assertIn(
-                '<label><strong>Depends on</strong></label>',
-                output.data)
-
-            # can edit depends on
-            self.assertIn(
-                '<input class="form-control" id="depends" type="text"'
-                '\n                placeholder="issue depending" name="depends"\n',
-                output.data)
-
-            # the user should be able to do public -> private
-            # the other way round won't be possible since GET and POST
-            # to this endpoint for this user will be blocked
-
-            # checkbox for private
-            self.assertIn(
-                '<input id="private" name="private" type="checkbox" value="y">',
-                output.data)
-
-        # Create private issue
-        repo = pagure.lib.get_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
-            session=self.session,
-            repo=repo,
-            title='Test issue',
-            content='We should work on this',
-            user='pingou',
-            ticketfolder=None,
-            private=True,
-        )
-        self.session.commit()
-        self.assertEqual(msg.title, 'Test issue')
-
-        # Not logged in
-        output = self.app.get('/test/issue/2')
-        self.assertEqual(output.status_code, 403)
-
-        # Wrong user
-        user = tests.FakeUser()
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/2')
-            self.assertEqual(output.status_code, 403)
-
-        # reporter
-        user.username = 'pingou'
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/2')
-            self.assertEqual(output.status_code, 200)
-            self.assertIn(
-                '<title>Issue #2: Test issue - test - Pagure</title>',
-                output.data)
-            self.assertIn(
-                '<span class="oi red-icon" data-glyph="lock-locked" '
-                'title="Private issue"></span>', output.data)
-            self.assertIn(
-                '<a class="btn btn-primary btn-sm" '
-                'href="/test/issue/2/edit" title="Edit this issue">',
-                output.data)
-
-    @patch('pagure.lib.git.update_git')
-    @patch('pagure.lib.notify.send_email')
-    def test_view_issue_commit_access(self, p_send_email, p_ugt):
-        """ Test the view_issue endpoint. when a user has commit access on repo """
-        p_send_email.return_value = True
-        p_ugt.return_value = True
-
-        output = self.app.get('/foo/issue/1')
-        self.assertEqual(output.status_code, 404)
-
-        tests.create_projects(self.session)
-        tests.create_projects_git(
-            os.path.join(self.path), bare=True)
-
-        output = self.app.get('/test/issue/1')
-        self.assertEqual(output.status_code, 404)
-
-        # Create issues to play with
-        repo = pagure.lib.get_project(self.session, 'test')
-
-        # Add user 'foo' with ticket access on repo
-        msg = pagure.lib.add_user_to_project(
-            self.session,
-            repo,
-            new_user='foo',
-            user='pingou',
-            access='commit',
-        )
-        self.assertEqual(msg, 'User added')
-        self.session.commit()
-
-        repo = pagure.lib.get_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
-            session=self.session,
-            repo=repo,
-            title='Test issue',
-            content='We should work on this',
-            user='pingou',
-            ticketfolder=None
-        )
-
-        self.session.commit()
-        self.assertEqual(msg.title, 'Test issue')
-
-        # Add milestone
-        repo.milestones = {'77': None}
-        self.session.add(repo)
-        issue = pagure.lib.search_issues(
-            self.session,
-            repo=repo,
-            issueid=1
-        )
-
-        pagure.lib.edit_issue(
-            self.session,
-            issue,
-            pagure.APP.config.get('TICKETS_FOLDER'),
-            user='pingou',
-            milestone='77'
-        )
-        self.session.add(repo)
-        self.session.add(issue)
-
-        msg = pagure.lib.set_custom_key_fields(
-            self.session,
-            project=repo,
-            fields=['abc', 'xyz'],
-            types=['boolean', 'boolean'],
-            data=[None, None],
-        )
-        self.assertEqual(msg, 'List of custom fields updated')
-        self.session.add(repo)
-
-        msg = pagure.lib.set_custom_key_value(
-            self.session,
-            issue=issue,
-            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
-            value=1
-        )
-        self.session.add(issue)
-        self.session.commit()
-
-
-        output = self.app.get('/test/issue/1')
-        self.assertEqual(output.status_code, 200)
-        # Not authentified = No edit
-        self.assertNotIn(
-            '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
-            'title="Edit this issue">',
-            output.data)
-        self.assertTrue(
-            '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
-            'Login</a>\n            to comment on this ticket.'
-            in output.data)
-
-        user = tests.FakeUser()
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/1')
-            self.assertEqual(output.status_code, 200)
-            # Not author nor admin = No edit
-            self.assertNotIn(
-                '<a class="btn btn-primary btn-sm" '
-                'href="/test/issue/1/edit" title="Edit this issue">',
-                output.data)
-            self.assertNotIn(
-                '<button class="btn btn-danger btn-sm" type="submit"',
-                output.data)
-            self.assertNotIn('title="Delete this ticket">', output.data)
-
-            # no edit metadata
-            self.assertNotIn(
-                '<a class="btn btn-secondary issue-metadata-display'
-                ' editmetadatatoggle">',
-                output.data)
-            self.assertFalse(
-                '<a href="/login/">Login</a> to comment on this ticket.'
-                in output.data)
-
-            # can view the milestone
-            self.assertIn(
-                '<label><strong>Milestone</strong></label>',
-                output.data)
-            self.assertIn(
-                '<span >77</span>',
-                output.data)
-            # but can't edit them
-            self.assertNotIn(
-                '<select class="form-control c-select" id="milestone" '
-                ' name="milestone"><option value=""></option><option '
-                'selected value="77">77</option></select>',
-                output.data)
-
-            # can view depends on
-            self.assertIn(
-                '<label><strong>Depends on</strong></label>',
-                output.data)
-
-            # can't edit depends on
-            self.assertNotIn(
-                '<input class="form-control" id="depends" type="text"\n\
-                                placeholder="issue depending" name="depends"\n\
-                                value="" />',
-                output.data)
-
-            # no toggle option for custom fields
-            self.assertNotIn(
-                '<a class="btn btn-secondary '
-                'issue-custom-display edit_custom_toggle">',
-                output.data)
-
-            # no checkbox for private
-            self.assertNotIn(
-                '<input id="private" name="private" type="checkbox" value="y">',
-                output.data)
-
-        user.username = 'foo'
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/1')
-            self.assertEqual(output.status_code, 200)
-
-            # the user can edit the issue
-            self.assertIn(
-                '<a class="btn btn-primary btn-sm" '
-                'href="/test/issue/1/edit" title="Edit this issue">',
-                output.data)
-            self.assertIn(
-                '<button class="btn btn-danger btn-sm" type="submit"',
-                output.data)
-
-            # the user can delete the ticket
-            self.assertIn('title="Delete this ticket">', output.data)
-
-            csrf_token = output.data.split(
-                'name="csrf_token" type="hidden" value="')[1].split('">')[0]
-
-            # the user can do the following things
-            # edit metadata
-            self.assertIn(
-                '<a class="btn btn-secondary issue-metadata-display'
-                ' editmetadatatoggle">',
-                output.data)
-
-            # toggle option for custom fields
-            self.assertIn(
-                '<a class="btn btn-secondary '
-                'issue-custom-display edit_custom_toggle">',
-                output.data)
-
-            # can view the milestone
-            self.assertIn(
-                '<label><strong>Milestone</strong></label>',
-                output.data)
-            self.assertIn(
-                '<span >77</span>',
-                output.data)
-
-            # can edit them
-            self.assertIn(
-                '<select class="form-control c-select" id="milestone" '
-                'name="milestone"><option value=""></option><option selected '
-                'value="77">77</option></select>\n      <div>\n',
-                output.data)
-            # can view depends on
-            self.assertIn(
-                '<label><strong>Depends on</strong></label>',
-                output.data)
-
-            # can edit depends on
-            self.assertIn(
-                '<input class="form-control" id="depends" type="text"'
-                '\n                placeholder="issue depending" name="depends"\n',
-                output.data)
-
-            # the user should be able to do public -> private
-            # the other way round won't be possible since GET and POST
-            # to this endpoint for this user will be blocked
-
-            # checkbox for private
-            self.assertIn(
-                '<input id="private" name="private" type="checkbox" value="y">',
-                output.data)
-
-        # Create private issue
-        repo = pagure.lib.get_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
-            session=self.session,
-            repo=repo,
-            title='Test issue',
-            content='We should work on this',
-            user='pingou',
-            ticketfolder=None,
-            private=True,
-        )
-        self.session.commit()
-        self.assertEqual(msg.title, 'Test issue')
-
-        # Not logged in
-        output = self.app.get('/test/issue/2')
-        self.assertEqual(output.status_code, 403)
-
-        # Wrong user
-        user = tests.FakeUser()
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/2')
-            self.assertEqual(output.status_code, 403)
-
-        # reporter
-        user.username = 'pingou'
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/2')
-            self.assertEqual(output.status_code, 200)
-            self.assertIn(
-                '<title>Issue #2: Test issue - test - Pagure</title>',
-                output.data)
-            self.assertIn(
-                '<span class="oi red-icon" data-glyph="lock-locked" '
-                'title="Private issue"></span>', output.data)
-            self.assertIn(
-                '<a class="btn btn-primary btn-sm" '
-                'href="/test/issue/2/edit" title="Edit this issue">',
-                output.data)
-
-    @patch('pagure.lib.git.update_git')
-    @patch('pagure.lib.notify.send_email')
-    def test_view_issue_admin_access(self, p_send_email, p_ugt):
-        """ Test the view_issue endpoint. when a user has admin access on repo """
-        p_send_email.return_value = True
-        p_ugt.return_value = True
-
-        output = self.app.get('/foo/issue/1')
-        self.assertEqual(output.status_code, 404)
-
-        tests.create_projects(self.session)
-        tests.create_projects_git(
-            os.path.join(self.path), bare=True)
-
-        output = self.app.get('/test/issue/1')
-        self.assertEqual(output.status_code, 404)
-
-        # Create issues to play with
-        repo = pagure.lib.get_project(self.session, 'test')
-
-        # Add user 'foo' with ticket access on repo
-        msg = pagure.lib.add_user_to_project(
-            self.session,
-            repo,
-            new_user='foo',
-            user='pingou',
-            access='admin',
-        )
-        self.assertEqual(msg, 'User added')
-        self.session.commit()
-
-        repo = pagure.lib.get_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
-            session=self.session,
-            repo=repo,
-            title='Test issue',
-            content='We should work on this',
-            user='pingou',
-            ticketfolder=None
-        )
-
-        self.session.commit()
-        self.assertEqual(msg.title, 'Test issue')
-
-        # Add milestone
-        repo.milestones = {'77': None}
-        self.session.add(repo)
-        issue = pagure.lib.search_issues(
-            self.session,
-            repo=repo,
-            issueid=1
-        )
-
-        pagure.lib.edit_issue(
-            self.session,
-            issue,
-            pagure.APP.config.get('TICKETS_FOLDER'),
-            user='pingou',
-            milestone='77'
-        )
-        self.session.add(repo)
-        self.session.add(issue)
-
-        msg = pagure.lib.set_custom_key_fields(
-            self.session,
-            project=repo,
-            fields=['abc', 'xyz'],
-            types=['boolean', 'boolean'],
-            data=[None, None],
-        )
-        self.assertEqual(msg, 'List of custom fields updated')
-        self.session.add(repo)
-
-        msg = pagure.lib.set_custom_key_value(
-            self.session,
-            issue=issue,
-            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
-            value=1
-        )
-        self.session.add(issue)
-        self.session.commit()
-
-
-        output = self.app.get('/test/issue/1')
-        self.assertEqual(output.status_code, 200)
-        # Not authentified = No edit
-        self.assertNotIn(
-            '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
-            'title="Edit this issue">',
-            output.data)
-        self.assertTrue(
-            '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
-            'Login</a>\n            to comment on this ticket.'
-            in output.data)
-
-        user = tests.FakeUser()
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/1')
-            self.assertEqual(output.status_code, 200)
-            # Not author nor admin = No edit
-            self.assertNotIn(
-                '<a class="btn btn-primary btn-sm" '
-                'href="/test/issue/1/edit" title="Edit this issue">',
-                output.data)
-            self.assertNotIn(
-                '<button class="btn btn-danger btn-sm" type="submit"',
-                output.data)
-            self.assertNotIn('title="Delete this ticket">', output.data)
-
-            # no edit metadata
-            self.assertNotIn(
-                '<a class="btn btn-secondary issue-metadata-display'
-                ' editmetadatatoggle">',
-                output.data)
-            self.assertFalse(
-                '<a href="/login/">Login</a> to comment on this ticket.'
-                in output.data)
-
-            # can view the milestone
-            self.assertIn(
-                '<label><strong>Milestone</strong></label>',
-                output.data)
-            self.assertIn(
-                '<span >77</span>',
-                output.data)
-            # but can't edit them
-            self.assertNotIn(
-                '<select class="form-control c-select" id="milestone" '
-                ' name="milestone"><option value=""></option><option '
-                'selected value="77">77</option></select>',
-                output.data)
-
-            # can view depends on
-            self.assertIn(
-                '<label><strong>Depends on</strong></label>',
-                output.data)
-
-            # can't edit depends on
-            self.assertNotIn(
-                '<input class="form-control" id="depends" type="text"\n\
-                                placeholder="issue depending" name="depends"\n\
-                                value="" />',
-                output.data)
-
-            # no toggle option for custom fields
-            self.assertNotIn(
-                '<a class="btn btn-secondary '
-                'issue-custom-display edit_custom_toggle">',
-                output.data)
-
-            # no checkbox for private
-            self.assertNotIn(
-                '<input id="private" name="private" type="checkbox" value="y">',
-                output.data)
-
-        user.username = 'foo'
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/1')
-            self.assertEqual(output.status_code, 200)
-
-            # the user can edit the issue
-            self.assertIn(
-                '<a class="btn btn-primary btn-sm" '
-                'href="/test/issue/1/edit" title="Edit this issue">',
-                output.data)
-            self.assertIn(
-                '<button class="btn btn-danger btn-sm" type="submit"',
-                output.data)
-
-            # the user still can delete the ticket
-            self.assertIn('title="Delete this ticket">', output.data)
-
-            csrf_token = output.data.split(
-                'name="csrf_token" type="hidden" value="')[1].split('">')[0]
-
-            # the user can do the following things
-            # edit metadata
-            self.assertIn(
-                '<a class="btn btn-secondary issue-metadata-display'
-                ' editmetadatatoggle">',
-                output.data)
-
-            # toggle option for custom fields
-            self.assertIn(
-                '<a class="btn btn-secondary '
-                'issue-custom-display edit_custom_toggle">',
-                output.data)
-
-            # can view the milestone
-            self.assertIn(
-                '<label><strong>Milestone</strong></label>',
-                output.data)
-            self.assertIn(
-                '<span >77</span>',
-                output.data)
-
-            # can edit them
-            self.assertIn(
-                '<select class="form-control c-select" id="milestone" '
-                'name="milestone"><option value=""></option><option selected '
-                'value="77">77</option></select>\n      <div>\n',
-                output.data)
-
-            # can view depends on
-            self.assertIn(
-                '<label><strong>Depends on</strong></label>',
-                output.data)
-
-            # can edit depends on
-            self.assertIn(
-                '<input class="form-control" id="depends" type="text"'
-                '\n                placeholder="issue depending" name="depends"\n',
-                output.data)
-
-            # the user should be able to do public -> private
-            # the other way round won't be possible since GET and POST
-            # to this endpoint for this user will be blocked
-
-            # checkbox for private
-            self.assertIn(
-                '<input id="private" name="private" type="checkbox" value="y">',
-                output.data)
-
-        # Create private issue
-        repo = pagure.lib.get_project(self.session, 'test')
-        msg = pagure.lib.new_issue(
-            session=self.session,
-            repo=repo,
-            title='Test issue',
-            content='We should work on this',
-            user='pingou',
-            ticketfolder=None,
-            private=True,
-        )
-        self.session.commit()
-        self.assertEqual(msg.title, 'Test issue')
-
-        # Not logged in
-        output = self.app.get('/test/issue/2')
-        self.assertEqual(output.status_code, 403)
-
-        # Wrong user
-        user = tests.FakeUser()
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/2')
-            self.assertEqual(output.status_code, 403)
-
-        # reporter
-        user.username = 'pingou'
-        with tests.user_set(pagure.APP, user):
-            output = self.app.get('/test/issue/2')
-            self.assertEqual(output.status_code, 200)
-            self.assertIn(
-                '<title>Issue #2: Test issue - test - Pagure</title>',
-                output.data)
-            self.assertIn(
-                '<span class="oi red-icon" data-glyph="lock-locked" '
-                'title="Private issue"></span>', output.data)
-            self.assertIn(
-                '<a class="btn btn-primary btn-sm" '
-                'href="/test/issue/2/edit" title="Edit this issue">',
-                output.data)
-
-    @patch('pagure.lib.git.update_git')
-    @patch('pagure.lib.notify.send_email')
     def test_view_issue_non_ascii_milestone(self, p_send_email, p_ugt):
         """ Test the view_issue endpoint with non-ascii milestone. """
         p_send_email.return_value = True
diff --git a/tests/test_pagure_flask_ui_issues_acl_checks.py b/tests/test_pagure_flask_ui_issues_acl_checks.py
new file mode 100644
index 0000000..31e0a8e
--- /dev/null
+++ b/tests/test_pagure_flask_ui_issues_acl_checks.py
@@ -0,0 +1,1102 @@
+#!/usr/bin/env python
+# coding=utf-8
+
+"""
+ (c) 2017 - Copyright Red Hat Inc
+
+ Authors:
+   Vivek Anand <vivekanand1101@gmail.com>
+
+"""
+
+__requires__ = ['SQLAlchemy >= 0.8']
+import pkg_resources
+
+from unittest.case import SkipTest
+import json
+import unittest
+import shutil
+import sys
+import os
+try:
+    import pyclamd
+except:
+    pyclamd = None
+import tempfile
+
+import pygit2
+from mock import patch
+
+sys.path.insert(0, os.path.join(os.path.dirname(
+    os.path.abspath(__file__)), '..'))
+
+import pagure.lib
+import tests
+
+
+class PagureFlaskIssuesACLtests(tests.Modeltests):
+    """ Tests for flask issues controller of pagure for acls """
+
+    def setUp(self):
+        """ Set up the environnment, run before every tests. """
+        super(PagureFlaskIssuesACLtests, self).setUp()
+
+        pagure.APP.config['TESTING'] = True
+        pagure.SESSION = self.session
+        pagure.ui.SESSION = self.session
+        pagure.ui.app.SESSION = self.session
+        pagure.ui.issues.SESSION = self.session
+        pagure.ui.repo.SESSION = self.session
+        pagure.ui.filters.SESSION = self.session
+
+        pagure.APP.config['GIT_FOLDER'] = self.path
+        pagure.APP.config['TICKETS_FOLDER'] = os.path.join(
+            self.path, 'tickets')
+        pagure.APP.config['DOCS_FOLDER'] = os.path.join(
+            self.path, 'docs')
+        self.app = pagure.APP.test_client()
+
+    @patch('pagure.lib.git.update_git')
+    @patch('pagure.lib.notify.send_email')
+    def test_view_issue_no_access(self, p_send_email, p_ugt):
+        """ Test the view_issue endpoint. when a user has no access on repo """
+        p_send_email.return_value = True
+        p_ugt.return_value = True
+
+        output = self.app.get('/foo/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        tests.create_projects(self.session)
+        tests.create_projects_git(
+            os.path.join(self.path), bare=True)
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        # Create issues to play with
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None
+        )
+
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Add milestone
+        repo.milestones = {'77': None}
+        self.session.add(repo)
+        issue = pagure.lib.search_issues(
+            self.session,
+            repo=repo,
+            issueid=1
+        )
+
+        pagure.lib.edit_issue(
+            self.session,
+            issue,
+            pagure.APP.config.get('TICKETS_FOLDER'),
+            user='pingou',
+            milestone='77'
+        )
+        self.session.add(repo)
+        self.session.add(issue)
+
+        msg = pagure.lib.set_custom_key_fields(
+            self.session,
+            project=repo,
+            fields=['abc', 'xyz'],
+            types=['boolean', 'boolean'],
+            data=[None, None],
+        )
+        self.assertEqual(msg, 'List of custom fields updated')
+        self.session.add(repo)
+
+        msg = pagure.lib.set_custom_key_value(
+            self.session,
+            issue=issue,
+            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
+            value=1
+        )
+        self.session.add(issue)
+        self.session.commit()
+
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 200)
+        # Not authentified = No edit
+        self.assertNotIn(
+            '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
+            'title="Edit this issue">',
+            output.data)
+        self.assertTrue(
+            '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
+            'Login</a>\n            to comment on this ticket.'
+            in output.data)
+
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+            # Not author nor admin = No edit
+            self.assertNotIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertNotIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+            self.assertNotIn('title="Delete this ticket">', output.data)
+
+            # no edit metadata
+            self.assertNotIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+            self.assertFalse(
+                '<a href="/login/">Login</a> to comment on this ticket.'
+                in output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+            # but can't edit them
+            self.assertNotIn(
+                '<select class="form-control c-select" id="milestone" '
+                ' name="milestone"><option value=""></option><option '
+                'selected value="77">77</option></select>',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can't edit depends on
+            self.assertNotIn(
+                '<input class="form-control" id="depends" type="text"\n\
+                                placeholder="issue depending" name="depends"\n\
+                                value="" />',
+                output.data)
+
+            # no toggle option for custom fields
+            self.assertNotIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # no checkbox for private
+            self.assertNotIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        user.username = 'foo'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+            self.assertNotIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertNotIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+            self.assertNotIn('title="Delete this ticket">', output.data)
+
+            csrf_token = output.data.split(
+                'name="csrf_token" type="hidden" value="')[1].split('">')[0]
+
+            # no edit metadata
+            self.assertNotIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+            self.assertFalse(
+                '<a href="/login/">Login</a> to comment on this ticket.'
+                in output.data)
+
+            # no toggle option for custom fields
+            self.assertNotIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # can't see the custom field as a checkbox
+            self.assertNotIn(
+                '<input type="checkbox"                   '
+                'class="form-control" name="abc" id="abc"checked/>',
+                output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+
+            # but can't edit them
+            self.assertNotIn(
+                '<select class="form-control c-select" id="milestone" '
+                ' name="milestone"><option value=""></option><option '
+                'selected value="77">77</option></select>',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can't edit depends on
+            self.assertNotIn(
+                '<input class="form-control" id="depends" type="text"\n\
+                                placeholder="issue depending" name="depends"\n\
+                                value="" />',
+                output.data)
+
+            # no checkbox for private
+            self.assertNotIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        # Create private issue
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=True,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Not logged in
+        output = self.app.get('/test/issue/2')
+        self.assertEqual(output.status_code, 403)
+
+        # Wrong user
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 403)
+
+        # reporter
+        user.username = 'pingou'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 200)
+            self.assertIn(
+                '<title>Issue #2: Test issue - test - Pagure</title>',
+                output.data)
+            self.assertIn(
+                '<span class="oi red-icon" data-glyph="lock-locked" '
+                'title="Private issue"></span>', output.data)
+            self.assertIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/2/edit" title="Edit this issue">',
+                output.data)
+
+    @patch('pagure.lib.git.update_git')
+    @patch('pagure.lib.notify.send_email')
+    def test_view_issue_ticket_access(self, p_send_email, p_ugt):
+        """ Test the view_issue endpoint. when a user has ticket access on repo """
+        p_send_email.return_value = True
+        p_ugt.return_value = True
+
+        output = self.app.get('/foo/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        tests.create_projects(self.session)
+        tests.create_projects_git(
+            os.path.join(self.path), bare=True)
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        # Create issues to play with
+        repo = pagure.lib.get_project(self.session, 'test')
+
+        # Add user 'foo' with ticket access on repo
+        msg = pagure.lib.add_user_to_project(
+            self.session,
+            repo,
+            new_user='foo',
+            user='pingou',
+            access='ticket',
+        )
+        self.assertEqual(msg, 'User added')
+        self.session.commit()
+
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None
+        )
+
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Add milestone
+        repo.milestones = {'77': None}
+        self.session.add(repo)
+        issue = pagure.lib.search_issues(
+            self.session,
+            repo=repo,
+            issueid=1
+        )
+
+        pagure.lib.edit_issue(
+            self.session,
+            issue,
+            pagure.APP.config.get('TICKETS_FOLDER'),
+            user='pingou',
+            milestone='77'
+        )
+        self.session.add(repo)
+        self.session.add(issue)
+
+        msg = pagure.lib.set_custom_key_fields(
+            self.session,
+            project=repo,
+            fields=['abc', 'xyz'],
+            types=['boolean', 'boolean'],
+            data=[None, None],
+        )
+        self.assertEqual(msg, 'List of custom fields updated')
+        self.session.add(repo)
+
+        msg = pagure.lib.set_custom_key_value(
+            self.session,
+            issue=issue,
+            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
+            value=1
+        )
+        self.session.add(issue)
+        self.session.commit()
+
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 200)
+        # Not authentified = No edit
+        self.assertNotIn(
+            '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
+            'title="Edit this issue">',
+            output.data)
+        self.assertTrue(
+            '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
+            'Login</a>\n            to comment on this ticket.'
+            in output.data)
+
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+            # Not author nor admin = No edit
+            self.assertNotIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertNotIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+            self.assertNotIn('title="Delete this ticket">', output.data)
+
+            # no edit metadata
+            self.assertNotIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+            self.assertFalse(
+                '<a href="/login/">Login</a> to comment on this ticket.'
+                in output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+            # but can't edit them
+            self.assertNotIn(
+                '<select class="form-control c-select" id="milestone" '
+                ' name="milestone"><option value=""></option><option '
+                'selected value="77">77</option></select>',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can't edit depends on
+            self.assertNotIn(
+                '<input class="form-control" id="depends" type="text"\n\
+                                placeholder="issue depending" name="depends"\n\
+                                value="" />',
+                output.data)
+
+            # no toggle option for custom fields
+            self.assertNotIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # no checkbox for private
+            self.assertNotIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        user.username = 'foo'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+
+            # the user can't edit the issue
+            self.assertNotIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertNotIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+
+            # the user still can't delete the ticket
+            self.assertNotIn('title="Delete this ticket">', output.data)
+
+            csrf_token = output.data.split(
+                'name="csrf_token" type="hidden" value="')[1].split('">')[0]
+
+            # the user can do the following things
+            # edit metadata
+            self.assertIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+
+            # toggle option for custom fields
+            self.assertIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+
+            # can edit them
+            self.assertIn(
+                '<select class="form-control c-select" id="milestone" '
+                'name="milestone"><option value=""></option><option selected '
+                'value="77">77</option></select>\n      <div>\n',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can edit depends on
+            self.assertIn(
+                '<input class="form-control" id="depends" type="text"'
+                '\n                placeholder="issue depending" name="depends"\n',
+                output.data)
+
+            # the user should be able to do public -> private
+            # the other way round won't be possible since GET and POST
+            # to this endpoint for this user will be blocked
+
+            # checkbox for private
+            self.assertIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        # Create private issue
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=True,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Not logged in
+        output = self.app.get('/test/issue/2')
+        self.assertEqual(output.status_code, 403)
+
+        # Wrong user
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 403)
+
+        # reporter
+        user.username = 'pingou'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 200)
+            self.assertIn(
+                '<title>Issue #2: Test issue - test - Pagure</title>',
+                output.data)
+            self.assertIn(
+                '<span class="oi red-icon" data-glyph="lock-locked" '
+                'title="Private issue"></span>', output.data)
+            self.assertIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/2/edit" title="Edit this issue">',
+                output.data)
+
+    @patch('pagure.lib.git.update_git')
+    @patch('pagure.lib.notify.send_email')
+    def test_view_issue_commit_access(self, p_send_email, p_ugt):
+        """ Test the view_issue endpoint. when a user has commit access on repo """
+        p_send_email.return_value = True
+        p_ugt.return_value = True
+
+        output = self.app.get('/foo/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        tests.create_projects(self.session)
+        tests.create_projects_git(
+            os.path.join(self.path), bare=True)
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        # Create issues to play with
+        repo = pagure.lib.get_project(self.session, 'test')
+
+        # Add user 'foo' with ticket access on repo
+        msg = pagure.lib.add_user_to_project(
+            self.session,
+            repo,
+            new_user='foo',
+            user='pingou',
+            access='commit',
+        )
+        self.assertEqual(msg, 'User added')
+        self.session.commit()
+
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None
+        )
+
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Add milestone
+        repo.milestones = {'77': None}
+        self.session.add(repo)
+        issue = pagure.lib.search_issues(
+            self.session,
+            repo=repo,
+            issueid=1
+        )
+
+        pagure.lib.edit_issue(
+            self.session,
+            issue,
+            pagure.APP.config.get('TICKETS_FOLDER'),
+            user='pingou',
+            milestone='77'
+        )
+        self.session.add(repo)
+        self.session.add(issue)
+
+        msg = pagure.lib.set_custom_key_fields(
+            self.session,
+            project=repo,
+            fields=['abc', 'xyz'],
+            types=['boolean', 'boolean'],
+            data=[None, None],
+        )
+        self.assertEqual(msg, 'List of custom fields updated')
+        self.session.add(repo)
+
+        msg = pagure.lib.set_custom_key_value(
+            self.session,
+            issue=issue,
+            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
+            value=1
+        )
+        self.session.add(issue)
+        self.session.commit()
+
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 200)
+        # Not authentified = No edit
+        self.assertNotIn(
+            '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
+            'title="Edit this issue">',
+            output.data)
+        self.assertTrue(
+            '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
+            'Login</a>\n            to comment on this ticket.'
+            in output.data)
+
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+            # Not author nor admin = No edit
+            self.assertNotIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertNotIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+            self.assertNotIn('title="Delete this ticket">', output.data)
+
+            # no edit metadata
+            self.assertNotIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+            self.assertFalse(
+                '<a href="/login/">Login</a> to comment on this ticket.'
+                in output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+            # but can't edit them
+            self.assertNotIn(
+                '<select class="form-control c-select" id="milestone" '
+                ' name="milestone"><option value=""></option><option '
+                'selected value="77">77</option></select>',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can't edit depends on
+            self.assertNotIn(
+                '<input class="form-control" id="depends" type="text"\n\
+                                placeholder="issue depending" name="depends"\n\
+                                value="" />',
+                output.data)
+
+            # no toggle option for custom fields
+            self.assertNotIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # no checkbox for private
+            self.assertNotIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        user.username = 'foo'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+
+            # the user can edit the issue
+            self.assertIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+
+            # the user can delete the ticket
+            self.assertIn('title="Delete this ticket">', output.data)
+
+            csrf_token = output.data.split(
+                'name="csrf_token" type="hidden" value="')[1].split('">')[0]
+
+            # the user can do the following things
+            # edit metadata
+            self.assertIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+
+            # toggle option for custom fields
+            self.assertIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+
+            # can edit them
+            self.assertIn(
+                '<select class="form-control c-select" id="milestone" '
+                'name="milestone"><option value=""></option><option selected '
+                'value="77">77</option></select>\n      <div>\n',
+                output.data)
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can edit depends on
+            self.assertIn(
+                '<input class="form-control" id="depends" type="text"'
+                '\n                placeholder="issue depending" name="depends"\n',
+                output.data)
+
+            # the user should be able to do public -> private
+            # the other way round won't be possible since GET and POST
+            # to this endpoint for this user will be blocked
+
+            # checkbox for private
+            self.assertIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        # Create private issue
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=True,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Not logged in
+        output = self.app.get('/test/issue/2')
+        self.assertEqual(output.status_code, 403)
+
+        # Wrong user
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 403)
+
+        # reporter
+        user.username = 'pingou'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 200)
+            self.assertIn(
+                '<title>Issue #2: Test issue - test - Pagure</title>',
+                output.data)
+            self.assertIn(
+                '<span class="oi red-icon" data-glyph="lock-locked" '
+                'title="Private issue"></span>', output.data)
+            self.assertIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/2/edit" title="Edit this issue">',
+                output.data)
+
+    @patch('pagure.lib.git.update_git')
+    @patch('pagure.lib.notify.send_email')
+    def test_view_issue_admin_access(self, p_send_email, p_ugt):
+        """ Test the view_issue endpoint. when a user has admin access on repo """
+        p_send_email.return_value = True
+        p_ugt.return_value = True
+
+        output = self.app.get('/foo/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        tests.create_projects(self.session)
+        tests.create_projects_git(
+            os.path.join(self.path), bare=True)
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 404)
+
+        # Create issues to play with
+        repo = pagure.lib.get_project(self.session, 'test')
+
+        # Add user 'foo' with ticket access on repo
+        msg = pagure.lib.add_user_to_project(
+            self.session,
+            repo,
+            new_user='foo',
+            user='pingou',
+            access='admin',
+        )
+        self.assertEqual(msg, 'User added')
+        self.session.commit()
+
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None
+        )
+
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Add milestone
+        repo.milestones = {'77': None}
+        self.session.add(repo)
+        issue = pagure.lib.search_issues(
+            self.session,
+            repo=repo,
+            issueid=1
+        )
+
+        pagure.lib.edit_issue(
+            self.session,
+            issue,
+            pagure.APP.config.get('TICKETS_FOLDER'),
+            user='pingou',
+            milestone='77'
+        )
+        self.session.add(repo)
+        self.session.add(issue)
+
+        msg = pagure.lib.set_custom_key_fields(
+            self.session,
+            project=repo,
+            fields=['abc', 'xyz'],
+            types=['boolean', 'boolean'],
+            data=[None, None],
+        )
+        self.assertEqual(msg, 'List of custom fields updated')
+        self.session.add(repo)
+
+        msg = pagure.lib.set_custom_key_value(
+            self.session,
+            issue=issue,
+            key=pagure.lib.get_custom_key(self.session, repo, 'abc'),
+            value=1
+        )
+        self.session.add(issue)
+        self.session.commit()
+
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 200)
+        # Not authentified = No edit
+        self.assertNotIn(
+            '<a class="btn btn-primary btn-sm" href="/test/issue/1/edit" '
+            'title="Edit this issue">',
+            output.data)
+        self.assertTrue(
+            '<a href="/login/?next=http%3A%2F%2Flocalhost%2Ftest%2Fissue%2F1">'
+            'Login</a>\n            to comment on this ticket.'
+            in output.data)
+
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+            # Not author nor admin = No edit
+            self.assertNotIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertNotIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+            self.assertNotIn('title="Delete this ticket">', output.data)
+
+            # no edit metadata
+            self.assertNotIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+            self.assertFalse(
+                '<a href="/login/">Login</a> to comment on this ticket.'
+                in output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+            # but can't edit them
+            self.assertNotIn(
+                '<select class="form-control c-select" id="milestone" '
+                ' name="milestone"><option value=""></option><option '
+                'selected value="77">77</option></select>',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can't edit depends on
+            self.assertNotIn(
+                '<input class="form-control" id="depends" type="text"\n\
+                                placeholder="issue depending" name="depends"\n\
+                                value="" />',
+                output.data)
+
+            # no toggle option for custom fields
+            self.assertNotIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # no checkbox for private
+            self.assertNotIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        user.username = 'foo'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+
+            # the user can edit the issue
+            self.assertIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/1/edit" title="Edit this issue">',
+                output.data)
+            self.assertIn(
+                '<button class="btn btn-danger btn-sm" type="submit"',
+                output.data)
+
+            # the user still can delete the ticket
+            self.assertIn('title="Delete this ticket">', output.data)
+
+            csrf_token = output.data.split(
+                'name="csrf_token" type="hidden" value="')[1].split('">')[0]
+
+            # the user can do the following things
+            # edit metadata
+            self.assertIn(
+                '<a class="btn btn-secondary issue-metadata-display'
+                ' editmetadatatoggle">',
+                output.data)
+
+            # toggle option for custom fields
+            self.assertIn(
+                '<a class="btn btn-secondary '
+                'issue-custom-display edit_custom_toggle">',
+                output.data)
+
+            # can view the milestone
+            self.assertIn(
+                '<label><strong>Milestone</strong></label>',
+                output.data)
+            self.assertIn(
+                '<span >77</span>',
+                output.data)
+
+            # can edit them
+            self.assertIn(
+                '<select class="form-control c-select" id="milestone" '
+                'name="milestone"><option value=""></option><option selected '
+                'value="77">77</option></select>\n      <div>\n',
+                output.data)
+
+            # can view depends on
+            self.assertIn(
+                '<label><strong>Depends on</strong></label>',
+                output.data)
+
+            # can edit depends on
+            self.assertIn(
+                '<input class="form-control" id="depends" type="text"'
+                '\n                placeholder="issue depending" name="depends"\n',
+                output.data)
+
+            # the user should be able to do public -> private
+            # the other way round won't be possible since GET and POST
+            # to this endpoint for this user will be blocked
+
+            # checkbox for private
+            self.assertIn(
+                '<input id="private" name="private" type="checkbox" value="y">',
+                output.data)
+
+        # Create private issue
+        repo = pagure.lib.get_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=True,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue')
+
+        # Not logged in
+        output = self.app.get('/test/issue/2')
+        self.assertEqual(output.status_code, 403)
+
+        # Wrong user
+        user = tests.FakeUser()
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 403)
+
+        # reporter
+        user.username = 'pingou'
+        with tests.user_set(pagure.APP, user):
+            output = self.app.get('/test/issue/2')
+            self.assertEqual(output.status_code, 200)
+            self.assertIn(
+                '<title>Issue #2: Test issue - test - Pagure</title>',
+                output.data)
+            self.assertIn(
+                '<span class="oi red-icon" data-glyph="lock-locked" '
+                'title="Private issue"></span>', output.data)
+            self.assertIn(
+                '<a class="btn btn-primary btn-sm" '
+                'href="/test/issue/2/edit" title="Edit this issue">',
+                output.data)
+
+
+if __name__ == '__main__':
+    SUITE = unittest.TestLoader().loadTestsFromTestCase(
+        PagureFlaskIssuesACLtests)
+    unittest.TextTestRunner(verbosity=2).run(SUITE)

