feat(ui+backend): base of data persistence

This commit is contained in:
2020-09-11 09:19:18 +02:00
parent c7cea6e46b
commit 7fc1a7f3af
37 changed files with 1298 additions and 195 deletions

View File

@ -0,0 +1,49 @@
package graph
import (
"context"
"strconv"
"forge.cadoles.com/Cadoles/guesstimate/internal/model"
"github.com/pkg/errors"
)
func handleEstimations(ctx context.Context, task *model.Task) (*model.Estimations, error) {
estimations := &model.Estimations{}
if task.Estimations == nil {
return estimations, nil
}
rawOptimistic, exists := task.Estimations[model.EstimationOptimistic]
if exists && rawOptimistic != nil {
optimistic, err := strconv.ParseFloat(*rawOptimistic, 64)
if err != nil {
return nil, errors.WithStack(err)
}
estimations.Optimistic = optimistic
}
rawLikely, exists := task.Estimations[model.EstimationLikely]
if exists && rawLikely != nil {
likely, err := strconv.ParseFloat(*rawLikely, 64)
if err != nil {
return nil, errors.WithStack(err)
}
estimations.Likely = likely
}
rawPessimistic, exists := task.Estimations[model.EstimationPessimistic]
if exists && rawPessimistic != nil {
pessimistic, err := strconv.ParseFloat(*rawPessimistic, 64)
if err != nil {
return nil, errors.WithStack(err)
}
estimations.Pessimistic = pessimistic
}
return estimations, nil
}

View File

@ -2,6 +2,26 @@ input UserChanges {
name: String
}
input CreateProjectChanges {
title: String!
}
input ProjectTaskChanges {
label: String
categoryId: ID
estimations: ProjectTaskEstimationsChanges
}
input ProjectTaskEstimationsChanges {
optimistic: Float
likely: Float
pessimistic: Float
}
type Mutation {
updateUser(id: ID!, changes: UserChanges!): User!
createProject(changes: CreateProjectChanges!): Project!
updateProjectTitle(projectId: ID!, title: String!): Project!
addProjectTask(projectId: ID!, changes: ProjectTaskChanges): Task!
removeProjectTask(projectId: ID!, taskId: ID!): Boolean!
}

View File

@ -10,10 +10,26 @@ import (
"forge.cadoles.com/Cadoles/guesstimate/internal/model"
)
func (r *mutationResolver) UpdateUser(ctx context.Context, id string, changes model.UserChanges) (*model.User, error) {
func (r *mutationResolver) UpdateUser(ctx context.Context, id int64, changes model.UserChanges) (*model.User, error) {
return handleUpdateUser(ctx, id, changes)
}
func (r *mutationResolver) CreateProject(ctx context.Context, changes model.CreateProjectChanges) (*model.Project, error) {
return handleCreateProject(ctx, changes)
}
func (r *mutationResolver) UpdateProjectTitle(ctx context.Context, projectID int64, title string) (*model.Project, error) {
return handleUpdateProjectTitle(ctx, projectID, title)
}
func (r *mutationResolver) AddProjectTask(ctx context.Context, projectID int64, changes *model.ProjectTaskChanges) (*model.Task, error) {
return handleAddProjectTask(ctx, projectID, changes)
}
func (r *mutationResolver) RemoveProjectTask(ctx context.Context, projectID int64, taskID int64) (bool, error) {
return handleRemoveProjectTask(ctx, projectID, taskID)
}
// Mutation returns generated.MutationResolver implementation.
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }

View File

@ -0,0 +1,96 @@
package graph
import (
"context"
"forge.cadoles.com/Cadoles/guesstimate/internal/model"
model1 "forge.cadoles.com/Cadoles/guesstimate/internal/model"
"github.com/pkg/errors"
)
func handleProjects(ctx context.Context, filter *model1.ProjectsFilter) ([]*model1.Project, error) {
user, db, err := getSessionUser(ctx)
if err != nil {
return nil, errors.WithStack(err)
}
repo := model.NewProjectRepository(db)
if filter == nil {
filter = &model1.ProjectsFilter{
OwnerIds: make([]int64, 0, 1),
}
}
filter.OwnerIds = append(filter.OwnerIds, user.ID)
projects, err := repo.Search(ctx, filter)
if err != nil {
return nil, errors.WithStack(err)
}
return projects, nil
}
func handleCreateProject(ctx context.Context, input model.CreateProjectChanges) (*model.Project, error) {
user, db, err := getSessionUser(ctx)
if err != nil {
return nil, errors.WithStack(err)
}
repo := model.NewProjectRepository(db)
project, err := repo.Create(ctx, input.Title, user.ID)
if err != nil {
return nil, errors.WithStack(err)
}
return project, nil
}
func handleUpdateProjectTitle(ctx context.Context, projectID int64, title string) (*model.Project, error) {
db, err := getDB(ctx)
if err != nil {
return nil, errors.WithStack(err)
}
repo := model.NewProjectRepository(db)
project, err := repo.UpdateTitle(ctx, projectID, title)
if err != nil {
return nil, errors.WithStack(err)
}
return project, nil
}
func handleAddProjectTask(ctx context.Context, projectID int64, changes *model.ProjectTaskChanges) (*model.Task, error) {
db, err := getDB(ctx)
if err != nil {
return nil, errors.WithStack(err)
}
repo := model.NewProjectRepository(db)
task, err := repo.AddTask(ctx, projectID, changes)
if err != nil {
return nil, errors.WithStack(err)
}
return task, nil
}
func handleRemoveProjectTask(ctx context.Context, projectID int64, taskID int64) (bool, error) {
db, err := getDB(ctx)
if err != nil {
return false, errors.WithStack(err)
}
repo := model.NewProjectRepository(db)
if err := repo.RemoveTask(ctx, projectID, taskID); err != nil {
return false, errors.WithStack(err)
}
return true, nil
}

View File

@ -8,6 +8,60 @@ type User {
createdAt: Time!
}
type Project {
id: ID!
title: String!
tasks: [Task]!
params: ProjectParams!
acl: [Access]!
taskCategories: [TaskCategory]!
}
type Task {
id: ID!
label: String
category: TaskCategory
estimations: Estimations
}
type TaskCategory {
id: ID!
label: String!
costPerTimeUnit: Float!
}
type Access {
id: ID!
user: User!
level: String!
}
type ProjectParams {
timeUnit: TimeUnit
currency: String!
roundUpEstimations: Boolean!
hideFinancialPreviewOnPrint: Boolean!
}
type TimeUnit {
label: String!
acronym: String!
}
type Estimations {
optimistic: Float!
likely: Float!
pessimistic: Float!
}
input ProjectsFilter {
ids: [ID]
limit: Int
offset: Int
search: String
}
type Query {
currentUser: User
projects(filter: ProjectsFilter): [Project]
}

View File

@ -14,7 +14,19 @@ func (r *queryResolver) CurrentUser(ctx context.Context) (*model1.User, error) {
return handleCurrentUser(ctx)
}
func (r *queryResolver) Projects(ctx context.Context, filter *model1.ProjectsFilter) ([]*model1.Project, error) {
return handleProjects(ctx, filter)
}
func (r *taskResolver) Estimations(ctx context.Context, obj *model1.Task) (*model1.Estimations, error) {
return handleEstimations(ctx, obj)
}
// Query returns generated.QueryResolver implementation.
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
// Task returns generated.TaskResolver implementation.
func (r *Resolver) Task() generated.TaskResolver { return &taskResolver{r} }
type queryResolver struct{ *Resolver }
type taskResolver struct{ *Resolver }

View File

@ -19,7 +19,7 @@ func handleCurrentUser(ctx context.Context) (*model.User, error) {
return user, nil
}
func handleUpdateUser(ctx context.Context, id string, changes model.UserChanges) (*model.User, error) {
func handleUpdateUser(ctx context.Context, id int64, changes model.UserChanges) (*model.User, error) {
user, db, err := getSessionUser(ctx)
if err != nil {
return nil, errors.WithStack(err)