Browse Source

delete Item.

master
Gisle Aune 4 years ago
parent
commit
00e27abc5a
  1. 9
      graph/resolvers/issue.resolvers.go
  2. 46
      graph/resolvers/issueitem.resolvers.go
  3. 12
      graph/resolvers/log.resolvers.go
  4. 191
      graph/resolvers/mutation.resolvers.go
  5. 101
      graph/resolvers/query.resolvers.go
  6. 2
      graph/schema/issue.gql
  7. 75
      graph/schema/issueitem.gql
  8. 60
      graph/schema/item.gql
  9. 14
      graph/schema/log.gql
  10. 11
      graph/schema/mutation.gql
  11. 12
      graph/schema/query.gql

9
graph/resolvers/issue.resolvers.go

@ -85,15 +85,6 @@ func (r *issueResolver) Tasks(ctx context.Context, obj *models.Issue, filter *mo
return r.Database.IssueTasks().List(ctx, *filter) return r.Database.IssueTasks().List(ctx, *filter)
} }
func (r *issueResolver) Items(ctx context.Context, obj *models.Issue, filter *models.IssueItemFilter) ([]*models.IssueItem, error) {
if filter == nil {
filter = &models.IssueItemFilter{}
}
filter.IssueIDs = []string{obj.ID}
return r.Database.IssueItems().List(ctx, *filter)
}
func (r *issueResolver) Logs(ctx context.Context, obj *models.Issue) ([]*models.Log, error) { func (r *issueResolver) Logs(ctx context.Context, obj *models.Issue) ([]*models.Log, error) {
loader := loaders.LogsByIssueLoaderFromContext(ctx) loader := loaders.LogsByIssueLoaderFromContext(ctx)

46
graph/resolvers/issueitem.resolvers.go

@ -1,46 +0,0 @@
package resolvers
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
import (
"context"
"git.aiterp.net/stufflog/server/graph/graphcore"
"git.aiterp.net/stufflog/server/graph/loaders"
"git.aiterp.net/stufflog/server/models"
)
func (r *issueItemResolver) Issue(ctx context.Context, obj *models.IssueItem) (*models.Issue, error) {
return loaders.IssueLoaderFromContext(ctx).Load(obj.IssueID)
}
func (r *issueItemResolver) Item(ctx context.Context, obj *models.IssueItem) (*models.Item, error) {
return r.Database.Items().Find(ctx, obj.ItemID)
}
func (r *issueItemResolver) Remaining(ctx context.Context, obj *models.IssueItem) (int, error) {
if obj.Acquired {
return 0, nil
}
loader := loaders.LogsByIssueLoaderFromContext(ctx)
logs, err := loader.Load(obj.IssueID)
if err != nil {
return 0, err
}
remaining := obj.Quantity
for _, log := range logs {
if item := log.Item(obj.ID); item != nil {
remaining -= item.Amount
}
}
return remaining, nil
}
// IssueItem returns graphcore.IssueItemResolver implementation.
func (r *Resolver) IssueItem() graphcore.IssueItemResolver { return &issueItemResolver{r} }
type issueItemResolver struct{ *Resolver }

12
graph/resolvers/log.resolvers.go

@ -15,14 +15,6 @@ func (r *logResolver) User(ctx context.Context, obj *models.Log) (*models.User,
return r.Database.Users().Find(ctx, obj.UserID) return r.Database.Users().Find(ctx, obj.UserID)
} }
func (r *logItemResolver) Issue(ctx context.Context, obj *models.LogItem) (*models.Issue, error) {
return loaders.IssueLoaderFromContext(ctx).Load(obj.IssueID)
}
func (r *logItemResolver) Item(ctx context.Context, obj *models.LogItem) (*models.IssueItem, error) {
return r.Database.IssueItems().Find(ctx, obj.IssueItemID)
}
func (r *logTaskResolver) Issue(ctx context.Context, obj *models.LogTask) (*models.Issue, error) { func (r *logTaskResolver) Issue(ctx context.Context, obj *models.LogTask) (*models.Issue, error) {
return loaders.IssueLoaderFromContext(ctx).Load(obj.IssueID) return loaders.IssueLoaderFromContext(ctx).Load(obj.IssueID)
} }
@ -34,12 +26,8 @@ func (r *logTaskResolver) Task(ctx context.Context, obj *models.LogTask) (*model
// Log returns graphcore.LogResolver implementation. // Log returns graphcore.LogResolver implementation.
func (r *Resolver) Log() graphcore.LogResolver { return &logResolver{r} } func (r *Resolver) Log() graphcore.LogResolver { return &logResolver{r} }
// LogItem returns graphcore.LogItemResolver implementation.
func (r *Resolver) LogItem() graphcore.LogItemResolver { return &logItemResolver{r} }
// LogTask returns graphcore.LogTaskResolver implementation. // LogTask returns graphcore.LogTaskResolver implementation.
func (r *Resolver) LogTask() graphcore.LogTaskResolver { return &logTaskResolver{r} } func (r *Resolver) LogTask() graphcore.LogTaskResolver { return &logTaskResolver{r} }
type logResolver struct{ *Resolver } type logResolver struct{ *Resolver }
type logItemResolver struct{ *Resolver }
type logTaskResolver struct{ *Resolver } type logTaskResolver struct{ *Resolver }

191
graph/resolvers/mutation.resolvers.go

@ -6,13 +6,10 @@ package resolvers
import ( import (
"context" "context"
"errors" "errors"
"log"
"sort"
"time" "time"
"git.aiterp.net/stufflog/server/graph/graphcore" "git.aiterp.net/stufflog/server/graph/graphcore"
"git.aiterp.net/stufflog/server/graph/loaders" "git.aiterp.net/stufflog/server/graph/loaders"
"git.aiterp.net/stufflog/server/internal/generate"
"git.aiterp.net/stufflog/server/internal/slerrors" "git.aiterp.net/stufflog/server/internal/slerrors"
"git.aiterp.net/stufflog/server/models" "git.aiterp.net/stufflog/server/models"
) )
@ -127,131 +124,6 @@ func (r *mutationResolver) EditActivity(ctx context.Context, input graphcore.Act
return activity, nil return activity, nil
} }
func (r *mutationResolver) CreateItem(ctx context.Context, input *graphcore.ItemCreateInput) (*models.Item, error) {
user := r.Auth.UserFromContext(ctx)
if user == nil {
return nil, slerrors.PermissionDenied
}
if input.Name == "" {
return nil, errors.New("name cannot be blank")
}
if input.Description == "" {
return nil, errors.New("name cannot be blank")
}
if len(input.Tags) == 0 {
return nil, errors.New("at least one tag is required")
}
item := models.Item{
Name: input.Name,
Description: input.Description,
Tags: input.Tags,
QuantityUnit: input.QuantityUnit,
ImageURL: nil,
}
if input.Image != nil {
url, err := r.Upload.UploadImage(
ctx,
"item-image/"+generate.Generate(16, "I"),
input.Image.ContentType,
input.Image.Size,
input.Image.File,
)
if err != nil {
return nil, err
}
item.ImageURL = &url
}
return r.Database.Items().Insert(ctx, item)
}
func (r *mutationResolver) EditItem(ctx context.Context, input *graphcore.ItemEditInput) (*models.Item, error) {
user := r.Auth.UserFromContext(ctx)
if user == nil {
return nil, slerrors.PermissionDenied
}
item, err := r.Database.Items().Find(ctx, input.ItemID)
if err != nil {
return nil, err
}
deleteList := make([]int, 0, len(input.RemoveTags))
for _, tag := range input.RemoveTags {
for i, tag2 := range item.Tags {
if tag == tag2 {
deleteList = append(deleteList, i-len(deleteList))
break
}
}
}
for _, index := range deleteList {
item.Tags = append(item.Tags[:index], item.Tags[index+1:]...)
}
for _, tag := range input.AddTags {
found := false
for _, tag2 := range item.Tags {
if tag == tag2 {
found = true
break
}
}
if !found {
item.Tags = append(item.Tags, tag)
}
}
sort.Strings(item.Tags)
if input.SetQuantityUnit != nil {
item.QuantityUnit = input.SetQuantityUnit
}
if input.ClearQuantityUnit != nil && *input.ClearQuantityUnit {
item.QuantityUnit = nil
}
if input.SetName != nil {
item.Name = *input.SetName
}
if input.SetDescription != nil {
item.Description = *input.SetDescription
}
var prevFile *string
if input.UpdateImage != nil {
url, err := r.Upload.UploadImage(
ctx,
"item-image/"+generate.Generate(16, "U"),
input.UpdateImage.ContentType,
input.UpdateImage.Size,
input.UpdateImage.File,
)
if err != nil {
return nil, err
}
prevFile = item.ImageURL
item.ImageURL = &url
}
err = r.Database.Items().Save(ctx, *item)
if err != nil {
return nil, err
}
if prevFile != nil {
err := r.Upload.Delete(ctx, *prevFile)
if err != nil {
log.Printf("Failed to delete %s: %s", *prevFile, err)
}
}
return item, nil
}
func (r *mutationResolver) CreateIssue(ctx context.Context, input graphcore.IssueCreateInput) (*models.Issue, error) { func (r *mutationResolver) CreateIssue(ctx context.Context, input graphcore.IssueCreateInput) (*models.Issue, error) {
user := r.Auth.UserFromContext(ctx) user := r.Auth.UserFromContext(ctx)
if user == nil { if user == nil {
@ -473,69 +345,6 @@ func (r *mutationResolver) EditIssueTask(ctx context.Context, input graphcore.Is
return task, nil return task, nil
} }
func (r *mutationResolver) CreateIssueItem(ctx context.Context, input graphcore.IssueItemCreateInput) (*models.IssueItem, error) {
user := r.Auth.UserFromContext(ctx)
if user == nil {
return nil, slerrors.PermissionDenied
}
issue, err := loaders.IssueLoaderFromContext(ctx).Load(input.IssueID)
if err != nil {
return nil, err
}
if perm, err := r.Auth.IssuePermission(ctx, *issue); err != nil || !perm.CanManageOwnIssue() {
return nil, slerrors.PermissionDenied
}
item, err := r.Database.Items().Find(ctx, input.ItemID)
if err != nil {
return nil, err
}
issueItem := &models.IssueItem{
IssueID: issue.ID,
ItemID: item.ID,
Quantity: input.Quanitty,
Acquired: input.Acquired != nil && *input.Acquired,
}
return r.Database.IssueItems().Insert(ctx, *issueItem)
}
func (r *mutationResolver) EditIssueItem(ctx context.Context, input graphcore.IssueItemEditInput) (*models.IssueItem, error) {
user := r.Auth.UserFromContext(ctx)
if user == nil {
return nil, slerrors.PermissionDenied
}
item, err := r.Database.IssueItems().Find(ctx, input.IssueItemID)
if err != nil {
return nil, err
}
issue, err := loaders.IssueLoaderFromContext(ctx).Load(item.IssueID)
if err != nil {
return nil, err
}
if perm, err := r.Auth.IssuePermission(ctx, *issue); err != nil || !perm.CanManageOwnIssue() {
return nil, slerrors.PermissionDenied
}
if input.SetAcquired != nil {
item.Acquired = *input.SetAcquired
}
if input.SetQuanitty != nil {
item.Quantity = *input.SetQuanitty
}
err = r.Database.IssueItems().Save(ctx, *item)
if err != nil {
return nil, err
}
return item, nil
}
func (r *mutationResolver) CreateLog(ctx context.Context, input graphcore.LogCreateInput) (*models.Log, error) { func (r *mutationResolver) CreateLog(ctx context.Context, input graphcore.LogCreateInput) (*models.Log, error) {
user := r.Auth.UserFromContext(ctx) user := r.Auth.UserFromContext(ctx)
if user == nil { if user == nil {

101
graph/resolvers/query.resolvers.go

@ -65,107 +65,6 @@ func (r *queryResolver) Issues(ctx context.Context, filter *models.IssueFilter)
return issues, nil return issues, nil
} }
func (r *queryResolver) Item(ctx context.Context, id string) (*models.Item, error) {
user := r.Auth.UserFromContext(ctx)
if user == nil {
return nil, slerrors.PermissionDenied
}
return r.Database.Items().Find(ctx, id)
}
func (r *queryResolver) Items(ctx context.Context, filter *models.ItemFilter) ([]*models.Item, error) {
user := r.Auth.UserFromContext(ctx)
if user == nil {
return nil, slerrors.PermissionDenied
}
if filter == nil {
filter = &models.ItemFilter{}
}
return r.Database.Items().List(ctx, *filter)
}
func (r *queryResolver) ItemTags(ctx context.Context) ([]string, error) {
user := r.Auth.UserFromContext(ctx)
if user == nil {
return nil, slerrors.PermissionDenied
}
return r.Database.Items().GetTags(ctx)
}
func (r *queryResolver) IssueItem(ctx context.Context, id string) (*models.IssueItem, error) {
user := r.Auth.UserFromContext(ctx)
if user == nil {
return nil, slerrors.PermissionDenied
}
item, err := r.Database.IssueItems().Find(ctx, id)
if err != nil {
return nil, err
}
issue, err := loaders.IssueLoaderFromContext(ctx).Load(id)
if err != nil {
return nil, err
}
_, err = r.Auth.IssuePermission(ctx, *issue)
if err != nil {
return nil, err
}
return item, nil
}
func (r *queryResolver) IssueItems(ctx context.Context, filter *models.IssueItemFilter) ([]*models.IssueItem, error) {
user := r.Auth.UserFromContext(ctx)
if user == nil {
return nil, slerrors.PermissionDenied
}
if filter == nil {
filter = &models.IssueItemFilter{}
}
items, err := r.Database.IssueItems().List(ctx, *filter)
if err != nil {
return nil, err
}
accessMap := make(map[string]bool)
deleteList := make([]int, 0, len(items))
for i, item := range items {
if access, ok := accessMap[item.IssueID]; ok && access {
continue
} else if ok && !access {
deleteList = append(deleteList, i-len(deleteList))
continue
}
issue, err := loaders.IssueLoaderFromContext(ctx).Load(item.IssueID)
if err != nil {
deleteList = append(deleteList, i-len(deleteList))
accessMap[item.IssueID] = true
continue
}
_, err = r.Auth.IssuePermission(ctx, *issue)
if err != nil {
deleteList = append(deleteList, i-len(deleteList))
}
accessMap[issue.ID] = err != nil
}
for _, index := range deleteList {
items = append(items[:index], items[index+1:]...)
}
return items, nil
}
func (r *queryResolver) Project(ctx context.Context, id string) (*models.Project, error) { func (r *queryResolver) Project(ctx context.Context, id string) (*models.Project, error) {
user := r.Auth.UserFromContext(ctx) user := r.Auth.UserFromContext(ctx)
if user == nil { if user == nil {

2
graph/schema/issue.gql

@ -24,8 +24,6 @@ type Issue {
status: ProjectStatus! status: ProjectStatus!
"Issue tasks." "Issue tasks."
tasks(filter: IssueTaskFilter): [IssueTask!]! tasks(filter: IssueTaskFilter): [IssueTask!]!
"Issue items."
items(filter: IssueIssueItemFilter): [IssueItem!]!
"Logs related to this issue." "Logs related to this issue."
logs: [Log!]! logs: [Log!]!
} }

75
graph/schema/issueitem.gql

@ -1,75 +0,0 @@
"""
An issue item is a requirement of an item under an issue.
"""
type IssueItem {
"ID of the issue item listing."
id: String!
"The amount of the item associated with an issue."
quantity: Int!
"Whether the full quantity of item has been acquired."
acquired: Boolean!
"Parent issue of the issue item."
issue: Issue!
"The item associated with the issue."
item: Item!
"The amount of items remaining."
remaining: Int!
}
"Input for the items query."
input IssueItemFilter {
"Filter to only these IDs, used primarily by IDs."
issueItemIds: [String!]
"Filter to only these issues."
issueIds: [String!]
"Filter to only issues where these are the asignees."
issueAssignees: [String!]
"Filter to only issues where these are the owners."
issueOwners: [String!]
"Filter by issue minimum stage (inclusive)."
issueMinStage: Int
"Filter by issue maximum stage (inclusive)."
issueMaxStage: Int
"Filter to only list issue items with these items."
itemIds: [String!]
"Filter to only list issue items where the item has these tags."
itemTags: [String!]
"Only listed acquired or non-acquired items."
acquired: Boolean
}
"Input for the items query."
input IssueIssueItemFilter {
"Filter to only these IDs, used primarily by IDs."
issueItemIds: [String!]
"Filter to only list issue items with these items."
itemIds: [String!]
"Filter to only list issue items where the item has these tags."
itemTags: [String!]
"Only listed acquired or non-acquired items."
acquired: Boolean
}
"Input for the createIssueItem mutation."
input IssueItemCreateInput {
"Parent issue."
issueId: String!
"Item to associate with."
itemId: String!
"Quantity of the item."
quanitty: Int!
"Whether the item has already been acquired."
acquired: Boolean
}
"Input for the editIssueItem mutation."
input IssueItemEditInput {
"The ID of the issue item to edit."
issueItemId: String!
"Update the quantity of the item."
setQuanitty: Int
"Update whether the item has been acquired."
setAcquired: Boolean
}

60
graph/schema/item.gql

@ -1,60 +0,0 @@
"""
An item that can be required for an issue.
"""
type Item {
"The item's unique ID."
id: String!
"Name of the item."
name: String!
"A description of the item."
description: String!
"Item tags."
tags: [String!]!
"Quantity unit. Usually absent, but otherwise most often 'g' or 'ml'"
quantityUnit: String
"URL for the image, if available."
imageUrl: String
}
"Filter for the items query."
input ItemFilter {
"Get these item IDs. Mostly used internally."
itemIds: [String!]
"Limit to items with any of the following tags."
tags: [String!]
}
"Input for the createItem mutation."
input ItemCreateInput {
"Put a name on it."
name: String!
"Describe it for me."
description: String!
"Add a tag or a few"
tags: [String!]!
"Optional: Quanity unit."
quantityUnit: String
"Optional: Upload an image."
image: Upload
}
"Input for the editItem mutation."
input ItemEditInput {
"The item to edit."
itemId: String!
"Update the name."
setName: String
"Update the description."
setDescription: String
"Add new tags. The tags are added after removeTag tags are removed."
addTags: [String!]
"Remove existing tags. If a tag exists both here and in addTags, it will not be removed."
removeTags: [String!]
"Update quantity unit."
setQuantityUnit: String
"Clear quantity unit."
clearQuantityUnit: Boolean
"Update the image URL with a new image."
updateImage: Upload
}

14
graph/schema/log.gql

@ -13,8 +13,6 @@ type Log {
user: User! user: User!
"The tasks logged." "The tasks logged."
tasks: [LogTask!]! tasks: [LogTask!]!
"The items changed."
items: [LogItem!]!
} }
type LogTask { type LogTask {
@ -28,18 +26,6 @@ type LogTask {
duration: Duration! duration: Duration!
} }
"""
Log items are item changes related to a log.
"""
type LogItem {
"Parent issue of the item."
issue: Issue!
"The item that has been acquired."
item: IssueItem!
"The amount of items acquired."
amount: Int!
}
"Filter for the logs query." "Filter for the logs query."
input LogFilter { input LogFilter {
"Log IDs to select." "Log IDs to select."

11
graph/schema/mutation.gql

@ -9,12 +9,6 @@ type Mutation {
"Edit an activity." "Edit an activity."
editActivity(input: ActivityEditInput!): Activity! editActivity(input: ActivityEditInput!): Activity!
# ITEM
"Create an item."
createItem(input: ItemCreateInput): Item!
"Edit an item."
editItem(input: ItemEditInput): Item!
# ISSUE # ISSUE
"Create a new issue." "Create a new issue."
createIssue(input: IssueCreateInput!): Issue! createIssue(input: IssueCreateInput!): Issue!
@ -25,11 +19,6 @@ type Mutation {
createIssueTask(input: IssueTaskCreateInput!): IssueTask! createIssueTask(input: IssueTaskCreateInput!): IssueTask!
"Edit an issue task." "Edit an issue task."
editIssueTask(input: IssueTaskEditInput!): IssueTask! editIssueTask(input: IssueTaskEditInput!): IssueTask!
# ISSUE ITEM
"Create an issue item."
createIssueItem(input: IssueItemCreateInput!): IssueItem!
"Edit an issue item."
editIssueItem(input: IssueItemEditInput!): IssueItem!
# LOG # LOG
"Create a log." "Create a log."

12
graph/schema/query.gql

@ -4,18 +4,6 @@ type Query {
"List issues." "List issues."
issues(filter: IssueFilter): [Issue!]! issues(filter: IssueFilter): [Issue!]!
"Find item."
item(id: String!): Item!
"List items."
items(filter: ItemFilter): [Item!]!
"List item tags."
itemTags: [String!]!
"Find issue item."
issueItem(id: String!): IssueItem!
"List issue items."
issueItems(filter: IssueItemFilter): [IssueItem!]!
"Find project." "Find project."
project(id: String!): Project! project(id: String!): Project!
"List projects." "List projects."

Loading…
Cancel
Save