~netlandish/links

829bbc118e574f009361d83c403ec09176e28bda — Peter Sanchez a month ago ffcbea1
Moving organizations org_type to enum
M api/graph/generated.go => api/graph/generated.go +52 -9
@@ 480,6 480,8 @@ type OrgLinkResolver interface {
	Type(ctx context.Context, obj *models.OrgLink) (model.LinkType, error)
}
type OrganizationResolver interface {
	OrgType(ctx context.Context, obj *models.Organization) (model.OrgType, error)

	Image(ctx context.Context, obj *models.Organization) (*graphql.Upload, error)
}
type OrganizationSettingsResolver interface {


@@ 13549,7 13551,7 @@ func (ec *executionContext) _Organization_orgType(ctx context.Context, field gra
	}()
	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
		ctx = rctx // use context from middleware stack in children
		return obj.OrgType, nil
		return ec.resolvers.Organization().OrgType(rctx, obj)
	})
	if err != nil {
		ec.Error(ctx, err)


@@ 13561,19 13563,19 @@ func (ec *executionContext) _Organization_orgType(ctx context.Context, field gra
		}
		return graphql.Null
	}
	res := resTmp.(int)
	res := resTmp.(model.OrgType)
	fc.Result = res
	return ec.marshalNInt2int(ctx, field.Selections, res)
	return ec.marshalNOrgType2linksᚋapiᚋgraphᚋmodelᚐOrgType(ctx, field.Selections, res)
}

func (ec *executionContext) fieldContext_Organization_orgType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
	fc = &graphql.FieldContext{
		Object:     "Organization",
		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 OrgType does not have child fields")
		},
	}
	return fc, nil


@@ 25466,10 25468,41 @@ func (ec *executionContext) _Organization(ctx context.Context, sel ast.Selection
				atomic.AddUint32(&out.Invalids, 1)
			}
		case "orgType":
			out.Values[i] = ec._Organization_orgType(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._Organization_orgType(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 "name":
			out.Values[i] = ec._Organization_name(ctx, field, obj)
			if out.Values[i] == graphql.Null {


@@ 28000,6 28033,16 @@ func (ec *executionContext) marshalNOrgLinkCursor2ᚖlinksᚋapiᚋgraphᚋmodel
	return ec._OrgLinkCursor(ctx, sel, v)
}

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

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

func (ec *executionContext) marshalNOrganization2linksᚋmodelsᚐOrganization(ctx context.Context, sel ast.SelectionSet, v models.Organization) graphql.Marshaler {
	return ec._Organization(ctx, sel, &v)
}

M api/graph/model/models_gen.go => api/graph/model/models_gen.go +41 -0
@@ 809,3 809,44 @@ func (e *MemberPermission) UnmarshalGQL(v interface{}) error {
func (e MemberPermission) MarshalGQL(w io.Writer) {
	fmt.Fprint(w, strconv.Quote(e.String()))
}

type OrgType string

const (
	OrgTypeUser   OrgType = "USER"
	OrgTypeNormal OrgType = "NORMAL"
)

var AllOrgType = []OrgType{
	OrgTypeUser,
	OrgTypeNormal,
}

func (e OrgType) IsValid() bool {
	switch e {
	case OrgTypeUser, OrgTypeNormal:
		return true
	}
	return false
}

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

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

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

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

M api/graph/schema.graphqls => api/graph/schema.graphqls +7 -1
@@ 97,6 97,12 @@ enum MemberPermission {
  ADMIN_WRITE
}

enum OrgType {
  USER
  NORMAL
}


# Considering removing these Null* fields:
# https://todo.code.netlandish.com/~netlandish/links/75
type NullInt {


@@ 135,7 141,7 @@ type OrganizationSettings {
type Organization {
    id: Int!
    ownerId: Int! @access(scope: ORGS, kind: RO)
    orgType: Int!
    orgType: OrgType!
    name: String!
    slug: String!
    image: Upload

M api/graph/schema.resolvers.go => api/graph/schema.resolvers.go +5 -0
@@ 4205,6 4205,11 @@ func (r *orgLinkResolver) Type(ctx context.Context, obj *models.OrgLink) (model.
	return model.LinkType(obj.Type), nil
}

// OrgType is the resolver for the orgType field.
func (r *organizationResolver) OrgType(ctx context.Context, obj *models.Organization) (model.OrgType, error) {
	return model.OrgType(obj.OrgType), nil
}

// Image is the resolver for the image field.
func (r *organizationResolver) Image(ctx context.Context, obj *models.Organization) (*graphql.Upload, error) {
	panic(fmt.Errorf("not implemented: Image - image"))

M migrations/0001_initial.down.sql => migrations/0001_initial.down.sql +1 -0
@@ 39,3 39,4 @@ DROP TYPE IF EXISTS invoice_status;
DROP TYPE IF EXISTS org_link_visibility;
DROP TYPE IF EXISTS org_link_type;
DROP TYPE IF EXISTS org_user_perm;
DROP TYPE IF EXISTS org_type;

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

DO $$ BEGIN
  CREATE TYPE org_type AS ENUM (
    'USER',
    'NORMAL'
  );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;


CREATE TABLE users (
  id SERIAL PRIMARY KEY,


@@ 102,7 111,7 @@ CREATE INDEX users_id_idx ON users (id);
CREATE TABLE organizations (
  id SERIAL PRIMARY KEY,
  owner_id INT REFERENCES users (id) ON DELETE CASCADE NOT NULL,
  org_type INT DEFAULT 0,
  org_type org_type DEFAULT 'USER',
  name VARCHAR ( 150 ) NOT NULL,
  slug VARCHAR ( 150 ) UNIQUE NOT NULL,
  image VARCHAR(1024) DEFAULT '',

M migrations/test_migration.up.sql => migrations/test_migration.up.sql +1 -1
@@ 3,7 3,7 @@ INSERT INTO users (full_name, password, email, is_verified) VALUES ('test_api_us
INSERT INTO users (full_name, password, email, is_verified, is_superuser) VALUES ('superuser', 'qwerty', 'superuser@api.com', true, true);

INSERT INTO organizations (owner_id, name, slug) VALUES (1, 'personal org', 'personal-org');
INSERT INTO organizations (owner_id, name, slug, org_type) VALUES (1, 'business org', 'business_org', 1);
INSERT INTO organizations (owner_id, name, slug, org_type) VALUES (1, 'business org', 'business_org', 'NORMAL');

INSERT INTO organizations (owner_id, name, slug) VALUES (2, 'api test org', 'api-test-org');


M models/models.go => models/models.go +1 -1
@@ 37,7 37,7 @@ type User struct {
type Organization struct {
	ID        int                  `db:"id"`
	OwnerID   int                  `db:"owner_id"`
	OrgType   int                  `db:"org_type"`
	OrgType   string               `db:"org_type"`
	Name      string               `db:"name"`
	Slug      string               `db:"slug"`
	Image     string               `db:"image"`

M models/organization.go => models/organization.go +6 -2
@@ 16,9 16,13 @@ import (
	"netlandish.com/x/gobwebs/timezone"
)

// Organization type is used to define which was created as the "user" org during
// registration and which is a "normal" org created after registration.
// USER = Automatically created during registration based off provided username
// NORMAL = User created additional organization
const (
	OrgTypeUser int = iota
	OrgTypeNormal
	OrgTypeUser   string = "USER"
	OrgTypeNormal string = "NORMAL"
)

// Billing status, used for org billing setting/metadata

M models/schema.sql => models/schema.sql +7 -2
@@ 51,6 51,12 @@ CREATE TYPE org_link_perm AS ENUM (
  'ADMIN_WRITE'
);

CREATE TYPE org_type AS ENUM (
  'USER',
  'NORMAL'
);


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


@@ 72,7 78,7 @@ CREATE INDEX users_id_idx ON users (id);
CREATE TABLE organizations (
  id SERIAL PRIMARY KEY,
  owner_id INT REFERENCES users (id) ON DELETE CASCADE NOT NULL,
  org_type INT DEFAULT 0,
  org_type org_type DEFAULT 'USER',
  name VARCHAR ( 150 ) NOT NULL,
  slug VARCHAR ( 150 ) UNIQUE NOT NULL,
  image VARCHAR(1024) DEFAULT '',


@@ 145,7 151,6 @@ CREATE TABLE org_links (
  base_url_id INT REFERENCES base_urls (id) ON DELETE CASCADE,
  org_id INT REFERENCES organizations (id) ON DELETE CASCADE NOT NULL,
  user_id INT REFERENCES users (id) ON DELETE SET NULL,
  visibility INT DEFAULT 0,
  visibility org_link_visibility DEFAULT 'PUBLIC',
  unread BOOLEAN DEFAULT FALSE NOT NULL,
  starred BOOLEAN DEFAULT FALSE NOT NULL,