Monorepo for Tangled tangled.org
5

Configure Feed

Select the types of activity you want to include in your feed.

1package xrpc 2 3import ( 4 "database/sql" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "net/http" 9 "os" 10 11 comatproto "github.com/bluesky-social/indigo/api/atproto" 12 "github.com/bluesky-social/indigo/atproto/syntax" 13 "github.com/bluesky-social/indigo/xrpc" 14 securejoin "github.com/cyphar/filepath-securejoin" 15 "tangled.org/core/api/tangled" 16 "tangled.org/core/rbac" 17 xrpcerr "tangled.org/core/xrpc/errors" 18) 19 20func (x *Xrpc) DeleteRepo(w http.ResponseWriter, r *http.Request) { 21 l := x.Logger.With("handler", "DeleteRepo") 22 fail := func(e xrpcerr.XrpcError) { 23 l.Error("failed", "kind", e.Tag, "error", e.Message) 24 writeError(w, e, http.StatusBadRequest) 25 } 26 27 actorDid, ok := r.Context().Value(ActorDid).(syntax.DID) 28 if !ok { 29 fail(xrpcerr.MissingActorDidError) 30 return 31 } 32 33 var data tangled.RepoDelete_Input 34 if err := json.NewDecoder(r.Body).Decode(&data); err != nil { 35 fail(xrpcerr.GenericError(err)) 36 return 37 } 38 39 did := data.Did 40 name := data.Name 41 rkey := data.Rkey 42 43 if did == "" || name == "" { 44 fail(xrpcerr.GenericError(fmt.Errorf("did and name are required"))) 45 return 46 } 47 48 ident, err := x.Resolver.ResolveIdent(r.Context(), actorDid.String()) 49 if err != nil || ident.Handle.IsInvalidHandle() { 50 fail(xrpcerr.GenericError(err)) 51 return 52 } 53 54 xrpcc := xrpc.Client{ 55 Host: ident.PDSEndpoint(), 56 } 57 58 // ensure that the record does not exists 59 _, err = comatproto.RepoGetRecord(r.Context(), &xrpcc, "", tangled.RepoNSID, actorDid.String(), rkey) 60 if err == nil { 61 fail(xrpcerr.RecordExistsError(rkey)) 62 return 63 } 64 65 repoDid, err := x.Db.GetRepoDid(did, name) 66 if errors.Is(err, sql.ErrNoRows) { 67 repoDid, err = x.Db.GetRepoDidByName(did, name) 68 if errors.Is(err, sql.ErrNoRows) { 69 l.Info("repo already torn down or not found", "did", did, "name", name) 70 w.WriteHeader(http.StatusOK) 71 return 72 } 73 } 74 if err != nil { 75 l.Error("failed to look up repo", "error", err.Error()) 76 writeError(w, xrpcerr.GenericError(err), http.StatusInternalServerError) 77 return 78 } 79 80 repoPath, joinErr := securejoin.SecureJoin(x.Config.Repo.ScanPath, repoDid) 81 if joinErr != nil { 82 fail(xrpcerr.GenericError(joinErr)) 83 return 84 } 85 86 isDeleteAllowed, err := x.Enforcer.IsRepoDeleteAllowed(actorDid.String(), rbac.ThisServer, repoDid) 87 if err != nil { 88 fail(xrpcerr.GenericError(err)) 89 return 90 } 91 if !isDeleteAllowed { 92 fail(xrpcerr.AccessControlError(actorDid.String())) 93 return 94 } 95 96 if rmErr := os.RemoveAll(repoPath); rmErr != nil { 97 l.Error("deleting repo", "error", rmErr.Error()) 98 writeError(w, xrpcerr.GenericError(rmErr), http.StatusInternalServerError) 99 return 100 } 101 102 if rbacErr := x.Enforcer.WipeRepoPolicies(rbac.ThisServer, repoDid); rbacErr != nil { 103 l.Error("failed to delete repo from enforcer", "error", rbacErr.Error()) 104 writeError(w, xrpcerr.GenericError(rbacErr), http.StatusInternalServerError) 105 return 106 } 107 108 if delErr := x.Db.DeleteRepoKey(repoDid); delErr != nil { 109 l.Error("failed to delete repo key", "error", delErr.Error()) 110 writeError(w, xrpcerr.GenericError(delErr), http.StatusInternalServerError) 111 return 112 } 113 114 w.WriteHeader(http.StatusOK) 115}