~netlandish/links

1f483e44deae25e6d5a82f7f5fb13e0c141b2d29 — Peter Sanchez 4 months ago 4f5277a
GraphQL Mutation to remove a member.

References: https://todo.code.netlandish.com/~netlandish/links/79
3 files changed, 219 insertions(+), 0 deletions(-)

M api/graph/generated.go
M api/graph/schema.graphqls
M api/graph/schema.resolvers.go
M api/graph/generated.go => api/graph/generated.go +136 -0
@@ 227,6 227,7 @@ type ComplexityRoot struct {
		DeleteLinkShort        func(childComplexity int, id int) int
		DeleteListing          func(childComplexity int, id int) int
		DeleteListingLink      func(childComplexity int, id int) int
		DeleteMember           func(childComplexity int, orgSlug string, email string) int
		DeleteQRCode           func(childComplexity int, id int) int
		Follow                 func(childComplexity int, orgSlug string) int
		Register               func(childComplexity int, input *model.RegisterInput) int


@@ 438,6 439,7 @@ type MutationResolver interface {
	DeleteLink(ctx context.Context, id int) (*model.DeletePayload, error)
	AddNote(ctx context.Context, input *model.NoteInput) (*models.OrgLink, error)
	AddMember(ctx context.Context, input *model.MemberInput) (*model.AddMemberPayload, error)
	DeleteMember(ctx context.Context, orgSlug string, email string) (*model.AddMemberPayload, error)
	ConfirmMember(ctx context.Context, key string) (*model.AddMemberPayload, error)
	Register(ctx context.Context, input *model.RegisterInput) (*models.User, error)
	CompleteRegister(ctx context.Context, input *model.CompleteRegisterInput) (*models.User, error)


@@ 1394,6 1396,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in

		return e.complexity.Mutation.DeleteListingLink(childComplexity, args["id"].(int)), true

	case "Mutation.deleteMember":
		if e.complexity.Mutation.DeleteMember == nil {
			break
		}

		args, err := ec.field_Mutation_deleteMember_args(context.TODO(), rawArgs)
		if err != nil {
			return 0, false
		}

		return e.complexity.Mutation.DeleteMember(childComplexity, args["orgSlug"].(string), args["email"].(string)), true

	case "Mutation.deleteQRCode":
		if e.complexity.Mutation.DeleteQRCode == nil {
			break


@@ 2957,6 2971,30 @@ func (ec *executionContext) field_Mutation_deleteListing_args(ctx context.Contex
	return args, nil
}

func (ec *executionContext) field_Mutation_deleteMember_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
	var err error
	args := map[string]interface{}{}
	var arg0 string
	if tmp, ok := rawArgs["orgSlug"]; ok {
		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("orgSlug"))
		arg0, err = ec.unmarshalNString2string(ctx, tmp)
		if err != nil {
			return nil, err
		}
	}
	args["orgSlug"] = arg0
	var arg1 string
	if tmp, ok := rawArgs["email"]; ok {
		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email"))
		arg1, err = ec.unmarshalNString2string(ctx, tmp)
		if err != nil {
			return nil, err
		}
	}
	args["email"] = arg1
	return args, nil
}

func (ec *executionContext) field_Mutation_deleteQRCode_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
	var err error
	args := map[string]interface{}{}


@@ 9441,6 9479,95 @@ func (ec *executionContext) fieldContext_Mutation_addMember(ctx context.Context,
	return fc, nil
}

func (ec *executionContext) _Mutation_deleteMember(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
	fc, err := ec.fieldContext_Mutation_deleteMember(ctx, field)
	if err != nil {
		return graphql.Null
	}
	ctx = graphql.WithFieldContext(ctx, fc)
	defer func() {
		if r := recover(); r != nil {
			ec.Error(ctx, ec.Recover(ctx, r))
			ret = graphql.Null
		}
	}()
	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
		directive0 := func(rctx context.Context) (interface{}, error) {
			ctx = rctx // use context from middleware stack in children
			return ec.resolvers.Mutation().DeleteMember(rctx, fc.Args["orgSlug"].(string), fc.Args["email"].(string))
		}
		directive1 := func(ctx context.Context) (interface{}, error) {
			scope, err := ec.unmarshalNAccessScope2linksᚋapiᚋgraphᚋmodelᚐAccessScope(ctx, "ORGS")
			if err != nil {
				return nil, err
			}
			kind, err := ec.unmarshalNAccessKind2linksᚋapiᚋgraphᚋmodelᚐAccessKind(ctx, "RW")
			if err != nil {
				return nil, err
			}
			if ec.directives.Access == nil {
				return nil, errors.New("directive access is not implemented")
			}
			return ec.directives.Access(ctx, nil, directive0, scope, kind)
		}

		tmp, err := directive1(rctx)
		if err != nil {
			return nil, graphql.ErrorOnPath(ctx, err)
		}
		if tmp == nil {
			return nil, nil
		}
		if data, ok := tmp.(*model.AddMemberPayload); ok {
			return data, nil
		}
		return nil, fmt.Errorf(`unexpected type %T from directive, should be *links/api/graph/model.AddMemberPayload`, tmp)
	})
	if err != nil {
		ec.Error(ctx, err)
		return graphql.Null
	}
	if resTmp == nil {
		if !graphql.HasFieldError(ctx, fc) {
			ec.Errorf(ctx, "must not be null")
		}
		return graphql.Null
	}
	res := resTmp.(*model.AddMemberPayload)
	fc.Result = res
	return ec.marshalNAddMemberPayload2ᚖlinksᚋapiᚋgraphᚋmodelᚐAddMemberPayload(ctx, field.Selections, res)
}

func (ec *executionContext) fieldContext_Mutation_deleteMember(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
	fc = &graphql.FieldContext{
		Object:     "Mutation",
		Field:      field,
		IsMethod:   true,
		IsResolver: true,
		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
			switch field.Name {
			case "success":
				return ec.fieldContext_AddMemberPayload_success(ctx, field)
			case "message":
				return ec.fieldContext_AddMemberPayload_message(ctx, field)
			}
			return nil, fmt.Errorf("no field named %q was found under type AddMemberPayload", field.Name)
		},
	}
	defer func() {
		if r := recover(); r != nil {
			err = ec.Recover(ctx, r)
			ec.Error(ctx, err)
		}
	}()
	ctx = graphql.WithFieldContext(ctx, fc)
	if fc.Args, err = ec.field_Mutation_deleteMember_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
		ec.Error(ctx, err)
		return
	}
	return fc, nil
}

func (ec *executionContext) _Mutation_confirmMember(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
	fc, err := ec.fieldContext_Mutation_confirmMember(ctx, field)
	if err != nil {


@@ 24660,6 24787,15 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
			if out.Values[i] == graphql.Null {
				invalids++
			}
		case "deleteMember":

			out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
				return ec._Mutation_deleteMember(ctx, field)
			})

			if out.Values[i] == graphql.Null {
				invalids++
			}
		case "confirmMember":

			out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {

M api/graph/schema.graphqls => api/graph/schema.graphqls +1 -0
@@ 763,6 763,7 @@ type Mutation {
    
    "Add organization members"
    addMember(input: MemberInput): AddMemberPayload! @access(scope: ORGS, kind: RW)
    deleteMember(orgSlug: String!, email: String!): AddMemberPayload! @access(scope: ORGS, kind: RW)
    confirmMember(key: String!): AddMemberPayload! @access(scope: PROFILE, kind: RW)

    "Register an account"

M api/graph/schema.resolvers.go => api/graph/schema.resolvers.go +82 -0
@@ 896,6 896,88 @@ func (r *mutationResolver) AddMember(ctx context.Context, input *model.MemberInp
	return addMemberPayload, nil
}

// DeleteMember is the resolver for the deleteMember field.
func (r *mutationResolver) DeleteMember(ctx context.Context, orgSlug string, email string) (*model.AddMemberPayload, error) {
	tokenUser := oauth2.ForContext(ctx)
	if tokenUser == nil {
		return nil, valid.ErrAuthorization
	}
	user := tokenUser.User.(*models.User)
	c := server.EchoForContext(ctx)
	lang := links.GetLangFromRequest(c.Request(), user)
	lt := localizer.GetLocalizer(lang)

	emailRegex, err := regexp.Compile(links.EmailPattern)
	if err != nil {
		return nil, fmt.Errorf(lt.Translate("Error compiling url regex: %s", err))
	}

	validator := valid.New(ctx)
	validator.Expect(orgSlug != "", lt.Translate("Org slug is required")).
		WithField("org").
		WithCode(valid.ErrValidationCode)
	validator.Expect(email != "", lt.Translate("User email is required")).
		WithField("email").
		WithCode(valid.ErrValidationCode)
	validator.Expect(len(email) < 255, lt.Translate("Email may not exceed 255 characters")).
		WithField("email").
		WithCode(valid.ErrValidationCode)
	validator.Expect(emailRegex.MatchString(email), lt.Translate("Invalid email format")).
		WithField("email").
		WithCode(valid.ErrValidationCode)

	if !validator.Ok() {
		return nil, nil
	}

	org, err := user.GetOrgsSlug(ctx, models.OrgUserPermissionAdminWrite, orgSlug)
	if err != nil {
		return nil, err
	}
	if org == nil {
		validator.Error(lt.Translate("Organization Not Found")).
			WithCode(valid.ErrNotFoundCode)
		return nil, nil
	}

	opts := &database.FilterOptions{
		Filter: sq.Eq{"u.email": strings.ToLower(email)},
		Limit:  1,
	}

	users, err := models.GetUsers(ctx, opts)
	if err != nil {
		return nil, err
	}
	if len(users) == 0 {
		validator.Error(lt.Translate("User not found for given email")).
			WithCode(valid.ErrNotFoundCode)
		return nil, nil
	}
	duser := users[0]

	opts = &database.FilterOptions{
		Filter: sq.And{
			sq.Eq{"org_id": org.ID},
			sq.Eq{"user_id": duser.ID},
		},
	}
	ousers, err := models.GetOrgUsers(ctx, opts)
	if err != nil {
		return nil, err
	}

	addMemberPayload := &model.AddMemberPayload{}
	if len(ousers) == 0 {
		addMemberPayload.Success = false
		addMemberPayload.Message = lt.Translate("The user for given email is not a member of given organization")
	} else {
		addMemberPayload.Success = true
		addMemberPayload.Message = lt.Translate("The member was removed successfully")
	}
	return addMemberPayload, nil
}

// ConfirmMember is the resolver for the confirmMember field.
func (r *mutationResolver) ConfirmMember(ctx context.Context, key string) (*model.AddMemberPayload, error) {
	lang := links.GetLangFromRequest(server.EchoForContext(ctx).Request(), nil)