M api/graph/generated.go => api/graph/generated.go +52 -9
@@ 476,6 476,8 @@ type OrgLinkResolver interface {
BaseURLID(ctx context.Context, obj *models.OrgLink) (*model.NullInt, error)
Visibility(ctx context.Context, obj *models.OrgLink) (model.LinkVisibility, error)
+
+ Type(ctx context.Context, obj *models.OrgLink) (model.LinkType, error)
}
type OrganizationResolver interface {
Image(ctx context.Context, obj *models.Organization) (*graphql.Upload, error)
@@ 12948,7 12950,7 @@ func (ec *executionContext) _OrgLink_type(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.Type, nil
+ return ec.resolvers.OrgLink().Type(rctx, obj)
})
if err != nil {
ec.Error(ctx, err)
@@ 12960,19 12962,19 @@ func (ec *executionContext) _OrgLink_type(ctx context.Context, field graphql.Col
}
return graphql.Null
}
- res := resTmp.(int)
+ res := resTmp.(model.LinkType)
fc.Result = res
- return ec.marshalNInt2int(ctx, field.Selections, res)
+ return ec.marshalNLinkType2linksᚋapiᚋgraphᚋmodelᚐLinkType(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_OrgLink_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "OrgLink",
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 LinkType does not have child fields")
},
}
return fc, nil
@@ 25313,10 25315,41 @@ func (ec *executionContext) _OrgLink(ctx context.Context, sel ast.SelectionSet,
atomic.AddUint32(&out.Invalids, 1)
}
case "type":
- out.Values[i] = ec._OrgLink_type(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._OrgLink_type(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 "tags":
out.Values[i] = ec._OrgLink_tags(ctx, field, obj)
if out.Values[i] == graphql.Null {
@@ 27707,6 27740,16 @@ func (ec *executionContext) marshalNLinkShortCursor2ᚖlinksᚋapiᚋgraphᚋmod
return ec._LinkShortCursor(ctx, sel, v)
}
+func (ec *executionContext) unmarshalNLinkType2linksᚋapiᚋgraphᚋmodelᚐLinkType(ctx context.Context, v interface{}) (model.LinkType, error) {
+ var res model.LinkType
+ err := res.UnmarshalGQL(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalNLinkType2linksᚋapiᚋgraphᚋmodelᚐLinkType(ctx context.Context, sel ast.SelectionSet, v model.LinkType) graphql.Marshaler {
+ return v
+}
+
func (ec *executionContext) unmarshalNLinkVisibility2linksᚋapiᚋgraphᚋmodelᚐLinkVisibility(ctx context.Context, v interface{}) (model.LinkVisibility, error) {
var res model.LinkVisibility
err := res.UnmarshalGQL(v)
M api/graph/model/models_gen.go => api/graph/model/models_gen.go +41 -0
@@ 683,6 683,47 @@ func (e DomainStatus) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}
+type LinkType string
+
+const (
+ LinkTypeLink LinkType = "LINK"
+ LinkTypeNote LinkType = "NOTE"
+)
+
+var AllLinkType = []LinkType{
+ LinkTypeLink,
+ LinkTypeNote,
+}
+
+func (e LinkType) IsValid() bool {
+ switch e {
+ case LinkTypeLink, LinkTypeNote:
+ return true
+ }
+ return false
+}
+
+func (e LinkType) String() string {
+ return string(e)
+}
+
+func (e *LinkType) UnmarshalGQL(v interface{}) error {
+ str, ok := v.(string)
+ if !ok {
+ return fmt.Errorf("enums must be strings")
+ }
+
+ *e = LinkType(str)
+ if !e.IsValid() {
+ return fmt.Errorf("%s is not a valid LinkType", str)
+ }
+ return nil
+}
+
+func (e LinkType) MarshalGQL(w io.Writer) {
+ fmt.Fprint(w, strconv.Quote(e.String()))
+}
+
type LinkVisibility string
const (
M api/graph/schema.graphqls => api/graph/schema.graphqls +10 -2
@@ 86,6 86,11 @@ enum LinkVisibility {
RESTRICTED
}
+enum LinkType {
+ LINK
+ NOTE
+}
+
# Considering removing these Null* fields:
# https://todo.code.netlandish.com/~netlandish/links/75
@@ 194,7 199,7 @@ type OrgLink {
unread: Boolean! @access(scope: LINKS, kind: RO)
starred: Boolean! @access(scope: LINKS, kind: RO)
archiveUrl: String!
- type: Int!
+ type: LinkType!
tags: [Tag]!
author: String!
orgSlug: String! @access(scope: LINKS, kind: RO)
@@ 756,7 761,10 @@ type Query {
"Returns an array of organizations that the calling user follows"
getFeedFollowing: [Organization!]! @access(scope: PROFILE, kind: RO)
- "Admin only. Not open to public calls"
+ #
+ # Admin only. Not open to public calls
+ #
+
getUsers(input: GetUserInput): UserCursor! @admin
getUser(id: Int!): User! @admin
getAdminOrganizations(input: GetAdminOrganizationsInput): OrganizationCursor! @admin
M api/graph/schema.resolvers.go => api/graph/schema.resolvers.go +5 -0
@@ 4197,6 4197,11 @@ func (r *orgLinkResolver) Visibility(ctx context.Context, obj *models.OrgLink) (
return model.LinkVisibility(obj.Visibility), nil
}
+// Type is the resolver for the type field.
+func (r *orgLinkResolver) Type(ctx context.Context, obj *models.OrgLink) (model.LinkType, error) {
+ return model.LinkType(obj.Type), 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 core/import.go => core/import.go +1 -1
@@ 271,7 271,7 @@ func processOrgLinks(obj importObj, baseURLMap map[string]int,
vis = models.OrgLinkVisibilityPrivate
}
- var linkType int
+ var linkType string
if obj.IsNote() {
// Hash is set in processBaseURLs
linkType = models.NoteType
M migrations/0001_initial.down.sql => migrations/0001_initial.down.sql +1 -0
@@ 37,3 37,4 @@ DROP TYPE IF EXISTS domain_service;
DROP TYPE IF EXISTS domain_status;
DROP TYPE IF EXISTS invoice_status;
DROP TYPE IF EXISTS org_link_visibility;
+DROP TYPE IF EXISTS org_link_type;
M migrations/0001_initial.up.sql => migrations/0001_initial.up.sql +11 -1
@@ 61,6 61,16 @@ EXCEPTION
WHEN duplicate_object THEN null;
END $$;
+DO $$ BEGIN
+ CREATE TYPE org_link_type AS ENUM (
+ 'LINK',
+ 'NOTE'
+ );
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+
CREATE TABLE users (
id SERIAL PRIMARY KEY,
@@ 151,7 161,7 @@ CREATE TABLE org_links (
title VARCHAR ( 150 ) NOT NULL,
url TEXT NOT NULL,
description TEXT DEFAULT '',
- "type" INT NOT NULL DEFAULT 0,
+ "type" org_link_type default 'LINK',
hash VARCHAR(128) UNIQUE NOT NULL,
base_url_id INT REFERENCES base_urls (id) ON DELETE CASCADE,
org_id INT REFERENCES organizations (id) ON DELETE CASCADE NOT NULL,
M models/models.go => models/models.go +1 -1
@@ 80,7 80,7 @@ type OrgLink struct {
Unread bool `db:"unread" json:"unread"`
Starred bool `db:"starred" json:"starred"`
ArchiveURL string `db:"archive_url" json:"archiveUrl"`
- Type int `db:"type" json:"type"`
+ Type string `db:"type" json:"type"`
Hash string `db:"hash" json:"hash"`
CreatedOn time.Time `db:"created_on" json:"createdOn"`
UpdatedOn time.Time `db:"updated_on" json:"updatedOn"`
M models/org_link.go => models/org_link.go +6 -2
@@ 22,8 22,8 @@ const (
)
const (
- OrgLinkType int = iota
- NoteType
+ OrgLinkType string = "LINK"
+ NoteType string = "NOTE"
)
// GetOrgLinks ...
@@ 138,6 138,10 @@ func (o *OrgLink) Store(ctx context.Context) error {
if o.Visibility == "" {
o.Visibility = OrgLinkVisibilityPublic
}
+ if o.Type == "" {
+ o.Type = OrgLinkType
+ }
+
err = sq.
Insert("org_links").
Columns("title", "url", "description", "base_url_id", "org_id", "user_id", "visibility",
M models/schema.sql => models/schema.sql +7 -1
@@ 40,6 40,12 @@ CREATE TYPE org_link_visibility AS ENUM (
'RESTRICTED'
);
+CREATE TYPE org_link_type AS ENUM (
+ 'LINK',
+ 'NOTE'
+);
+
+
CREATE TABLE users (
id SERIAL PRIMARY KEY,
full_name VARCHAR ( 150 ) NOT NULL,
@@ 129,7 135,7 @@ CREATE TABLE org_links (
title VARCHAR ( 150 ) NOT NULL,
url TEXT NOT NULL,
description TEXT DEFAULT '',
- "type" INT NOT NULL DEFAULT 0,
+ "type" org_link_type default 'LINK',
hash VARCHAR(128) UNIQUE NOT NULL,
base_url_id INT REFERENCES base_urls (id) ON DELETE CASCADE,
org_id INT REFERENCES organizations (id) ON DELETE CASCADE NOT NULL,
M templates/link_detail.html => templates/link_detail.html +2 -2
@@ 28,7 28,7 @@
</div>
</div>
</header>
- {{if eq .link.Type 0}}
+ {{ if eq .link.Type "LINK" }}
<p><a href="{{reverse "core:link_redirect" .link.Hash}}" target="_blank">{{stripCommonProtocol .link.URL}}</a></p>
{{end}}
<p>{{.link.Description}}</p>
@@ 42,7 42,7 @@
{{end}}
{{if eq .link.UserID .currentUserID}}
<footer class="is-right">
- {{if eq .link.Type 0}}
+ {{ if eq .link.Type "LINK" }}
<a class="button dark" href="{{reverse "core:link_edit" .link.Hash}}">{{.pd.Data.edit}}</a>
{{else}}
<a class="button dark" href="{{reverse "core:note_edit" .link.Hash}}">{{.pd.Data.edit}}</a>