~netlandish/links

d1d4f9a9bc1f8e0d23ee54a4b9cf268385018768 — Peter Sanchez a day ago 3e5d7d2
Moving domain status to enum
M admin/input.go => admin/input.go +2 -2
@@ 59,7 59,7 @@ type DomainForm struct {
	LookupName   string `form:"lookup_name" validate:"required"`
	Service      string `form:"service" validate:"oneof=LINKS SHORT LIST"`
	Level        string `form:"level" validate:"oneof=SYSTEM USER"`
	Status       int    `form:"status" validate:"oneof=0 1 2"`
	Status       string `form:"status" validate:"oneof=PENDING APPROVED ERROR"`
	IsActive     bool   `form:"is_active"`
	OrgSlug      string `form:"org_slug"`
	MigrateLinks bool   `form:"migrate_links"`


@@ 73,7 73,7 @@ func (d *DomainForm) Validate(c echo.Context) error {
		String("lookup_name", &d.LookupName).
		String("service", &d.Service).
		String("level", &d.Level).
		Int("status", &d.Status).
		String("status", &d.Status).
		String("org_slug", &d.OrgSlug).
		Bool("is_active", &d.IsActive).
		Bool("migrate_links", &d.MigrateLinks).

M admin/routes.go => admin/routes.go +4 -4
@@ 618,7 618,7 @@ func (s *Service) DomainUpdate(c echo.Context) error {
		models.DomainLevelSystem: lt.Translate("System"),
		models.DomainLevelUser:   lt.Translate("User"),
	}
	statusOpt := map[int]string{
	statusOpt := map[string]string{
		models.DomainStatusPending:  lt.Translate("Pending"),
		models.DomainStatusApproved: lt.Translate("Approved"),
		models.DomainStatusError:    lt.Translate("Error"),


@@ 665,7 665,7 @@ func (s *Service) DomainUpdate(c echo.Context) error {
		var result GraphQLResponse

		op := gqlclient.NewOperation(
			`mutation UpdateAdminDomain($id: Int!, $name: String!, $lookupName: String!, $orgSlug: String, $level: DomainLevel!, $status: Int!
			`mutation UpdateAdminDomain($id: Int!, $name: String!, $lookupName: String!, $orgSlug: String, $level: DomainLevel!, $status: DomainStatus!
								$service: DomainService!, $migrate: Boolean, $isActive: Boolean!) {
					updateAdminDomain(input: {
						id: $id,


@@ 747,7 747,7 @@ func (s *Service) DomainCreate(c echo.Context) error {
		models.DomainLevelSystem: lt.Translate("System"),
		models.DomainLevelUser:   lt.Translate("User"),
	}
	statusOpt := map[int]string{
	statusOpt := map[string]string{
		models.DomainStatusPending:  lt.Translate("Pending"),
		models.DomainStatusApproved: lt.Translate("Approved"),
		models.DomainStatusError:    lt.Translate("Error"),


@@ 793,7 793,7 @@ func (s *Service) DomainCreate(c echo.Context) error {
		}

		op := gqlclient.NewOperation(
			`mutation AddAdminDomain($name: String!, $lookupName: String!, $orgSlug: String, $level: DomainLevel!, $status: Int!
			`mutation AddAdminDomain($name: String!, $lookupName: String!, $orgSlug: String, $level: DomainLevel!, $status: DomainStatus!
								$service: DomainService!, $migrate: Boolean, $isActive: Boolean!) {
					addAdminDomain(input: {
						name: $name,

M api/graph/generated.go => api/graph/generated.go +53 -11
@@ 435,6 435,7 @@ type DomainResolver interface {
	OrgSlug(ctx context.Context, obj *models.Domain) (*model.NullString, error)
	Service(ctx context.Context, obj *models.Domain) (model.DomainService, error)
	Level(ctx context.Context, obj *models.Domain) (model.DomainLevel, error)
	Status(ctx context.Context, obj *models.Domain) (model.DomainStatus, error)
}
type MutationResolver interface {
	AddOrganization(ctx context.Context, input model.OrganizationInput) (*models.Organization, error)


@@ 5725,7 5726,7 @@ func (ec *executionContext) _Domain_status(ctx context.Context, field graphql.Co
	}()
	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
		ctx = rctx // use context from middleware stack in children
		return obj.Status, nil
		return ec.resolvers.Domain().Status(rctx, obj)
	})
	if err != nil {
		ec.Error(ctx, err)


@@ 5737,19 5738,19 @@ func (ec *executionContext) _Domain_status(ctx context.Context, field graphql.Co
		}
		return graphql.Null
	}
	res := resTmp.(int)
	res := resTmp.(model.DomainStatus)
	fc.Result = res
	return ec.marshalNInt2int(ctx, field.Selections, res)
	return ec.marshalNDomainStatus2linksᚋapiᚋgraphᚋmodelᚐDomainStatus(ctx, field.Selections, res)
}

func (ec *executionContext) fieldContext_Domain_status(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
	fc = &graphql.FieldContext{
		Object:     "Domain",
		Field:      field,
		IsMethod:   false,
		IsResolver: false,
		IsMethod:   true,
		IsResolver: true,
		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
			return nil, errors.New("field of type Int does not have child fields")
			return nil, errors.New("field of type DomainStatus does not have child fields")
		},
	}
	return fc, nil


@@ 21776,7 21777,7 @@ func (ec *executionContext) unmarshalInputAdminDomainInput(ctx context.Context, 
			it.Level = data
		case "status":
			ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("status"))
			data, err := ec.unmarshalNInt2int(ctx, v)
			data, err := ec.unmarshalNDomainStatus2linksᚋapiᚋgraphᚋmodelᚐDomainStatus(ctx, v)
			if err != nil {
				return it, err
			}


@@ 23084,7 23085,7 @@ func (ec *executionContext) unmarshalInputUpdateAdminDomainInput(ctx context.Con
			it.Level = data
		case "status":
			ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("status"))
			data, err := ec.unmarshalNInt2int(ctx, v)
			data, err := ec.unmarshalNDomainStatus2linksᚋapiᚋgraphᚋmodelᚐDomainStatus(ctx, v)
			if err != nil {
				return it, err
			}


@@ 24146,10 24147,41 @@ func (ec *executionContext) _Domain(ctx context.Context, sel ast.SelectionSet, o

			out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
		case "status":
			out.Values[i] = ec._Domain_status(ctx, field, obj)
			if out.Values[i] == graphql.Null {
				atomic.AddUint32(&out.Invalids, 1)
			field := field

			innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
				defer func() {
					if r := recover(); r != nil {
						ec.Error(ctx, ec.Recover(ctx, r))
					}
				}()
				res = ec._Domain_status(ctx, field, obj)
				if res == graphql.Null {
					atomic.AddUint32(&fs.Invalids, 1)
				}
				return res
			}

			if field.Deferrable != nil {
				dfs, ok := deferred[field.Deferrable.Label]
				di := 0
				if ok {
					dfs.AddField(field)
					di = len(dfs.Values) - 1
				} else {
					dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
					deferred[field.Deferrable.Label] = dfs
				}
				dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
					return innerFunc(ctx, dfs)
				})

				// don't run the out.Concurrently() call below
				out.Values[i] = graphql.Null
				continue
			}

			out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
		case "isActive":
			out.Values[i] = ec._Domain_isActive(ctx, field, obj)
			if out.Values[i] == graphql.Null {


@@ 27459,6 27491,16 @@ func (ec *executionContext) marshalNDomainService2linksᚋapiᚋgraphᚋmodelᚐ
	return v
}

func (ec *executionContext) unmarshalNDomainStatus2linksᚋapiᚋgraphᚋmodelᚐDomainStatus(ctx context.Context, v interface{}) (model.DomainStatus, error) {
	var res model.DomainStatus
	err := res.UnmarshalGQL(v)
	return res, graphql.ErrorOnPath(ctx, err)
}

func (ec *executionContext) marshalNDomainStatus2linksᚋapiᚋgraphᚋmodelᚐDomainStatus(ctx context.Context, sel ast.SelectionSet, v model.DomainStatus) graphql.Marshaler {
	return v
}

func (ec *executionContext) marshalNFollowPayload2linksᚋapiᚋgraphᚋmodelᚐFollowPayload(ctx context.Context, sel ast.SelectionSet, v model.FollowPayload) graphql.Marshaler {
	return ec._FollowPayload(ctx, sel, &v)
}

M api/graph/model/models_gen.go => api/graph/model/models_gen.go +45 -2
@@ 72,7 72,7 @@ type AdminDomainInput struct {
	OrgSlug      *string       `json:"orgSlug,omitempty"`
	Service      DomainService `json:"service"`
	Level        DomainLevel   `json:"level"`
	Status       int           `json:"status"`
	Status       DomainStatus  `json:"status"`
	IsActive     bool          `json:"isActive"`
	MigrateLinks *bool         `json:"migrateLinks,omitempty"`
}


@@ 378,7 378,7 @@ type UpdateAdminDomainInput struct {
	OrgSlug      *string       `json:"orgSlug,omitempty"`
	Service      DomainService `json:"service"`
	Level        DomainLevel   `json:"level"`
	Status       int           `json:"status"`
	Status       DomainStatus  `json:"status"`
	IsActive     bool          `json:"isActive"`
	MigrateLinks *bool         `json:"migrateLinks,omitempty"`
}


@@ 639,3 639,46 @@ func (e *DomainService) UnmarshalGQL(v interface{}) error {
func (e DomainService) MarshalGQL(w io.Writer) {
	fmt.Fprint(w, strconv.Quote(e.String()))
}

type DomainStatus string

const (
	DomainStatusPending  DomainStatus = "PENDING"
	DomainStatusApproved DomainStatus = "APPROVED"
	DomainStatusError    DomainStatus = "ERROR"
)

var AllDomainStatus = []DomainStatus{
	DomainStatusPending,
	DomainStatusApproved,
	DomainStatusError,
}

func (e DomainStatus) IsValid() bool {
	switch e {
	case DomainStatusPending, DomainStatusApproved, DomainStatusError:
		return true
	}
	return false
}

func (e DomainStatus) String() string {
	return string(e)
}

func (e *DomainStatus) UnmarshalGQL(v interface{}) error {
	str, ok := v.(string)
	if !ok {
		return fmt.Errorf("enums must be strings")
	}

	*e = DomainStatus(str)
	if !e.IsValid() {
		return fmt.Errorf("%s is not a valid DomainStatus", str)
	}
	return nil
}

func (e DomainStatus) MarshalGQL(w io.Writer) {
	fmt.Fprint(w, strconv.Quote(e.String()))
}

M api/graph/schema.graphqls => api/graph/schema.graphqls +8 -3
@@ 74,6 74,11 @@ enum DomainService {
  LIST
}

enum DomainStatus {
  PENDING
  APPROVED
  ERROR
}


# Considering removing these Null* fields:


@@ 256,7 261,7 @@ type Domain {
    orgSlug: NullString! @access(scope: DOMAINS, kind: RO)
    service: DomainService!
    level: DomainLevel!
    status: Int!
    status: DomainStatus!
    isActive: Boolean! @access(scope: DOMAINS, kind: RO)
    createdOn: Time! @access(scope: DOMAINS, kind: RO)
    updatedOn: Time! @access(scope: DOMAINS, kind: RO)


@@ 641,7 646,7 @@ input AdminDomainInput {
    orgSlug: String
    service: DomainService!
    level: DomainLevel!
    status: Int!
    status: DomainStatus!
    isActive: Boolean!
    migrateLinks: Boolean
}


@@ 653,7 658,7 @@ input UpdateAdminDomainInput {
    orgSlug: String
    service: DomainService!
    level: DomainLevel!
    status: Int!
    status: DomainStatus!
    isActive: Boolean!
    migrateLinks: Boolean
}

M api/graph/schema.resolvers.go => api/graph/schema.resolvers.go +10 -7
@@ 39,7 39,7 @@ import (
	"golang.org/x/image/draw"
	"golang.org/x/net/idna"
	"netlandish.com/x/gobwebs"
	"netlandish.com/x/gobwebs-oauth2"
	oauth2 "netlandish.com/x/gobwebs-oauth2"
	gaccounts "netlandish.com/x/gobwebs/accounts"
	"netlandish.com/x/gobwebs/crypto"
	"netlandish.com/x/gobwebs/database"


@@ 70,6 70,11 @@ func (r *domainResolver) Level(ctx context.Context, obj *models.Domain) (model.D
	return model.DomainLevel(obj.Level), nil
}

// Status is the resolver for the status field.
func (r *domainResolver) Status(ctx context.Context, obj *models.Domain) (model.DomainStatus, error) {
	return model.DomainStatus(obj.Status), nil
}

// AddOrganization is the resolver for the addOrganization field.
func (r *mutationResolver) AddOrganization(ctx context.Context, input model.OrganizationInput) (*models.Organization, error) {
	tokenUser := oauth2.ForContext(ctx)


@@ 3714,8 3719,7 @@ func (r *mutationResolver) AddAdminDomain(ctx context.Context, input model.Admin
		lt.Translate("Invalid level value.")).
		WithField("level").
		WithCode(valid.ErrValidationCode)
	validator.Expect(input.Status >= models.DomainStatusPending &&
		input.Status <= models.DomainStatusError,
	validator.Expect(domain.ValidateDomainStatus(string(input.Status)),
		lt.Translate("Invalid status value.")).
		WithField("status").
		WithCode(valid.ErrValidationCode)


@@ 3833,7 3837,7 @@ func (r *mutationResolver) AddAdminDomain(ctx context.Context, input model.Admin
		LookupName: host,
		Level:      string(input.Level),
		Service:    string(input.Service),
		Status:     input.Status,
		Status:     string(input.Status),
		IsActive:   input.IsActive,
	}
	if org != nil {


@@ 3889,8 3893,7 @@ func (r *mutationResolver) UpdateAdminDomain(ctx context.Context, input model.Up
		lt.Translate("Invalid level value.")).
		WithField("level").
		WithCode(valid.ErrValidationCode)
	validator.Expect(input.Status >= models.DomainStatusPending &&
		input.Status <= models.DomainStatusError,
	validator.Expect(domain.ValidateDomainStatus(string(input.Status)),
		lt.Translate("Invalid status value.")).
		WithField("status").
		WithCode(valid.ErrValidationCode)


@@ 4027,7 4030,7 @@ func (r *mutationResolver) UpdateAdminDomain(ctx context.Context, input model.Up
	ldomain.LookupName = host
	ldomain.Level = string(input.Level)
	ldomain.Service = string(input.Service)
	ldomain.Status = input.Status
	ldomain.Status = string(input.Status)
	ldomain.IsActive = input.IsActive

	if org != nil {

M domain/logic.go => domain/logic.go +11 -0
@@ 137,3 137,14 @@ func ValidateDomainService(service string) bool {
	_, ok := serviceMap[service]
	return ok
}

// ValidateDomainStatus is a helper to verify the service given is valid
func ValidateDomainStatus(status string) bool {
	statusMap := map[string]bool{
		models.DomainStatusPending:  true,
		models.DomainStatusApproved: true,
		models.DomainStatusError:    true,
	}
	_, ok := statusMap[status]
	return ok
}

M migrations/0001_initial.down.sql => migrations/0001_initial.down.sql +1 -0
@@ 34,3 34,4 @@ DROP TABLE IF EXISTS users;

DROP TYPE IF EXISTS domain_level;
DROP TYPE IF EXISTS domain_service;
DROP TYPE IF EXISTS domain_status;

M migrations/0001_initial.up.sql => migrations/0001_initial.up.sql +10 -1
@@ 30,6 30,15 @@ EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

DO $$ BEGIN
  CREATE TYPE domain_status AS ENUM (
    'PENDING',
    'APPROVED',
    'ERROR'
  );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;


CREATE TABLE users (


@@ 165,7 174,7 @@ CREATE TABLE domains (
  org_id INT REFERENCES organizations (id) ON DELETE CASCADE,
  level domain_level NOT NULL,
  service domain_service NOT NULL,
  status INT DEFAULT 0 NOT NULL,
  status domain_status DEFAULT 'PENDING' NOT NULL,
  is_active BOOLEAN DEFAULT TRUE,
  last_action TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_on TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,

M migrations/test_migration.up.sql => migrations/test_migration.up.sql +2 -2
@@ 15,8 15,8 @@ INSERT INTO org_links (title, url, base_url_id, user_id, org_id, visibility, has
INSERT INTO org_links (title, url, base_url_id, user_id, org_id, visibility, hash) VALUES
    ('Private Business url', 'http://base.com?vis=private', 1, 1, 2, 1, 'hash2');

INSERT INTO domains (name, lookup_name, org_id, level, service, status) VALUES ('short domain', 'short.domain.org', 1, 'SYSTEM', 'SHORT', 1);
INSERT INTO domains (name, lookup_name, org_id, service, status, level) VALUES ('listing domain', 'list.domain.org', 1, 'LIST', 1, 'USER');
INSERT INTO domains (name, lookup_name, org_id, level, service, status) VALUES ('short domain', 'short.domain.org', 1, 'SYSTEM', 'SHORT', 'APPROVED');
INSERT INTO domains (name, lookup_name, org_id, service, status, level) VALUES ('listing domain', 'list.domain.org', 1, 'LIST', 'APPROVED', 'USER');

INSERT INTO link_shorts (id, title, url, domain_id, org_id, short_code, user_id) VALUES (100, 'testing short', 'http://test.domain.org', 1, 1, 'foo', 1);
INSERT INTO listings (id, title, slug, domain_id, is_default, user_id, org_id) VALUES (100, 'test listing', 'test-listing-slug', 2, false, 1, 1);

M models/domains.go => models/domains.go +6 -3
@@ 31,11 31,11 @@ const (

const (
	// DomainStatusPending ...
	DomainStatusPending int = iota
	DomainStatusPending string = "PENDING"
	// DomainStatusApproved ...
	DomainStatusApproved
	DomainStatusApproved string = "APPROVED"
	// DomainStatusError ...
	DomainStatusError
	DomainStatusError string = "ERROR"
)

// GetDomains ...


@@ 140,6 140,9 @@ func (d *Domain) Store(ctx context.Context) error {
			if d.Service == "" {
				d.Service = DomainServiceLinks
			}
			if d.Status == "" {
				d.Status = DomainStatusPending
			}
			err = sq.
				Insert("domains").
				Columns("name", "lookup_name", "org_id", "level", "service", "status", "is_active").

M models/models.go => models/models.go +1 -1
@@ 111,7 111,7 @@ type Domain struct {
	OrgID      sql.NullInt64 `db:"org_id"`
	Level      string        `db:"level"`
	Service    string        `db:"service"`
	Status     int           `db:"status"`
	Status     string        `db:"status"`
	IsActive   bool          `db:"is_active"`
	LastAction time.Time     `db:"last_action"`
	CreatedOn  time.Time     `db:"created_on"`

M models/schema.sql => models/schema.sql +8 -1
@@ 21,6 21,13 @@ CREATE TYPE domain_service AS ENUM (
  'LIST'
);

CREATE TYPE domain_status AS ENUM (
  'PENDING',
  'APPROVED',
  'ERROR'
);


CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  full_name VARCHAR ( 150 ) NOT NULL,


@@ 154,7 161,7 @@ CREATE TABLE domains (
  org_id INT REFERENCES organizations (id) ON DELETE CASCADE,
  level domain_level NOT NULL,
  service domain_service NOT NULL,
  status INT DEFAULT 0 NOT NULL,
  status domain_status DEFAULT 'PENDING' NOT NULL,
  is_active BOOLEAN DEFAULT TRUE,
  last_action TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_on TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,