You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: validator_globaldns.go
    path of file: ./repos/rancher/pkg/api/norman/customization/globaldns
    
    the code of the file until where you have to start completion: package globaldns

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/rancher/norman/types"
	"github.com/rancher/norman/types/convert"
	gaccess "github.com/rancher/rancher/pkg/api/norman/customization/globalnamespaceaccess"
	client "github.com/rancher/rancher/pkg/client/generated/management/v3"
	v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
	"k8s.io/apimachinery/pkg/api/meta"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type Wrapper struct {
	GlobalDNSLister       v3.GlobalDnsLister
	GlobalDNSes           v3.GlobalDnsInterface
	PrtbLister            v3.ProjectRoleTemplateBindingLister
	MultiClusterAppLister v3.MultiClusterAppLister
	Users                 v3.UserInterface
	GrbLister             v3.GlobalRoleBindingLister
	GrLister              v3.GlobalRoleLister
}

const (
	creatorIDAnn = "field.cattle.io/creatorId"
)

func (w Wrapper) Validator(request *types.APIContext, schema *types.Schema, data map[string]interface{}) error {
	if request.Method != http.MethodPut && request.Method != http.MethodPost {
		return nil
	}

	var targetProjects []string
	ma := gaccess.MemberAccess{
		Users:     w.Users,
		GrLister:  w.GrLister,
		GrbLister: w.GrbLister,
	}

	callerID := request.Request.Header.Get(gaccess.ImpersonateUserHeader)
	if request.Method == http.MethodPost {
		// create request, caller is owner/creator
		// Request is POST, hence global DNS is being created.
		// if multiclusterapp ID is provided check access to its projects
		mcappID := convert.ToString(data[client.GlobalDnsFieldMultiClusterAppID])
		if mcappID != "" {
			split := strings.SplitN(mcappID, ":", 2)
			if len(split) != 2 {
				return fmt.Errorf("incorrect multiclusterapp id %v provided for global dns %v", mcappID, request.ID)
			}
			mcapp, err := w.MultiClusterAppLister.Get(spli
    
func (w Wrapper) Validator(request *types.APIContext, schema *types.Schema, data map[string]interface{}) error {
	if request.Method != http.MethodPut && request.Method != http.MethodPost {
		return nil
	}

	var targetProjects []string
	ma := gaccess.MemberAccess{
		Users:     w.Users,
		GrLister:  w.GrLister,
		GrbLister: w.GrbLister,
	}

	callerID := request.Request.Header.Get(gaccess.ImpersonateUserHeader)
	if request.Method == http.MethodPost {
		// create request, caller is owner/creator
		// Request is POST, hence global DNS is being created.
		// if multiclusterapp ID is provided check access to its projects
		mcappID := convert.ToString(data[client.GlobalDnsFieldMultiClusterAppID])
		if mcappID != "" {
			split := strings.SplitN(mcappID, ":", 2)
			if len(split) != 2 {
				return fmt.Errorf("incorrect multiclusterapp id %v provided for global dns %v", mcappID, request.ID)
			}
			mcapp, err := w.MultiClusterAppLister.Get(split[0], split[1])
			if err != nil {
				return err
			}
			for _, t := range mcapp.Spec.Targets {
				targetProjects = append(targetProjects, t.ProjectName)
			}
		} else {
			// if not, check access to all projects provided in the projects list
			targetProjects = convert.ToStringSlice(data[client.GlobalDnsFieldProjectIDs])
		}
		return ma.CheckCallerAccessToTargets(request, targetProjects, client.ProjectType, &client.Project{})
	}
	// edit request, check access type caller has
	split := strings.SplitN(request.ID, ":", 2)
	if len(split) != 2 {
		return fmt.Errorf("incorrect global DNS ID %v", request.ID)
	}

	gDNS, err := w.GlobalDNSes.GetNamespaced(split[0], split[1], v1.GetOptions{})
	if err != nil {
		return err
	}
	metaAccessor, err := meta.Accessor(gDNS)
	if err != nil {
		return err
	}
	creatorID, ok := metaAccessor.GetAnnotations()[creatorIDAnn]
	if !ok {
		return fmt.Errorf("GlobalDNS %v has no creatorId annotation", metaAccessor.GetName())
	}
	accessType, err := ma.GetAccessTypeOfCaller(callerID, creatorID, gDNS.Name, gDNS.Spec.Members)
	if err != nil {
		return err
	}
	if accessType != gaccess.OwnerAccess {
		return fmt.Errorf("invalid access type %v for globaldns member", accessType)
	}
	// only members list, FQDN and multiclusterappID can be edited through PUT, for updating projects, we need to use actions only
	// that's why projects and multiclusterappID field have been made non updatable in rancher/types
	if err := gaccess.CheckAccessToUpdateMembers(gDNS.Spec.Members, data, accessType == gaccess.OwnerAccess); err != nil {
		return err
	}

	originalMultiClusterApp := gDNS.Spec.MultiClusterAppName
	newMultiClusterApp := convert.ToString(data[client.GlobalDnsFieldMultiClusterAppID])
	if newMultiClusterApp != "" && originalMultiClusterApp != newMultiClusterApp {
		// check access to new multiclusterapp
		return ma.CheckCallerAccessToTargets(request, []string{newMultiClusterApp}, client.MultiClusterAppType, &client.MultiClusterApp{})
	}
	return nil
}