bug: add the optional field AvatarUrl to Person

Michael Muré created

Change summary

bug/person.go                   |   9 +
graphql/graph/gen_graph.go      | 129 ++++++++++++++++++++++++----------
graphql/resolvers/operations.go |  20 +++++
graphql/schema.graphql          |   5 +
util/text/validate.go           |  11 ++
5 files changed, 133 insertions(+), 41 deletions(-)

Detailed changes

bug/person.go 🔗

@@ -10,8 +10,9 @@ import (
 )
 
 type Person struct {
-	Name  string `json:"name"`
-	Email string `json:"email"`
+	Name      string `json:"name"`
+	Email     string `json:"email"`
+	AvatarUrl string `json:"avatar_url"`
 }
 
 // GetUser will query the repository for user detail and build the corresponding Person
@@ -61,6 +62,10 @@ func (p Person) Validate() error {
 		return fmt.Errorf("email is not fully printable")
 	}
 
+	if p.AvatarUrl != "" && !text.ValidUrl(p.AvatarUrl) {
+		return fmt.Errorf("avatarUrl is not a valid URL")
+	}
+
 	return nil
 }
 

graphql/graph/gen_graph.go 🔗

@@ -146,8 +146,9 @@ type ComplexityRoot struct {
 	}
 
 	Person struct {
-		Email func(childComplexity int) int
-		Name  func(childComplexity int) int
+		Email     func(childComplexity int) int
+		Name      func(childComplexity int) int
+		AvatarUrl func(childComplexity int) int
 	}
 
 	Query struct {
@@ -175,6 +176,7 @@ type ComplexityRoot struct {
 }
 
 type AddCommentOperationResolver interface {
+	Author(ctx context.Context, obj *operations.AddCommentOperation) (bug.Person, error)
 	Date(ctx context.Context, obj *operations.AddCommentOperation) (time.Time, error)
 }
 type BugResolver interface {
@@ -185,9 +187,11 @@ type BugResolver interface {
 	Operations(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (models.OperationConnection, error)
 }
 type CreateOperationResolver interface {
+	Author(ctx context.Context, obj *operations.CreateOperation) (bug.Person, error)
 	Date(ctx context.Context, obj *operations.CreateOperation) (time.Time, error)
 }
 type LabelChangeOperationResolver interface {
+	Author(ctx context.Context, obj *operations.LabelChangeOperation) (bug.Person, error)
 	Date(ctx context.Context, obj *operations.LabelChangeOperation) (time.Time, error)
 }
 type MutationResolver interface {
@@ -208,10 +212,12 @@ type RepositoryResolver interface {
 	Bug(ctx context.Context, obj *models.Repository, prefix string) (*bug.Snapshot, error)
 }
 type SetStatusOperationResolver interface {
+	Author(ctx context.Context, obj *operations.SetStatusOperation) (bug.Person, error)
 	Date(ctx context.Context, obj *operations.SetStatusOperation) (time.Time, error)
 	Status(ctx context.Context, obj *operations.SetStatusOperation) (models.Status, error)
 }
 type SetTitleOperationResolver interface {
+	Author(ctx context.Context, obj *operations.SetTitleOperation) (bug.Person, error)
 	Date(ctx context.Context, obj *operations.SetTitleOperation) (time.Time, error)
 }
 
@@ -1257,6 +1263,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.Person.Name(childComplexity), true
 
+	case "Person.avatarUrl":
+		if e.complexity.Person.AvatarUrl == nil {
+			break
+		}
+
+		return e.complexity.Person.AvatarUrl(childComplexity), true
+
 	case "Query.defaultRepository":
 		if e.complexity.Query.DefaultRepository == nil {
 			break
@@ -1410,10 +1423,14 @@ func (ec *executionContext) _AddCommentOperation(ctx context.Context, sel ast.Se
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("AddCommentOperation")
 		case "author":
-			out.Values[i] = ec._AddCommentOperation_author(ctx, field, obj)
-			if out.Values[i] == graphql.Null {
-				invalid = true
-			}
+			wg.Add(1)
+			go func(i int, field graphql.CollectedField) {
+				out.Values[i] = ec._AddCommentOperation_author(ctx, field, obj)
+				if out.Values[i] == graphql.Null {
+					invalid = true
+				}
+				wg.Done()
+			}(i, field)
 		case "date":
 			wg.Add(1)
 			go func(i int, field graphql.CollectedField) {
@@ -1453,7 +1470,7 @@ func (ec *executionContext) _AddCommentOperation_author(ctx context.Context, fie
 	}
 	ctx = graphql.WithResolverContext(ctx, rctx)
 	resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
-		return obj.Author, nil
+		return ec.resolvers.AddCommentOperation().Author(ctx, obj)
 	})
 	if resTmp == nil {
 		if !ec.HasError(rctx) {
@@ -2570,10 +2587,14 @@ func (ec *executionContext) _CreateOperation(ctx context.Context, sel ast.Select
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("CreateOperation")
 		case "author":
-			out.Values[i] = ec._CreateOperation_author(ctx, field, obj)
-			if out.Values[i] == graphql.Null {
-				invalid = true
-			}
+			wg.Add(1)
+			go func(i int, field graphql.CollectedField) {
+				out.Values[i] = ec._CreateOperation_author(ctx, field, obj)
+				if out.Values[i] == graphql.Null {
+					invalid = true
+				}
+				wg.Done()
+			}(i, field)
 		case "date":
 			wg.Add(1)
 			go func(i int, field graphql.CollectedField) {
@@ -2618,7 +2639,7 @@ func (ec *executionContext) _CreateOperation_author(ctx context.Context, field g
 	}
 	ctx = graphql.WithResolverContext(ctx, rctx)
 	resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
-		return obj.Author, nil
+		return ec.resolvers.CreateOperation().Author(ctx, obj)
 	})
 	if resTmp == nil {
 		if !ec.HasError(rctx) {
@@ -2745,10 +2766,14 @@ func (ec *executionContext) _LabelChangeOperation(ctx context.Context, sel ast.S
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("LabelChangeOperation")
 		case "author":
-			out.Values[i] = ec._LabelChangeOperation_author(ctx, field, obj)
-			if out.Values[i] == graphql.Null {
-				invalid = true
-			}
+			wg.Add(1)
+			go func(i int, field graphql.CollectedField) {
+				out.Values[i] = ec._LabelChangeOperation_author(ctx, field, obj)
+				if out.Values[i] == graphql.Null {
+					invalid = true
+				}
+				wg.Done()
+			}(i, field)
 		case "date":
 			wg.Add(1)
 			go func(i int, field graphql.CollectedField) {
@@ -2788,7 +2813,7 @@ func (ec *executionContext) _LabelChangeOperation_author(ctx context.Context, fi
 	}
 	ctx = graphql.WithResolverContext(ctx, rctx)
 	resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
-		return obj.Author, nil
+		return ec.resolvers.LabelChangeOperation().Author(ctx, obj)
 	})
 	if resTmp == nil {
 		if !ec.HasError(rctx) {
@@ -3584,6 +3609,11 @@ func (ec *executionContext) _Person(ctx context.Context, sel ast.SelectionSet, o
 			out.Values[i] = ec._Person_email(ctx, field, obj)
 		case "name":
 			out.Values[i] = ec._Person_name(ctx, field, obj)
+			if out.Values[i] == graphql.Null {
+				invalid = true
+			}
+		case "avatarUrl":
+			out.Values[i] = ec._Person_avatarUrl(ctx, field, obj)
 		default:
 			panic("unknown field " + strconv.Quote(field.Name))
 		}
@@ -3625,6 +3655,28 @@ func (ec *executionContext) _Person_name(ctx context.Context, field graphql.Coll
 	resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
 		return obj.Name, nil
 	})
+	if resTmp == nil {
+		if !ec.HasError(rctx) {
+			ec.Errorf(ctx, "must not be null")
+		}
+		return graphql.Null
+	}
+	res := resTmp.(string)
+	rctx.Result = res
+	return graphql.MarshalString(res)
+}
+
+// nolint: vetshadow
+func (ec *executionContext) _Person_avatarUrl(ctx context.Context, field graphql.CollectedField, obj *bug.Person) graphql.Marshaler {
+	rctx := &graphql.ResolverContext{
+		Object: "Person",
+		Args:   nil,
+		Field:  field,
+	}
+	ctx = graphql.WithResolverContext(ctx, rctx)
+	resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+		return obj.AvatarUrl, nil
+	})
 	if resTmp == nil {
 		return graphql.Null
 	}
@@ -3903,10 +3955,14 @@ func (ec *executionContext) _SetStatusOperation(ctx context.Context, sel ast.Sel
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("SetStatusOperation")
 		case "author":
-			out.Values[i] = ec._SetStatusOperation_author(ctx, field, obj)
-			if out.Values[i] == graphql.Null {
-				invalid = true
-			}
+			wg.Add(1)
+			go func(i int, field graphql.CollectedField) {
+				out.Values[i] = ec._SetStatusOperation_author(ctx, field, obj)
+				if out.Values[i] == graphql.Null {
+					invalid = true
+				}
+				wg.Done()
+			}(i, field)
 		case "date":
 			wg.Add(1)
 			go func(i int, field graphql.CollectedField) {
@@ -3945,7 +4001,7 @@ func (ec *executionContext) _SetStatusOperation_author(ctx context.Context, fiel
 	}
 	ctx = graphql.WithResolverContext(ctx, rctx)
 	resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
-		return obj.Author, nil
+		return ec.resolvers.SetStatusOperation().Author(ctx, obj)
 	})
 	if resTmp == nil {
 		if !ec.HasError(rctx) {
@@ -4019,10 +4075,14 @@ func (ec *executionContext) _SetTitleOperation(ctx context.Context, sel ast.Sele
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("SetTitleOperation")
 		case "author":
-			out.Values[i] = ec._SetTitleOperation_author(ctx, field, obj)
-			if out.Values[i] == graphql.Null {
-				invalid = true
-			}
+			wg.Add(1)
+			go func(i int, field graphql.CollectedField) {
+				out.Values[i] = ec._SetTitleOperation_author(ctx, field, obj)
+				if out.Values[i] == graphql.Null {
+					invalid = true
+				}
+				wg.Done()
+			}(i, field)
 		case "date":
 			wg.Add(1)
 			go func(i int, field graphql.CollectedField) {
@@ -4062,7 +4122,7 @@ func (ec *executionContext) _SetTitleOperation_author(ctx context.Context, field
 	}
 	ctx = graphql.WithResolverContext(ctx, rctx)
 	resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
-		return obj.Author, nil
+		return ec.resolvers.SetTitleOperation().Author(ctx, obj)
 	})
 	if resTmp == nil {
 		if !ec.HasError(rctx) {
@@ -5456,24 +5516,14 @@ func (ec *executionContext) _Operation(ctx context.Context, sel ast.SelectionSet
 	switch obj := (*obj).(type) {
 	case nil:
 		return graphql.Null
-	case operations.CreateOperation:
-		return ec._CreateOperation(ctx, sel, &obj)
 	case *operations.CreateOperation:
 		return ec._CreateOperation(ctx, sel, obj)
-	case operations.SetTitleOperation:
-		return ec._SetTitleOperation(ctx, sel, &obj)
 	case *operations.SetTitleOperation:
 		return ec._SetTitleOperation(ctx, sel, obj)
-	case operations.AddCommentOperation:
-		return ec._AddCommentOperation(ctx, sel, &obj)
 	case *operations.AddCommentOperation:
 		return ec._AddCommentOperation(ctx, sel, obj)
-	case operations.SetStatusOperation:
-		return ec._SetStatusOperation(ctx, sel, &obj)
 	case *operations.SetStatusOperation:
 		return ec._SetStatusOperation(ctx, sel, obj)
-	case operations.LabelChangeOperation:
-		return ec._LabelChangeOperation(ctx, sel, &obj)
 	case *operations.LabelChangeOperation:
 		return ec._LabelChangeOperation(ctx, sel, obj)
 	default:
@@ -5527,7 +5577,10 @@ type Person {
   email: String
 
   """The name of the person."""
-  name: String
+  name: String!
+
+  """An url to an avatar"""
+  avatarUrl: String
 }
 
 type CommentConnection {

graphql/resolvers/operations.go 🔗

@@ -12,24 +12,40 @@ import (
 
 type addCommentOperationResolver struct{}
 
+func (addCommentOperationResolver) Author(ctx context.Context, obj *operations.AddCommentOperation) (bug.Person, error) {
+	return obj.Author, nil
+}
+
 func (addCommentOperationResolver) Date(ctx context.Context, obj *operations.AddCommentOperation) (time.Time, error) {
 	return obj.Time(), nil
 }
 
 type createOperationResolver struct{}
 
+func (createOperationResolver) Author(ctx context.Context, obj *operations.CreateOperation) (bug.Person, error) {
+	return obj.Author, nil
+}
+
 func (createOperationResolver) Date(ctx context.Context, obj *operations.CreateOperation) (time.Time, error) {
 	return obj.Time(), nil
 }
 
 type labelChangeOperation struct{}
 
+func (labelChangeOperation) Author(ctx context.Context, obj *operations.LabelChangeOperation) (bug.Person, error) {
+	return obj.Author, nil
+}
+
 func (labelChangeOperation) Date(ctx context.Context, obj *operations.LabelChangeOperation) (time.Time, error) {
 	return obj.Time(), nil
 }
 
 type setStatusOperationResolver struct{}
 
+func (setStatusOperationResolver) Author(ctx context.Context, obj *operations.SetStatusOperation) (bug.Person, error) {
+	return obj.Author, nil
+}
+
 func (setStatusOperationResolver) Date(ctx context.Context, obj *operations.SetStatusOperation) (time.Time, error) {
 	return obj.Time(), nil
 }
@@ -40,6 +56,10 @@ func (setStatusOperationResolver) Status(ctx context.Context, obj *operations.Se
 
 type setTitleOperationResolver struct{}
 
+func (setTitleOperationResolver) Author(ctx context.Context, obj *operations.SetTitleOperation) (bug.Person, error) {
+	return obj.Author, nil
+}
+
 func (setTitleOperationResolver) Date(ctx context.Context, obj *operations.SetTitleOperation) (time.Time, error) {
 	return obj.Time(), nil
 }

graphql/schema.graphql 🔗

@@ -20,7 +20,10 @@ type Person {
   email: String
 
   """The name of the person."""
-  name: String
+  name: String!
+
+  """An url to an avatar"""
+  avatarUrl: String
 }
 
 type CommentConnection {

util/text/validate.go 🔗

@@ -1,6 +1,7 @@
 package text
 
 import (
+	"net/url"
 	"strings"
 	"unicode"
 )
@@ -31,3 +32,13 @@ func Safe(s string) bool {
 
 	return true
 }
+
+// ValidUrl will tell if the string contains what seems to be a valid URL
+func ValidUrl(s string) bool {
+	if strings.Contains(s, "\n") {
+		return false
+	}
+
+	_, err := url.ParseRequestURI(s)
+	return err == nil
+}