1 package index
2
3 import (
4 "context"
5 "fmt"
6 "os"
7 "strconv"
8 "time"
9
10 "perkeep.org/pkg/blob"
11 "perkeep.org/pkg/schema/nodeattr"
12 "perkeep.org/pkg/types/camtypes"
13 )
14
15
16
17
18
19 type LocationHelper struct {
20 index *Index
21 corpus *Corpus
22 }
23
24
25
26 func NewLocationHelper(ix *Index) *LocationHelper {
27 lh := &LocationHelper{index: ix}
28 if ix.corpus != nil {
29 lh.corpus = ix.corpus
30 }
31 return lh
32 }
33
34
35
36 func (lh *LocationHelper) SetCorpus(corpus *Corpus) {
37 lh.corpus = corpus
38 }
39
40
41
42 var altLocationRef = map[string][]string{
43
44 "foursquare.com:checkin": {"foursquareVenuePermanode"},
45 }
46
47
48
49
50
51
52
53
54
55
56 func (lh *LocationHelper) PermanodeLocation(ctx context.Context, permaNode blob.Ref,
57 at time.Time, owner *Owner) (camtypes.Location, error) {
58 return lh.permanodeLocation(ctx, permaNode, at, owner, true)
59 }
60
61 func (lh *LocationHelper) permanodeLocation(ctx context.Context,
62 pn blob.Ref, at time.Time, owner *Owner,
63 useRef bool) (loc camtypes.Location, err error) {
64
65 signerID := owner.KeyID()
66 pa := permAttr{at: at, signerFilter: owner.RefSet(signerID)}
67 if lh.corpus != nil {
68 var claims []*camtypes.Claim
69 pa.attrs, claims = lh.corpus.permanodeAttrsOrClaims(pn, at, signerID)
70 if claims != nil {
71 pa.claims = claimPtrSlice(claims)
72 }
73 } else {
74 var claims []camtypes.Claim
75 claims, err = lh.index.AppendClaims(ctx, nil, pn, signerID, "")
76 if err != nil {
77 return camtypes.Location{}, err
78 }
79 pa.claims = claimSlice(claims)
80 }
81
82
83
84 slat, slong := pa.get(nodeattr.Latitude), pa.get(nodeattr.Longitude)
85 if slat != "" && slong != "" {
86 lat, latErr := strconv.ParseFloat(slat, 64)
87 long, longErr := strconv.ParseFloat(slong, 64)
88 switch {
89 case latErr != nil:
90 err = fmt.Errorf("invalid latitude in %v: %v", pn, latErr)
91 case longErr != nil:
92 err = fmt.Errorf("invalid longitude in %v: %v", pn, longErr)
93 default:
94 err = nil
95 }
96 return camtypes.Location{Latitude: lat, Longitude: long}, err
97 }
98
99 if useRef {
100
101 nodeType := pa.get(nodeattr.Type)
102 if nodeType != "" {
103 for _, a := range altLocationRef[nodeType] {
104 refPn, hasRef := blob.Parse(pa.get(a))
105 if !hasRef {
106 continue
107 }
108 loc, err = lh.permanodeLocation(ctx, refPn, at, owner, false)
109 if err == nil {
110 return loc, err
111 }
112 }
113 }
114
115
116
117
118 if content, ok := blob.Parse(pa.get(nodeattr.CamliContent)); ok {
119 return lh.index.GetFileLocation(ctx, content)
120 }
121 }
122
123 return camtypes.Location{}, os.ErrNotExist
124 }
125
126
127
128
129 type permAttr struct {
130
131
132
133 attrs map[string][]string
134
135
136
137
138
139
140
141 claims claimsIntf
142
143 at time.Time
144 signerFilter SignerRefSet
145 }
146
147
148 func (pa permAttr) get(attr string) string {
149 if pa.attrs != nil {
150 v := pa.attrs[attr]
151 if len(v) != 0 {
152 return v[0]
153 }
154 return ""
155 }
156
157 if pa.claims != nil {
158 return claimsIntfAttrValue(pa.claims, attr, pa.at, pa.signerFilter)
159 }
160
161 return ""
162 }