MCPcopy Create free account
hub / github.com/bytebase/bytebase / DeleteWorkspace

Method DeleteWorkspace

backend/api/v1/workspace_service.go:211–264  ·  view source on GitHub ↗

DeleteWorkspace soft-deletes a workspace. SaaS only. Cancels any active Stripe subscription before deleting, then switches to the next available workspace and returns new auth tokens.

(ctx context.Context, req *connect.Request[v1pb.DeleteWorkspaceRequest])

Source from the content-addressed store, hash-verified

209// Cancels any active Stripe subscription before deleting, then switches
210// to the next available workspace and returns new auth tokens.
211func (s *WorkspaceService) DeleteWorkspace(ctx context.Context, req *connect.Request[v1pb.DeleteWorkspaceRequest]) (*connect.Response[v1pb.LoginResponse], error) {
212 if !s.profile.SaaS {
213 return nil, connect.NewError(connect.CodeFailedPrecondition, errors.New("workspace deletion is only supported in SaaS mode"))
214 }
215
216 user, ok := GetUserFromContext(ctx)
217 if !ok || user == nil {
218 return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("user not found"))
219 }
220
221 workspaceID, err := common.GetWorkspaceID(req.Msg.Name)
222 if err != nil {
223 return nil, connect.NewError(connect.CodeInvalidArgument, err)
224 }
225 if contextWorkspaceID := common.GetWorkspaceIDFromContext(ctx); workspaceID != contextWorkspaceID {
226 return nil, connect.NewError(connect.CodePermissionDenied, errors.Errorf("cannot delete workspace %q from workspace %q", workspaceID, contextWorkspaceID))
227 }
228
229 // Cancel active Stripe subscription if any.
230 sub, err := s.store.GetSubscriptionByWorkspace(ctx, workspaceID)
231 if err != nil {
232 return nil, connect.NewError(connect.CodeInternal, errors.Wrap(err, "failed to check subscription"))
233 }
234 if sub != nil && sub.Payload != nil && sub.Payload.StripeSubscriptionId != "" {
235 if _, err := stripeplugin.CancelSubscription(sub.Payload.StripeSubscriptionId, workspaceID, true, "other", "Delete workspace"); err != nil {
236 slog.Warn("failed to cancel Stripe subscription during workspace deletion",
237 slog.String("workspace", workspaceID),
238 log.BBError(err),
239 )
240 }
241 }
242
243 if err := s.store.DeleteWorkspace(ctx, workspaceID); err != nil {
244 return nil, connect.NewError(connect.CodeInternal, errors.Wrap(err, "failed to delete workspace"))
245 }
246
247 // Find the next workspace and switch to it.
248 nextWS, err := s.store.FindWorkspace(ctx, &store.FindWorkspaceMessage{
249 Email: user.Email,
250 })
251 if err != nil {
252 return nil, connect.NewError(connect.CodeInternal, errors.Wrap(err, "failed to find next workspace"))
253 }
254 if nextWS == nil {
255 // No remaining workspace — clear auth cookies and return empty response.
256 // Frontend redirects to login which will provision a new workspace.
257 resp := connect.NewResponse(&v1pb.LoginResponse{})
258 s.authService.clearSessionAndSetCookies(ctx, req.Header(), resp.Header(), workspaceID)
259 return resp, nil
260 }
261
262 isWeb := auth.GetRefreshTokenFromCookie(req.Header()) != ""
263 return s.authService.switchWorkspaceInternal(ctx, user, nextWS.ResourceID, isWeb, req.Header())
264}
265
266// LeaveWorkspace removes the calling user from a workspace's IAM bindings,
267// then switches to the next available workspace.

Callers

nothing calls this directly

Calls 12

GetWorkspaceIDFunction · 0.92
BBErrorFunction · 0.92
GetUserFromContextFunction · 0.85
ErrorfMethod · 0.80
StringMethod · 0.65
DeleteWorkspaceMethod · 0.65
FindWorkspaceMethod · 0.65

Tested by

no test coverage detected