add issue item stuff.
This commit is contained in:
@@ -20,6 +20,8 @@ models:
|
||||
resolver: true
|
||||
Duration:
|
||||
model: git.aiterp.net/stufflog/server/graph/scalars.Duration
|
||||
IssueIssueItemFilter:
|
||||
model: git.aiterp.net/stufflog/server/models.IssueItemFilter
|
||||
|
||||
resolver:
|
||||
layout: follow-schema
|
||||
|
||||
@@ -85,6 +85,15 @@ func (r *issueResolver) Tasks(ctx context.Context, obj *models.Issue, filter *mo
|
||||
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)
|
||||
}
|
||||
|
||||
// Issue returns graphcore.IssueResolver implementation.
|
||||
func (r *Resolver) Issue() graphcore.IssueResolver { return &issueResolver{r} }
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
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"
|
||||
"fmt"
|
||||
|
||||
"git.aiterp.net/stufflog/server/graph/graphcore"
|
||||
"git.aiterp.net/stufflog/server/models"
|
||||
)
|
||||
|
||||
func (r *issueItemResolver) Issue(ctx context.Context, obj *models.IssueItem) (*models.Issue, error) {
|
||||
return r.Database.Issues().Find(ctx, 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
|
||||
}
|
||||
|
||||
// TODO: Use logs
|
||||
return obj.Quantity, nil
|
||||
}
|
||||
|
||||
// IssueItem returns graphcore.IssueItemResolver implementation.
|
||||
func (r *Resolver) IssueItem() graphcore.IssueItemResolver { return &issueItemResolver{r} }
|
||||
|
||||
type issueItemResolver struct{ *Resolver }
|
||||
|
||||
// !!! WARNING !!!
|
||||
// The code below was going to be deleted when updating resolvers. It has been copied here so you have
|
||||
// one last chance to move it out of harms way if you want. There are two reasons this happens:
|
||||
// - When renaming or deleting a resolver the old code will be put in here. You can safely delete
|
||||
// it when you're done.
|
||||
// - You have helper methods in this file. Move them out to keep these resolver files clean.
|
||||
func (r *issueItemResolver) Quanity(ctx context.Context, obj *models.IssueItem) (int, error) {
|
||||
panic(fmt.Errorf("not implemented"))
|
||||
}
|
||||
@@ -412,6 +412,69 @@ func (r *mutationResolver) EditIssueTask(ctx context.Context, input graphcore.Is
|
||||
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 := r.Database.Issues().Find(ctx, 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 := r.Database.Issues().Find(ctx, 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) LoginUser(ctx context.Context, input graphcore.UserLoginInput) (*models.User, error) {
|
||||
return r.Auth.Login(ctx, input.Username, input.Password)
|
||||
}
|
||||
|
||||
@@ -89,6 +89,76 @@ func (r *queryResolver) ItemTags(ctx context.Context) ([]string, error) {
|
||||
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 := r.Database.Issues().Find(ctx, item.IssueID)
|
||||
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 := r.Database.Issues().Find(ctx, 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) {
|
||||
user := r.Auth.UserFromContext(ctx)
|
||||
if user == nil {
|
||||
|
||||
@@ -24,6 +24,8 @@ type Issue {
|
||||
status: ProjectStatus!
|
||||
"Issue tasks."
|
||||
tasks(filter: IssueTaskFilter): [IssueTask!]!
|
||||
"Issue items."
|
||||
items(filter: IssueIssueItemFilter): [IssueItem!]!
|
||||
#"Logs related to this issue."
|
||||
#logs: [Log!]!
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
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
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ type Mutation {
|
||||
"Edit an issue task."
|
||||
editIssueTask(input: IssueTaskEditInput!): IssueTask!
|
||||
# ISSUE ITEM
|
||||
"Create an issue item."
|
||||
createIssueItem(input: IssueItemCreateInput!): IssueItem!
|
||||
"Edit an issue item."
|
||||
editIssueItem(input: IssueItemEditInput!): IssueItem!
|
||||
|
||||
# LOG
|
||||
|
||||
|
||||
@@ -11,6 +11,11 @@ type Query {
|
||||
"List item tags."
|
||||
itemTags: [String!]!
|
||||
|
||||
"Find issue item."
|
||||
issueItem(id: String!): IssueItem!
|
||||
"List issue items."
|
||||
issueItems(filter: IssueItemFilter): [IssueItem!]!
|
||||
|
||||
"Find project."
|
||||
project(id: String!): Project!
|
||||
"List projects."
|
||||
|
||||
Reference in New Issue
Block a user