+108
-13
appview/db/label.go
+108
-13
appview/db/label.go
···
13
14
"github.com/bluesky-social/indigo/atproto/syntax"
15
"tangled.sh/tangled.sh/core/api/tangled"
16
)
17
18
type ConcreteType string
···
77
return vt.Type == ConcreteTypeBool
78
}
79
80
-
func (vt ValueType) IsEnumType() bool {
81
return len(vt.Enum) > 0
82
}
83
···
96
97
Name string
98
ValueType ValueType
99
-
Scope syntax.NSID
100
Color *string
101
Multiple bool
102
Created time.Time
···
113
Color: l.Color,
114
CreatedAt: l.Created.Format(time.RFC3339),
115
Multiple: &l.Multiple,
116
-
Scope: l.Scope.String(),
117
ValueType: &vt,
118
}
119
}
···
139
return *ld.Color
140
}
141
142
-
func LabelDefinitionFromRecord(did, rkey string, record tangled.LabelDefinition) LabelDefinition {
143
created, err := time.Parse(time.RFC3339, record.CreatedAt)
144
if err != nil {
145
created = time.Now()
···
155
vt = ValueTypeFromRecord(*record.ValueType)
156
}
157
158
-
return LabelDefinition{
159
Did: did,
160
Rkey: rkey,
161
162
Name: record.Name,
163
ValueType: vt,
164
-
Scope: syntax.NSID(record.Scope),
165
Color: record.Color,
166
Multiple: multiple,
167
Created: created,
168
-
}
169
}
170
171
func DeleteLabelDefinition(e Execer, filters ...filter) error {
···
184
return err
185
}
186
187
func AddLabelDefinition(e Execer, l *LabelDefinition) (int64, error) {
188
result, err := e.Exec(
189
`insert into label_definitions (
···
210
l.ValueType.Type,
211
l.ValueType.Format,
212
strings.Join(l.ValueType.Enum, ","),
213
-
l.Scope.String(),
214
l.Color,
215
l.Multiple,
216
l.Created.Format(time.RFC3339),
···
274
275
for rows.Next() {
276
var labelDefinition LabelDefinition
277
-
var createdAt, enumVariants string
278
var color sql.Null[string]
279
var multiple int
280
···
286
&labelDefinition.ValueType.Type,
287
&labelDefinition.ValueType.Format,
288
&enumVariants,
289
-
&labelDefinition.Scope,
290
&color,
291
&multiple,
292
&createdAt,
···
309
310
if enumVariants != "" {
311
labelDefinition.ValueType.Enum = strings.Split(enumVariants, ",")
312
}
313
314
labelDefinitions = append(labelDefinitions, labelDefinition)
···
631
return false
632
}
633
634
-
func (s *LabelState) GetValSet(l string) set {
635
-
return s.inner[l]
636
}
637
638
type LabelApplicationCtx struct {
···
658
}
659
660
func (c *LabelApplicationCtx) ApplyLabelOp(state LabelState, op LabelOp) error {
661
-
def := c.Defs[op.OperandKey]
662
663
switch op.Operation {
664
case LabelOperationAdd:
···
719
_ = c.ApplyLabelOp(state, o)
720
}
721
}
···
13
14
"github.com/bluesky-social/indigo/atproto/syntax"
15
"tangled.sh/tangled.sh/core/api/tangled"
16
+
"tangled.sh/tangled.sh/core/consts"
17
)
18
19
type ConcreteType string
···
78
return vt.Type == ConcreteTypeBool
79
}
80
81
+
func (vt ValueType) IsEnum() bool {
82
return len(vt.Enum) > 0
83
}
84
···
97
98
Name string
99
ValueType ValueType
100
+
Scope []string
101
Color *string
102
Multiple bool
103
Created time.Time
···
114
Color: l.Color,
115
CreatedAt: l.Created.Format(time.RFC3339),
116
Multiple: &l.Multiple,
117
+
Scope: l.Scope,
118
ValueType: &vt,
119
}
120
}
···
140
return *ld.Color
141
}
142
143
+
func LabelDefinitionFromRecord(did, rkey string, record tangled.LabelDefinition) (*LabelDefinition, error) {
144
created, err := time.Parse(time.RFC3339, record.CreatedAt)
145
if err != nil {
146
created = time.Now()
···
156
vt = ValueTypeFromRecord(*record.ValueType)
157
}
158
159
+
return &LabelDefinition{
160
Did: did,
161
Rkey: rkey,
162
163
Name: record.Name,
164
ValueType: vt,
165
+
Scope: record.Scope,
166
Color: record.Color,
167
Multiple: multiple,
168
Created: created,
169
+
}, nil
170
}
171
172
func DeleteLabelDefinition(e Execer, filters ...filter) error {
···
185
return err
186
}
187
188
+
// no updating type for now
189
func AddLabelDefinition(e Execer, l *LabelDefinition) (int64, error) {
190
result, err := e.Exec(
191
`insert into label_definitions (
···
212
l.ValueType.Type,
213
l.ValueType.Format,
214
strings.Join(l.ValueType.Enum, ","),
215
+
strings.Join(l.Scope, ","),
216
l.Color,
217
l.Multiple,
218
l.Created.Format(time.RFC3339),
···
276
277
for rows.Next() {
278
var labelDefinition LabelDefinition
279
+
var createdAt, enumVariants, scopes string
280
var color sql.Null[string]
281
var multiple int
282
···
288
&labelDefinition.ValueType.Type,
289
&labelDefinition.ValueType.Format,
290
&enumVariants,
291
+
&scopes,
292
&color,
293
&multiple,
294
&createdAt,
···
311
312
if enumVariants != "" {
313
labelDefinition.ValueType.Enum = strings.Split(enumVariants, ",")
314
+
}
315
+
316
+
for s := range strings.SplitSeq(scopes, ",") {
317
+
labelDefinition.Scope = append(labelDefinition.Scope, s)
318
}
319
320
labelDefinitions = append(labelDefinitions, labelDefinition)
···
637
return false
638
}
639
640
+
// go maps behavior in templates make this necessary,
641
+
// indexing a map and getting `set` in return is apparently truthy
642
+
func (s LabelState) ContainsLabelAndVal(l, v string) bool {
643
+
if valset, exists := s.inner[l]; exists {
644
+
if _, exists := valset[v]; exists {
645
+
return true
646
+
}
647
+
}
648
+
649
+
return false
650
+
}
651
+
652
+
func (s LabelState) GetValSet(l string) set {
653
+
if valset, exists := s.inner[l]; exists {
654
+
return valset
655
+
} else {
656
+
return make(set)
657
+
}
658
}
659
660
type LabelApplicationCtx struct {
···
680
}
681
682
func (c *LabelApplicationCtx) ApplyLabelOp(state LabelState, op LabelOp) error {
683
+
def, ok := c.Defs[op.OperandKey]
684
+
if !ok {
685
+
// this def was deleted, but an op exists, so we just skip over the op
686
+
return nil
687
+
}
688
689
switch op.Operation {
690
case LabelOperationAdd:
···
745
_ = c.ApplyLabelOp(state, o)
746
}
747
}
748
+
749
+
// IsInverse checks if one label operation is the inverse of another
750
+
// returns true if one is an add and the other is a delete with the same key and value
751
+
func (op1 LabelOp) IsInverse(op2 LabelOp) bool {
752
+
if op1.OperandKey != op2.OperandKey || op1.OperandValue != op2.OperandValue {
753
+
return false
754
+
}
755
+
756
+
return (op1.Operation == LabelOperationAdd && op2.Operation == LabelOperationDel) ||
757
+
(op1.Operation == LabelOperationDel && op2.Operation == LabelOperationAdd)
758
+
}
759
+
760
+
// removes pairs of label operations that are inverses of each other
761
+
// from the given slice. the function preserves the order of remaining operations.
762
+
func ReduceLabelOps(ops []LabelOp) []LabelOp {
763
+
if len(ops) <= 1 {
764
+
return ops
765
+
}
766
+
767
+
keep := make([]bool, len(ops))
768
+
for i := range keep {
769
+
keep[i] = true
770
+
}
771
+
772
+
for i := range ops {
773
+
if !keep[i] {
774
+
continue
775
+
}
776
+
777
+
for j := i + 1; j < len(ops); j++ {
778
+
if !keep[j] {
779
+
continue
780
+
}
781
+
782
+
if ops[i].IsInverse(ops[j]) {
783
+
keep[i] = false
784
+
keep[j] = false
785
+
break // move to next i since this one is now eliminated
786
+
}
787
+
}
788
+
}
789
+
790
+
// build result slice with only kept operations
791
+
var result []LabelOp
792
+
for i, op := range ops {
793
+
if keep[i] {
794
+
result = append(result, op)
795
+
}
796
+
}
797
+
798
+
return result
799
+
}
800
+
801
+
func DefaultLabelDefs() []string {
802
+
rkeys := []string{
803
+
"wontfix",
804
+
"duplicate",
805
+
"assignee",
806
+
"good-first-issue",
807
+
"documentation",
808
+
}
809
+
810
+
defs := make([]string, len(rkeys))
811
+
for i, r := range rkeys {
812
+
defs[i] = fmt.Sprintf("at://%s/%s/%s", consts.TangledDid, tangled.LabelDefinitionNSID, r)
813
+
}
814
+
815
+
return defs
816
+
}
+7
-14
appview/oauth/handler/handler.go
+7
-14
appview/oauth/handler/handler.go
···
25
"tangled.sh/tangled.sh/core/appview/oauth"
26
"tangled.sh/tangled.sh/core/appview/oauth/client"
27
"tangled.sh/tangled.sh/core/appview/pages"
28
"tangled.sh/tangled.sh/core/idresolver"
29
"tangled.sh/tangled.sh/core/rbac"
30
"tangled.sh/tangled.sh/core/tid"
···
353
return pubKey, nil
354
}
355
356
-
var (
357
-
tangledDid = "did:plc:wshs7t2adsemcrrd4snkeqli"
358
-
icyDid = "did:plc:hwevmowznbiukdf6uk5dwrrq"
359
-
360
-
defaultSpindle = "spindle.tangled.sh"
361
-
defaultKnot = "knot1.tangled.sh"
362
-
)
363
-
364
func (o *OAuthHandler) addToDefaultSpindle(did string) {
365
// use the tangled.sh app password to get an accessJwt
366
// and create an sh.tangled.spindle.member record with that
···
380
}
381
382
log.Printf("adding %s to default spindle", did)
383
-
session, err := o.createAppPasswordSession(o.config.Core.AppPassword, tangledDid)
384
if err != nil {
385
log.Printf("failed to create session: %s", err)
386
return
···
389
record := tangled.SpindleMember{
390
LexiconTypeID: "sh.tangled.spindle.member",
391
Subject: did,
392
-
Instance: defaultSpindle,
393
CreatedAt: time.Now().Format(time.RFC3339),
394
}
395
···
411
return
412
}
413
414
-
if slices.Contains(allKnots, defaultKnot) {
415
log.Printf("did %s is already a member of the default knot", did)
416
return
417
}
418
419
log.Printf("adding %s to default knot", did)
420
-
session, err := o.createAppPasswordSession(o.config.Core.TmpAltAppPassword, icyDid)
421
if err != nil {
422
log.Printf("failed to create session: %s", err)
423
return
···
426
record := tangled.KnotMember{
427
LexiconTypeID: "sh.tangled.knot.member",
428
Subject: did,
429
-
Domain: defaultKnot,
430
CreatedAt: time.Now().Format(time.RFC3339),
431
}
432
···
435
return
436
}
437
438
-
if err := o.enforcer.AddKnotMember(defaultKnot, did); err != nil {
439
log.Printf("failed to set up enforcer rules: %s", err)
440
return
441
}
···
25
"tangled.sh/tangled.sh/core/appview/oauth"
26
"tangled.sh/tangled.sh/core/appview/oauth/client"
27
"tangled.sh/tangled.sh/core/appview/pages"
28
+
"tangled.sh/tangled.sh/core/consts"
29
"tangled.sh/tangled.sh/core/idresolver"
30
"tangled.sh/tangled.sh/core/rbac"
31
"tangled.sh/tangled.sh/core/tid"
···
354
return pubKey, nil
355
}
356
357
func (o *OAuthHandler) addToDefaultSpindle(did string) {
358
// use the tangled.sh app password to get an accessJwt
359
// and create an sh.tangled.spindle.member record with that
···
373
}
374
375
log.Printf("adding %s to default spindle", did)
376
+
session, err := o.createAppPasswordSession(o.config.Core.AppPassword, consts.TangledDid)
377
if err != nil {
378
log.Printf("failed to create session: %s", err)
379
return
···
382
record := tangled.SpindleMember{
383
LexiconTypeID: "sh.tangled.spindle.member",
384
Subject: did,
385
+
Instance: consts.DefaultSpindle,
386
CreatedAt: time.Now().Format(time.RFC3339),
387
}
388
···
404
return
405
}
406
407
+
if slices.Contains(allKnots, consts.DefaultKnot) {
408
log.Printf("did %s is already a member of the default knot", did)
409
return
410
}
411
412
log.Printf("adding %s to default knot", did)
413
+
session, err := o.createAppPasswordSession(o.config.Core.TmpAltAppPassword, consts.IcyDid)
414
if err != nil {
415
log.Printf("failed to create session: %s", err)
416
return
···
419
record := tangled.KnotMember{
420
LexiconTypeID: "sh.tangled.knot.member",
421
Subject: did,
422
+
Domain: consts.DefaultKnot,
423
CreatedAt: time.Now().Format(time.RFC3339),
424
}
425
···
428
return
429
}
430
431
+
if err := o.enforcer.AddKnotMember(consts.DefaultKnot, did); err != nil {
432
log.Printf("failed to set up enforcer rules: %s", err)
433
return
434
}