M admin/input.go => admin/input.go +2 -2
@@ 58,7 58,7 @@ type DomainForm struct {
Name string `form:"name" validate:"required"`
LookupName string `form:"lookup_name" validate:"required"`
Service int `form:"service" validate:"oneof=0 1 2"`
- Level int `form:"level" validate:"oneof=0 1"`
+ Level string `form:"level" validate:"oneof=SYSTEM USER"`
Status int `form:"status" validate:"oneof=0 1 2"`
IsActive bool `form:"is_active"`
OrgSlug string `form:"org_slug"`
@@ 72,7 72,7 @@ func (d *DomainForm) Validate(c echo.Context) error {
String("name", &d.Name).
String("lookup_name", &d.LookupName).
Int("service", &d.Service).
- Int("level", &d.Level).
+ String("level", &d.Level).
Int("status", &d.Status).
String("org_slug", &d.OrgSlug).
Bool("is_active", &d.IsActive).
M admin/routes.go => admin/routes.go +4 -4
@@ 614,7 614,7 @@ func (s *Service) DomainUpdate(c echo.Context) error {
models.DomainServiceList: lt.Translate("Link Listing"),
}
- levelOpt := map[int]string{
+ levelOpt := map[string]string{
models.DomainLevelSystem: lt.Translate("System"),
models.DomainLevelUser: lt.Translate("User"),
}
@@ 743,7 743,7 @@ func (s *Service) DomainCreate(c echo.Context) error {
models.DomainServiceList: lt.Translate("Link Listing"),
}
- levelOpt := map[int]string{
+ levelOpt := map[string]string{
models.DomainLevelSystem: lt.Translate("System"),
models.DomainLevelUser: lt.Translate("User"),
}
@@ 1057,7 1057,7 @@ func (s *Service) DomainList(c echo.Context) error {
pd.Data["clear"] = lt.Translate("Clear")
pd.Data["add"] = lt.Translate("Add")
- filterType := map[int]string{
+ filterType := map[string]string{
models.DomainLevelSystem: lt.Translate("System"),
models.DomainLevelUser: lt.Translate("User"),
}
@@ 1092,7 1092,7 @@ func (s *Service) DomainList(c echo.Context) error {
}
var result GraphQLResponse
op := gqlclient.NewOperation(
- `query GetAdminDomains($search: String, $after: Cursor, $before: Cursor, $filterLevel: Int, $filterService: Int, $filterActive: Boolean) {
+ `query GetAdminDomains($search: String, $after: Cursor, $before: Cursor, $filterLevel: String, $filterService: Int, $filterActive: Boolean) {
getAdminDomains(input: {
search: $search,
after: $after,
M api/graph/generated.go => api/graph/generated.go +71 -12
@@ 433,6 433,8 @@ type ComplexityRoot struct {
type DomainResolver interface {
OrgID(ctx context.Context, obj *models.Domain) (*model.NullInt, error)
OrgSlug(ctx context.Context, obj *models.Domain) (*model.NullString, error)
+
+ Level(ctx context.Context, obj *models.Domain) (model.DomainLevel, error)
}
type MutationResolver interface {
AddOrganization(ctx context.Context, input model.OrganizationInput) (*models.Organization, error)
@@ 5679,7 5681,7 @@ func (ec *executionContext) _Domain_level(ctx context.Context, field graphql.Col
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
- return obj.Level, nil
+ return ec.resolvers.Domain().Level(rctx, obj)
})
if err != nil {
ec.Error(ctx, err)
@@ 5691,19 5693,19 @@ func (ec *executionContext) _Domain_level(ctx context.Context, field graphql.Col
}
return graphql.Null
}
- res := resTmp.(int)
+ res := resTmp.(model.DomainLevel)
fc.Result = res
- return ec.marshalNInt2int(ctx, field.Selections, res)
+ return ec.marshalNDomainLevel2linksᚋapiᚋgraphᚋmodelᚐDomainLevel(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Domain_level(_ 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 DomainLevel does not have child fields")
},
}
return fc, nil
@@ 21767,7 21769,7 @@ func (ec *executionContext) unmarshalInputAdminDomainInput(ctx context.Context,
it.Service = data
case "level":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("level"))
- data, err := ec.unmarshalNInt2int(ctx, v)
+ data, err := ec.unmarshalNDomainLevel2linksᚋapiᚋgraphᚋmodelᚐDomainLevel(ctx, v)
if err != nil {
return it, err
}
@@ 22008,7 22010,7 @@ func (ec *executionContext) unmarshalInputGetAdminDomainInput(ctx context.Contex
it.Search = data
case "filterLevel":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filterLevel"))
- data, err := ec.unmarshalOInt2ᚖint(ctx, v)
+ data, err := ec.unmarshalODomainLevel2ᚖlinksᚋapiᚋgraphᚋmodelᚐDomainLevel(ctx, v)
if err != nil {
return it, err
}
@@ 23075,7 23077,7 @@ func (ec *executionContext) unmarshalInputUpdateAdminDomainInput(ctx context.Con
it.Service = data
case "level":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("level"))
- data, err := ec.unmarshalNInt2int(ctx, v)
+ data, err := ec.unmarshalNDomainLevel2linksᚋapiᚋgraphᚋmodelᚐDomainLevel(ctx, v)
if err != nil {
return it, err
}
@@ 24077,10 24079,41 @@ func (ec *executionContext) _Domain(ctx context.Context, sel ast.SelectionSet, o
atomic.AddUint32(&out.Invalids, 1)
}
case "level":
- out.Values[i] = ec._Domain_level(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_level(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 "status":
out.Values[i] = ec._Domain_status(ctx, field, obj)
if out.Values[i] == graphql.Null {
@@ 27375,6 27408,16 @@ func (ec *executionContext) unmarshalNDomainInput2linksᚋapiᚋgraphᚋmodelᚐ
return res, graphql.ErrorOnPath(ctx, err)
}
+func (ec *executionContext) unmarshalNDomainLevel2linksᚋapiᚋgraphᚋmodelᚐDomainLevel(ctx context.Context, v interface{}) (model.DomainLevel, error) {
+ var res model.DomainLevel
+ err := res.UnmarshalGQL(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalNDomainLevel2linksᚋapiᚋgraphᚋmodelᚐDomainLevel(ctx context.Context, sel ast.SelectionSet, v model.DomainLevel) 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)
}
@@ 28475,6 28518,22 @@ func (ec *executionContext) marshalODomain2ᚖlinksᚋmodelsᚐDomain(ctx contex
return ec._Domain(ctx, sel, v)
}
+func (ec *executionContext) unmarshalODomainLevel2ᚖlinksᚋapiᚋgraphᚋmodelᚐDomainLevel(ctx context.Context, v interface{}) (*model.DomainLevel, error) {
+ if v == nil {
+ return nil, nil
+ }
+ var res = new(model.DomainLevel)
+ err := res.UnmarshalGQL(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalODomainLevel2ᚖlinksᚋapiᚋgraphᚋmodelᚐDomainLevel(ctx context.Context, sel ast.SelectionSet, v *model.DomainLevel) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ return v
+}
+
func (ec *executionContext) unmarshalOGetAdminDomainInput2ᚖlinksᚋapiᚋgraphᚋmodelᚐGetAdminDomainInput(ctx context.Context, v interface{}) (*model.GetAdminDomainInput, error) {
if v == nil {
return nil, nil
M api/graph/model/models_gen.go => api/graph/model/models_gen.go +66 -28
@@ 67,14 67,14 @@ type AdminBillingStats struct {
}
type AdminDomainInput struct {
- Name string `json:"name"`
- LookupName string `json:"lookupName"`
- OrgSlug *string `json:"orgSlug,omitempty"`
- Service int `json:"service"`
- Level int `json:"level"`
- Status int `json:"status"`
- IsActive bool `json:"isActive"`
- MigrateLinks *bool `json:"migrateLinks,omitempty"`
+ Name string `json:"name"`
+ LookupName string `json:"lookupName"`
+ OrgSlug *string `json:"orgSlug,omitempty"`
+ Service int `json:"service"`
+ Level DomainLevel `json:"level"`
+ Status int `json:"status"`
+ IsActive bool `json:"isActive"`
+ MigrateLinks *bool `json:"migrateLinks,omitempty"`
}
type AnalyticData struct {
@@ 133,14 133,14 @@ type FollowPayload struct {
}
type GetAdminDomainInput struct {
- Limit *int `json:"limit,omitempty"`
- After *Cursor `json:"after,omitempty"`
- Before *Cursor `json:"before,omitempty"`
- Search *string `json:"search,omitempty"`
- FilterLevel *int `json:"filterLevel,omitempty"`
- FilterService *int `json:"filterService,omitempty"`
- FilterActive *bool `json:"filterActive,omitempty"`
- OrgSlug *string `json:"orgSlug,omitempty"`
+ Limit *int `json:"limit,omitempty"`
+ After *Cursor `json:"after,omitempty"`
+ Before *Cursor `json:"before,omitempty"`
+ Search *string `json:"search,omitempty"`
+ FilterLevel *DomainLevel `json:"filterLevel,omitempty"`
+ FilterService *int `json:"filterService,omitempty"`
+ FilterActive *bool `json:"filterActive,omitempty"`
+ OrgSlug *string `json:"orgSlug,omitempty"`
}
type GetAdminOrganizationsInput struct {
@@ 277,9 277,6 @@ type NoteInput struct {
OrgSlug string `json:"orgSlug"`
}
-// Considering removing these Null* fields:
-//
-// https://todo.code.netlandish.com/~netlandish/links/75
type NullInt struct {
Int64 int `json:"int64"`
Valid bool `json:"valid"`
@@ 375,15 372,15 @@ type RegisterInvitation struct {
}
type UpdateAdminDomainInput struct {
- ID int `json:"id"`
- Name string `json:"name"`
- LookupName string `json:"lookupName"`
- OrgSlug *string `json:"orgSlug,omitempty"`
- Service int `json:"service"`
- Level int `json:"level"`
- Status int `json:"status"`
- IsActive bool `json:"isActive"`
- MigrateLinks *bool `json:"migrateLinks,omitempty"`
+ ID int `json:"id"`
+ Name string `json:"name"`
+ LookupName string `json:"lookupName"`
+ OrgSlug *string `json:"orgSlug,omitempty"`
+ Service int `json:"service"`
+ Level DomainLevel `json:"level"`
+ Status int `json:"status"`
+ IsActive bool `json:"isActive"`
+ MigrateLinks *bool `json:"migrateLinks,omitempty"`
}
type UpdateLinkInput struct {
@@ 558,3 555,44 @@ func (e *AccessScope) UnmarshalGQL(v interface{}) error {
func (e AccessScope) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}
+
+type DomainLevel string
+
+const (
+ DomainLevelSystem DomainLevel = "SYSTEM"
+ DomainLevelUser DomainLevel = "USER"
+)
+
+var AllDomainLevel = []DomainLevel{
+ DomainLevelSystem,
+ DomainLevelUser,
+}
+
+func (e DomainLevel) IsValid() bool {
+ switch e {
+ case DomainLevelSystem, DomainLevelUser:
+ return true
+ }
+ return false
+}
+
+func (e DomainLevel) String() string {
+ return string(e)
+}
+
+func (e *DomainLevel) UnmarshalGQL(v interface{}) error {
+ str, ok := v.(string)
+ if !ok {
+ return fmt.Errorf("enums must be strings")
+ }
+
+ *e = DomainLevel(str)
+ if !e.IsValid() {
+ return fmt.Errorf("%s is not a valid DomainLevel", str)
+ }
+ return nil
+}
+
+func (e DomainLevel) MarshalGQL(w io.Writer) {
+ fmt.Fprint(w, strconv.Quote(e.String()))
+}
M api/graph/schema.graphqls => api/graph/schema.graphqls +15 -9
@@ 63,11 63,14 @@ type Version {
deprecationDate: Time
}
-"""
-Considering removing these Null* fields:
+enum DomainLevel {
+ SYSTEM
+ USER
+}
-https://todo.code.netlandish.com/~netlandish/links/75
-"""
+
+# Considering removing these Null* fields:
+# https://todo.code.netlandish.com/~netlandish/links/75
type NullInt {
int64: Int!
valid: Boolean!
@@ 245,7 248,7 @@ type Domain {
orgId: NullInt! @access(scope: DOMAINS, kind: RO)
orgSlug: NullString! @access(scope: DOMAINS, kind: RO)
service: Int!
- level: Int!
+ level: DomainLevel!
status: Int!
isActive: Boolean! @access(scope: DOMAINS, kind: RO)
createdOn: Time! @access(scope: DOMAINS, kind: RO)
@@ 451,7 454,7 @@ input GetAdminDomainInput {
after: Cursor
before: Cursor
search: String
- filterLevel: Int
+ filterLevel: DomainLevel
filterService: Int
filterActive: Boolean
orgSlug: String
@@ 630,7 633,7 @@ input AdminDomainInput {
lookupName: String!
orgSlug: String
service: Int!
- level: Int!
+ level: DomainLevel!
status: Int!
isActive: Boolean!
migrateLinks: Boolean
@@ 642,7 645,7 @@ input UpdateAdminDomainInput {
lookupName: String!
orgSlug: String
service: Int!
- level: Int!
+ level: DomainLevel!
status: Int!
isActive: Boolean!
migrateLinks: Boolean
@@ 796,7 799,10 @@ type Mutation {
follow(orgSlug: String!): FollowPayload! @access(scope: PROFILE, kind: RW)
unfollow(orgSlug: String!): FollowPayload! @access(scope: PROFILE, kind: RW)
- "Admin only. Not open to public calls"
+ #
+ # Admin only. Not open to public calls
+ #
+
updateAdminOrgType(orgSlug: String!, orgType: Int!): Organization! @admin
addAdminDomain(input: AdminDomainInput!): Domain! @admin
updateAdminDomain(input: UpdateAdminDomainInput!): Domain! @admin
M api/graph/schema.resolvers.go => api/graph/schema.resolvers.go +14 -9
@@ 39,7 39,7 @@ import (
"golang.org/x/image/draw"
"golang.org/x/net/idna"
"netlandish.com/x/gobwebs"
- oauth2 "netlandish.com/x/gobwebs-oauth2"
+ "netlandish.com/x/gobwebs-oauth2"
gaccounts "netlandish.com/x/gobwebs/accounts"
"netlandish.com/x/gobwebs/crypto"
"netlandish.com/x/gobwebs/database"
@@ 60,6 60,11 @@ func (r *domainResolver) OrgSlug(ctx context.Context, obj *models.Domain) (*mode
return &model.NullString{String: obj.OrgSlug.String, Valid: obj.OrgSlug.Valid}, nil
}
+// Level is the resolver for the level field.
+func (r *domainResolver) Level(ctx context.Context, obj *models.Domain) (model.DomainLevel, error) {
+ panic(fmt.Errorf("not implemented: Level - level"))
+}
+
// 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)
@@ 3701,8 3706,8 @@ func (r *mutationResolver) AddAdminDomain(ctx context.Context, input model.Admin
lt.Translate("Invalid service value.")).
WithField("service").
WithCode(valid.ErrValidationCode)
- validator.Expect(input.Level == models.DomainLevelSystem ||
- input.Level == models.DomainLevelUser,
+ validator.Expect(string(input.Level) == models.DomainLevelSystem ||
+ string(input.Level) == models.DomainLevelUser,
lt.Translate("Invalid level value.")).
WithField("level").
WithCode(valid.ErrValidationCode)
@@ 3736,7 3741,7 @@ func (r *mutationResolver) AddAdminDomain(ctx context.Context, input model.Admin
}
host = strings.ToLower(host)
- if input.Level == models.DomainLevelUser && input.OrgSlug == nil {
+ if string(input.Level) == models.DomainLevelUser && input.OrgSlug == nil {
validator.Error(lt.Translate("Organization Slug is required for user level domains")).
WithField("orgSlug").
WithCode(valid.ErrValidationCode)
@@ 3823,7 3828,7 @@ func (r *mutationResolver) AddAdminDomain(ctx context.Context, input model.Admin
domain := &models.Domain{
Name: input.Name,
LookupName: host,
- Level: input.Level,
+ Level: string(input.Level),
Service: input.Service,
Status: input.Status,
IsActive: input.IsActive,
@@ 3877,8 3882,8 @@ func (r *mutationResolver) UpdateAdminDomain(ctx context.Context, input model.Up
lt.Translate("Invalid service value.")).
WithField("service").
WithCode(valid.ErrValidationCode)
- validator.Expect(input.Level == models.DomainLevelSystem ||
- input.Level == models.DomainLevelUser,
+ validator.Expect(string(input.Level) == models.DomainLevelSystem ||
+ string(input.Level) == models.DomainLevelUser,
lt.Translate("Invalid level value.")).
WithField("level").
WithCode(valid.ErrValidationCode)
@@ 3912,7 3917,7 @@ func (r *mutationResolver) UpdateAdminDomain(ctx context.Context, input model.Up
}
host = strings.ToLower(host)
- if input.Level == models.DomainLevelUser && input.OrgSlug == nil {
+ if string(input.Level) == models.DomainLevelUser && input.OrgSlug == nil {
validator.Error(lt.Translate("Organization Slug is required for user level domains")).
WithField("orgSlug").
WithCode(valid.ErrValidationCode)
@@ 4018,7 4023,7 @@ func (r *mutationResolver) UpdateAdminDomain(ctx context.Context, input model.Up
ldomain.Name = input.Name
ldomain.LookupName = host
- ldomain.Level = input.Level
+ ldomain.Level = string(input.Level)
ldomain.Service = input.Service
ldomain.Status = input.Status
ldomain.IsActive = input.IsActive
M migrations/0001_initial.down.sql => migrations/0001_initial.down.sql +2 -0
@@ 31,3 31,5 @@ DROP TABLE IF EXISTS domains;
DROP TABLE IF EXISTS followers;
DROP TABLE IF EXISTS organizations;
DROP TABLE IF EXISTS users;
+
+DROP TYPE IF EXISTS domain_level;
M migrations/0001_initial.up.sql => migrations/0001_initial.up.sql +12 -1
@@ 10,6 10,17 @@ BEGIN
END;
$$ language 'plpgsql';
+-- Wrap in exceptions here for tests
+DO $$ BEGIN
+ CREATE TYPE domain_level AS ENUM (
+ 'SYSTEM',
+ 'USER'
+ );
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+
CREATE TABLE users (
id SERIAL PRIMARY KEY,
full_name VARCHAR ( 150 ) NOT NULL,
@@ 141,7 152,7 @@ CREATE TABLE domains (
name VARCHAR (255) NOT NULL,
lookup_name VARCHAR (500) NOT NULL, -- padded in case...
org_id INT REFERENCES organizations (id) ON DELETE CASCADE,
- level INT DEFAULT 0 NOT NULL,
+ level domain_level NOT NULL,
service INT NOT NULL,
status INT DEFAULT 0 NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
M models/domains.go => models/domains.go +7 -2
@@ 15,9 15,9 @@ import (
const (
// DomainLevelSystem ...
- DomainLevelSystem int = iota
+ DomainLevelSystem string = "SYSTEM"
// DomainLevelUser ...
- DomainLevelUser
+ DomainLevelUser string = "USER"
)
const (
@@ 132,6 132,11 @@ func (d *Domain) Store(ctx context.Context) error {
return err
}
}
+
+ // Added for fail safes after migration to enums. Can be removed later
+ if d.Level == "" {
+ d.Level = DomainLevelSystem
+ }
err = sq.
Insert("domains").
Columns("name", "lookup_name", "org_id", "level", "service", "status", "is_active").
M models/models.go => models/models.go +1 -1
@@ 109,7 109,7 @@ type Domain struct {
Name string `db:"name"`
LookupName string `db:"lookup_name"`
OrgID sql.NullInt64 `db:"org_id"`
- Level int `db:"level"`
+ Level string `db:"level"`
Service int `db:"service"`
Status int `db:"status"`
IsActive bool `db:"is_active"`
M models/schema.sql => models/schema.sql +7 -1
@@ 10,6 10,12 @@ BEGIN
END;
$$ language 'plpgsql';
+CREATE TYPE domain_level AS ENUM (
+ 'SYSTEM',
+ 'USER'
+);
+
+
CREATE TABLE users (
id SERIAL PRIMARY KEY,
full_name VARCHAR ( 150 ) NOT NULL,
@@ 141,7 147,7 @@ CREATE TABLE domains (
name VARCHAR (255) NOT NULL,
lookup_name VARCHAR (500) NOT NULL, -- padded in case...
org_id INT REFERENCES organizations (id) ON DELETE CASCADE,
- level INT DEFAULT 0 NOT NULL,
+ level domain_level NOT NULL,
service INT NOT NULL,
status INT DEFAULT 0 NOT NULL,
is_active BOOLEAN DEFAULT TRUE,