فهرست منبع

Merge pull request #12671 from overleaf/em-git-bridge-delete-project

Add endpoint to delete project data in git bridge

GitOrigin-RevId: bdc9701284255166bf4a122dad5fd89ced0c0ca2
Eric Mc Sween 3 سال پیش
والد
کامیت
c539e960e7

+ 14 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/Bridge.java

@@ -677,6 +677,20 @@ public class Bridge {
         );
     }
 
+    /**
+     * Delete a project's data
+     */
+    public void deleteProject(String projectName) {
+      Log.info("[{}] deleting project", projectName);
+      dbStore.deleteProject(projectName);
+      try {
+        repoStore.remove(projectName);
+      } catch (IOException e) {
+        Log.warn("Failed to delete repository for project {}: {}", projectName, e);
+      }
+      swapStore.remove(projectName);
+    }
+
     /* PRIVATE */
 
     /**

+ 4 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/DBStore.java

@@ -41,4 +41,8 @@ public interface DBStore {
      */
     void setLastAccessedTime(String projectName, Timestamp time);
 
+    /**
+     * Delete the metadata associated with the given project.
+     */
+    void deleteProject(String projectName);
 }

+ 3 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/noop/NoopDbStore.java

@@ -72,4 +72,7 @@ public class NoopDbStore implements DBStore {
     public String getSwapCompression(String projectName) {
         return null;
     }
+
+    @Override
+    public void deleteProject(String projectName) {}
 }

+ 8 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/SqliteDBStore.java

@@ -112,12 +112,12 @@ public class SqliteDBStore implements DBStore {
 
     @Override
     public void swap(String projectName, String compressionMethod) {
-      update(new UpdateSwap(projectName, compressionMethod));
+        update(new UpdateSwap(projectName, compressionMethod));
     }
 
     @Override
     public void restore(String projectName) {
-      update(new UpdateRestore(projectName));
+        update(new UpdateRestore(projectName));
     }
 
     @Override
@@ -125,6 +125,12 @@ public class SqliteDBStore implements DBStore {
         return query(new GetSwapCompression(projectName));
     }
 
+    @Override
+    public void deleteProject(String projectName) {
+        update(new DeleteAllFilesInProjectSQLUpdate(projectName));
+        update(new DeleteProjectSQLUpdate(projectName));
+    }
+
     private Connection openConnectionTo(File dbFile) {
         File parentDir = dbFile.getParentFile();
         if (!parentDir.exists() && !parentDir.mkdirs()) {

+ 24 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/delete/DeleteAllFilesInProjectSQLUpdate.java

@@ -0,0 +1,24 @@
+package uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.delete;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SQLUpdate;
+
+public class DeleteAllFilesInProjectSQLUpdate implements SQLUpdate {
+  private final String projectName;
+
+  public DeleteAllFilesInProjectSQLUpdate(String projectName) {
+    this.projectName = projectName;
+  }
+
+  @Override
+  public String getSQL() {
+    return "DELETE FROM `url_index_store` WHERE `project_name` = ?";
+  }
+
+  @Override
+  public void addParametersToStatement(PreparedStatement statement) throws SQLException {
+    statement.setString(1, projectName);
+  }
+}

+ 24 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/delete/DeleteProjectSQLUpdate.java

@@ -0,0 +1,24 @@
+package uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.delete;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SQLUpdate;
+
+public class DeleteProjectSQLUpdate implements SQLUpdate {
+  private final String projectName;
+
+  public DeleteProjectSQLUpdate(String projectName) {
+    this.projectName = projectName;
+  }
+
+  @Override
+  public String getSQL() {
+    return "DELETE FROM `projects` WHERE `name` = ?";
+  }
+
+  @Override
+  public void addParametersToStatement(PreparedStatement statement) throws SQLException {
+    statement.setString(1, projectName);
+  }
+}

+ 1 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/GitBridgeServer.java

@@ -148,6 +148,7 @@ public class GitBridgeServer {
         HandlerCollection handlers = new HandlerList();
         handlers.addHandler(initResourceHandler());
         handlers.addHandler(new PostbackHandler(bridge));
+        handlers.addHandler(new ProjectDeletionHandler(bridge));
         handlers.addHandler(new DefaultHandler());
 
         api.setHandler(handlers);

+ 39 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/ProjectDeletionHandler.java

@@ -0,0 +1,39 @@
+package uk.ac.ic.wlgitbridge.server;
+
+import java.io.IOException;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.server.Request;
+
+import uk.ac.ic.wlgitbridge.bridge.Bridge;
+
+public class ProjectDeletionHandler extends AbstractHandler {
+
+  private final Bridge bridge;
+  private final Pattern routePattern = Pattern.compile("^/projects/([0-9a-f]{24})$");
+
+  public ProjectDeletionHandler(Bridge bridge) {
+    this.bridge = bridge;
+  }
+
+  @Override
+  public void handle(
+    String target,
+    Request baseRequest,
+    HttpServletRequest request,
+    HttpServletResponse response
+  ) throws IOException {
+    String method = baseRequest.getMethod();
+    Matcher matcher = routePattern.matcher(target);
+    if (method.equals("DELETE") && target != null && matcher.matches()) {
+      String projectName = matcher.group(1);
+      response.setContentType("text/plain");
+      response.setStatus(204);
+      this.bridge.deleteProject(projectName);
+      baseRequest.setHandled(true);
+    }
+  }
+}

+ 19 - 9
services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/SqliteDBStoreTest.java

@@ -71,15 +71,15 @@ public class SqliteDBStoreTest {
 
     @Test
     public void swapAndRestore() {
-      String projectName = "something";
-      String compression = "bzip2";
-      dbStore.setLatestVersionForProject(projectName, 42);
-      dbStore.swap(projectName, compression);
-      assertNull(dbStore.getOldestUnswappedProject());
-      assertEquals(dbStore.getSwapCompression(projectName), compression);
-      // and restore
-      dbStore.restore(projectName);
-      assertEquals(dbStore.getSwapCompression(projectName), null);
+        String projectName = "something";
+        String compression = "bzip2";
+        dbStore.setLatestVersionForProject(projectName, 42);
+        dbStore.swap(projectName, compression);
+        assertNull(dbStore.getOldestUnswappedProject());
+        assertEquals(dbStore.getSwapCompression(projectName), compression);
+        // and restore
+        dbStore.restore(projectName);
+        assertEquals(dbStore.getSwapCompression(projectName), null);
     }
 
     @Test
@@ -160,4 +160,14 @@ public class SqliteDBStoreTest {
         assertEquals(ProjectState.SWAPPED, dbStore.getProjectState("asdf"));
     }
 
+    @Test
+    public void testDeleteProject() {
+        dbStore.setLatestVersionForProject("project1", 1);
+        dbStore.setLatestVersionForProject("project2", 1);
+        assertEquals(ProjectState.PRESENT, dbStore.getProjectState("project1"));
+        assertEquals(ProjectState.PRESENT, dbStore.getProjectState("project2"));
+        dbStore.deleteProject("project1");
+        assertEquals(ProjectState.NOT_PRESENT, dbStore.getProjectState("project1"));
+        assertEquals(ProjectState.PRESENT, dbStore.getProjectState("project2"));
+    }
 }