From 826266404b6b7b5e4441b525d8cb553b6623e5a8 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Tue, 12 Sep 2023 16:40:39 +0200 Subject: [PATCH] renamed `GetTopNews` -> `GetTopNewsAlert` --- server/api/tumdev/campus_backend.pb.gw.go | 37 +++++++---- server/api/tumdev/campus_backend.proto | 11 +++- server/api/tumdev/campus_backend.swagger.json | 66 +++++++++++-------- server/api/tumdev/campus_backend_grpc.pb.go | 28 ++++---- server/backend/news.go | 25 ++++++- server/backend/news_test.go | 27 ++++---- 6 files changed, 119 insertions(+), 75 deletions(-) diff --git a/server/api/tumdev/campus_backend.pb.gw.go b/server/api/tumdev/campus_backend.pb.gw.go index a143fd43..2490593c 100644 --- a/server/api/tumdev/campus_backend.pb.gw.go +++ b/server/api/tumdev/campus_backend.pb.gw.go @@ -32,20 +32,20 @@ var _ = runtime.String var _ = utilities.NewDoubleArray var _ = metadata.Join -func request_Campus_GetTopNews_0(ctx context.Context, marshaler runtime.Marshaler, client CampusClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { +func request_Campus_GetTopNewsAlert_0(ctx context.Context, marshaler runtime.Marshaler, client CampusClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq emptypb.Empty var metadata runtime.ServerMetadata - msg, err := client.GetTopNews(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.GetTopNewsAlert(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Campus_GetTopNews_0(ctx context.Context, marshaler runtime.Marshaler, server CampusServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { +func local_request_Campus_GetTopNewsAlert_0(ctx context.Context, marshaler runtime.Marshaler, server CampusServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq emptypb.Empty var metadata runtime.ServerMetadata - msg, err := server.GetTopNews(ctx, &protoReq) + msg, err := server.GetTopNewsAlert(ctx, &protoReq) return msg, metadata, err } @@ -1312,7 +1312,7 @@ func local_request_Campus_RemoveDevice_0(ctx context.Context, marshaler runtime. // Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterCampusHandlerFromEndpoint instead. func RegisterCampusHandlerServer(ctx context.Context, mux *runtime.ServeMux, server CampusServer) error { - mux.Handle("GET", pattern_Campus_GetTopNews_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Campus_GetTopNewsAlert_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -1320,12 +1320,12 @@ func RegisterCampusHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/api.Campus/GetTopNews", runtime.WithHTTPPathPattern("/news/top")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/api.Campus/GetTopNewsAlert", runtime.WithHTTPPathPattern("/news/alerts/top")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Campus_GetTopNews_0(annotatedContext, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Campus_GetTopNewsAlert_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { @@ -1333,7 +1333,7 @@ func RegisterCampusHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser return } - forward_Campus_GetTopNews_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Campus_GetTopNewsAlert_0(annotatedContext, mux, outboundMarshaler, w, req, response_Campus_GetTopNewsAlert_0{resp}, mux.GetForwardResponseOptions()...) }) @@ -2253,25 +2253,25 @@ func RegisterCampusHandler(ctx context.Context, mux *runtime.ServeMux, conn *grp // "CampusClient" to call the correct interceptors. func RegisterCampusHandlerClient(ctx context.Context, mux *runtime.ServeMux, client CampusClient) error { - mux.Handle("GET", pattern_Campus_GetTopNews_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Campus_GetTopNewsAlert_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/api.Campus/GetTopNews", runtime.WithHTTPPathPattern("/news/top")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/api.Campus/GetTopNewsAlert", runtime.WithHTTPPathPattern("/news/alerts/top")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Campus_GetTopNews_0(annotatedContext, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Campus_GetTopNewsAlert_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Campus_GetTopNews_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Campus_GetTopNewsAlert_0(annotatedContext, mux, outboundMarshaler, w, req, response_Campus_GetTopNewsAlert_0{resp}, mux.GetForwardResponseOptions()...) }) @@ -3048,6 +3048,15 @@ func RegisterCampusHandlerClient(ctx context.Context, mux *runtime.ServeMux, cli return nil } +type response_Campus_GetTopNewsAlert_0 struct { + proto.Message +} + +func (m response_Campus_GetTopNewsAlert_0) XXX_ResponseBody() interface{} { + response := m.Message.(*GetTopNewsAlertReply) + return response.Alert +} + type response_Campus_GetNewsSources_0 struct { proto.Message } @@ -3139,7 +3148,7 @@ func (m response_Campus_GetDishes_0) XXX_ResponseBody() interface{} { } var ( - pattern_Campus_GetTopNews_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"news", "top"}, "")) + pattern_Campus_GetTopNewsAlert_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"news", "alerts", "top"}, "")) pattern_Campus_GetNewsSources_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"news", "sources"}, "")) @@ -3213,7 +3222,7 @@ var ( ) var ( - forward_Campus_GetTopNews_0 = runtime.ForwardResponseMessage + forward_Campus_GetTopNewsAlert_0 = runtime.ForwardResponseMessage forward_Campus_GetNewsSources_0 = runtime.ForwardResponseMessage diff --git a/server/api/tumdev/campus_backend.proto b/server/api/tumdev/campus_backend.proto index acf930d4..0d59602e 100644 --- a/server/api/tumdev/campus_backend.proto +++ b/server/api/tumdev/campus_backend.proto @@ -13,9 +13,10 @@ import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; service Campus { - rpc GetTopNews (google.protobuf.Empty) returns (GetTopNewsReply) { + rpc GetTopNewsAlert (google.protobuf.Empty) returns (GetTopNewsAlertReply) { option (google.api.http) = { - get: "/news/top" + get: "/news/alerts/top" + response_body: "alert" }; } @@ -386,7 +387,11 @@ message NewsSource { string icon = 3; } -message GetTopNewsReply { +message GetTopNewsAlertReply { + NewsAlert alert = 1; +} + +message NewsAlert { string image_url = 1; string link = 2; google.protobuf.Timestamp created = 3; diff --git a/server/api/tumdev/campus_backend.swagger.json b/server/api/tumdev/campus_backend.swagger.json index 81962c9a..ebc58afb 100644 --- a/server/api/tumdev/campus_backend.swagger.json +++ b/server/api/tumdev/campus_backend.swagger.json @@ -835,18 +835,14 @@ ] } }, - "/news/sources": { + "/news/alerts/top": { "get": { - "operationId": "Campus_GetNewsSources", + "operationId": "Campus_GetTopNewsAlert", "responses": { "200": { "description": "", "schema": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/apiNewsSource" - } + "$ref": "#/definitions/apiNewsAlert" } }, "default": { @@ -861,14 +857,18 @@ ] } }, - "/news/top": { + "/news/sources": { "get": { - "operationId": "Campus_GetTopNews", + "operationId": "Campus_GetNewsSources", "responses": { "200": { - "description": "A successful response.", + "description": "", "schema": { - "$ref": "#/definitions/apiGetTopNewsReply" + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/apiNewsSource" + } } }, "default": { @@ -1706,26 +1706,11 @@ } } }, - "apiGetTopNewsReply": { + "apiGetTopNewsAlertReply": { "type": "object", "properties": { - "imageUrl": { - "type": "string" - }, - "link": { - "type": "string" - }, - "created": { - "type": "string", - "format": "date-time" - }, - "from": { - "type": "string", - "format": "date-time" - }, - "to": { - "type": "string", - "format": "date-time" + "alert": { + "$ref": "#/definitions/apiNewsAlert" } } }, @@ -1911,6 +1896,29 @@ } } }, + "apiNewsAlert": { + "type": "object", + "properties": { + "imageUrl": { + "type": "string" + }, + "link": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "from": { + "type": "string", + "format": "date-time" + }, + "to": { + "type": "string", + "format": "date-time" + } + } + }, "apiNewsSource": { "type": "object", "properties": { diff --git a/server/api/tumdev/campus_backend_grpc.pb.go b/server/api/tumdev/campus_backend_grpc.pb.go index af68c745..4c8cee17 100644 --- a/server/api/tumdev/campus_backend_grpc.pb.go +++ b/server/api/tumdev/campus_backend_grpc.pb.go @@ -20,7 +20,7 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - Campus_GetTopNews_FullMethodName = "/api.Campus/GetTopNews" + Campus_GetTopNewsAlert_FullMethodName = "/api.Campus/GetTopNewsAlert" Campus_GetNewsSources_FullMethodName = "/api.Campus/GetNewsSources" Campus_SearchRooms_FullMethodName = "/api.Campus/SearchRooms" Campus_GetLocations_FullMethodName = "/api.Campus/GetLocations" @@ -62,7 +62,7 @@ const ( // // 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 CampusClient interface { - GetTopNews(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetTopNewsReply, error) + GetTopNewsAlert(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetTopNewsAlertReply, error) GetNewsSources(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*NewsSourceReply, error) SearchRooms(ctx context.Context, in *SearchRoomsRequest, opts ...grpc.CallOption) (*SearchRoomsReply, error) // a location is a campus location/building, e.g. "Garching Forschungszentrum" @@ -113,9 +113,9 @@ func NewCampusClient(cc grpc.ClientConnInterface) CampusClient { return &campusClient{cc} } -func (c *campusClient) GetTopNews(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetTopNewsReply, error) { - out := new(GetTopNewsReply) - err := c.cc.Invoke(ctx, Campus_GetTopNews_FullMethodName, in, out, opts...) +func (c *campusClient) GetTopNewsAlert(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetTopNewsAlertReply, error) { + out := new(GetTopNewsAlertReply) + err := c.cc.Invoke(ctx, Campus_GetTopNewsAlert_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -441,7 +441,7 @@ func (c *campusClient) RemoveDevice(ctx context.Context, in *RemoveDeviceRequest // All implementations must embed UnimplementedCampusServer // for forward compatibility type CampusServer interface { - GetTopNews(context.Context, *emptypb.Empty) (*GetTopNewsReply, error) + GetTopNewsAlert(context.Context, *emptypb.Empty) (*GetTopNewsAlertReply, error) GetNewsSources(context.Context, *emptypb.Empty) (*NewsSourceReply, error) SearchRooms(context.Context, *SearchRoomsRequest) (*SearchRoomsReply, error) // a location is a campus location/building, e.g. "Garching Forschungszentrum" @@ -489,8 +489,8 @@ type CampusServer interface { type UnimplementedCampusServer struct { } -func (UnimplementedCampusServer) GetTopNews(context.Context, *emptypb.Empty) (*GetTopNewsReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetTopNews not implemented") +func (UnimplementedCampusServer) GetTopNewsAlert(context.Context, *emptypb.Empty) (*GetTopNewsAlertReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTopNewsAlert not implemented") } func (UnimplementedCampusServer) GetNewsSources(context.Context, *emptypb.Empty) (*NewsSourceReply, error) { return nil, status.Errorf(codes.Unimplemented, "method GetNewsSources not implemented") @@ -610,20 +610,20 @@ func RegisterCampusServer(s grpc.ServiceRegistrar, srv CampusServer) { s.RegisterService(&Campus_ServiceDesc, srv) } -func _Campus_GetTopNews_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Campus_GetTopNewsAlert_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(emptypb.Empty) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(CampusServer).GetTopNews(ctx, in) + return srv.(CampusServer).GetTopNewsAlert(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Campus_GetTopNews_FullMethodName, + FullMethod: Campus_GetTopNewsAlert_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CampusServer).GetTopNews(ctx, req.(*emptypb.Empty)) + return srv.(CampusServer).GetTopNewsAlert(ctx, req.(*emptypb.Empty)) } return interceptor(ctx, in, info, handler) } @@ -1266,8 +1266,8 @@ var Campus_ServiceDesc = grpc.ServiceDesc{ HandlerType: (*CampusServer)(nil), Methods: []grpc.MethodDesc{ { - MethodName: "GetTopNews", - Handler: _Campus_GetTopNews_Handler, + MethodName: "GetTopNewsAlert", + Handler: _Campus_GetTopNewsAlert_Handler, }, { MethodName: "GetNewsSources", diff --git a/server/backend/news.go b/server/backend/news.go index a5bc0877..1e59df59 100644 --- a/server/backend/news.go +++ b/server/backend/news.go @@ -37,7 +37,30 @@ func (s *CampusServer) GetNewsSources(ctx context.Context, _ *emptypb.Empty) (ne return &pb.NewsSourceReply{Sources: resp}, nil } -func (s *CampusServer) GetTopNews(ctx context.Context, _ *emptypb.Empty) (*pb.GetTopNewsReply, error) { +func (s *CampusServer) GetTopNewsAlert(ctx context.Context, _ *emptypb.Empty) (*pb.GetTopNewsAlertReply, error) { + if err := s.checkDevice(ctx); err != nil { + return nil, err + } + + var res *model.NewsAlert + err := s.db.Joins("Files").Where("NOW() between `from` and `to`").First(&res).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, status.Error(codes.NotFound, "no currenty active top news") + } else if err != nil { + log.WithError(err).Error("could not GetTopNewsAlert") + return nil, status.Error(codes.Internal, "could not GetTopNewsAlert") + } + + return &pb.GetTopNewsAlertReply{Alert: &pb.NewsAlert{ + ImageUrl: res.Files.URL.String, + Link: res.Link.String, + Created: timestamppb.New(res.Created), + From: timestamppb.New(res.From), + To: timestamppb.New(res.To), + }}, nil +} + +func (s *CampusServer) GetNewsAlerts(ctx context.Context, _ *pb.GetNewsAlertsRequest) (*pb.GetNewsAlertsReply, error) { if err := s.checkDevice(ctx); err != nil { return nil, err } diff --git a/server/backend/news_test.go b/server/backend/news_test.go index 39ee5680..9b84f455 100644 --- a/server/backend/news_test.go +++ b/server/backend/news_test.go @@ -120,9 +120,9 @@ func (s *NewsSuite) Test_GetNewsSourcesNone() { require.Equal(s.T(), expectedResp, response) } -const ExpectedGetTopNewsQuery = "SELECT `news_alert`.`news_alert`,`news_alert`.`file`,`news_alert`.`name`,`news_alert`.`link`,`news_alert`.`created`,`news_alert`.`from`,`news_alert`.`to`,`Files`.`file` AS `Files__file`,`Files`.`name` AS `Files__name`,`Files`.`path` AS `Files__path`,`Files`.`downloads` AS `Files__downloads`,`Files`.`url` AS `Files__url`,`Files`.`downloaded` AS `Files__downloaded` FROM `news_alert` LEFT JOIN `files` `Files` ON `news_alert`.`file` = `Files`.`file` WHERE NOW() between `from` and `to` ORDER BY `news_alert`.`news_alert` LIMIT 1" +const ExpectedGetTopNewsAlertQuery = "SELECT `news_alert`.`news_alert`,`news_alert`.`file`,`news_alert`.`name`,`news_alert`.`link`,`news_alert`.`created`,`news_alert`.`from`,`news_alert`.`to`,`Files`.`file` AS `Files__file`,`Files`.`name` AS `Files__name`,`Files`.`path` AS `Files__path`,`Files`.`downloads` AS `Files__downloads`,`Files`.`url` AS `Files__url`,`Files`.`downloaded` AS `Files__downloaded` FROM `news_alert` LEFT JOIN `files` `Files` ON `news_alert`.`file` = `Files`.`file` WHERE NOW() between `from` and `to` ORDER BY `news_alert`.`news_alert` LIMIT 1" -func (s *NewsSuite) Test_GetTopNewsOne() { +func (s *NewsSuite) Test_GetTopNewsAlertOne() { expectedAlert := model.NewsAlert{ NewsAlert: 1, FilesID: 3001, @@ -140,38 +140,37 @@ func (s *NewsSuite) Test_GetTopNewsOne() { From: time.Time.Add(time.Now(), time.Hour*-2), To: time.Time.Add(time.Now(), time.Hour*2), } - s.mock.ExpectQuery(regexp.QuoteMeta(ExpectedGetTopNewsQuery)). + s.mock.ExpectQuery(regexp.QuoteMeta(ExpectedGetTopNewsAlertQuery)). WillReturnRows(sqlmock.NewRows([]string{"news_alert", "file", "name", "link", "created", "from", "to", "Files__file", "Files__name", "Files__path", "Files__downloads", "Files__url", "Files__downloaded"}). AddRow(expectedAlert.NewsAlert, expectedAlert.FilesID, expectedAlert.Name, expectedAlert.Link, expectedAlert.Created, expectedAlert.From, expectedAlert.To, expectedAlert.Files.File, expectedAlert.Files.Name, expectedAlert.Files.Path, expectedAlert.Files.Downloads, expectedAlert.Files.URL, expectedAlert.Files.Downloaded)) meta := metadata.MD{} server := CampusServer{db: s.DB, deviceBuf: s.deviceBuf} - response, err := server.GetTopNews(metadata.NewIncomingContext(context.Background(), meta), nil) + response, err := server.GetTopNewsAlert(metadata.NewIncomingContext(context.Background(), meta), nil) require.NoError(s.T(), err) - require.Equal(s.T(), &pb.GetTopNewsReply{ + require.Equal(s.T(), &pb.GetTopNewsAlertReply{Alert: &pb.NewsAlert{ ImageUrl: expectedAlert.Files.URL.String, Link: expectedAlert.Link.String, Created: timestamppb.New(expectedAlert.Created), From: timestamppb.New(expectedAlert.From), - To: timestamppb.New(expectedAlert.To), - }, response) + To: timestamppb.New(expectedAlert.To)}}, response) } -func (s *NewsSuite) Test_GetTopNewsNone() { - s.mock.ExpectQuery(regexp.QuoteMeta(ExpectedGetTopNewsQuery)).WillReturnError(gorm.ErrRecordNotFound) +func (s *NewsSuite) Test_GetTopNewsAlertNone() { + s.mock.ExpectQuery(regexp.QuoteMeta(ExpectedGetTopNewsAlertQuery)).WillReturnError(gorm.ErrRecordNotFound) meta := metadata.MD{} server := CampusServer{db: s.DB, deviceBuf: s.deviceBuf} - response, err := server.GetTopNews(metadata.NewIncomingContext(context.Background(), meta), nil) + response, err := server.GetTopNewsAlert(metadata.NewIncomingContext(context.Background(), meta), nil) require.Equal(s.T(), status.Error(codes.NotFound, "no currenty active top news"), err) require.Nil(s.T(), response) } -func (s *NewsSuite) Test_GetTopNewsError() { - s.mock.ExpectQuery(regexp.QuoteMeta(ExpectedGetTopNewsQuery)).WillReturnError(gorm.ErrInvalidDB) +func (s *NewsSuite) Test_GetTopNewsAlertError() { + s.mock.ExpectQuery(regexp.QuoteMeta(ExpectedGetTopNewsAlertQuery)).WillReturnError(gorm.ErrInvalidDB) meta := metadata.MD{} server := CampusServer{db: s.DB, deviceBuf: s.deviceBuf} - response, err := server.GetTopNews(metadata.NewIncomingContext(context.Background(), meta), nil) - require.Equal(s.T(), status.Error(codes.Internal, "could not GetTopNews"), err) + response, err := server.GetTopNewsAlert(metadata.NewIncomingContext(context.Background(), meta), nil) + require.Equal(s.T(), status.Error(codes.Internal, "could not GetTopNewsAlert"), err) require.Nil(s.T(), response) }