API: rig up tracker { acl }

This commit is contained in:
Drew DeVault 2021-02-19 10:52:31 -05:00
parent 01df69ef46
commit 837d887647
6 changed files with 86 additions and 306 deletions

View File

@ -97,12 +97,6 @@ type ComplexityRoot struct {
Triage func(childComplexity int) int Triage func(childComplexity int) int
} }
DefaultACLs struct {
Anonymous func(childComplexity int) int
LoggedIn func(childComplexity int) int
Submitter func(childComplexity int) int
}
EmailAddress struct { EmailAddress struct {
CanonicalName func(childComplexity int) int CanonicalName func(childComplexity int) int
Mailbox func(childComplexity int) int Mailbox func(childComplexity int) int
@ -217,7 +211,6 @@ type ComplexityRoot struct {
ACL func(childComplexity int) int ACL func(childComplexity int) int
Acls func(childComplexity int, cursor *model1.Cursor) int Acls func(childComplexity int, cursor *model1.Cursor) int
Created func(childComplexity int) int Created func(childComplexity int) int
DefaultACLs func(childComplexity int) int
Description func(childComplexity int) int Description func(childComplexity int) int
ID func(childComplexity int) int ID func(childComplexity int) int
Labels func(childComplexity int, cursor *model1.Cursor) int Labels func(childComplexity int, cursor *model1.Cursor) int
@ -346,7 +339,6 @@ type TrackerResolver interface {
Tickets(ctx context.Context, obj *model.Tracker, cursor *model1.Cursor) (*model.TicketCursor, error) Tickets(ctx context.Context, obj *model.Tracker, cursor *model1.Cursor) (*model.TicketCursor, error)
Labels(ctx context.Context, obj *model.Tracker, cursor *model1.Cursor) (*model.LabelCursor, error) Labels(ctx context.Context, obj *model.Tracker, cursor *model1.Cursor) (*model.LabelCursor, error)
Acls(ctx context.Context, obj *model.Tracker, cursor *model1.Cursor) (*model.ACLCursor, error) Acls(ctx context.Context, obj *model.Tracker, cursor *model1.Cursor) (*model.ACLCursor, error)
Subscription(ctx context.Context, obj *model.Tracker) (*model.TrackerSubscription, error) Subscription(ctx context.Context, obj *model.Tracker) (*model.TrackerSubscription, error)
ACL(ctx context.Context, obj *model.Tracker) (model.ACL, error) ACL(ctx context.Context, obj *model.Tracker) (model.ACL, error)
@ -522,27 +514,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.DefaultACL.Triage(childComplexity), true return e.complexity.DefaultACL.Triage(childComplexity), true
case "DefaultACLs.anonymous":
if e.complexity.DefaultACLs.Anonymous == nil {
break
}
return e.complexity.DefaultACLs.Anonymous(childComplexity), true
case "DefaultACLs.logged_in":
if e.complexity.DefaultACLs.LoggedIn == nil {
break
}
return e.complexity.DefaultACLs.LoggedIn(childComplexity), true
case "DefaultACLs.submitter":
if e.complexity.DefaultACLs.Submitter == nil {
break
}
return e.complexity.DefaultACLs.Submitter(childComplexity), true
case "EmailAddress.canonicalName": case "EmailAddress.canonicalName":
if e.complexity.EmailAddress.CanonicalName == nil { if e.complexity.EmailAddress.CanonicalName == nil {
break break
@ -1090,13 +1061,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Tracker.Created(childComplexity), true return e.complexity.Tracker.Created(childComplexity), true
case "Tracker.defaultACLs":
if e.complexity.Tracker.DefaultACLs == nil {
break
}
return e.complexity.Tracker.DefaultACLs(childComplexity), true
case "Tracker.description": case "Tracker.description":
if e.complexity.Tracker.Description == nil { if e.complexity.Tracker.Description == nil {
break break
@ -1526,8 +1490,6 @@ type Tracker {
tickets(cursor: Cursor): TicketCursor! @access(scope: TICKETS, kind: RO) tickets(cursor: Cursor): TicketCursor! @access(scope: TICKETS, kind: RO)
labels(cursor: Cursor): LabelCursor! labels(cursor: Cursor): LabelCursor!
defaultACLs: DefaultACLs @access(scope: ACLS, kind: RO)
# Only available to the tracker owner: # Only available to the tracker owner:
acls(cursor: Cursor): ACLCursor! @access(scope: ACLS, kind: RO) acls(cursor: Cursor): ACLCursor! @access(scope: ACLS, kind: RO)
@ -1619,7 +1581,7 @@ interface ACL {
type TrackerACL implements ACL { type TrackerACL implements ACL {
id: Int! id: Int!
created: Time! created: Time!
tracker: Tracker! tracker: Tracker! @access(scope: TRACKERS, kind: RO)
entity: Entity! @access(scope: PROFILE, kind: RO) entity: Entity! @access(scope: PROFILE, kind: RO)
browse: Boolean! browse: Boolean!
@ -1629,6 +1591,8 @@ type TrackerACL implements ACL {
triage: Boolean! triage: Boolean!
} }
# These ACL policies are applied non-specifically, e.g. the default ACL for all
# authenticated users.
type DefaultACL implements ACL { type DefaultACL implements ACL {
browse: Boolean! browse: Boolean!
submit: Boolean! submit: Boolean!
@ -1637,18 +1601,6 @@ type DefaultACL implements ACL {
triage: Boolean! triage: Boolean!
} }
# These ACLs are inherited by users who do not have a more specific ACL
# configured.
type DefaultACLs {
# Permissions granted to anyone who visits this tracker, logged in or
# otherwise.
anonymous: ACL!
# Permissions granted to the ticket submitter on the tickets they submit.
submitter: ACL!
# Permissions granted to any logged-in sourcehut user.
logged_in: ACL!
}
type Label { type Label {
id: Int! id: Int!
created: Time! created: Time!
@ -2860,111 +2812,6 @@ func (ec *executionContext) _DefaultACL_triage(ctx context.Context, field graphq
return ec.marshalNBoolean2bool(ctx, field.Selections, res) return ec.marshalNBoolean2bool(ctx, field.Selections, res)
} }
func (ec *executionContext) _DefaultACLs_anonymous(ctx context.Context, field graphql.CollectedField, obj *model.DefaultACLs) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "DefaultACLs",
Field: field,
Args: nil,
IsMethod: false,
IsResolver: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Anonymous, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(model.ACL)
fc.Result = res
return ec.marshalNACL2gitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐACL(ctx, field.Selections, res)
}
func (ec *executionContext) _DefaultACLs_submitter(ctx context.Context, field graphql.CollectedField, obj *model.DefaultACLs) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "DefaultACLs",
Field: field,
Args: nil,
IsMethod: false,
IsResolver: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Submitter, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(model.ACL)
fc.Result = res
return ec.marshalNACL2gitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐACL(ctx, field.Selections, res)
}
func (ec *executionContext) _DefaultACLs_logged_in(ctx context.Context, field graphql.CollectedField, obj *model.DefaultACLs) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "DefaultACLs",
Field: field,
Args: nil,
IsMethod: false,
IsResolver: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.LoggedIn, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(model.ACL)
fc.Result = res
return ec.marshalNACL2gitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐACL(ctx, field.Selections, res)
}
func (ec *executionContext) _EmailAddress_canonicalName(ctx context.Context, field graphql.CollectedField, obj *model.EmailAddress) (ret graphql.Marshaler) { func (ec *executionContext) _EmailAddress_canonicalName(ctx context.Context, field graphql.CollectedField, obj *model.EmailAddress) (ret graphql.Marshaler) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@ -6226,66 +6073,6 @@ func (ec *executionContext) _Tracker_labels(ctx context.Context, field graphql.C
return ec.marshalNLabelCursor2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐLabelCursor(ctx, field.Selections, res) return ec.marshalNLabelCursor2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐLabelCursor(ctx, field.Selections, res)
} }
func (ec *executionContext) _Tracker_defaultACLs(ctx context.Context, field graphql.CollectedField, obj *model.Tracker) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "Tracker",
Field: field,
Args: nil,
IsMethod: false,
IsResolver: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
directive0 := func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.DefaultACLs, nil
}
directive1 := func(ctx context.Context) (interface{}, error) {
scope, err := ec.unmarshalNAccessScope2gitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐAccessScope(ctx, "ACLS")
if err != nil {
return nil, err
}
kind, err := ec.unmarshalNAccessKind2gitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐAccessKind(ctx, "RO")
if err != nil {
return nil, err
}
if ec.directives.Access == nil {
return nil, errors.New("directive access is not implemented")
}
return ec.directives.Access(ctx, obj, directive0, scope, kind)
}
tmp, err := directive1(rctx)
if err != nil {
return nil, graphql.ErrorOnPath(ctx, err)
}
if tmp == nil {
return nil, nil
}
if data, ok := tmp.(*model.DefaultACLs); ok {
return data, nil
}
return nil, fmt.Errorf(`unexpected type %T from directive, should be *git.sr.ht/~sircmpwn/todo.sr.ht/api/graph/model.DefaultACLs`, tmp)
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*model.DefaultACLs)
fc.Result = res
return ec.marshalODefaultACLs2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐDefaultACLs(ctx, field.Selections, res)
}
func (ec *executionContext) _Tracker_acls(ctx context.Context, field graphql.CollectedField, obj *model.Tracker) (ret graphql.Marshaler) { func (ec *executionContext) _Tracker_acls(ctx context.Context, field graphql.CollectedField, obj *model.Tracker) (ret graphql.Marshaler) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@ -6535,8 +6322,36 @@ func (ec *executionContext) _TrackerACL_tracker(ctx context.Context, field graph
ctx = graphql.WithFieldContext(ctx, fc) ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children directive0 := func(rctx context.Context) (interface{}, error) {
return ec.resolvers.TrackerACL().Tracker(rctx, obj) ctx = rctx // use context from middleware stack in children
return ec.resolvers.TrackerACL().Tracker(rctx, obj)
}
directive1 := func(ctx context.Context) (interface{}, error) {
scope, err := ec.unmarshalNAccessScope2gitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐAccessScope(ctx, "TRACKERS")
if err != nil {
return nil, err
}
kind, err := ec.unmarshalNAccessKind2gitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐAccessKind(ctx, "RO")
if err != nil {
return nil, err
}
if ec.directives.Access == nil {
return nil, errors.New("directive access is not implemented")
}
return ec.directives.Access(ctx, obj, directive0, scope, kind)
}
tmp, err := directive1(rctx)
if err != nil {
return nil, graphql.ErrorOnPath(ctx, err)
}
if tmp == nil {
return nil, nil
}
if data, ok := tmp.(*model.Tracker); ok {
return data, nil
}
return nil, fmt.Errorf(`unexpected type %T from directive, should be *git.sr.ht/~sircmpwn/todo.sr.ht/api/graph/model.Tracker`, tmp)
}) })
if err != nil { if err != nil {
ec.Error(ctx, err) ec.Error(ctx, err)
@ -9167,43 +8982,6 @@ func (ec *executionContext) _DefaultACL(ctx context.Context, sel ast.SelectionSe
return out return out
} }
var defaultACLsImplementors = []string{"DefaultACLs"}
func (ec *executionContext) _DefaultACLs(ctx context.Context, sel ast.SelectionSet, obj *model.DefaultACLs) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, defaultACLsImplementors)
out := graphql.NewFieldSet(fields)
var invalids uint32
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("DefaultACLs")
case "anonymous":
out.Values[i] = ec._DefaultACLs_anonymous(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "submitter":
out.Values[i] = ec._DefaultACLs_submitter(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "logged_in":
out.Values[i] = ec._DefaultACLs_logged_in(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch()
if invalids > 0 {
return graphql.Null
}
return out
}
var emailAddressImplementors = []string{"EmailAddress", "Entity"} var emailAddressImplementors = []string{"EmailAddress", "Entity"}
func (ec *executionContext) _EmailAddress(ctx context.Context, sel ast.SelectionSet, obj *model.EmailAddress) graphql.Marshaler { func (ec *executionContext) _EmailAddress(ctx context.Context, sel ast.SelectionSet, obj *model.EmailAddress) graphql.Marshaler {
@ -10139,8 +9917,6 @@ func (ec *executionContext) _Tracker(ctx context.Context, sel ast.SelectionSet,
} }
return res return res
}) })
case "defaultACLs":
out.Values[i] = ec._Tracker_defaultACLs(ctx, field, obj)
case "acls": case "acls":
field := field field := field
out.Concurrently(i, func() (res graphql.Marshaler) { out.Concurrently(i, func() (res graphql.Marshaler) {
@ -10773,16 +10549,6 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o
// region ***************************** type.gotpl ***************************** // region ***************************** type.gotpl *****************************
func (ec *executionContext) marshalNACL2gitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐACL(ctx context.Context, sel ast.SelectionSet, v model.ACL) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
return ec._ACL(ctx, sel, v)
}
func (ec *executionContext) marshalNACLCursor2gitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐACLCursor(ctx context.Context, sel ast.SelectionSet, v model.ACLCursor) graphql.Marshaler { func (ec *executionContext) marshalNACLCursor2gitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐACLCursor(ctx context.Context, sel ast.SelectionSet, v model.ACLCursor) graphql.Marshaler {
return ec._ACLCursor(ctx, sel, &v) return ec._ACLCursor(ctx, sel, &v)
} }
@ -11632,13 +11398,6 @@ func (ec *executionContext) marshalOCursor2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋcore
return v return v
} }
func (ec *executionContext) marshalODefaultACLs2ᚖgitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐDefaultACLs(ctx context.Context, sel ast.SelectionSet, v *model.DefaultACLs) graphql.Marshaler {
if v == nil {
return graphql.Null
}
return ec._DefaultACLs(ctx, sel, v)
}
func (ec *executionContext) marshalOEntity2gitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐEntity(ctx context.Context, sel ast.SelectionSet, v model.Entity) graphql.Marshaler { func (ec *executionContext) marshalOEntity2gitᚗsrᚗhtᚋאsircmpwnᚋtodoᚗsrᚗhtᚋapiᚋgraphᚋmodelᚐEntity(ctx context.Context, sel ast.SelectionSet, v model.Entity) graphql.Marshaler {
if v == nil { if v == nil {
return graphql.Null return graphql.Null

View File

@ -26,12 +26,6 @@ type DefaultACL struct {
func (DefaultACL) IsACL() {} func (DefaultACL) IsACL() {}
type DefaultACLs struct {
Anonymous ACL `json:"anonymous"`
Submitter ACL `json:"submitter"`
LoggedIn ACL `json:"logged_in"`
}
type TrackerACL struct { type TrackerACL struct {
ID int `json:"id"` ID int `json:"id"`
Created time.Time `json:"created"` Created time.Time `json:"created"`
@ -93,7 +87,7 @@ func (acl *TrackerACL) QueryWithCursor(ctx context.Context, runner sq.BaseRunner
q = q.Where(database.WithAlias(acl.alias, "id")+"<= ?", next) q = q.Where(database.WithAlias(acl.alias, "id")+"<= ?", next)
} }
q = q. q = q.
Column(`permissions`). Column(database.WithAlias(acl.alias, `permissions`)).
OrderBy(database.WithAlias(acl.alias, "id")). OrderBy(database.WithAlias(acl.alias, "id")).
Limit(uint64(cur.Count + 1)) Limit(uint64(cur.Count + 1))

View File

@ -25,15 +25,15 @@ const (
) )
type Tracker struct { type Tracker struct {
ID int `json:"id"` ID int `json:"id"`
Created time.Time `json:"created"` Created time.Time `json:"created"`
Updated time.Time `json:"updated"` Updated time.Time `json:"updated"`
Name string `json:"name"` Name string `json:"name"`
Description *string `json:"description"` Description *string `json:"description"`
DefaultACLs *DefaultACLs `json:"defaultACLs"`
OwnerID int OwnerID int
Access int Access int
ACLID *int
alias string alias string
fields *database.ModelFields fields *database.ModelFields
@ -95,6 +95,7 @@ func (t *Tracker) QueryWithCursor(ctx context.Context, runner sq.BaseRunner,
ELSE tr.default_user_perms ELSE tr.default_user_perms
END)`, END)`,
ACCESS_ALL, auser.UserID). ACCESS_ALL, auser.UserID).
Column(`tr_ua.id`).
Where(`COALESCE(tr_ua.user_id, ?) = ?`, auser.UserID, auser.UserID) Where(`COALESCE(tr_ua.user_id, ?) = ?`, auser.UserID, auser.UserID)
if rows, err = q.RunWith(runner).QueryContext(ctx); err != nil { if rows, err = q.RunWith(runner).QueryContext(ctx); err != nil {
@ -106,7 +107,7 @@ func (t *Tracker) QueryWithCursor(ctx context.Context, runner sq.BaseRunner,
for rows.Next() { for rows.Next() {
var tracker Tracker var tracker Tracker
if err := rows.Scan(append(database.Scan( if err := rows.Scan(append(database.Scan(
ctx, &tracker), &tracker.Access)...); err != nil { ctx, &tracker), &tracker.Access, &tracker.ACLID)...); err != nil {
panic(err) panic(err)
} }
trackers = append(trackers, &tracker) trackers = append(trackers, &tracker)

View File

@ -82,8 +82,6 @@ type Tracker {
tickets(cursor: Cursor): TicketCursor! @access(scope: TICKETS, kind: RO) tickets(cursor: Cursor): TicketCursor! @access(scope: TICKETS, kind: RO)
labels(cursor: Cursor): LabelCursor! labels(cursor: Cursor): LabelCursor!
defaultACLs: DefaultACLs @access(scope: ACLS, kind: RO)
# Only available to the tracker owner: # Only available to the tracker owner:
acls(cursor: Cursor): ACLCursor! @access(scope: ACLS, kind: RO) acls(cursor: Cursor): ACLCursor! @access(scope: ACLS, kind: RO)
@ -175,7 +173,7 @@ interface ACL {
type TrackerACL implements ACL { type TrackerACL implements ACL {
id: Int! id: Int!
created: Time! created: Time!
tracker: Tracker! tracker: Tracker! @access(scope: TRACKERS, kind: RO)
entity: Entity! @access(scope: PROFILE, kind: RO) entity: Entity! @access(scope: PROFILE, kind: RO)
browse: Boolean! browse: Boolean!
@ -185,6 +183,8 @@ type TrackerACL implements ACL {
triage: Boolean! triage: Boolean!
} }
# These ACL policies are applied non-specifically, e.g. the default ACL for all
# authenticated users.
type DefaultACL implements ACL { type DefaultACL implements ACL {
browse: Boolean! browse: Boolean!
submit: Boolean! submit: Boolean!
@ -193,18 +193,6 @@ type DefaultACL implements ACL {
triage: Boolean! triage: Boolean!
} }
# These ACLs are inherited by users who do not have a more specific ACL
# configured.
type DefaultACLs {
# Permissions granted to anyone who visits this tracker, logged in or
# otherwise.
anonymous: ACL!
# Permissions granted to the ticket submitter on the tickets they submit.
submitter: ACL!
# Permissions granted to any logged-in sourcehut user.
logged_in: ACL!
}
type Label { type Label {
id: Int! id: Int!
created: Time! created: Time!

View File

@ -456,11 +456,47 @@ func (r *trackerResolver) Subscription(ctx context.Context, obj *model.Tracker)
} }
func (r *trackerResolver) ACL(ctx context.Context, obj *model.Tracker) (model.ACL, error) { func (r *trackerResolver) ACL(ctx context.Context, obj *model.Tracker) (model.ACL, error) {
panic(fmt.Errorf("not implemented")) if obj.ACLID == nil {
return &model.DefaultACL{
Browse: obj.CanBrowse(),
Submit: obj.CanSubmit(),
Comment: obj.CanComment(),
Edit: obj.CanEdit(),
Triage: obj.CanTriage(),
}, nil
}
acl := (&model.TrackerACL{}).As(`ua`)
if err := database.WithTx(ctx, &sql.TxOptions{
Isolation: 0,
ReadOnly: true,
}, func(tx *sql.Tx) error {
var access int
query := database.
Select(ctx, acl).
Column(`ua.permissions`).
From(`user_access ua`).
Where(`ua.id = ?`, *obj.ACLID)
row := query.RunWith(tx).QueryRowContext(ctx)
if err := row.Scan(append(database.Scan(ctx, acl),
&access)...); err != nil {
return err
}
acl.Browse = access & model.ACCESS_BROWSE != 0
acl.Submit = access & model.ACCESS_SUBMIT != 0
acl.Comment = access & model.ACCESS_COMMENT != 0
acl.Edit = access & model.ACCESS_EDIT != 0
acl.Triage = access & model.ACCESS_TRIAGE != 0
return nil
}); err != nil {
return nil, err
}
return acl, nil
} }
func (r *trackerACLResolver) Tracker(ctx context.Context, obj *model.TrackerACL) (*model.Tracker, error) { func (r *trackerACLResolver) Tracker(ctx context.Context, obj *model.TrackerACL) (*model.Tracker, error) {
panic(fmt.Errorf("not implemented")) return loaders.ForContext(ctx).TrackersByID.Load(obj.TrackerID)
} }
func (r *trackerACLResolver) Entity(ctx context.Context, obj *model.TrackerACL) (model.Entity, error) { func (r *trackerACLResolver) Entity(ctx context.Context, obj *model.TrackerACL) (model.Entity, error) {

View File

@ -162,6 +162,7 @@ func fetchTrackersByID(ctx context.Context) func(ids []int) ([]*model.Tracker, [
ELSE tr.default_user_perms ELSE tr.default_user_perms
END)`, END)`,
model.ACCESS_ALL, auser.UserID). model.ACCESS_ALL, auser.UserID).
Column(`ua.id`).
Where(sq.And{ Where(sq.And{
sq.Expr(`tr.id = ANY(?)`, pq.Array(ids)), sq.Expr(`tr.id = ANY(?)`, pq.Array(ids)),
sq.Or{ sq.Or{
@ -182,7 +183,8 @@ func fetchTrackersByID(ctx context.Context) func(ids []int) ([]*model.Tracker, [
for rows.Next() { for rows.Next() {
tracker := model.Tracker{} tracker := model.Tracker{}
if err := rows.Scan(append(database.Scan( if err := rows.Scan(append(database.Scan(
ctx, &tracker), &tracker.Access)...); err != nil { ctx, &tracker), &tracker.Access,
&tracker.ACLID)...); err != nil {
return err return err
} }
trackersByID[tracker.ID] = &tracker trackersByID[tracker.ID] = &tracker