package projectv1 import ( "context" "errors" "slices" "connectrpc.com/connect" "git.kocoder.xyz/kocoded/vt/fx" projectv1 "git.kocoder.xyz/kocoded/vt/gen/project/v1" "git.kocoder.xyz/kocoded/vt/gen/project/v1/projectv1connect" "git.kocoder.xyz/kocoded/vt/interceptors" "git.kocoder.xyz/kocoded/vt/model" "git.kocoder.xyz/kocoded/vt/query" "gorm.io/gorm" ) func NewProjectRoute(db *gorm.DB, oidcInterceptor *interceptors.AuthenticationInterceptor) fx.Handler { path, handler := projectv1connect.NewProjectServiceHandler(&projectService{db: db}, connect.WithInterceptors(oidcInterceptor)) return fx.NewRoute(path, handler) } type projectService struct{ db *gorm.DB } // ListProjects implements projectv1connect.ProjectServiceHandler. func (s *projectService) ListProjects(ctx context.Context, req *projectv1.ListProjectsRequest) (*projectv1.ListProjectsResponse, error) { session, ok := interceptors.SessionFromContext(ctx) if !ok { return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("No session set in interceptor")) } p := query.Use(s.db).Projekt query := p.Where(p.MandantID.Eq(session.MandantId)).Limit(int(req.PerPage)).Offset(int(req.Page)) if req.OrberBy != "" { f, ok := p.GetFieldByName(req.OrberBy) if ok { if !req.Asc { query = query.Order(f.Desc()) } else { query = query.Order(f.Asc()) } } } else { query = query.Order(p.ID.Asc()) } projects, err := query.Find() if err != nil { return nil, connect.NewError(connect.CodeUnknown, err) } cnt, err := p.Where(p.MandantID.Eq(session.MandantId)).Count() if err != nil { return nil, connect.NewError(connect.CodeUnimplemented, err) } data := make([]*projectv1.GetProjectResponse, len(projects)) for i, p := range projects { data[i] = &projectv1.GetProjectResponse{ Id: int64(p.ID), Name: p.Name, Description: p.Description, IsMaterialized: newPointerBoolean(true), IsPersonalized: newPointerBoolean(true), IsConfirmed: newPointerBoolean(true), IsPaid: nil, IsDone: s.IsDone(p), } } return &projectv1.ListProjectsResponse{ Data: data, Meta: &projectv1.Metadata{TotalCount: int32(cnt)}, }, nil } func newPointerBoolean(val bool) *bool { b := val return &b } func (s *projectService) IsDone(p *model.Projekt) *bool { t := query.Use(s.db).Task tasks, err := t.Where(t.ProjektID.Eq(p.ID)).Find() if err != nil { panic(err) } if len(tasks) == 0 { return nil } if i := slices.IndexFunc(tasks, func(t *model.Task) bool { return !t.Status.IsDone() }); i != -1 { return newPointerBoolean(false) } return newPointerBoolean(true) } func (s *projectService) GetProject(ctx context.Context, req *projectv1.GetProjectRequest) (*projectv1.GetProjectResponse, error) { session, ok := interceptors.SessionFromContext(ctx) if !ok { return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("No session set in interceptor")) } p := query.Use(s.db).Projekt query, err := p.Where(p.ID.Eq(uint(req.Id))).Where(p.MandantID.Eq(session.MandantId)).First() if err != nil { return nil, err } return &projectv1.GetProjectResponse{ Id: int64(query.ID), Name: query.Name, Description: query.Description, IsMaterialized: newPointerBoolean(true), IsPersonalized: newPointerBoolean(true), IsConfirmed: newPointerBoolean(true), IsPaid: newPointerBoolean(true), IsDone: newPointerBoolean(true), }, nil }