DeleteProject deletes a project.
(ctx context.Context, req *connect.Request[v1pb.DeleteProjectRequest])
| 387 | |
| 388 | // DeleteProject deletes a project. |
| 389 | func (s *ProjectService) DeleteProject(ctx context.Context, req *connect.Request[v1pb.DeleteProjectRequest]) (*connect.Response[emptypb.Empty], error) { |
| 390 | project, err := s.getProjectMessage(ctx, req.Msg.Name) |
| 391 | if err != nil { |
| 392 | return nil, err |
| 393 | } |
| 394 | |
| 395 | // Handle purge (hard delete) |
| 396 | if req.Msg.Purge { |
| 397 | if common.IsDefaultProject(project.Workspace, project.ResourceID) { |
| 398 | return nil, connect.NewError(connect.CodeInvalidArgument, errors.Errorf("default project cannot be purged")) |
| 399 | } |
| 400 | |
| 401 | // If project is not already soft-deleted, soft-delete it first |
| 402 | if !project.Deleted { |
| 403 | if err := s.store.UpdateProjects(ctx, &store.UpdateProjectMessage{ |
| 404 | ResourceID: project.ResourceID, |
| 405 | Workspace: project.Workspace, |
| 406 | Delete: &deletePatch, |
| 407 | }); err != nil { |
| 408 | return nil, connect.NewError(connect.CodeInternal, err) |
| 409 | } |
| 410 | } |
| 411 | |
| 412 | // Permanently delete the project and all related resources (moves databases to default project) |
| 413 | if err := s.store.DeleteProject(ctx, project.Workspace, project.ResourceID); err != nil { |
| 414 | return nil, connect.NewError(connect.CodeInternal, errors.Wrap(err, "failed to purge project")) |
| 415 | } |
| 416 | |
| 417 | return connect.NewResponse(&emptypb.Empty{}), nil |
| 418 | } |
| 419 | |
| 420 | // Regular soft delete (archive) flow |
| 421 | if common.IsDefaultProject(project.Workspace, project.ResourceID) { |
| 422 | return nil, connect.NewError(connect.CodeInvalidArgument, errors.Errorf("default project cannot be deleted")) |
| 423 | } |
| 424 | // Idempotent: if already deleted, return success |
| 425 | if project.Deleted { |
| 426 | return connect.NewResponse(&emptypb.Empty{}), nil |
| 427 | } |
| 428 | |
| 429 | // For archive (soft delete), just mark the project as deleted without touching databases or issues |
| 430 | if err := s.store.UpdateProjects(ctx, &store.UpdateProjectMessage{ |
| 431 | ResourceID: project.ResourceID, |
| 432 | Workspace: project.Workspace, |
| 433 | Delete: &deletePatch, |
| 434 | }); err != nil { |
| 435 | return nil, connect.NewError(connect.CodeInternal, err) |
| 436 | } |
| 437 | |
| 438 | return connect.NewResponse(&emptypb.Empty{}), nil |
| 439 | } |
| 440 | |
| 441 | // UndeleteProject undeletes a project. |
| 442 | func (s *ProjectService) UndeleteProject(ctx context.Context, req *connect.Request[v1pb.UndeleteProjectRequest]) (*connect.Response[v1pb.Project], error) { |
nothing calls this directly
no test coverage detected