package server import ( "context" "errors" "connectrpc.com/connect" "github.com/tigorlazuardi/bluemage/go/api" "github.com/tigorlazuardi/bluemage/go/gen/converter" subreddits "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1" v1connect "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1/subredditsv1connect" "github.com/tigorlazuardi/bluemage/go/pkg/errs" ) var subredditConverter = converter.SubredditConverterImpl{} type SubredditHandler struct { API *api.API v1connect.UnimplementedSubredditsServiceHandler } // SubredditExists checks if the subreddits already handled in database. // THIS ENDPOINT DOES NOT CALL REDDIT API, ONLY DATABASE. // // Use ResolveSubredditName to check if subreddit actually exists in Reddit. func (su *SubredditHandler) SubredditExists(ctx context.Context, request *connect.Request[subreddits.SubredditExistsRequest]) (*connect.Response[subreddits.SubredditExistsResponse], error) { exist, err := su.API.SubredditExists(ctx, request.Msg.Name) if err != nil { return nil, errs.IntoConnectError(err) } resp := &subreddits.SubredditExistsResponse{ Exist: exist, } return connect.NewResponse(resp), nil } // Count the existing subreddits using given filter. // Default values count all. func (su *SubredditHandler) CountSubreddits(ctx context.Context, request *connect.Request[subreddits.CountSubredditsRequest]) (*connect.Response[subreddits.CountSubredditsResponse], error) { countRequest := subredditConverter.ProtoCountSubredditsRequestToAPICountSubredditsRequest(request.Msg) count, err := su.API.CountSubreddits(ctx, countRequest) if err != nil { return nil, errs.IntoConnectError(err) } resp := &subreddits.CountSubredditsResponse{ Count: count, } return connect.NewResponse(resp), nil } // CreateSubreddit creates a new subreddit // Returns the subreddit name. // // Returns the following error codes: // - connect.CodeAlreadyExists if subreddit with the same name already exists. // - connect.CodeInvalidArgument if validation failed, e.g. Invalid schedule cron format. // - connect.CodeNotFound if the subreddit does not exist. func (su *SubredditHandler) CreateSubreddit(ctx context.Context, request *connect.Request[subreddits.CreateSubredditRequest]) (*connect.Response[subreddits.CreateSubredditResponse], error) { resolveRequest := subredditConverter.ProtoCreateSubredditRequestToAPISubredditResolveNameRequest(request.Msg) resolved, err := su.API.SubredditResolveName(ctx, resolveRequest) if err != nil { return nil, errs.IntoConnectError(err) } request.Msg.Name = resolved data := subredditConverter.CreateSubredditRequestToModelsSubredditSetter(request.Msg) if err := su.API.SubredditCreate(ctx, data); err != nil { return nil, errs.IntoConnectError(err) } resp := &subreddits.CreateSubredditResponse{ Name: resolved, } return connect.NewResponse(resp), nil } // GetSubreddit returns a subreddit by its name. // // Returns error with connect.CodeNotFound if subreddit does not exist. func (su *SubredditHandler) GetSubreddit(ctx context.Context, request *connect.Request[subreddits.GetSubredditRequest]) (*connect.Response[subreddits.GetSubredditResponse], error) { data, err := su.API.GetSubreddit(ctx, request.Msg.Name) if err != nil { return nil, errs.IntoConnectError(err) } resp := &subreddits.GetSubredditResponse{ Subreddit: subredditConverter.JetSubredditToProtoSubreddit(data), } return connect.NewResponse(resp), nil } // ListSubreddits returns a list of subreddits. func (su *SubredditHandler) ListSubreddits(ctx context.Context, request *connect.Request[subreddits.ListSubredditsRequest]) (*connect.Response[subreddits.ListSubredditsResponse], error) { req := subredditConverter.ProtoListSubredditsRequestToAPIListSubredditsRequest(request.Msg) subs, err := su.API.ListSubreddits(ctx, req) if err != nil { return nil, errs.IntoConnectError(err) } resp := &subreddits.ListSubredditsResponse{ Subreddits: subredditConverter.JetSubredditsToProtoSubreddits(subs), } return connect.NewResponse(resp), nil } // UpdateSubreddit updates a subreddit. // // Only the fields that are set in the request will be updated. // // Returns error with connect.CodeNotFound if subreddit does not exist. func (su *SubredditHandler) UpdateSubreddit(ctx context.Context, request *connect.Request[subreddits.UpdateSubredditRequest]) (*connect.Response[subreddits.UpdateSubredditResponse], error) { exist, err := su.API.SubredditExists(ctx, request.Msg.Name) if err != nil { return nil, errs.IntoConnectError(err) } if !exist { err := errs. Failf("subreddit '%s' is not registered", request.Msg.Name). Details("request", request.Msg). Code(connect.CodeNotFound) return nil, errs.IntoConnectError(err) } set := subredditConverter.ProtoSubredditSetterToBobSubredditSetter(request.Msg.Set) err = su.API.UpdateSubreddit(ctx, request.Msg.Name, set) if err != nil { return nil, errs.IntoConnectError(err) } resp := &subreddits.UpdateSubredditResponse{ Name: request.Msg.Name, } return connect.NewResponse(resp), nil } // DeleteSubreddit deletes a subreddit. // // Returns error with connect.CodeNotFound if subreddit does not exist. func (su *SubredditHandler) DeleteSubreddit(ctx context.Context, request *connect.Request[subreddits.DeleteSubredditRequest]) (*connect.Response[subreddits.DeleteSubredditResponse], error) { exist, err := su.API.SubredditExists(ctx, request.Msg.Name) if err != nil { return nil, errs.IntoConnectError(err) } if !exist { err := errs. Failf("subreddit '%s' is not registered", request.Msg.Name). Code(connect.CodeNotFound) return nil, errs.IntoConnectError(err) } return nil, connect.NewError(connect.CodeUnimplemented, errors.New("deleting subreddit is still unimplemented")) } // ResolveSubredditName resolves the given subreddit name. // // The returned resolved_name is the name that is actually // used in Reddit. // // Returns error with connect.CodeNotFound if subreddit does not exist. // So this rpc endpoint also acts to check subreddit's existence. func (su *SubredditHandler) ResolveSubredditName(ctx context.Context, request *connect.Request[subreddits.ResolveSubredditNameRequest]) (*connect.Response[subreddits.ResolveSubredditNameResponse], error) { req := subredditConverter.ProtoResolveSubredditNameRequestToAPISubredditResolveName(request.Msg) resolved, err := su.API.SubredditResolveName(ctx, req) if err != nil { return nil, errs.IntoConnectError(err) } resp := &subreddits.ResolveSubredditNameResponse{ Resolved: resolved, } return connect.NewResponse(resp), nil }