diff --git a/file/handler/files.go b/file/handler/files.go index 679a8f9..d36fbca 100644 --- a/file/handler/files.go +++ b/file/handler/files.go @@ -2,6 +2,7 @@ package handler import ( "context" + "path/filepath" "strings" "github.com/micro/micro/v3/service/errors" @@ -32,6 +33,47 @@ func NewFile() *File { } } +func (e *File) Delete(ctx context.Context, req *file.DeleteRequest, rsp *file.DeleteResponse) error { + if len(req.Path) == 0 { + return errors.BadRequest("file.read", "missing file path") + } + + tenantId, ok := tenant.FromContext(ctx) + if !ok { + tenantId = "micro" + } + + path := filepath.Join(tenantId, req.Project, req.Path) + project := tenantId + "/" + req.Project + + // delete one file + if !strings.HasSuffix(req.Path, "/") { + return e.db.Delete(model.QueryEquals("Path", path)) + } + + var files []*file.Record + + // read all the files for the project + err := e.db.Read(model.QueryEquals("project", project), &files) + if err != nil { + return err + } + + for _, file := range files { + // delete a list of files + if file.Project != project { + continue + } + if !strings.HasPrefix(file.Path, path) { + continue + } + // delete the file + e.db.Delete(model.QueryEquals("Path", file.Path)) + } + + return nil +} + func (e *File) Read(ctx context.Context, req *file.ReadRequest, rsp *file.ReadResponse) error { log.Info("Received File.Read request") @@ -63,7 +105,7 @@ func (e *File) Read(ctx context.Context, req *file.ReadRequest, rsp *file.ReadRe // strip the tenant id file.Project = strings.TrimPrefix(file.Project, tenantId+"/") - file.Path = strings.TrimPrefix(file.Path, req.Project+"/") + file.Path = strings.TrimPrefix(file.Path, filepath.Join(tenantId, req.Project)) // check the path matches the request if req.Path == file.Path { @@ -146,7 +188,7 @@ func (e *File) List(ctx context.Context, req *file.ListRequest, rsp *file.ListRe // strip the prefixes file.Project = strings.TrimPrefix(file.Project, tenantId+"/") - file.Path = strings.TrimPrefix(file.Path, req.Project+"/") + file.Path = strings.TrimPrefix(file.Path, filepath.Join(tenantId, req.Project)) // strip the file contents // no file listing ever contains it diff --git a/file/proto/file.pb.go b/file/proto/file.pb.go index 6101dc1..a3cb3d6 100644 --- a/file/proto/file.pb.go +++ b/file/proto/file.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.26.0 -// protoc v3.6.1 +// protoc v3.15.6 // source: proto/file.proto package file @@ -518,6 +518,102 @@ func (x *ListResponse) GetFiles() []*Record { return nil } +// Delete a file by project name/path +type DeleteRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The project name + Project string `protobuf:"bytes,1,opt,name=project,proto3" json:"project,omitempty"` + // Path to the file + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` +} + +func (x *DeleteRequest) Reset() { + *x = DeleteRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_file_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteRequest) ProtoMessage() {} + +func (x *DeleteRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_file_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteRequest.ProtoReflect.Descriptor instead. +func (*DeleteRequest) Descriptor() ([]byte, []int) { + return file_proto_file_proto_rawDescGZIP(), []int{9} +} + +func (x *DeleteRequest) GetProject() string { + if x != nil { + return x.Project + } + return "" +} + +func (x *DeleteRequest) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +type DeleteResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteResponse) Reset() { + *x = DeleteResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_file_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteResponse) ProtoMessage() {} + +func (x *DeleteResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_file_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteResponse.ProtoReflect.Descriptor instead. +func (*DeleteResponse) Descriptor() ([]byte, []int) { + return file_proto_file_proto_rawDescGZIP(), []int{10} +} + var File_proto_file_proto protoreflect.FileDescriptor var file_proto_file_proto_rawDesc = []byte{ @@ -564,22 +660,31 @@ var file_proto_file_proto_rawDesc = []byte{ 0x68, 0x22, 0x32, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x05, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x32, 0xd9, 0x01, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x2f, - 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x52, 0x65, - 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x66, 0x69, 0x6c, 0x65, - 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x2f, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x66, 0x69, 0x6c, - 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x2f, 0x0a, 0x04, 0x53, 0x61, 0x76, 0x65, 0x12, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x2e, - 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x66, 0x69, - 0x6c, 0x65, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x3e, 0x0a, 0x09, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x61, 0x76, 0x65, 0x12, 0x16, + 0x66, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x3d, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x70, 0x61, 0x74, 0x68, 0x22, 0x10, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x90, 0x02, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, + 0x2f, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x52, + 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x66, 0x69, 0x6c, + 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x2f, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x66, 0x69, + 0x6c, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x2f, 0x0a, 0x04, 0x53, 0x61, 0x76, 0x65, 0x12, 0x11, 0x2e, 0x66, 0x69, 0x6c, 0x65, + 0x2e, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x66, + 0x69, 0x6c, 0x65, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x35, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x66, + 0x69, 0x6c, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x14, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x09, 0x42, 0x61, 0x74, + 0x63, 0x68, 0x53, 0x61, 0x76, 0x65, 0x12, 0x16, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x42, 0x61, + 0x74, 0x63, 0x68, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x61, 0x76, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x42, 0x61, - 0x74, 0x63, 0x68, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x66, 0x69, 0x6c, - 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x66, 0x69, 0x6c, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -594,7 +699,7 @@ func file_proto_file_proto_rawDescGZIP() []byte { return file_proto_file_proto_rawDescData } -var file_proto_file_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_proto_file_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_proto_file_proto_goTypes = []interface{}{ (*Record)(nil), // 0: file.Record (*BatchSaveRequest)(nil), // 1: file.BatchSaveRequest @@ -605,27 +710,31 @@ var file_proto_file_proto_goTypes = []interface{}{ (*SaveResponse)(nil), // 6: file.SaveResponse (*ListRequest)(nil), // 7: file.ListRequest (*ListResponse)(nil), // 8: file.ListResponse - nil, // 9: file.Record.MetadataEntry + (*DeleteRequest)(nil), // 9: file.DeleteRequest + (*DeleteResponse)(nil), // 10: file.DeleteResponse + nil, // 11: file.Record.MetadataEntry } var file_proto_file_proto_depIdxs = []int32{ - 9, // 0: file.Record.metadata:type_name -> file.Record.MetadataEntry - 0, // 1: file.BatchSaveRequest.files:type_name -> file.Record - 0, // 2: file.ReadResponse.file:type_name -> file.Record - 0, // 3: file.SaveRequest.file:type_name -> file.Record - 0, // 4: file.ListResponse.files:type_name -> file.Record - 3, // 5: file.File.Read:input_type -> file.ReadRequest - 7, // 6: file.File.List:input_type -> file.ListRequest - 5, // 7: file.File.Save:input_type -> file.SaveRequest - 1, // 8: file.File.BatchSave:input_type -> file.BatchSaveRequest - 4, // 9: file.File.Read:output_type -> file.ReadResponse - 8, // 10: file.File.List:output_type -> file.ListResponse - 6, // 11: file.File.Save:output_type -> file.SaveResponse - 2, // 12: file.File.BatchSave:output_type -> file.BatchSaveResponse - 9, // [9:13] is the sub-list for method output_type - 5, // [5:9] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 11, // 0: file.Record.metadata:type_name -> file.Record.MetadataEntry + 0, // 1: file.BatchSaveRequest.files:type_name -> file.Record + 0, // 2: file.ReadResponse.file:type_name -> file.Record + 0, // 3: file.SaveRequest.file:type_name -> file.Record + 0, // 4: file.ListResponse.files:type_name -> file.Record + 3, // 5: file.File.Read:input_type -> file.ReadRequest + 7, // 6: file.File.List:input_type -> file.ListRequest + 5, // 7: file.File.Save:input_type -> file.SaveRequest + 9, // 8: file.File.Delete:input_type -> file.DeleteRequest + 1, // 9: file.File.BatchSave:input_type -> file.BatchSaveRequest + 4, // 10: file.File.Read:output_type -> file.ReadResponse + 8, // 11: file.File.List:output_type -> file.ListResponse + 6, // 12: file.File.Save:output_type -> file.SaveResponse + 10, // 13: file.File.Delete:output_type -> file.DeleteResponse + 2, // 14: file.File.BatchSave:output_type -> file.BatchSaveResponse + 10, // [10:15] is the sub-list for method output_type + 5, // [5:10] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } func init() { file_proto_file_proto_init() } @@ -742,6 +851,30 @@ func file_proto_file_proto_init() { return nil } } + file_proto_file_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_file_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -749,7 +882,7 @@ func file_proto_file_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_file_proto_rawDesc, NumEnums: 0, - NumMessages: 10, + NumMessages: 12, NumExtensions: 0, NumServices: 1, }, diff --git a/file/proto/file.pb.micro.go b/file/proto/file.pb.micro.go index 9b30232..cfdf956 100644 --- a/file/proto/file.pb.micro.go +++ b/file/proto/file.pb.micro.go @@ -45,6 +45,7 @@ type FileService interface { Read(ctx context.Context, in *ReadRequest, opts ...client.CallOption) (*ReadResponse, error) List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) Save(ctx context.Context, in *SaveRequest, opts ...client.CallOption) (*SaveResponse, error) + Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error) BatchSave(ctx context.Context, in *BatchSaveRequest, opts ...client.CallOption) (*BatchSaveResponse, error) } @@ -90,6 +91,16 @@ func (c *fileService) Save(ctx context.Context, in *SaveRequest, opts ...client. return out, nil } +func (c *fileService) Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error) { + req := c.c.NewRequest(c.name, "File.Delete", in) + out := new(DeleteResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *fileService) BatchSave(ctx context.Context, in *BatchSaveRequest, opts ...client.CallOption) (*BatchSaveResponse, error) { req := c.c.NewRequest(c.name, "File.BatchSave", in) out := new(BatchSaveResponse) @@ -106,6 +117,7 @@ type FileHandler interface { Read(context.Context, *ReadRequest, *ReadResponse) error List(context.Context, *ListRequest, *ListResponse) error Save(context.Context, *SaveRequest, *SaveResponse) error + Delete(context.Context, *DeleteRequest, *DeleteResponse) error BatchSave(context.Context, *BatchSaveRequest, *BatchSaveResponse) error } @@ -114,6 +126,7 @@ func RegisterFileHandler(s server.Server, hdlr FileHandler, opts ...server.Handl Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error List(ctx context.Context, in *ListRequest, out *ListResponse) error Save(ctx context.Context, in *SaveRequest, out *SaveResponse) error + Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error BatchSave(ctx context.Context, in *BatchSaveRequest, out *BatchSaveResponse) error } type File struct { @@ -139,6 +152,10 @@ func (h *fileHandler) Save(ctx context.Context, in *SaveRequest, out *SaveRespon return h.FileHandler.Save(ctx, in, out) } +func (h *fileHandler) Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error { + return h.FileHandler.Delete(ctx, in, out) +} + func (h *fileHandler) BatchSave(ctx context.Context, in *BatchSaveRequest, out *BatchSaveResponse) error { return h.FileHandler.BatchSave(ctx, in, out) } diff --git a/file/proto/file.proto b/file/proto/file.proto index 6bfb12f..475d335 100644 --- a/file/proto/file.proto +++ b/file/proto/file.proto @@ -8,6 +8,7 @@ service File { rpc Read(ReadRequest) returns (ReadResponse) {} rpc List(ListRequest) returns (ListResponse) {} rpc Save(SaveRequest) returns (SaveResponse) {} + rpc Delete(DeleteRequest) returns (DeleteResponse) {} rpc BatchSave(BatchSaveRequest) returns (BatchSaveResponse) {} } @@ -74,3 +75,14 @@ message ListRequest { message ListResponse { repeated Record files = 1; } + +// Delete a file by project name/path +message DeleteRequest { + // The project name + string project = 1; + // Path to the file + string path = 2; +} + +message DeleteResponse {} +