diff --git a/pagure/lib/model.py b/pagure/lib/model.py index a9322ec..092a965 100644 --- a/pagure/lib/model.py +++ b/pagure/lib/model.py @@ -379,7 +379,8 @@ class Project(BASE): secondary="user_projects", primaryjoin="projects.c.id==user_projects.c.project_id", secondaryjoin="users.c.id==user_projects.c.user_id", - backref='co_projects' + backref='co_projects', + viewonly=True ) admins = relation( @@ -388,7 +389,8 @@ class Project(BASE): primaryjoin="projects.c.id==user_projects.c.project_id", secondaryjoin="and_(users.c.id==user_projects.c.user_id,\ user_projects.c.access=='admin')", - backref='co_projects_admins' + backref='co_projects_admins', + viewonly=True ) committers = relation( @@ -398,7 +400,8 @@ class Project(BASE): secondaryjoin="and_(users.c.id==user_projects.c.user_id,\ or_(user_projects.c.access=='commit',\ user_projects.c.access=='admin'))", - backref='co_projects_committers' + backref='co_projects_committers', + viewonly=True ) groups = relation( @@ -410,7 +413,8 @@ class Project(BASE): "projects", order_by="func.lower(projects.c.namespace).desc(), \ func.lower(projects.c.name)" - ) + ), + viewonly=True ) admin_groups = relation( @@ -420,6 +424,7 @@ class Project(BASE): secondaryjoin="and_(pagure_group.c.id==projects_groups.c.group_id,\ projects_groups.c.access=='admin')", backref="projects_admin_groups", + viewonly=True ) committer_groups = relation( @@ -430,6 +435,7 @@ class Project(BASE): or_(projects_groups.c.access=='admin',\ projects_groups.c.access=='commit'))", backref="projects_committer_groups", + viewonly=True ) unwatchers = relation( @@ -725,7 +731,11 @@ class ProjectUser(BASE): project = relation( 'Project', remote_side=[Project.id], - backref='user_projects') + backref=backref( + 'user_projects', cascade="delete,delete-orphan", + single_parent=True + ) + ) user = relation('User', backref='user_projects') @@ -826,8 +836,10 @@ class Issue(BASE): project = relation( 'Project', foreign_keys=[project_id], remote_side=[Project.id], backref=backref( - 'issues', cascade="delete, delete-orphan", single_parent=True) - ) + 'issues', cascade="delete, delete-orphan", + ), + single_parent=True + ) user = relation('User', foreign_keys=[user_id], remote_side=[User.id], backref='issues') @@ -847,6 +859,7 @@ class Issue(BASE): secondary="tags_issues_colored", primaryjoin="issues.c.uid==tags_issues_colored.c.issue_uid", secondaryjoin="tags_issues_colored.c.tag_id==tags_colored.c.id", + viewonly=True ) def __repr__(self): @@ -1262,7 +1275,10 @@ class TagColored(BASE): project = relation( 'Project', foreign_keys=[project_id], remote_side=[Project.id], - backref="tags_colored", + backref=backref( + 'tags_colored', cascade="delete,delete-orphan", + single_parent=True + ) ) def __repr__(self): @@ -1846,8 +1862,12 @@ class ProjectGroup(BASE): nullable=False) project = relation( - 'Project', remote_side=[Project.id], - backref='projects_groups') + 'Project', foreign_keys=[project_id], remote_side=[Project.id], + backref=backref( + 'projects_groups', cascade="delete,delete-orphan", + single_parent=True + ) + ) group = relation('PagureGroup', backref='projects_groups') diff --git a/pagure/ui/repo.py b/pagure/ui/repo.py index 211614c..7eb6dd5 100644 --- a/pagure/ui/repo.py +++ b/pagure/ui/repo.py @@ -1485,14 +1485,8 @@ def delete_repo(repo, username=None, namespace=None): 'You are not allowed to change the settings for this project') try: - for issue in repo.issues: - for comment in issue.comments: - SESSION.delete(comment) - SESSION.commit() - SESSION.delete(issue) SESSION.delete(repo) SESSION.commit() - except SQLAlchemyError as err: # pragma: no cover SESSION.rollback() APP.logger.exception(err) diff --git a/tests/test_pagure_flask_ui_repo.py b/tests/test_pagure_flask_ui_repo.py index 5e36265..f37bdca 100644 --- a/tests/test_pagure_flask_ui_repo.py +++ b/tests/test_pagure_flask_ui_repo.py @@ -2714,7 +2714,6 @@ index 0000000..fb7093d pagure.APP.config['ENABLE_DEL_PROJECTS'] = True - @patch('pagure.lib.notify.send_email') @patch('pagure.ui.repo.admin_session_timedout') def test_delete_repo(self, ast, send_email): @@ -2976,6 +2975,274 @@ index 0000000..fb7093d 'Forks 0', output.data) + @patch('pagure.lib.notify.send_email') + @patch('pagure.ui.repo.admin_session_timedout') + def test_delete_repo_with_users(self, ast, send_email): + """ Test the delete_repo endpoint. """ + ast.return_value = False + send_email.return_value = True + + user = tests.FakeUser() + user = tests.FakeUser(username='pingou') + with tests.user_set(pagure.APP, user): + # Create new project + item = pagure.lib.model.Project( + user_id=1, # pingou + name='test', + description='test project #1', + hook_token='aaabbbiii', + ) + self.session.add(item) + self.session.commit() + + # Create all the git repos + tests.create_projects_git(self.path) + tests.create_projects_git( + os.path.join(self.path, 'docs'), bare=True) + tests.create_projects_git( + os.path.join(self.path, 'tickets'), bare=True) + tests.create_projects_git( + os.path.join(self.path, 'requests'), bare=True) + + # Check repo was created + output = self.app.get('/') + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n My Projects 1', output.data) + self.assertIn( + 'Forks 0', + output.data) + + # add user + repo = pagure.lib.get_project(self.session, 'test') + msg = pagure.lib.add_user_to_project( + session=self.session, + project=repo, + new_user='foo', + user='pingou', + ) + self.session.commit() + self.assertEqual(msg, 'User added') + + # Check before deleting the project + output = self.app.get('/') + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n My Projects 1', output.data) + self.assertIn( + 'Forks 0', + output.data) + repo = pagure.lib.get_project(self.session, 'test') + self.assertNotEqual(repo, None) + repo = pagure.lib.get_project(self.session, 'test2') + self.assertEqual(repo, None) + + # Delete the project + output = self.app.post('/test/delete', follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n Projects 0', output.data) + self.assertIn( + 'Forks 0', + output.data) + + # Check after + repo = pagure.lib.get_project(self.session, 'test') + self.assertEqual(repo, None) + repo = pagure.lib.get_project(self.session, 'test2') + self.assertEqual(repo, None) + + @patch('pagure.lib.notify.send_email') + @patch('pagure.ui.repo.admin_session_timedout') + def test_delete_repo_with_group(self, ast, send_email): + """ Test the delete_repo endpoint. """ + ast.return_value = False + send_email.return_value = True + + user = tests.FakeUser() + user = tests.FakeUser(username='pingou') + with tests.user_set(pagure.APP, user): + # Create new project + item = pagure.lib.model.Project( + user_id=1, # pingou + name='test', + description='test project #1', + hook_token='aaabbbiii', + ) + self.session.add(item) + self.session.commit() + + # Create all the git repos + tests.create_projects_git(self.path) + tests.create_projects_git( + os.path.join(self.path, 'docs'), bare=True) + tests.create_projects_git( + os.path.join(self.path, 'tickets'), bare=True) + tests.create_projects_git( + os.path.join(self.path, 'requests'), bare=True) + + # Check repo was created + output = self.app.get('/') + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n My Projects 1', output.data) + self.assertIn( + 'Forks 0', + output.data) + + # Create group + msg = pagure.lib.add_group( + self.session, + group_name='foo', + display_name='foo group', + description=None, + group_type='bar', + user='pingou', + is_admin=False, + blacklist=[], + ) + self.session.commit() + self.assertEqual(msg, 'User `pingou` added to the group `foo`.') + + # Add group to the project + repo = pagure.lib.get_project(self.session, 'test') + msg = pagure.lib.add_group_to_project( + session=self.session, + project=repo, + new_group='foo', + user='pingou', + ) + self.session.commit() + self.assertEqual(msg, 'Group added') + + # check if group where we expect it + repo = pagure.lib.get_project(self.session, 'test') + self.assertEqual(len(repo.projects_groups), 1) + + # Check before deleting the project + output = self.app.get('/') + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n My Projects 1', output.data) + self.assertIn( + 'Forks 0', + output.data) + repo = pagure.lib.get_project(self.session, 'test') + self.assertNotEqual(repo, None) + + # Delete the project + output = self.app.post('/test/delete', follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n Projects 0', output.data) + self.assertIn( + 'Forks 0', + output.data) + + # Check after + repo = pagure.lib.get_project(self.session, 'test') + self.assertEqual(repo, None) + + @patch('pagure.lib.notify.send_email') + @patch('pagure.ui.repo.admin_session_timedout') + def test_delete_repo_with_coloredtag(self, ast, send_email): + """ Test the delete_repo endpoint. """ + ast.return_value = False + send_email.return_value = True + + user = tests.FakeUser() + user = tests.FakeUser(username='pingou') + with tests.user_set(pagure.APP, user): + # Create new project + item = pagure.lib.model.Project( + user_id=1, # pingou + name='test', + description='test project #1', + hook_token='aaabbbiii', + ) + self.session.add(item) + self.session.commit() + + # Create all the git repos + tests.create_projects_git(self.path) + tests.create_projects_git( + os.path.join(self.path, 'docs'), bare=True) + tests.create_projects_git( + os.path.join(self.path, 'tickets'), bare=True) + tests.create_projects_git( + os.path.join(self.path, 'requests'), bare=True) + + # Check repo was created + output = self.app.get('/') + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n My Projects 1', output.data) + self.assertIn( + 'Forks 0', + output.data) + + # Create the 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=os.path.join(self.path, 'tickets') + ) + self.session.commit() + self.assertEqual(msg.title, 'Test issue') + + # Add a tag to the issue + repo = pagure.lib.get_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=1) + msg = pagure.lib.add_tag_obj( + session=self.session, + obj=issue, + tags='tag1', + user='pingou', + ticketfolder=None) + self.session.commit() + self.assertEqual(msg, 'Issue tagged with: tag1') + + # Check before deleting the project + output = self.app.get('/') + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n My Projects 1', output.data) + self.assertIn( + 'Forks 0', + output.data) + repo = pagure.lib.get_project(self.session, 'test') + self.assertNotEqual(repo, None) + repo = pagure.lib.get_project(self.session, 'test2') + self.assertEqual(repo, None) + + # Delete the project + output = self.app.post('/test/delete', follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n Projects 0', output.data) + self.assertIn( + 'Forks 0', + output.data) + + # Check after + repo = pagure.lib.get_project(self.session, 'test') + self.assertEqual(repo, None) + repo = pagure.lib.get_project(self.session, 'test2') + self.assertEqual(repo, None) + @patch('pagure.ui.repo.admin_session_timedout') def test_new_repo_hook_token(self, ast): """ Test the new_repo_hook_token endpoint. """ diff --git a/tests/test_pagure_lib_model_delete_project.py b/tests/test_pagure_lib_model_delete_project.py new file mode 100644 index 0000000..59ac8c5 --- /dev/null +++ b/tests/test_pagure_lib_model_delete_project.py @@ -0,0 +1,349 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2017 - Copyright Red Hat Inc + + Authors: + Pierre-Yves Chibon + +""" + +__requires__ = ['SQLAlchemy >= 0.8'] +import pkg_resources + +import json +import unittest +import sys +import os +import uuid + + +sys.path.insert(0, os.path.join(os.path.dirname( + os.path.abspath(__file__)), '..')) + +import pagure.lib +import pagure.lib.model as model + +import tests + + +class DeleteProjectTests(tests.Modeltests): + """ Tests for flask issues controller of pagure """ + + def setUp(self): + """ Set up the environnment, run before every tests. """ + super(DeleteProjectTests, self).setUp() + + pagure.APP.config['TESTING'] = True + pagure.SESSION = self.session + + def test_delete_project_with_group(self): + """ Test the model when we delete a project with a group. """ + + # Create a project + item = model.Project( + user_id=1, # pingou + name='test', + description='test project #1', + hook_token='aaabbbiii', + ) + self.session.add(item) + self.session.commit() + + # Create a group + grp = model.PagureGroup( + group_name='testgrp', + display_name='Test group', + description=None, + group_type='user', + user_id=1, # pingou + ) + self.session.add(grp) + self.session.commit() + + # Add group to project + project_group = model.ProjectGroup( + project_id=1, + group_id=1, + access='admin', + ) + self.session.add(project_group) + self.session.commit() + + self.assertEqual( + self.session.query(model.Project).count(), 1) + self.assertEqual( + self.session.query(model.ProjectGroup).count(), 1) + + project = self.session.query( + model.Project + ).filter( + model.Project.id==1 + ).one() + self.session.delete(project) + self.session.commit() + + self.assertEqual( + self.session.query(model.Project).count(), 0) + self.assertEqual( + self.session.query(model.ProjectGroup).count(), 0) + + def test_delete_project_with_user(self): + """ Test the model when we delete a project with users. """ + + # Create a project + item = model.Project( + user_id=1, # pingou + name='test', + description='test project #1', + hook_token='aaabbbiii', + ) + self.session.add(item) + self.session.commit() + + # Add user #2 to project + project_user = model.ProjectUser( + project_id=1, + user_id=2, + access='admin', + ) + self.session.add(project_user) + self.session.commit() + + self.assertEqual( + self.session.query(model.Project).count(), 1) + self.assertEqual( + self.session.query(model.ProjectUser).count(), 1) + self.assertEqual( + self.session.query(model.User).count(), 2) + + project = self.session.query( + model.Project + ).filter( + model.Project.id==1 + ).one() + self.session.delete(project) + self.session.commit() + + self.assertEqual( + self.session.query(model.Project).count(), 0) + self.assertEqual( + self.session.query(model.ProjectUser).count(), 0) + self.assertEqual( + self.session.query(model.User).count(), 2) + + def test_delete_project_with_coloredtags(self): + """ Test the model when we delete a project with Colored tags. """ + + # Create a project + item = model.Project( + user_id=1, # pingou + name='test', + description='test project #1', + hook_token='aaabbbiii', + ) + self.session.add(item) + self.session.commit() + + # Create two ColoredTags + tagobj = model.TagColored( + tag='Tag#1', + project_id=1 + ) + self.session.add(tagobj) + self.session.flush() + + tagobj = model.TagColored( + tag='Tag#2', + project_id=1 + ) + self.session.add(tagobj) + self.session.flush() + + self.assertEqual( + self.session.query(model.Project).count(), 1) + self.assertEqual( + self.session.query(model.TagColored).count(), 2) + + project = self.session.query( + model.Project + ).filter( + model.Project.id==1 + ).one() + self.session.delete(project) + self.session.commit() + + self.assertEqual( + self.session.query(model.Project).count(), 0) + self.assertEqual( + self.session.query(model.TagColored).count(), 0) + + def test_delete_project_with_coloredtags_and_issues(self): + """ Test the model when we delete a project with Colored tags and + issues. """ + + # Create a project + item = model.Project( + user_id=1, # pingou + name='test', + description='test project #1', + hook_token='aaabbbiii', + ) + self.session.add(item) + self.session.commit() + + # Create two ColoredTags + tagobj = model.TagColored( + tag='Tag#1', + project_id=1 + ) + self.session.add(tagobj) + self.session.flush() + + tagobj = model.TagColored( + tag='Tag#2', + project_id=1 + ) + self.session.add(tagobj) + self.session.flush() + + # Create issues + issue = model.Issue( + id=pagure.lib.get_next_id(self.session, 1), + project_id=1, + title='Issue #1', + content='Description #1', + user_id=1, + uid=uuid.uuid4().hex, + private=False, + ) + self.session.add(issue) + self.session.commit() + + issue = model.Issue( + id=pagure.lib.get_next_id(self.session, 1), + project_id=1, + title='Issue #2', + content='Description #2', + user_id=1, + uid=uuid.uuid4().hex, + private=False, + ) + self.session.add(issue) + self.session.commit() + + self.assertEqual( + self.session.query(model.Project).count(), 1) + self.assertEqual( + self.session.query(model.TagColored).count(), 2) + self.assertEqual( + self.session.query(model.Issue).count(), 2) + + project = self.session.query( + model.Project + ).filter( + model.Project.id==1 + ).one() + self.session.delete(project) + self.session.commit() + + self.assertEqual( + self.session.query(model.Project).count(), 0) + self.assertEqual( + self.session.query(model.TagColored).count(), 0) + self.assertEqual( + self.session.query(model.Issue).count(), 0) + + def test_delete_project_with_coloredtags_and_tagged_issues(self): + """ Test the model when we delete a project with Colored tags and + tagged issues. """ + + # Create a project + item = model.Project( + user_id=1, # pingou + name='test', + description='test project #1', + hook_token='aaabbbiii', + ) + self.session.add(item) + self.session.commit() + + # Create two ColoredTags + tagobj = model.TagColored( + tag='Tag#1', + project_id=1 + ) + self.session.add(tagobj) + self.session.flush() + + tagobj = model.TagColored( + tag='Tag#2', + project_id=1 + ) + self.session.add(tagobj) + self.session.flush() + + # Create issues + issue = model.Issue( + id=pagure.lib.get_next_id(self.session, 1), + project_id=1, + title='Issue #1', + content='Description #1', + user_id=1, + uid='Issue#1', + private=False, + ) + self.session.add(issue) + self.session.commit() + + issue = model.Issue( + id=pagure.lib.get_next_id(self.session, 1), + project_id=1, + title='Issue #2', + content='Description #2', + user_id=1, + uid='Issue#2', + private=False, + ) + self.session.add(issue) + self.session.commit() + + # Tag the issue + tagissue = model.TagIssueColored( + issue_uid='Issue#1', + tag_id=1 + ) + self.session.add(tagissue) + self.session.commit() + + tagissue = model.TagIssueColored( + issue_uid='Issue#2', + tag_id=2 + ) + self.session.add(tagissue) + self.session.commit() + + self.assertEqual( + self.session.query(model.Project).count(), 1) + self.assertEqual( + self.session.query(model.TagColored).count(), 2) + self.assertEqual( + self.session.query(model.Issue).count(), 2) + + project = self.session.query( + model.Project + ).filter( + model.Project.id==1 + ).one() + self.session.delete(project) + self.session.commit() + + self.assertEqual( + self.session.query(model.Project).count(), 0) + self.assertEqual( + self.session.query(model.TagColored).count(), 0) + self.assertEqual( + self.session.query(model.Issue).count(), 0) + +if __name__ == '__main__': + unittest.main(verbosity=2)