From 3175b106228c1c4d867d0d6db46e3f5c78cdc395 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Dec 22 2016 14:10:16 +0000 Subject: [PATCH 1/3] Introduce the USER_NAMESPACE configuration key When this configuration key is set to True, the default namespace of the project is the user's username, basically as does github or gitlab. This isn't really how we envisioned pagure at the beginning but this is a request that has came up a few times and which this configuration key easily allows now that we have full namespaces. So basically, this commit fixes https://pagure.io/pagure/issue/1231 --- diff --git a/pagure/api/project.py b/pagure/api/project.py index 3f26404..a2a1acd 100644 --- a/pagure/api/project.py +++ b/pagure/api/project.py @@ -291,12 +291,13 @@ def api_new_project(): name = form.name.data description = form.description.data namespace = form.namespace.data - if namespace: - namespace = namespace.strip() url = form.url.data avatar_email = form.avatar_email.data create_readme = form.create_readme.data + if namespace: + namespace = namespace.strip() + try: message = pagure.lib.new_project( SESSION, @@ -316,6 +317,7 @@ def api_new_project(): userobj=user, prevent_40_chars=APP.config.get( 'OLD_VIEW_COMMIT_ENABLED', False), + user_ns=APP.config.get('USER_NAMESPACE', False), ) SESSION.commit() pagure.lib.git.generate_gitolite_acls() diff --git a/pagure/default_config.py b/pagure/default_config.py index 6dff333..a1c002d 100644 --- a/pagure/default_config.py +++ b/pagure/default_config.py @@ -229,3 +229,6 @@ BOOTSTRAP_URLS_JS = 'https://apps.fedoraproject.org/global/' \ # List of the type of CI service supported by this pagure instance PAGURE_CI_SERVICES = [] + +# Boolean to turn on project being by default in the user's namespace +USER_NAMESPACE = False diff --git a/pagure/forms.py b/pagure/forms.py index 85b1768..e5daf63 100644 --- a/pagure/forms.py +++ b/pagure/forms.py @@ -158,7 +158,8 @@ class ProjectForm(ProjectFormSimplified): self.namespace.choices = [ (namespace, namespace) for namespace in kwargs['namespaces'] ] - self.namespace.choices.insert(0, ('', '')) + if not pagure.APP.config.get('USER_NAMESPACE', False): + self.namespace.choices.insert(0, ('', '')) class IssueFormSimplied(PagureForm): diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index 1553754..dbbe5c8 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -1049,7 +1049,7 @@ def new_project(session, user, name, blacklist, allowed_prefix, gitfolder, docfolder, ticketfolder, requestfolder, description=None, url=None, avatar_email=None, parent_id=None, add_readme=False, userobj=None, - prevent_40_chars=False, namespace=None): + prevent_40_chars=False, namespace=None, user_ns=False): ''' Create a new project based on the information provided. ''' if name in blacklist or ( @@ -1061,6 +1061,10 @@ def new_project(session, user, name, blacklist, allowed_prefix, user_obj = get_user(session, user) allowed_prefix = allowed_prefix + [grp for grp in user_obj.groups] + if user_ns: + allowed_prefix.append(user) + if not namespace: + namespace = user if namespace and namespace not in allowed_prefix: raise pagure.exceptions.PagureException( diff --git a/pagure/ui/app.py b/pagure/ui/app.py index 587e054..302e70b 100644 --- a/pagure/ui/app.py +++ b/pagure/ui/app.py @@ -393,6 +393,8 @@ def new_project(): namespaces = APP.config['ALLOWED_PREFIX'][:] if user: namespaces.extend([grp for grp in user.groups]) + if APP.config.get('USER_NAMESPACE', False): + namespaces.insert(0, flask.g.fas_user.username) form = pagure.forms.ProjectForm(namespaces=namespaces) @@ -425,6 +427,7 @@ def new_project(): userobj=user, prevent_40_chars=APP.config.get( 'OLD_VIEW_COMMIT_ENABLED', False), + user_ns=APP.config.get('USER_NAMESPACE', False), ) SESSION.commit() pagure.lib.git.generate_gitolite_acls() From baec0932fe990825b49d06b7a3afa5de7bf52a32 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Dec 22 2016 14:10:16 +0000 Subject: [PATCH 2/3] Add unit-tests checking the behavior of the lib and the API with USER_NAMESPACE on --- diff --git a/tests/test_pagure_flask_api_project.py b/tests/test_pagure_flask_api_project.py index 0a8c3f8..09b19b8 100644 --- a/tests/test_pagure_flask_api_project.py +++ b/tests/test_pagure_flask_api_project.py @@ -459,6 +459,55 @@ class PagureFlaskApiProjecttests(tests.Modeltests): ) @patch('pagure.lib.git.generate_gitolite_acls') + def test_api_new_project_user_ns(self, p_gga): + """ Test the api_new_project method of the flask api. """ + pagure.APP.config['USER_NAMESPACE'] = True + p_gga.return_value = True + + tests.create_projects(self.session) + tests.create_projects_git(os.path.join(self.path, 'tickets')) + tests.create_tokens(self.session) + tests.create_tokens_acl(self.session) + + headers = {'Authorization': 'token aaabbbcccddd'} + + # Create a project with the user namespace feature on + data = { + 'name': 'testproject', + 'description': 'Just another small test project', + } + + # Valid request + output = self.app.post( + '/api/0/new/', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertDictEqual( + data, + {'message': 'Project "pingou/testproject" created'} + ) + + # Create a project with a namespace and the user namespace feature on + pagure.APP.config['ALLOWED_PREFIX'] = ['testns'] + data = { + 'name': 'testproject2', + 'namespace': 'testns', + 'description': 'Just another small test project', + } + + # Valid request + output = self.app.post( + '/api/0/new/', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertDictEqual( + data, + {'message': 'Project "testns/testproject2" created'} + ) + + pagure.APP.config['USER_NAMESPACE'] = False + + @patch('pagure.lib.git.generate_gitolite_acls') def test_api_fork_project(self, p_gga): """ Test the api_fork_project method of the flask api. """ p_gga.return_value = True diff --git a/tests/test_pagure_lib.py b/tests/test_pagure_lib.py index 6432e7f..b7ad650 100644 --- a/tests/test_pagure_lib.py +++ b/tests/test_pagure_lib.py @@ -912,6 +912,79 @@ class PagureLibtests(tests.Modeltests): 'Project "pingou/ssssssssssssssssssssssssssssssssssssssss" ' 'created') + + def test_new_project_user_ns(self): + """ Test the new_project of pagure.lib with user_ns on. """ + gitfolder = os.path.join(self.path, 'repos') + docfolder = os.path.join(self.path, 'docs') + ticketfolder = os.path.join(self.path, 'tickets') + requestfolder = os.path.join(self.path, 'requests') + + # Create a new project with user_ns as True + pagure.APP.config['GIT_FOLDER'] = gitfolder + msg = pagure.lib.new_project( + session=self.session, + user='pingou', + name='testproject', + blacklist=[], + allowed_prefix=[], + gitfolder=gitfolder, + docfolder=docfolder, + ticketfolder=ticketfolder, + requestfolder=requestfolder, + description='description for testproject', + parent_id=None, + user_ns=True, + ) + self.session.commit() + self.assertEqual(msg, 'Project "pingou/testproject" created') + + repo = pagure.lib.get_project( + self.session, 'testproject', namespace='pingou') + self.assertEqual(repo.path, 'pingou/testproject.git') + + gitrepo = os.path.join(gitfolder, repo.path) + docrepo = os.path.join(docfolder, repo.path) + ticketrepo = os.path.join(ticketfolder, repo.path) + requestrepo = os.path.join(requestfolder, repo.path) + + for path in [gitrepo, docrepo, ticketrepo, requestrepo]: + self.assertTrue(os.path.exists(path)) + shutil.rmtree(path) + + # Create a new project with a namespace and user_ns as True + pagure.APP.config['GIT_FOLDER'] = gitfolder + msg = pagure.lib.new_project( + session=self.session, + user='pingou', + name='testproject2', + namespace='testns', + blacklist=[], + allowed_prefix=['testns'], + gitfolder=gitfolder, + docfolder=docfolder, + ticketfolder=ticketfolder, + requestfolder=requestfolder, + description='description for testproject2', + parent_id=None, + user_ns=True, + ) + self.session.commit() + self.assertEqual(msg, 'Project "testns/testproject2" created') + + repo = pagure.lib.get_project( + self.session, 'testproject2', namespace='testns') + self.assertEqual(repo.path, 'testns/testproject2.git') + + gitrepo = os.path.join(gitfolder, repo.path) + docrepo = os.path.join(docfolder, repo.path) + ticketrepo = os.path.join(ticketfolder, repo.path) + requestrepo = os.path.join(requestfolder, repo.path) + + for path in [gitrepo, docrepo, ticketrepo, requestrepo]: + self.assertTrue(os.path.exists(path)) + shutil.rmtree(path) + def test_update_project_settings(self): """ Test the update_project_settings of pagure.lib. """ From d1b9a30bff4cd397bebd5b50aa8919f5f6f1c338 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Dec 22 2016 14:10:16 +0000 Subject: [PATCH 3/3] Document the ``USER_NAMESPACE`` configuration key --- diff --git a/doc/configuration.rst b/doc/configuration.rst index 94919b2..4daeaa1 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -576,6 +576,17 @@ Defaults to: ``Pagure`` authentication. +USER_NAMESPACE +~~~~~~~~~~~~~~ + +This configuration key allows to enforce that project are namespaced under +the user's username, behaving in this way in a similar fashion as github.com +or gitlab.com. + +Defaults to: ``False`` + + + Deprecated configuration keys -----------------------------