Monorepo for Tangled

appview: integrate label-value search and DID resolution in handlers

Use shared searchquery helpers (ResolveAuthor, ExtractTextFilters) to
replace duplicated resolution logic in both issue and pull handlers.

Wire up dynamic tag extraction for label-value queries. When label
definitions with DID format are present, resolve handle values to DIDs
at query time via ResolveDIDLabelValues.

Signed-off-by: Thomas Karpiniec <tom.karpiniec@outlook.com>

authored by

Thomas Karpiniec and committed by tangled.org 3496fef9 44086392

+80 -82
+40 -41
appview/issues/issues.go
··· 827 827 query.Set("state", "open") 828 828 } 829 829 830 - var authorDid string 831 - if authorHandle := query.Get("author"); authorHandle != nil { 832 - identity, err := rp.idResolver.ResolveIdent(r.Context(), *authorHandle) 830 + resolve := func(ctx context.Context, ident string) (string, error) { 831 + id, err := rp.idResolver.ResolveIdent(ctx, ident) 833 832 if err != nil { 834 - l.Debug("failed to resolve author handle", "handle", *authorHandle, "err", err) 835 - } else { 836 - authorDid = identity.DID.String() 833 + return "", err 837 834 } 835 + return id.DID.String(), nil 838 836 } 839 837 840 - var negatedAuthorDid string 841 - if negatedAuthors := query.GetAllNegated("author"); len(negatedAuthors) > 0 { 842 - identity, err := rp.idResolver.ResolveIdent(r.Context(), negatedAuthors[0]) 843 - if err != nil { 844 - l.Debug("failed to resolve negated author handle", "handle", negatedAuthors[0], "err", err) 845 - } else { 846 - negatedAuthorDid = identity.DID.String() 847 - } 848 - } 838 + authorDid, negatedAuthorDids := searchquery.ResolveAuthor(r.Context(), query, resolve, l) 849 839 850 840 labels := query.GetAll("label") 851 841 negatedLabels := query.GetAllNegated("label") 842 + labelValues := query.GetDynamicTags() 843 + negatedLabelValues := query.GetNegatedDynamicTags() 852 844 853 - var keywords, negatedKeywords []string 854 - var phrases, negatedPhrases []string 855 - for _, item := range query.Items() { 856 - switch item.Kind { 857 - case searchquery.KindKeyword: 858 - if item.Negated { 859 - negatedKeywords = append(negatedKeywords, item.Value) 860 - } else { 861 - keywords = append(keywords, item.Value) 862 - } 863 - case searchquery.KindQuoted: 864 - if item.Negated { 865 - negatedPhrases = append(negatedPhrases, item.Value) 866 - } else { 867 - phrases = append(phrases, item.Value) 845 + // resolve DID-format label values: if a dynamic tag's label 846 + // definition has format "did", resolve the handle to a DID 847 + if len(labelValues) > 0 || len(negatedLabelValues) > 0 { 848 + labelDefs, err := db.GetLabelDefinitions( 849 + rp.db, 850 + orm.FilterIn("at_uri", f.Labels), 851 + orm.FilterContains("scope", tangled.RepoIssueNSID), 852 + ) 853 + if err == nil { 854 + didLabels := make(map[string]bool) 855 + for _, def := range labelDefs { 856 + if def.ValueType.Format == models.ValueTypeFormatDid { 857 + didLabels[def.Name] = true 858 + } 868 859 } 860 + labelValues = searchquery.ResolveDIDLabelValues(r.Context(), labelValues, didLabels, resolve, l) 861 + negatedLabelValues = searchquery.ResolveDIDLabelValues(r.Context(), negatedLabelValues, didLabels, resolve, l) 862 + } else { 863 + l.Debug("failed to fetch label definitions for DID resolution", "err", err) 869 864 } 870 865 } 871 866 867 + tf := searchquery.ExtractTextFilters(query) 868 + 872 869 searchOpts := models.IssueSearchOptions{ 873 - Keywords: keywords, 874 - Phrases: phrases, 875 - RepoAt: f.RepoAt().String(), 876 - IsOpen: isOpen, 877 - AuthorDid: authorDid, 878 - Labels: labels, 879 - NegatedKeywords: negatedKeywords, 880 - NegatedPhrases: negatedPhrases, 881 - NegatedLabels: negatedLabels, 882 - NegatedAuthorDid: negatedAuthorDid, 883 - Page: page, 870 + Keywords: tf.Keywords, 871 + Phrases: tf.Phrases, 872 + RepoAt: f.RepoAt().String(), 873 + IsOpen: isOpen, 874 + AuthorDid: authorDid, 875 + Labels: labels, 876 + LabelValues: labelValues, 877 + NegatedKeywords: tf.NegatedKeywords, 878 + NegatedPhrases: tf.NegatedPhrases, 879 + NegatedLabels: negatedLabels, 880 + NegatedLabelValues: negatedLabelValues, 881 + NegatedAuthorDids: negatedAuthorDids, 882 + Page: page, 884 883 } 885 884 886 885 totalIssues := 0
+40 -41
appview/pulls/pulls.go
··· 560 560 query.Set("state", "open") 561 561 } 562 562 563 - var authorDid string 564 - if authorHandle := query.Get("author"); authorHandle != nil { 565 - identity, err := s.idResolver.ResolveIdent(r.Context(), *authorHandle) 563 + resolve := func(ctx context.Context, ident string) (string, error) { 564 + id, err := s.idResolver.ResolveIdent(ctx, ident) 566 565 if err != nil { 567 - l.Debug("failed to resolve author handle", "handle", *authorHandle, "err", err) 568 - } else { 569 - authorDid = identity.DID.String() 566 + return "", err 570 567 } 568 + return id.DID.String(), nil 571 569 } 572 570 573 - var negatedAuthorDid string 574 - if negatedAuthors := query.GetAllNegated("author"); len(negatedAuthors) > 0 { 575 - identity, err := s.idResolver.ResolveIdent(r.Context(), negatedAuthors[0]) 576 - if err != nil { 577 - l.Debug("failed to resolve negated author handle", "handle", negatedAuthors[0], "err", err) 578 - } else { 579 - negatedAuthorDid = identity.DID.String() 580 - } 581 - } 571 + authorDid, negatedAuthorDids := searchquery.ResolveAuthor(r.Context(), query, resolve, l) 582 572 583 573 labels := query.GetAll("label") 584 574 negatedLabels := query.GetAllNegated("label") 575 + labelValues := query.GetDynamicTags() 576 + negatedLabelValues := query.GetNegatedDynamicTags() 585 577 586 - var keywords, negatedKeywords []string 587 - var phrases, negatedPhrases []string 588 - for _, item := range query.Items() { 589 - switch item.Kind { 590 - case searchquery.KindKeyword: 591 - if item.Negated { 592 - negatedKeywords = append(negatedKeywords, item.Value) 593 - } else { 594 - keywords = append(keywords, item.Value) 595 - } 596 - case searchquery.KindQuoted: 597 - if item.Negated { 598 - negatedPhrases = append(negatedPhrases, item.Value) 599 - } else { 600 - phrases = append(phrases, item.Value) 578 + // resolve DID-format label values: if a dynamic tag's label 579 + // definition has format "did", resolve the handle to a DID 580 + if len(labelValues) > 0 || len(negatedLabelValues) > 0 { 581 + labelDefs, err := db.GetLabelDefinitions( 582 + s.db, 583 + orm.FilterIn("at_uri", f.Labels), 584 + orm.FilterContains("scope", tangled.RepoPullNSID), 585 + ) 586 + if err == nil { 587 + didLabels := make(map[string]bool) 588 + for _, def := range labelDefs { 589 + if def.ValueType.Format == models.ValueTypeFormatDid { 590 + didLabels[def.Name] = true 591 + } 601 592 } 593 + labelValues = searchquery.ResolveDIDLabelValues(r.Context(), labelValues, didLabels, resolve, l) 594 + negatedLabelValues = searchquery.ResolveDIDLabelValues(r.Context(), negatedLabelValues, didLabels, resolve, l) 595 + } else { 596 + l.Debug("failed to fetch label definitions for DID resolution", "err", err) 602 597 } 603 598 } 604 599 600 + tf := searchquery.ExtractTextFilters(query) 601 + 605 602 searchOpts := models.PullSearchOptions{ 606 - Keywords: keywords, 607 - Phrases: phrases, 608 - RepoAt: f.RepoAt().String(), 609 - State: state, 610 - AuthorDid: authorDid, 611 - Labels: labels, 612 - NegatedKeywords: negatedKeywords, 613 - NegatedPhrases: negatedPhrases, 614 - NegatedLabels: negatedLabels, 615 - NegatedAuthorDid: negatedAuthorDid, 616 - Page: page, 603 + Keywords: tf.Keywords, 604 + Phrases: tf.Phrases, 605 + RepoAt: f.RepoAt().String(), 606 + State: state, 607 + AuthorDid: authorDid, 608 + Labels: labels, 609 + LabelValues: labelValues, 610 + NegatedKeywords: tf.NegatedKeywords, 611 + NegatedPhrases: tf.NegatedPhrases, 612 + NegatedLabels: negatedLabels, 613 + NegatedLabelValues: negatedLabelValues, 614 + NegatedAuthorDids: negatedAuthorDids, 615 + Page: page, 617 616 } 618 617 619 618 var totalPulls int