From edbdc9a3c4dd08ccf06251367bb56744773b30e7 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 08 2017 11:29:11 +0000
Subject: Add a configuration key to make pagure case sensitive


Fixes https://pagure.io/fedora-infrastructure/issue/6213

Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/doc/configuration.rst b/doc/configuration.rst
index 3935851..2019bff 100644
--- a/doc/configuration.rst
+++ b/doc/configuration.rst
@@ -849,6 +849,15 @@ pages, from ``... - pagure`` (default) to ``... - <your value>``.
 Defaults to: ``Pagure``
 
 
+CASE_SENSITIVE
+~~~~~~~~~~~~~~
+
+This configuration key allows to make this pagure instance case sensitive
+instead of its default: case-insensitive.
+
+Defaults to: ``False``
+
+
 Deprecated configuration keys
 -----------------------------
 
diff --git a/pagure-loadjson/pagure_loadjson_server.py b/pagure-loadjson/pagure_loadjson_server.py
index f46e7b2..d10efcd 100644
--- a/pagure-loadjson/pagure_loadjson_server.py
+++ b/pagure-loadjson/pagure_loadjson_server.py
@@ -158,7 +158,8 @@ def handle_messages():
                  '%s/' % namespace if namespace else '',
                  repo, username)
         project = pagure.lib._get_project(
-            session, repo, user=username, namespace=namespace)
+            session, repo, user=username, namespace=namespace,
+            case=pagure.APP.config.get('CASE_SENSITIVE', False))
 
         if not project:
             _log.info('No project found')
diff --git a/pagure-logcom/pagure_logcom_server.py b/pagure-logcom/pagure_logcom_server.py
index ddffa54..0c0ed3c 100644
--- a/pagure-logcom/pagure_logcom_server.py
+++ b/pagure-logcom/pagure_logcom_server.py
@@ -104,7 +104,8 @@ def handle_messages():
                  '%s/' % namespace if namespace else '',
                  repo, username)
         project = pagure.lib._get_project(
-            pagure.SESSION, repo, user=username, namespace=namespace)
+            pagure.SESSION, repo, user=username, namespace=namespace,
+            case=pagure.APP.config.get('CASE_SENSITIVE', False))
 
         if not project:
             _log.info('No project found')
diff --git a/pagure-webhook/pagure-webhook-server.py b/pagure-webhook/pagure-webhook-server.py
index cbcb1dc..7bc66fe 100644
--- a/pagure-webhook/pagure-webhook-server.py
+++ b/pagure-webhook/pagure-webhook-server.py
@@ -139,7 +139,8 @@ def handle_messages():
         session = pagure.lib.create_session(pagure.APP.config['DB_URL'])
         project = pagure.lib._get_project(
             session=session, name=projectname, user=username,
-            namespace=namespace)
+            namespace=namespace,
+            case=pagure.APP.config.get('CASE_SENSITIVE', False))
         if not project:
             log.info('No project found with these criteria')
             session.close()
diff --git a/pagure/__init__.py b/pagure/__init__.py
index 909b1b9..91fd7d9 100644
--- a/pagure/__init__.py
+++ b/pagure/__init__.py
@@ -388,7 +388,10 @@ def get_authorized_project(session, project_name, user=None, namespace=None):
     :rtype: Project
 
     '''
-    repo = pagure.lib._get_project(session, project_name, user, namespace)
+    repo = pagure.lib._get_project(
+        session, project_name, user, namespace,
+        case=APP.config.get('CASE_SENSITIVE', False)
+    )
 
     if repo and repo.private and not is_repo_admin(repo):
         return None
diff --git a/pagure/api/ci/jenkins.py b/pagure/api/ci/jenkins.py
index e539ab6..2c53d2a 100644
--- a/pagure/api/ci/jenkins.py
+++ b/pagure/api/ci/jenkins.py
@@ -45,7 +45,8 @@ def jenkins_ci_notification(
     """
 
     project = pagure.lib._get_project(
-        SESSION, repo, user=username, namespace=namespace)
+        SESSION, repo, user=username, namespace=namespace,
+        case=APP.config.get('CASE_SENSITIVE', False))
     flask.g.repo_locked = True
     flask.g.repo = project
     if not project:
diff --git a/pagure/api/project.py b/pagure/api/project.py
index a63b981..52cfa76 100644
--- a/pagure/api/project.py
+++ b/pagure/api/project.py
@@ -764,7 +764,8 @@ def api_new_project():
                 result = pagure.lib.tasks.get_result(taskid).get()
                 project = pagure.lib._get_project(
                     SESSION, name=result['repo'],
-                    namespace=result['namespace'])
+                    namespace=result['namespace'],
+                    case=APP.config.get('CASE_SENSITIVE', False))
                 output = {'message': 'Project "%s" created' % project.fullname}
         except pagure.exceptions.PagureException as err:
             raise pagure.exceptions.APIError(
diff --git a/pagure/hooks/files/default_hook.py b/pagure/hooks/files/default_hook.py
index ab73492..d87a403 100755
--- a/pagure/hooks/files/default_hook.py
+++ b/pagure/hooks/files/default_hook.py
@@ -38,7 +38,8 @@ def run_as_post_receive_hook():
         print('namespace:', namespace)
 
     project = pagure.lib._get_project(
-        pagure.SESSION, repo, user=username, namespace=namespace)
+        pagure.SESSION, repo, user=username, namespace=namespace,
+        case=pagure.APP.config.get('CASE_SENSITIVE', False))
 
     for line in sys.stdin:
         if pagure.APP.config.get('HOOK_DEBUG', False):
diff --git a/pagure/hooks/files/fedmsg_hook.py b/pagure/hooks/files/fedmsg_hook.py
index 2965d8a..434c131 100755
--- a/pagure/hooks/files/fedmsg_hook.py
+++ b/pagure/hooks/files/fedmsg_hook.py
@@ -52,7 +52,9 @@ for line in sys.stdin.readlines():
     username = pagure.lib.git.get_username(abspath)
     namespace = pagure.lib.git.get_repo_namespace(abspath)
     project = pagure.lib._get_project(
-        pagure.SESSION, project_name, username, namespace=namespace)
+        pagure.SESSION, project_name, username, namespace=namespace,
+        case=pagure.APP.config.get('CASE_SENSITIVE', False))
+
     if not project:
         project = project_name
 
diff --git a/pagure/hooks/files/pagure_force_commit_hook.py b/pagure/hooks/files/pagure_force_commit_hook.py
index d06971d..56a273c 100755
--- a/pagure/hooks/files/pagure_force_commit_hook.py
+++ b/pagure/hooks/files/pagure_force_commit_hook.py
@@ -32,7 +32,9 @@ def run_as_pre_receive_hook():
         print 'namspaces:', namespace
 
     repo = pagure.lib._get_project(
-        pagure.SESSION, reponame, user=username, namespace=namespace)
+        pagure.SESSION, reponame, user=username, namespace=namespace,
+        case=pagure.APP.config.get('CASE_SENSITIVE', False))
+
     if not repo:
         print 'Unknown repo %s of username: %s in namespace %s' % (
             reponame, username, namespace)
diff --git a/pagure/hooks/files/pagure_hook_tickets.py b/pagure/hooks/files/pagure_hook_tickets.py
index 4c5fac5..ce5bdef 100755
--- a/pagure/hooks/files/pagure_hook_tickets.py
+++ b/pagure/hooks/files/pagure_hook_tickets.py
@@ -37,7 +37,8 @@ def run_as_post_receive_hook():
         print('namespace:', namespace)
 
     project = pagure.lib._get_project(
-        pagure.SESSION, repo, user=username, namespace=namespace)
+        pagure.SESSION, repo, user=username, namespace=namespace,
+        case=pagure.APP.config.get('CASE_SENSITIVE', False))
 
     for line in sys.stdin:
         if pagure.APP.config.get('HOOK_DEBUG', False):
diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py
index b84d6d9..19e0e0d 100644
--- a/pagure/lib/__init__.py
+++ b/pagure/lib/__init__.py
@@ -2006,19 +2006,31 @@ def search_projects(
         return query.all()
 
 
-def _get_project(session, name, user=None, namespace=None):
+def _get_project(session, name, user=None, namespace=None, case=False):
     '''Get a project from the database
     '''
     query = session.query(
         model.Project
-    ).filter(
-        func.lower(model.Project.name) == name.lower()
     )
 
-    if namespace:
+    if not case:
+        query = query.filter(
+            func.lower(model.Project.name) == name.lower()
+        )
+    else:
         query = query.filter(
-            func.lower(model.Project.namespace) == namespace.lower()
+            model.Project.name == name
         )
+
+    if namespace:
+        if not case:
+            query = query.filter(
+                func.lower(model.Project.namespace) == namespace.lower()
+            )
+        else:
+            query = query.filter(
+                model.Project.namespace == namespace
+            )
     else:
         query = query.filter(model.Project.namespace == namespace)
 
diff --git a/pagure/lib/git.py b/pagure/lib/git.py
index 40695ea..3619fe1 100644
--- a/pagure/lib/git.py
+++ b/pagure/lib/git.py
@@ -365,8 +365,10 @@ def get_project_from_json(
     project_user = None
     if jsondata.get('parent'):
         project_user = user.username
+
     project = pagure.lib._get_project(
-        session, name, user=project_user, namespace=namespace)
+        session, name, user=project_user, namespace=namespace,
+        case=pagure.APP.config.get('CASE_SENSITIVE', False))
 
     if not project:
         parent = None
@@ -406,7 +408,8 @@ def get_project_from_json(
 
         session.commit()
         project = pagure.lib._get_project(
-            session, name, user=user.username, namespace=namespace)
+            session, name, user=user.username, namespace=namespace,
+            case=pagure.APP.config.get('CASE_SENSITIVE', False))
 
         tags = jsondata.get('tags', None)
         if tags:
@@ -484,7 +487,8 @@ def update_ticket_from_git(
     """
 
     repo = pagure.lib._get_project(
-        session, reponame, user=username, namespace=namespace)
+        session, reponame, user=username, namespace=namespace,
+        case=pagure.APP.config.get('CASE_SENSITIVE', False))
 
     if not repo:
         raise pagure.exceptions.PagureException(
@@ -663,7 +667,9 @@ def update_request_from_git(
     """
 
     repo = pagure.lib._get_project(
-        session, reponame, user=username, namespace=namespace)
+        session, reponame, user=username, namespace=namespace,
+        case=pagure.APP.config.get('CASE_SENSITIVE', False))
+
     if not repo:
         raise pagure.exceptions.PagureException(
             'Unknown repo %s of username: %s in namespace: %s' % (
diff --git a/pagure/lib/tasks.py b/pagure/lib/tasks.py
index 22a376e..bf171aa 100644
--- a/pagure/lib/tasks.py
+++ b/pagure/lib/tasks.py
@@ -86,7 +86,9 @@ def generate_gitolite_acls(namespace=None, name=None, user=None, group=None):
     project = None
     if name and name != -1:
         project = pagure.lib._get_project(
-            session, namespace=namespace, name=name, user=user)
+            session, namespace=namespace, name=name, user=user,
+            case=APP.config.get('CASE_SENSITIVE', False))
+
     elif name == -1:
         project = name
     helper = pagure.lib.git_auth.get_git_auth_helper(
@@ -125,8 +127,10 @@ def create_project(username, namespace, name, add_readme,
     """
     session = pagure.lib.create_session()
 
-    project = pagure.lib._get_project(session, namespace=namespace,
-                                      name=name)
+    project = pagure.lib._get_project(
+        session, namespace=namespace, name=name,
+        case=APP.config.get('CASE_SENSITIVE', False))
+
     with project.lock('WORKER'):
         userobj = pagure.lib.search_user(session, username=username)
         gitrepo = os.path.join(APP.config['GIT_FOLDER'], project.path)
@@ -231,8 +235,10 @@ def create_project(username, namespace, name, add_readme,
 def update_git(name, namespace, user, ticketuid=None, requestuid=None):
     session = pagure.lib.create_session()
 
-    project = pagure.lib._get_project(session, namespace=namespace, name=name,
-                                      user=user)
+    project = pagure.lib._get_project(
+        session, namespace=namespace, name=name, user=user,
+        case=APP.config.get('CASE_SENSITIVE', False))
+
     with project.lock('WORKER'):
         if ticketuid is not None:
             obj = pagure.lib.get_issue_by_uid(session, ticketuid)
@@ -257,8 +263,10 @@ def update_git(name, namespace, user, ticketuid=None, requestuid=None):
 def clean_git(name, namespace, user, ticketuid):
     session = pagure.lib.create_session()
 
-    project = pagure.lib._get_project(session, namespace=namespace, name=name,
-                                      user=user)
+    project = pagure.lib._get_project(
+        session, namespace=namespace, name=name, user=user,
+        case=APP.config.get('CASE_SENSITIVE', False))
+
     with project.lock('WORKER'):
         obj = pagure.lib.get_issue_by_uid(session, ticketuid)
         folder = APP.config['TICKETS_FOLDER']
@@ -278,8 +286,9 @@ def update_file_in_git(name, namespace, user, branch, branchto, filename,
     session = pagure.lib.create_session()
 
     userobj = pagure.lib.search_user(session, username=username)
-    project = pagure.lib._get_project(session, namespace=namespace, name=name,
-                                      user=user)
+    project = pagure.lib._get_project(
+        session, namespace=namespace, name=name, user=user,
+        case=APP.config.get('CASE_SENSITIVE', False))
 
     with project.lock('WORKER'):
         pagure.lib.git._update_file_in_git(project, branch, branchto, filename,
@@ -294,8 +303,10 @@ def update_file_in_git(name, namespace, user, branch, branchto, filename,
 def delete_branch(name, namespace, user, branchname):
     session = pagure.lib.create_session()
 
-    project = pagure.lib._get_project(session, namespace=namespace, name=name,
-                                      user=user)
+    project = pagure.lib._get_project(
+        session, namespace=namespace, name=name, user=user,
+        case=APP.config.get('CASE_SENSITIVE', False))
+
     with project.lock('WORKER'):
         repo_obj = pygit2.Repository(pagure.get_repo_path(project))
 
@@ -332,9 +343,12 @@ def fork(name, namespace, user_owner, user_forker, editbranch, editfile):
     session = pagure.lib.create_session()
 
     repo_from = pagure.lib._get_project(
-        session, namespace=namespace, name=name, user=user_owner)
+        session, namespace=namespace, name=name, user=user_owner,
+        case=APP.config.get('CASE_SENSITIVE', False))
+
     repo_to = pagure.lib._get_project(
-        session, namespace=namespace, name=name, user=user_forker)
+        session, namespace=namespace, name=name, user=user_forker,
+        case=APP.config.get('CASE_SENSITIVE', False))
 
     with repo_to.lock('WORKER'):
         reponame = os.path.join(APP.config['GIT_FOLDER'], repo_from.path)
@@ -436,8 +450,9 @@ def pull_remote_repo(remote_git, branch_from):
 def refresh_pr_cache(name, namespace, user):
     session = pagure.lib.create_session()
 
-    project = pagure.lib._get_project(session, namespace=namespace,
-                                      name=name, user=user)
+    project = pagure.lib._get_project(
+        session, namespace=namespace, name=name, user=user,
+        case=APP.config.get('CASE_SENSITIVE', False))
 
     pagure.lib.reset_status_pull_request(session, project)
 
@@ -449,8 +464,10 @@ def refresh_pr_cache(name, namespace, user):
 def merge_pull_request(name, namespace, user, requestid, user_merger):
     session = pagure.lib.create_session()
 
-    project = pagure.lib._get_project(session, namespace=namespace,
-                                      name=name, user=user)
+    project = pagure.lib._get_project(
+        session, namespace=namespace, name=name, user=user,
+        case=APP.config.get('CASE_SENSITIVE', False))
+
     with project.lock('WORKER'):
         request = pagure.lib.search_pull_requests(
             session, project_id=project.id, requestid=requestid)
@@ -470,8 +487,10 @@ def merge_pull_request(name, namespace, user, requestid, user_merger):
 def add_file_to_git(name, namespace, user, user_attacher, issueuid, filename):
     session = pagure.lib.create_session()
 
-    project = pagure.lib._get_project(session, namespace=namespace,
-                                      name=name, user=user)
+    project = pagure.lib._get_project(
+        session, namespace=namespace, name=name, user=user,
+        case=APP.config.get('CASE_SENSITIVE', False))
+
     with project.lock('WORKER'):
         issue = pagure.lib.get_issue_by_uid(session, issueuid)
         user_attacher = pagure.lib.search_user(session, username=user_attacher)
@@ -502,8 +521,10 @@ def project_dowait(name, namespace, user):
 
     session = pagure.lib.create_session()
 
-    project = pagure.lib._get_project(session, namespace=namespace,
-                                      name=name, user=user)
+    project = pagure.lib._get_project(
+        session, namespace=namespace, name=name, user=user,
+        case=APP.config.get('CASE_SENSITIVE', False))
+
     with project.lock('WORKER'):
         time.sleep(10)
 
@@ -521,7 +542,8 @@ def sync_pull_ref(name, namespace, user, requestid):
     session = pagure.lib.create_session()
 
     project = pagure.lib._get_project(
-        session, namespace=namespace, name=name, user=user)
+        session, namespace=namespace, name=name, user=user,
+        case=APP.config.get('CASE_SENSITIVE', False))
 
     with project.lock('WORKER'):
         request = pagure.lib.search_pull_requests(
diff --git a/pagure/ui/fork.py b/pagure/ui/fork.py
index 1b5111f..35cc51f 100644
--- a/pagure/ui/fork.py
+++ b/pagure/ui/fork.py
@@ -881,7 +881,8 @@ def fork_project(repo, username=None, namespace=None):
 
     if pagure.lib._get_project(
             SESSION, repo.name, user=flask.g.fas_user.username,
-            namespace=namespace):
+            namespace=namespace,
+            case=APP.config.get('CASE_SENSITIVE', False)):
         return flask.redirect(flask.url_for(
             'view_repo', repo=repo.name, username=flask.g.fas_user.username,
             namespace=namespace))
@@ -1256,7 +1257,8 @@ def fork_edit_file(
         flask.abort(400)
 
     if pagure.lib._get_project(
-            SESSION, repo.name, user=flask.g.fas_user.username):
+            SESSION, repo.name, user=flask.g.fas_user.username,
+            case=APP.config.get('CASE_SENSITIVE', False)):
         flask.flash('You had already forked this project')
         return flask.redirect(flask.url_for(
             'edit_file',
diff --git a/tests/test_pagure_flask_ui_repo.py b/tests/test_pagure_flask_ui_repo.py
index 7d0a2d6..1e2e7a9 100644
--- a/tests/test_pagure_flask_ui_repo.py
+++ b/tests/test_pagure_flask_ui_repo.py
@@ -1290,6 +1290,20 @@ class PagureFlaskRepotests(tests.Modeltests):
         self.assertEqual(output.status_code, 200)
         self.assertTrue('This project has not been forked.' in output.data)
 
+    @patch.dict('pagure.APP.config', {'CASE_SENSITIVE': True})
+    def test_view_repo_case_sensitive(self):
+        """ Test the view_repo endpoint. """
+
+        tests.create_projects(self.session)
+        tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
+
+        output = self.app.get('/test')
+        self.assertEqual(output.status_code, 200)
+        self.assertTrue('<p>This repo is brand new!</p>' in output.data)
+
+        output = self.app.get('/TEST')
+        self.assertEqual(output.status_code, 404)
+
     def test_view_repo(self):
         """ Test the view_repo endpoint. """
 

