Commit: Bulk unfinished work

This commit is contained in:
2026-01-22 17:39:04 +01:00
parent 6c46b4efcc
commit 3a9acc42a2
68 changed files with 5047 additions and 1064 deletions

182
routers/todo/v1/todo.go Normal file
View File

@@ -0,0 +1,182 @@
package todov1
import (
"context"
"errors"
"log/slog"
"strconv"
"connectrpc.com/connect"
"git.kocoder.xyz/kocoded/vt/fx"
todov1 "git.kocoder.xyz/kocoded/vt/gen/todo/v1"
"git.kocoder.xyz/kocoded/vt/gen/todo/v1/todov1connect"
"git.kocoder.xyz/kocoded/vt/interceptors"
"git.kocoder.xyz/kocoded/vt/query"
"gorm.io/gen/field"
"gorm.io/gorm"
)
func NewTodoRoute(db *gorm.DB, logger *slog.Logger, oidcInterceptor *interceptors.AuthenticationInterceptor) fx.Handler {
path, handler := todov1connect.NewTodoServiceHandler(&todoService{logger: logger, db: db}, connect.WithInterceptors(oidcInterceptor))
return fx.NewRoute(path, handler)
}
type todoService struct {
logger *slog.Logger
db *gorm.DB
}
func (ts *todoService) GetTodo(ctx context.Context, req *todov1.GetTodosRequest) (*todov1.GetTodosResponse, error) {
s, ok := interceptors.SessionFromContext(ctx)
if !ok {
return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("No session set."))
}
t := query.Use(ts.db).Task
res, err := t.Where(t.ID.Eq(uint(req.Id))).Where(t.MandantID.Eq(s.MandantId)).First()
if err != nil {
return nil, connect.NewError(connect.CodeInternal, err)
}
tres := &todov1.GetTodosResponse{
Id: int64(res.ID),
Title: res.Titel,
Description: res.Description,
Status: todov1.Status(res.Status),
}
return tres, nil
// return &todov1.GetTodosResponse{
// Id: 1,
// Title: "Sample Todo",
// Description: "This is a sample todo item.",
// Status: todov1.Status_Doing,
// }, nil
}
func (ts *todoService) ContributeToQuery(f *todov1.Filter, q query.ITaskDo) query.ITaskDo {
t := query.Use(ts.db).Task
switch f.Field {
case todov1.Field_FieldDescription, todov1.Field_FieldTitle:
var field field.String
if f.Field == todov1.Field_FieldDescription {
field = t.Description
} else {
field = t.Titel
}
switch f.Operation {
case todov1.Operation_Equals:
q = q.Where(field.Eq(f.Value))
case todov1.Operation_NotEquals:
q = q.Where(field.Neq(f.Value))
case todov1.Operation_GreaterThan:
q = q.Where(field.Gt(f.Value))
case todov1.Operation_LessThan:
q = q.Where(field.Lt(f.Value))
case todov1.Operation_Like:
q = q.Where(field.Like(f.Value))
}
case todov1.Field_FieldId:
i, err := strconv.Atoi(f.Value)
if err != nil {
slog.Warn("Value not an int", "err", err)
return q
}
switch f.Operation {
case todov1.Operation_Equals:
q = q.Where(t.ID.Eq(uint(i)))
case todov1.Operation_NotEquals:
q = q.Where(t.ID.Neq(uint(i)))
case todov1.Operation_GreaterThan:
q = q.Where(t.ID.Gt(uint(i)))
case todov1.Operation_LessThan:
q = q.Where(t.ID.Lt(uint(i)))
}
case todov1.Field_FieldStatus:
i, err := strconv.Atoi(f.Value)
if err != nil {
slog.Warn("Value not an int", "err", err)
return q
}
switch f.Operation {
case todov1.Operation_Equals:
q = q.Where(t.Status.Eq(i))
case todov1.Operation_NotEquals:
q = q.Where(t.Status.Neq(i))
case todov1.Operation_GreaterThan:
q = q.Where(t.Status.Gt(i))
case todov1.Operation_LessThan:
q = q.Where(t.Status.Lt(i))
}
default:
return q
}
return q
}
func (ts *todoService) ListTodos(ctx context.Context, req *todov1.ListTodosRequest) (*todov1.ListTodosResponse, error) {
ts.logger.Info("ListTodos called", "request", req)
s, ok := interceptors.SessionFromContext(ctx)
if !ok {
return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("No session set."))
}
t := query.Use(ts.db).Task
taskQuery := t.Where(t.MandantID.Eq(s.MandantId))
for _, v := range req.Filters {
taskQuery = ts.ContributeToQuery(v, taskQuery)
}
taskQuery = taskQuery.Limit(int(req.PerPage)).Offset(int(req.Page))
if req.OrberBy != "" {
f, ok := t.GetFieldByName(req.OrberBy)
if ok {
if !req.Asc {
taskQuery = taskQuery.Order(f.Desc())
} else {
taskQuery = taskQuery.Order(f.Asc())
}
}
} else {
taskQuery = taskQuery.Order(t.ID.Asc())
}
tasks, err := taskQuery.Find()
if err != nil {
return nil, err
}
taskQuery = t.Where(t.MandantID.Eq(s.MandantId))
for _, v := range req.Filters {
taskQuery = ts.ContributeToQuery(v, taskQuery)
}
cnt, err := taskQuery.Count()
if err != nil {
ts.logger.Info("Counting Todos failed", "request", req, "err", err)
panic(err)
}
data := make([]*todov1.GetTodosResponse, len(tasks))
for i, p := range tasks {
data[i] = &todov1.GetTodosResponse{
Id: int64(p.ID),
Title: p.Titel,
Description: p.Description,
Status: todov1.Status(p.Status),
}
}
return &todov1.ListTodosResponse{
Data: data,
Meta: &todov1.Metadata{
TotalCount: int32(cnt),
},
}, nil
}

View File

@@ -0,0 +1,64 @@
syntax = "proto3";
package todo.v1;
enum Status {
Todo = 0;
NeedsMoreInfo = 1;
Doing = 2;
Done = 3;
}
enum Field {
FieldId = 0;
FieldTitle = 1;
FieldDescription = 2;
FieldStatus = 3;
}
enum Operation {
Equals = 0;
NotEquals = 1;
GreaterThan = 2;
LessThan = 3;
Like = 4;
}
message GetTodosRequest {
int32 id = 1;
}
message GetTodosResponse {
int64 id = 1;
string title = 2;
string description = 3;
Status status = 4;
}
message ListTodosRequest {
int32 page = 1;
int32 per_page = 2;
string orber_by = 3;
bool asc = 4;
repeated Filter filters = 5;
}
message Filter {
Field field = 1;
string value = 2;
Operation operation = 3;
}
message Metadata {
int32 totalCount = 1;
}
message ListTodosResponse {
repeated GetTodosResponse data = 1;
Metadata meta = 2;
}
service TodoService {
rpc GetTodo(GetTodosRequest) returns (GetTodosResponse);
rpc ListTodos(ListTodosRequest) returns (ListTodosResponse);
}