1 | from paste.request import parse_querystring |
---|
2 | from milk_server.lib.Utilities import getURLConstraints |
---|
3 | import cgi,urllib |
---|
4 | |
---|
5 | |
---|
6 | def getURLFormattedConstraints(environ, **kw): |
---|
7 | ''' |
---|
8 | Get the constraints in a url friendly string - modified by the keyword arguments |
---|
9 | offset and stride which are to be part of the querystring |
---|
10 | @param environ: wsgi environ object |
---|
11 | @return constraints in a url friendly string |
---|
12 | ''' |
---|
13 | args = dict(parse_querystring(environ)) |
---|
14 | |
---|
15 | constrained = kw.get('constrained') |
---|
16 | if not constrained: |
---|
17 | offset, stride = kw.get('offset'), kw.get('stride') |
---|
18 | if offset: |
---|
19 | args['start'] = offset |
---|
20 | if stride: |
---|
21 | args['howmany'] = stride |
---|
22 | |
---|
23 | q = '' |
---|
24 | for i in args: |
---|
25 | # NB, the constraints may already be encoded as a hidden variable |
---|
26 | if i != 'constraints': |
---|
27 | q+='%s=%s&'%(i,args[i]) |
---|
28 | |
---|
29 | # add constraints last to avoid duplicate params - NB, constraint params |
---|
30 | # can be overridden by direct inputs to the page |
---|
31 | if 'constraints' in args: |
---|
32 | constraints = getURLConstraints(args['constraints']) |
---|
33 | for key, val in constraints.items(): |
---|
34 | if key not in args: |
---|
35 | q+='%s=%s&'%(key, val) |
---|
36 | |
---|
37 | return q[0:-1] |
---|
38 | |
---|
39 | |
---|
40 | def getURL(environ, **kw): |
---|
41 | ''' |
---|
42 | Get a url from the wsgi environment |
---|
43 | @param environ: wsgi environ object |
---|
44 | @return url with constraints added from wsgi environ |
---|
45 | ''' |
---|
46 | constraints = getURLFormattedConstraints(environ, **kw) |
---|
47 | return urllib.quote(environ.get('SCRIPT_NAME','')) + \ |
---|
48 | urllib.quote(environ.get('PATH_INFO','')) + '?' + constraints |
---|
49 | |
---|
50 | |
---|
51 | class constraints: |
---|
52 | ''' |
---|
53 | A container object for constraints on a search |
---|
54 | ''' |
---|
55 | def __init__(self, **kw): |
---|
56 | self.values={} |
---|
57 | keys=['dateRange','bbox','scope','textTarget','searchString','geoSearchType'] |
---|
58 | for key in keys: |
---|
59 | self.values[key]=None |
---|
60 | for k in kw: |
---|
61 | self[k]=kw[k] |
---|
62 | |
---|
63 | |
---|
64 | def __setitem__(self, key, value): |
---|
65 | if key in self.values: |
---|
66 | self.values[key]=value |
---|
67 | else: |
---|
68 | raise ValueError('Unknown key [%s] in constraints') |
---|
69 | |
---|
70 | |
---|
71 | def __getitem__(self,key): |
---|
72 | if key in self.values: |
---|
73 | return self.values[key] |
---|
74 | else: |
---|
75 | raise ValueError('Unknown key [%s] in constraints'%key) |
---|
76 | |
---|
77 | |
---|
78 | def __str__(self): |
---|
79 | c='' |
---|
80 | if self.values['dateRange'] is not None: |
---|
81 | dr = self.values['dateRange'] |
---|
82 | c += 'Date range: %s to %s'%('%s/%s/%s'%dr[0],'%s/%s/%s'%dr[1]) |
---|
83 | bbox=self.values['bbox'] |
---|
84 | if c: |
---|
85 | c += ', ' |
---|
86 | |
---|
87 | c += 'Bounding box: ' |
---|
88 | |
---|
89 | #Need to put workaround for browsers that dont let map window global search = 180 etc.. |
---|
90 | #if bbox is None or bbox==['90.0','-180.0','180.0','-90.0']: |
---|
91 | |
---|
92 | if bbox is None or ((float(bbox[0]) >= 89) & (float(bbox[1]) <= -179) & (float(bbox[2]) >= 179) & (float(bbox[3]) <= 89)): |
---|
93 | |
---|
94 | c+='Global' |
---|
95 | |
---|
96 | else: |
---|
97 | overlaps = self.values['geoSearchType'] or 'overlaps' |
---|
98 | c+='%s latitude %s to %sN and longitude %s to %sE' \ |
---|
99 | %(overlaps,bbox[3],bbox[0],bbox[1],bbox[2]) |
---|
100 | |
---|
101 | |
---|
102 | # c+='Global' # fudge sjd |
---|
103 | if self.values['scope']: |
---|
104 | if c: |
---|
105 | c += ', ' |
---|
106 | c += 'Scope: %s'%self.values['scope'] |
---|
107 | if self.values['textTarget']: |
---|
108 | if c: |
---|
109 | c += ', ' |
---|
110 | c += 'Target: %s'%self.values['textTarget'] |
---|
111 | return c |
---|
112 | |
---|
113 | |
---|
114 | class PagerState: |
---|
115 | ''' |
---|
116 | Object to hold the current page state of the displayed results - e.g. which |
---|
117 | page number and how many records, before and after those displayed, are available |
---|
118 | ''' |
---|
119 | |
---|
120 | def __init__(self, hits, environ, offset=1, stride=10, defaultStride = 10): |
---|
121 | ''' |
---|
122 | Initialise PagerState object |
---|
123 | @param hits: total number of records available to view |
---|
124 | @param environ: wsgi environ object |
---|
125 | @keyword offset: offset being used in the currently displayed record set |
---|
126 | - i.e. the array number of the topmost record displayed. Default = 1 |
---|
127 | @keyword stride: Number of records currently visible. Default = 10 |
---|
128 | @keyword defaultStride: Standard number of records to display on a page. |
---|
129 | Default = 10 |
---|
130 | ''' |
---|
131 | self.hits = hits |
---|
132 | self.offset = offset |
---|
133 | self.stride = stride |
---|
134 | |
---|
135 | self.previousPageURL = None |
---|
136 | self.previousNumber = None |
---|
137 | self.startPageURL = None |
---|
138 | self.nextPageURL = None |
---|
139 | self.nextNumber = None |
---|
140 | self.lastPageURL = None |
---|
141 | |
---|
142 | self.defaultStride = defaultStride |
---|
143 | |
---|
144 | n, p = self.getNext() |
---|
145 | start, end = "", "" |
---|
146 | if p: |
---|
147 | self.previousPageURL = getURL(environ, offset = p[0], stride = p[1]) |
---|
148 | self.previousNumber = p[1] |
---|
149 | self.startPageURL = getURL(environ, offset = 1, stride = self.defaultStride) |
---|
150 | if n: |
---|
151 | self.nextPageURL = getURL(environ, offset = n[0], stride = n[1]) |
---|
152 | self.nextNumber = n[1] |
---|
153 | off = self.hits - self.defaultStride + 1 |
---|
154 | if off < 1: |
---|
155 | off = 1 |
---|
156 | self.lastPageURL = getURL(environ, offset = off, stride = self.defaultStride) |
---|
157 | |
---|
158 | self.upperRange = self.offset + self.stride - 1 |
---|
159 | self.lowerRange = self.offset |
---|
160 | |
---|
161 | |
---|
162 | def getNext(self): |
---|
163 | ''' |
---|
164 | Get info on what number of records are available on current page |
---|
165 | @return result - list with format [[offSetForNextPage, numberOfRecordsOnNextPage], |
---|
166 | [offSetForLastPage, numberOfRecordsOnLastPage]] |
---|
167 | ''' |
---|
168 | result=[] |
---|
169 | if self.offset+self.stride < self.hits: |
---|
170 | #there are more to look at |
---|
171 | r = [self.offset+self.stride, self.stride] |
---|
172 | if r[0]+r[1]-1 > self.hits: |
---|
173 | r[1] = self.hits+1-r[0] |
---|
174 | result.append(r) |
---|
175 | else: |
---|
176 | result.append([]) |
---|
177 | |
---|
178 | if self.offset > 1: |
---|
179 | #there are previous records |
---|
180 | b = max(self.stride, self.defaultStride) |
---|
181 | r = [self.offset-b,b] |
---|
182 | if r[0] < 1: |
---|
183 | r[0] = 1 |
---|
184 | if r[1] > self.hits: |
---|
185 | r[1] = self.hits |
---|
186 | result.append(r) |
---|
187 | else: |
---|
188 | result.append([]) |
---|
189 | return result |
---|
190 | |
---|
191 | |
---|
192 | |
---|
193 | class DiscoveryState: |
---|
194 | ''' This class holds the state associated with a search (including presenting multiple slices |
---|
195 | of a large result set) ''' |
---|
196 | def __init__(self,sessionID,searchString,environ,hits,constraints,offset=1,stride=10): |
---|
197 | ''' On instantiation, provide |
---|
198 | the backend sessionID |
---|
199 | the application URL that produced this query |
---|
200 | the stride through the result set ''' |
---|
201 | self.environ=environ # the wsgi environment |
---|
202 | self.constraintsInstance=constraints |
---|
203 | self.constraints=str(constraints) # some text to show constraints on search |
---|
204 | self.urlformattedconstraints = getURLFormattedConstraints(self.environ) |
---|
205 | self.sessID=sessionID |
---|
206 | self.hits=hits |
---|
207 | |
---|
208 | self.searchString=searchString |
---|
209 | self.alternatives=None |
---|
210 | self.constrainedurl = getURL(self.environ, constrained=1)+'&constrained' |
---|
211 | self.pager = PagerState(hits, self.environ, offset=offset, stride=stride) |
---|
212 | |
---|
213 | def __str__(self): |
---|
214 | return ''' |
---|
215 | ___ Discovery State ___ |
---|
216 | searchString: %s |
---|
217 | constraints: %s |
---|
218 | sessionID: %s |
---|
219 | hits: %s |
---|
220 | offset,stride: %s,%s |
---|
221 | environment: %s |
---|
222 | ======================== |
---|
223 | '''%(self.searchString,self.constraints,self.sessID,self.hits,self.offset,self.stride,self.environ) |
---|