Bluemage/go/server/subreddit_handlers.go

171 lines
6.5 KiB
Go

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
}