← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/launchpad/ppa-delete-api into lp:launchpad

 

William Grant has proposed merging lp:~wgrant/launchpad/ppa-delete-api into lp:launchpad.

Commit message:
Export archive deletion on the API.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #814633 in Launchpad itself: "Cannot delete a PPA over the API"
  https://bugs.launchpad.net/launchpad/+bug/814633

For more details, see:
https://code.launchpad.net/~wgrant/launchpad/ppa-delete-api/+merge/271239

Export archive deletion on the API.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/ppa-delete-api into lp:launchpad.
=== modified file 'lib/lp/soyuz/browser/tests/test_archive_webservice.py'
--- lib/lp/soyuz/browser/tests/test_archive_webservice.py	2015-05-19 02:24:48 +0000
+++ lib/lp/soyuz/browser/tests/test_archive_webservice.py	2015-09-16 07:56:13 +0000
@@ -12,7 +12,10 @@
     Unauthorized as LRUnauthorized,
     )
 from testtools import ExpectedException
-from testtools.matchers import Equals
+from testtools.matchers import (
+    Equals,
+    MatchesStructure,
+    )
 import transaction
 from zope.component import getUtility
 
@@ -107,6 +110,40 @@
             get_permissions, create_permission, 1)
         self.assertThat(recorder2, HasQueryCount(Equals(recorder1.count)))
 
+    def test_delete(self):
+        with admin_logged_in():
+            ppa = self.factory.makeArchive(purpose=ArchivePurpose.PPA)
+            ppa_url = api_url(ppa)
+            ws = webservice_for_person(
+                ppa.owner, permission=OAuthPermission.WRITE_PRIVATE)
+
+        # DELETE on an archive resource doesn't actually remove it
+        # immediately, but it asks the publisher to delete it later.
+        self.assertEqual(
+            'Active',
+            ws.get(ppa_url, api_version='devel').jsonBody()['status'])
+        self.assertEqual(200, ws.delete(ppa_url, api_version='devel').status)
+        self.assertEqual(
+            'Deleting',
+            ws.get(ppa_url, api_version='devel').jsonBody()['status'])
+
+        # Deleting the PPA again fails.
+        self.assertThat(
+            ws.delete(ppa_url, api_version='devel'),
+            MatchesStructure.byEquality(
+                status=400, body="Archive already deleted."))
+
+    def test_delete_is_restricted(self):
+        with admin_logged_in():
+            ppa = self.factory.makeArchive(purpose=ArchivePurpose.PPA)
+            ppa_url = api_url(ppa)
+            ws = webservice_for_person(
+                self.factory.makePerson(),
+                permission=OAuthPermission.WRITE_PRIVATE)
+
+        # A random user can't delete someone else's PPA.
+        self.assertEqual(401, ws.delete(ppa_url, api_version='devel').status)
+
 
 class TestExternalDependencies(WebServiceTestCase):
 

=== modified file 'lib/lp/soyuz/interfaces/archive.py'
--- lib/lp/soyuz/interfaces/archive.py	2015-08-25 16:10:09 +0000
+++ lib/lp/soyuz/interfaces/archive.py	2015-09-16 07:56:13 +0000
@@ -59,6 +59,7 @@
     error_status,
     export_as_webservice_collection,
     export_as_webservice_entry,
+    export_destructor_operation,
     export_factory_operation,
     export_operation_as,
     export_read_operation,
@@ -183,6 +184,11 @@
     """Raised on some queries when version is specified but name is not."""
 
 
+@error_status(httplib.BAD_REQUEST)
+class ArchiveAlreadyDeleted(Exception):
+    """Archive already deleted."""
+
+
 @error_status(httplib.FORBIDDEN)
 class CannotUploadToArchive(Exception):
     """A reason for not being able to upload to an archive."""
@@ -1968,6 +1974,9 @@
     def disable():
         """Disable the archive."""
 
+    @export_destructor_operation()
+    @call_with(deleted_by=REQUEST_USER)
+    @operation_for_version('devel')
     def delete(deleted_by):
         """Delete this archive.
 

=== modified file 'lib/lp/soyuz/model/archive.py'
--- lib/lp/soyuz/model/archive.py	2015-08-28 16:47:33 +0000
+++ lib/lp/soyuz/model/archive.py	2015-09-16 07:56:13 +0000
@@ -134,6 +134,7 @@
     )
 from lp.soyuz.interfaces.archive import (
     AlreadySubscribed,
+    ArchiveAlreadyDeleted,
     ArchiveDependencyError,
     ArchiveDisabled,
     ArchiveNotPrivate,
@@ -2088,9 +2089,8 @@
 
     def delete(self, deleted_by):
         """See `IArchive`."""
-        assert self.status not in (
-            ArchiveStatus.DELETING, ArchiveStatus.DELETED,
-            "This archive is already deleted.")
+        if self.status != ArchiveStatus.ACTIVE:
+            raise ArchiveAlreadyDeleted("Archive already deleted.")
 
         # Mark the archive's status as DELETING so the repository can be
         # removed by the publisher.


Follow ups