diff --git a/services/Makefile b/services/Makefile index 526dddd..94269fa 100644 --- a/services/Makefile +++ b/services/Makefile @@ -10,7 +10,7 @@ build-ical: gen: @protoc \ --proto_path=protobuf "protobuf/modules.proto" \ - --go_out=common/genproto/modules \ + --go_out="common/genproto/modules" \ --go_opt=paths=source_relative \ - --go-grpc_out=common/genproto/modules \ + --go-grpc_out="common/genproto/modules" \ --go-grpc_opt=paths=source_relative \ No newline at end of file diff --git a/services/README.md b/services/README.md new file mode 100644 index 0000000..c309315 --- /dev/null +++ b/services/README.md @@ -0,0 +1,6 @@ +To execute the protobuf gen script, install the protobuf compiler and the python protobuf library. Then run the following command: + +```bash +go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 +go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2 +``` diff --git a/services/common/genproto/modules/modules.pb.go b/services/common/genproto/modules/modules.pb.go index cc88a8b..3ce1b6b 100644 --- a/services/common/genproto/modules/modules.pb.go +++ b/services/common/genproto/modules/modules.pb.go @@ -305,6 +305,53 @@ func (x *GetModuleRequest) GetUuid() string { return "" } +type GetModulesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Uuids []string `protobuf:"bytes,1,rep,name=uuids,proto3" json:"uuids,omitempty"` +} + +func (x *GetModulesRequest) Reset() { + *x = GetModulesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_modules_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetModulesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetModulesRequest) ProtoMessage() {} + +func (x *GetModulesRequest) ProtoReflect() protoreflect.Message { + mi := &file_modules_proto_msgTypes[3] + 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 GetModulesRequest.ProtoReflect.Descriptor instead. +func (*GetModulesRequest) Descriptor() ([]byte, []int) { + return file_modules_proto_rawDescGZIP(), []int{3} +} + +func (x *GetModulesRequest) GetUuids() []string { + if x != nil { + return x.Uuids + } + return nil +} + type GetModuleResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -316,7 +363,7 @@ type GetModuleResponse struct { func (x *GetModuleResponse) Reset() { *x = GetModuleResponse{} if protoimpl.UnsafeEnabled { - mi := &file_modules_proto_msgTypes[3] + mi := &file_modules_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -329,7 +376,7 @@ func (x *GetModuleResponse) String() string { func (*GetModuleResponse) ProtoMessage() {} func (x *GetModuleResponse) ProtoReflect() protoreflect.Message { - mi := &file_modules_proto_msgTypes[3] + mi := &file_modules_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -342,7 +389,7 @@ func (x *GetModuleResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetModuleResponse.ProtoReflect.Descriptor instead. func (*GetModuleResponse) Descriptor() ([]byte, []int) { - return file_modules_proto_rawDescGZIP(), []int{3} + return file_modules_proto_rawDescGZIP(), []int{4} } func (x *GetModuleResponse) GetModule() *Module { @@ -352,6 +399,100 @@ func (x *GetModuleResponse) GetModule() *Module { return nil } +type GetModulesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Modules []*Module `protobuf:"bytes,1,rep,name=modules,proto3" json:"modules,omitempty"` +} + +func (x *GetModulesResponse) Reset() { + *x = GetModulesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_modules_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetModulesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetModulesResponse) ProtoMessage() {} + +func (x *GetModulesResponse) ProtoReflect() protoreflect.Message { + mi := &file_modules_proto_msgTypes[5] + 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 GetModulesResponse.ProtoReflect.Descriptor instead. +func (*GetModulesResponse) Descriptor() ([]byte, []int) { + return file_modules_proto_rawDescGZIP(), []int{5} +} + +func (x *GetModulesResponse) GetModules() []*Module { + if x != nil { + return x.Modules + } + return nil +} + +type GetEventsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Events []*Event `protobuf:"bytes,1,rep,name=events,proto3" json:"events,omitempty"` +} + +func (x *GetEventsResponse) Reset() { + *x = GetEventsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_modules_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetEventsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEventsResponse) ProtoMessage() {} + +func (x *GetEventsResponse) ProtoReflect() protoreflect.Message { + mi := &file_modules_proto_msgTypes[6] + 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 GetEventsResponse.ProtoReflect.Descriptor instead. +func (*GetEventsResponse) Descriptor() ([]byte, []int) { + return file_modules_proto_rawDescGZIP(), []int{6} +} + +func (x *GetEventsResponse) GetEvents() []*Event { + if x != nil { + return x.Events + } + return nil +} + var File_modules_proto protoreflect.FileDescriptor var file_modules_proto_rawDesc = []byte{ @@ -389,17 +530,34 @@ var file_modules_proto_rawDesc = []byte{ 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x26, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, - 0x22, 0x34, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x06, - 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x32, 0x45, 0x0a, 0x0d, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x4d, 0x6f, - 0x64, 0x75, 0x6c, 0x65, 0x12, 0x11, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x6f, 0x64, - 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x1c, 0x5a, - 0x1a, 0x68, 0x74, 0x77, 0x6b, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x22, 0x29, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x75, 0x75, 0x69, 0x64, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x75, 0x75, 0x69, 0x64, 0x73, 0x22, 0x34, 0x0a, 0x11, 0x47, + 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x1f, 0x0a, 0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x07, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, + 0x65, 0x22, 0x37, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, + 0x65, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x33, 0x0a, 0x11, 0x47, 0x65, + 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x1e, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x06, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x32, + 0xbf, 0x01, 0x0a, 0x0d, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x34, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x11, + 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x12, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4d, 0x6f, + 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x12, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x47, 0x65, 0x74, 0x4d, + 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x3f, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x46, 0x6f, 0x72, + 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x12, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x6f, 0x64, + 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x47, 0x65, + 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x42, 0x1c, 0x5a, 0x1a, 0x68, 0x74, 0x77, 0x6b, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -414,23 +572,32 @@ func file_modules_proto_rawDescGZIP() []byte { return file_modules_proto_rawDescData } -var file_modules_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_modules_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_modules_proto_goTypes = []interface{}{ - (*Event)(nil), // 0: Event - (*Module)(nil), // 1: Module - (*GetModuleRequest)(nil), // 2: GetModuleRequest - (*GetModuleResponse)(nil), // 3: GetModuleResponse + (*Event)(nil), // 0: Event + (*Module)(nil), // 1: Module + (*GetModuleRequest)(nil), // 2: GetModuleRequest + (*GetModulesRequest)(nil), // 3: GetModulesRequest + (*GetModuleResponse)(nil), // 4: GetModuleResponse + (*GetModulesResponse)(nil), // 5: GetModulesResponse + (*GetEventsResponse)(nil), // 6: GetEventsResponse } var file_modules_proto_depIdxs = []int32{ 0, // 0: Module.events:type_name -> Event 1, // 1: GetModuleResponse.module:type_name -> Module - 2, // 2: ModuleService.GetModule:input_type -> GetModuleRequest - 3, // 3: ModuleService.GetModule:output_type -> GetModuleResponse - 3, // [3:4] is the sub-list for method output_type - 2, // [2:3] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 1, // 2: GetModulesResponse.modules:type_name -> Module + 0, // 3: GetEventsResponse.events:type_name -> Event + 2, // 4: ModuleService.GetModule:input_type -> GetModuleRequest + 3, // 5: ModuleService.GetModules:input_type -> GetModulesRequest + 3, // 6: ModuleService.GetEventsForModules:input_type -> GetModulesRequest + 4, // 7: ModuleService.GetModule:output_type -> GetModuleResponse + 5, // 8: ModuleService.GetModules:output_type -> GetModulesResponse + 6, // 9: ModuleService.GetEventsForModules:output_type -> GetEventsResponse + 7, // [7:10] is the sub-list for method output_type + 4, // [4:7] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_modules_proto_init() } @@ -476,6 +643,18 @@ func file_modules_proto_init() { } } file_modules_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetModulesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_modules_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetModuleResponse); i { case 0: return &v.state @@ -487,6 +666,30 @@ func file_modules_proto_init() { return nil } } + file_modules_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetModulesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_modules_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetEventsResponse); 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{ @@ -494,7 +697,7 @@ func file_modules_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_modules_proto_rawDesc, NumEnums: 0, - NumMessages: 4, + NumMessages: 7, NumExtensions: 0, NumServices: 1, }, diff --git a/services/common/genproto/modules/modules_grpc.pb.go b/services/common/genproto/modules/modules_grpc.pb.go index eafc547..5c6a689 100644 --- a/services/common/genproto/modules/modules_grpc.pb.go +++ b/services/common/genproto/modules/modules_grpc.pb.go @@ -23,6 +23,8 @@ const _ = grpc.SupportPackageIsVersion7 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type ModuleServiceClient interface { GetModule(ctx context.Context, in *GetModuleRequest, opts ...grpc.CallOption) (*GetModuleResponse, error) + GetModules(ctx context.Context, in *GetModulesRequest, opts ...grpc.CallOption) (*GetModulesResponse, error) + GetEventsForModules(ctx context.Context, in *GetModulesRequest, opts ...grpc.CallOption) (*GetEventsResponse, error) } type moduleServiceClient struct { @@ -42,11 +44,31 @@ func (c *moduleServiceClient) GetModule(ctx context.Context, in *GetModuleReques return out, nil } +func (c *moduleServiceClient) GetModules(ctx context.Context, in *GetModulesRequest, opts ...grpc.CallOption) (*GetModulesResponse, error) { + out := new(GetModulesResponse) + err := c.cc.Invoke(ctx, "/ModuleService/GetModules", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *moduleServiceClient) GetEventsForModules(ctx context.Context, in *GetModulesRequest, opts ...grpc.CallOption) (*GetEventsResponse, error) { + out := new(GetEventsResponse) + err := c.cc.Invoke(ctx, "/ModuleService/GetEventsForModules", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ModuleServiceServer is the server API for ModuleService service. // All implementations must embed UnimplementedModuleServiceServer // for forward compatibility type ModuleServiceServer interface { GetModule(context.Context, *GetModuleRequest) (*GetModuleResponse, error) + GetModules(context.Context, *GetModulesRequest) (*GetModulesResponse, error) + GetEventsForModules(context.Context, *GetModulesRequest) (*GetEventsResponse, error) mustEmbedUnimplementedModuleServiceServer() } @@ -57,6 +79,12 @@ type UnimplementedModuleServiceServer struct { func (UnimplementedModuleServiceServer) GetModule(context.Context, *GetModuleRequest) (*GetModuleResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetModule not implemented") } +func (UnimplementedModuleServiceServer) GetModules(context.Context, *GetModulesRequest) (*GetModulesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetModules not implemented") +} +func (UnimplementedModuleServiceServer) GetEventsForModules(context.Context, *GetModulesRequest) (*GetEventsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetEventsForModules not implemented") +} func (UnimplementedModuleServiceServer) mustEmbedUnimplementedModuleServiceServer() {} // UnsafeModuleServiceServer may be embedded to opt out of forward compatibility for this service. @@ -88,6 +116,42 @@ func _ModuleService_GetModule_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _ModuleService_GetModules_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetModulesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ModuleServiceServer).GetModules(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ModuleService/GetModules", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ModuleServiceServer).GetModules(ctx, req.(*GetModulesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ModuleService_GetEventsForModules_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetModulesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ModuleServiceServer).GetEventsForModules(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ModuleService/GetEventsForModules", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ModuleServiceServer).GetEventsForModules(ctx, req.(*GetModulesRequest)) + } + return interceptor(ctx, in, info, handler) +} + // ModuleService_ServiceDesc is the grpc.ServiceDesc for ModuleService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -99,6 +163,14 @@ var ModuleService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetModule", Handler: _ModuleService_GetModule_Handler, }, + { + MethodName: "GetModules", + Handler: _ModuleService_GetModules_Handler, + }, + { + MethodName: "GetEventsForModules", + Handler: _ModuleService_GetEventsForModules_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "modules.proto", diff --git a/services/data-manager/service/db/dbEvents.go b/services/data-manager/service/db/dbEvents.go index 2296de8..0686695 100644 --- a/services/data-manager/service/db/dbEvents.go +++ b/services/data-manager/service/db/dbEvents.go @@ -131,25 +131,37 @@ func findEventByDayWeekStartEndNameCourse(event model.Event, course string, dao } } -func buildIcalQueryForModules(modules []model.FeedCollection) dbx.Expression { +func buildIcalQueryForModules(modulesUuid []string) dbx.Expression { + + // check uuids against sql injection + // uuids are generated by the system and are not user input + // following the pattern of only containing alphanumeric characters and dashes + + for _, moduleUuid := range modulesUuid { + if !IsSafeIdentifier(moduleUuid) { + slog.Warn("Module UUID is not safe: ", "moduleUuid", moduleUuid) + return dbx.HashExp{} + } + + } // build where conditions for each module //first check if modules is empty - if len(modules) == 0 { + if len(modulesUuid) == 0 { return dbx.HashExp{} } //second check if modules has only one element - if len(modules) == 1 { - return dbx.HashExp{"uuid": modules[0].UUID} + if len(modulesUuid) == 1 { + return dbx.HashExp{"uuid": modulesUuid[0]} } //third check if modules has more than one element var wheres []dbx.Expression - for _, module := range modules { - where := dbx.HashExp{"uuid": module.UUID} + for _, moduleUuid := range modulesUuid { + where := dbx.HashExp{"uuid": moduleUuid} wheres = append(wheres, where) } @@ -162,18 +174,18 @@ func buildIcalQueryForModules(modules []model.FeedCollection) dbx.Expression { // GetPlanForModules returns all events for the given modules with the given course // used for the ical feed -func GetPlanForModules(app *pocketbase.PocketBase, modules map[string]model.FeedCollection) (model.Events, error) { +func GetPlanForModules(app *pocketbase.PocketBase, modules []string) (model.Events, error) { var events model.Events - modulesArray := make([]model.FeedCollection, 0, len(modules)) + modulesArray := make([]string, 0, len(modules)) for _, value := range modules { modulesArray = append(modulesArray, value) } // iterate over modules in 100 batch sizes for i := 0; i < len(modules); i += 100 { - var moduleBatch []model.FeedCollection + var moduleBatch []string if i+100 > len(modules) { moduleBatch = modulesArray[i:] diff --git a/services/data-manager/service/db/dbEvents_test.go b/services/data-manager/service/db/dbEvents_test.go index 14542e0..5941c58 100644 --- a/services/data-manager/service/db/dbEvents_test.go +++ b/services/data-manager/service/db/dbEvents_test.go @@ -18,14 +18,13 @@ package db import ( "github.com/pocketbase/dbx" - "htwkalender/data-manager/model" "reflect" "testing" ) func Test_buildIcalQueryForModules(t *testing.T) { type args struct { - modules []model.FeedCollection + modules []string } tests := []struct { name string @@ -34,17 +33,17 @@ func Test_buildIcalQueryForModules(t *testing.T) { }{ { name: "empty modules", - args: args{modules: []model.FeedCollection{}}, + args: args{modules: []string{}}, want: dbx.HashExp{}, }, { name: "one module", - args: args{modules: []model.FeedCollection{{Name: "test", Course: "test", UUID: "test"}}}, + args: args{modules: []string{"test"}}, want: dbx.HashExp{"uuid": "test"}, }, { name: "two modules", - args: args{modules: []model.FeedCollection{{Name: "test", Course: "test", UUID: "test"}, {Name: "test2", Course: "test2", UUID: "test2"}}}, + args: args{modules: []string{"test", "test2"}}, want: dbx.Or(dbx.HashExp{"uuid": "test"}, dbx.HashExp{"uuid": "test2"}), }, } diff --git a/services/data-manager/service/db/dbFunctions.go b/services/data-manager/service/db/dbFunctions.go index 05cd48b..3f6f2b6 100644 --- a/services/data-manager/service/db/dbFunctions.go +++ b/services/data-manager/service/db/dbFunctions.go @@ -19,9 +19,26 @@ package db import ( "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/models" + "log/slog" + "regexp" ) func FindCollection(app *pocketbase.PocketBase, collectionName string) (*models.Collection, error) { collection, dbError := app.Dao().FindCollectionByNameOrId(collectionName) return collection, dbError } + +// IsSafeIdentifier check uuids against sql injection +// uuids are generated by the system and are not user input +// following the pattern of only containing alphanumeric characters and dashes +func IsSafeIdentifier(uuid string) bool { + // Define a regular expression that matches only valid UUID characters (alphanumeric and dashes) + validUUIDPattern := `^[a-zA-Z0-9-]+$` + match, err := regexp.MatchString(validUUIDPattern, uuid) + if err != nil { + // Handle the error according to your application's needs + slog.Warn("Invalid UUID pattern", "uuid", uuid) + return false + } + return match +} diff --git a/services/data-manager/service/db/dbFunctions_test.go b/services/data-manager/service/db/dbFunctions_test.go new file mode 100644 index 0000000..2f1612f --- /dev/null +++ b/services/data-manager/service/db/dbFunctions_test.go @@ -0,0 +1,50 @@ +package db + +import "testing" + +func TestIsSafeIdentifier(t *testing.T) { + type args struct { + uuid string + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "Test safe identifier", + args: args{ + uuid: "1234567890-1234567890-1234567890-1234567890", + }, + want: true, + }, + { + name: "Test safe identifier", + args: args{ + uuid: "1234567890-1234567890-1234567890-1234567890", + }, + want: true, + }, + { + name: "Test safe identifier", + args: args{ + uuid: "77eddc32-c49d-5d0a-8c36-17b266396641", + }, + want: true, + }, + { + name: "Test unsafe identifier", + args: args{ + uuid: "77eddc32-c49d-5d0a-8c36-17/1!!b266396641-", + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := IsSafeIdentifier(tt.args.uuid); got != tt.want { + t.Errorf("IsSafeIdentifier() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/services/data-manager/service/grpc/mapper.go b/services/data-manager/service/grpc/mapper.go index b352d45..01f439c 100644 --- a/services/data-manager/service/grpc/mapper.go +++ b/services/data-manager/service/grpc/mapper.go @@ -23,3 +23,11 @@ func eventToProto(event *model.Event) *pb.Event { Semester: event.Semester, } } + +func eventsToProto(events model.Events) []*pb.Event { + protoEvents := make([]*pb.Event, 0) + for _, event := range events { + protoEvents = append(protoEvents, eventToProto(&event)) + } + return protoEvents +} diff --git a/services/data-manager/service/grpc/server.go b/services/data-manager/service/grpc/server.go index 9ad33f9..7841b5e 100644 --- a/services/data-manager/service/grpc/server.go +++ b/services/data-manager/service/grpc/server.go @@ -67,3 +67,15 @@ func StartGRPCServer(app *pocketbase.PocketBase) { log.Fatalf("failed to serve: %v", err) } } + +func (s *ModulesGrpcHandler) GetEventsForModules(ctx context.Context, in *pb.GetModulesRequest) (*pb.GetEventsResponse, error) { + + events, err := db.GetPlanForModules(s.app, in.Uuids) + if err != nil { + return nil, err + } + + return &pb.GetEventsResponse{ + Events: eventsToProto(events), + }, nil +} diff --git a/services/ical/service/connector/grpc/events.go b/services/ical/service/connector/grpc/events.go new file mode 100644 index 0000000..fc82755 --- /dev/null +++ b/services/ical/service/connector/grpc/events.go @@ -0,0 +1,34 @@ +package grpc + +import ( + "context" + "google.golang.org/grpc" + pb "htwkalender/common/genproto/modules" + "htwkalender/ical/model" + "log/slog" + "time" +) + +func GetEvents(modules []model.FeedModule, conn *grpc.ClientConn) (model.Events, error) { + c := pb.NewModuleServiceClient(conn) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + // List of uuids + uuids := make([]string, 0) + for _, module := range modules { + uuids = append(uuids, module.UUID) + } + + r, err := c.GetEventsForModules(ctx, &pb.GetModulesRequest{Uuids: uuids}) + if err != nil { + slog.Error("could not get modules: %v", "error", err) + } + + events := make(model.Events, 0) + for _, event := range r.GetEvents() { + events = append(events, protoToEvent(event)) + } + + return events, nil +} diff --git a/services/ical/service/connector/grpc/modules.go b/services/ical/service/connector/grpc/modules.go index 0574cf7..aa47d79 100644 --- a/services/ical/service/connector/grpc/modules.go +++ b/services/ical/service/connector/grpc/modules.go @@ -33,6 +33,42 @@ func GetModuleWithEvents(module model.FeedModule, conn *grpc.ClientConn) (model. }, nil } +func GetModulesWithEvents(modules []model.FeedModule, conn *grpc.ClientConn) ([]model.Module, error) { + c := pb.NewModuleServiceClient(conn) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + // List of uuids + uuids := make([]string, 0) + for _, module := range modules { + uuids = append(uuids, module.UUID) + } + + r, err := c.GetModules(ctx, &pb.GetModulesRequest{Uuids: uuids}) + if err != nil { + slog.Error("could not get modules: %v", "error", err) + } + + moduleList := make([]model.Module, 0) + for _, module := range r.GetModules() { + events := make([]model.Event, 0) + for _, event := range module.Events { + events = append(events, protoToEvent(event)) + } + + moduleList = append(moduleList, model.Module{ + UUID: module.Uuid, + Name: module.Name, + Prof: module.Prof, + Course: module.Course, + Semester: module.Semester, + Events: events, + }) + } + + return moduleList, nil +} + func protoToEvent(event *pb.Event) model.Event { return model.Event{ diff --git a/services/ical/service/ical/ical.go b/services/ical/service/ical/ical.go index 42f2227..be57533 100644 --- a/services/ical/service/ical/ical.go +++ b/services/ical/service/ical/ical.go @@ -21,13 +21,10 @@ func Feed(app model.AppType, token string) (string, error) { var events model.Events - for _, module := range feed.Modules { - moduleWithEvents, err := htwkalenderGrpc.GetModuleWithEvents(module, app.GrpcClient) - if err != nil { - return "", err - } - - events = append(events, moduleWithEvents.Events...) + // Get all events for modules + events, err = htwkalenderGrpc.GetEvents(feed.Modules, app.GrpcClient) + if err != nil { + return "", err } // Sort events by start date diff --git a/services/protobuf/modules.proto b/services/protobuf/modules.proto index 1b608bd..1ba6c27 100644 --- a/services/protobuf/modules.proto +++ b/services/protobuf/modules.proto @@ -4,6 +4,8 @@ option go_package = "htwkalender/common/modules"; service ModuleService { rpc GetModule(GetModuleRequest) returns (GetModuleResponse) {} + rpc GetModules(GetModulesRequest) returns (GetModulesResponse) {} + rpc GetEventsForModules(GetModulesRequest) returns (GetEventsResponse) {} } message Event { @@ -36,6 +38,18 @@ message GetModuleRequest { string uuid = 1; } +message GetModulesRequest { + repeated string uuids = 1; +} + message GetModuleResponse { Module module = 1; +} + +message GetModulesResponse { + repeated Module modules = 1; +} + +message GetEventsResponse { + repeated Event events = 1; } \ No newline at end of file