20 __authors__ = [ |
20 __authors__ = [ |
21 '"Chen Lunpeng" <forever.clp@gmail.com>', |
21 '"Chen Lunpeng" <forever.clp@gmail.com>', |
22 '"Pawel Solyga" <pawel.solyga@gmail.com>', |
22 '"Pawel Solyga" <pawel.solyga@gmail.com>', |
23 ] |
23 ] |
24 |
24 |
|
25 import logging |
25 |
26 |
26 from soc.logic import dicts |
27 from soc.logic import dicts |
27 from soc.logic.models.user import logic as user_logic |
28 from soc.logic.models.user import logic as user_logic |
28 |
29 |
29 import soc.views.helper.forms |
30 import soc.views.helper.forms |
56 # TODO: eventually this limit should be a User profile preference |
57 # TODO: eventually this limit should be a User profile preference |
57 # (stored in the site-wide User Model) preference |
58 # (stored in the site-wide User Model) preference |
58 return DEF_DEFAULT_PAGINATION |
59 return DEF_DEFAULT_PAGINATION |
59 |
60 |
60 |
61 |
61 def getLimitAndOffset(request, offset_key, limit_key): |
62 OFFSET_KEY = 'offset_%d' |
62 """Retrieves, converts and validates offset and limit values |
63 LIMIT_KEY = 'limit_%d' |
63 |
64 |
64 Args: |
65 |
65 offset: offset in list which defines first item to return |
66 def makeOffsetKey(limit_idx): |
66 limit: max amount of items per page |
67 return OFFSET_KEY % limit_idx |
|
68 |
|
69 |
|
70 def makeLimitKey(limit_idx): |
|
71 return LIMIT_KEY % limit_idx |
|
72 |
|
73 |
|
74 def getListParameters(request, list_index): |
|
75 """Retrieves, converts and validates values for one list |
|
76 |
|
77 Args: |
|
78 list_index, int: which list to get the values for. |
|
79 (there may be multiple lists on one page, which are multiplexed |
|
80 by an integer.) |
67 |
81 |
68 Returns: |
82 Returns: |
69 updated offset and limit values |
83 a dictionary of str -> str. field name -> field value. |
70 """ |
84 """ |
71 |
85 |
72 offset = request.GET.get(offset_key) |
86 offset = request.GET.get(makeOffsetKey(list_index)) |
73 limit = request.GET.get(limit_key) |
87 limit = request.GET.get(makeLimitKey(list_index)) |
74 |
88 |
75 if offset is None: |
89 if offset is None: |
76 offset = '' |
90 offset = '' |
77 |
91 |
78 if limit is None: |
92 if limit is None: |
94 if user_logic.isDeveloper(): |
108 if user_logic.isDeveloper(): |
95 limit = min(DEF_MAX_DEV_PAGINATION, limit) |
109 limit = min(DEF_MAX_DEV_PAGINATION, limit) |
96 else: |
110 else: |
97 limit = min(DEF_MAX_PAGINATION, limit) |
111 limit = min(DEF_MAX_PAGINATION, limit) |
98 |
112 |
99 return limit, offset |
113 return dict(limit=limit, offset=offset) |
100 |
114 |
101 |
115 |
102 def generateLinkFromGetArgs(request, offset_and_limits): |
116 def generateLinkFromGetArgs(request, offset_and_limits): |
103 """Constructs the get args for the url. |
117 """Constructs the get args for the url. |
104 """ |
118 """ |
105 |
119 |
106 args = ["%s=%s" % (k, v) for k, v in offset_and_limits.iteritems()] |
120 args = ["%s=%s" % (k, v) for k, v in offset_and_limits.iteritems()] |
107 link_suffix = '?' + '&'.join(args) |
121 link_suffix = '?' + '&'.join(args) |
108 |
122 |
109 return request.path + link_suffix |
123 return request.path + link_suffix |
|
124 |
|
125 |
|
126 def generateLinkForRequest(request, base_params, updated_params): |
|
127 """Create a link to the same page as request but with different params |
|
128 |
|
129 Params: |
|
130 request: the request for the page |
|
131 base_params: the base parameters |
|
132 updated_params: the parameters to update |
|
133 """ |
|
134 params = base_params.copy() |
|
135 params.update(updated_params) |
|
136 return generateLinkFromGetArgs(request, params) |
110 |
137 |
111 |
138 |
112 def getListContent(request, params, filter=None, order=None, |
139 def getListContent(request, params, filter=None, order=None, |
113 idx=0, need_content=False): |
140 idx=0, need_content=False): |
114 """Returns a dict with fields used for rendering lists. |
141 """Returns a dict with fields used for rendering lists. |
115 |
142 |
116 TODO(dbentley): we need better terminology. List in this context can have |
143 TODO(dbentley): we need better terminology. List, in this context, can have |
117 one of two meanings. |
144 one of two meanings. |
118 Meaning 1: the underlying list, which may be very large. |
145 Meaning 1: the underlying list, which may be very large. |
119 Meaning 2: the returned list, which is at most 'limit' items. |
146 Meaning 2: the returned list, which is at most 'limit' items. |
120 |
147 |
121 Args: |
148 Args: |
138 'limit': max amount of items per page, |
165 'limit': max amount of items per page, |
139 'newest': url to first page of the list |
166 'newest': url to first page of the list |
140 'prev': url to previous page |
167 'prev': url to previous page |
141 'next': url to next page |
168 'next': url to next page |
142 'first': offset of the first item in the list |
169 'first': offset of the first item in the list |
143 'last': offest of the last item in the list |
170 'last': offset of the last item in the list |
144 } |
171 } |
145 """ |
172 """ |
146 |
173 # TODO(dbentley): this appears to be unnecessary indirection, |
|
174 # as we only use this logic for getForFields, which is never overridden |
147 logic = params['logic'] |
175 logic = params['logic'] |
148 |
176 |
149 offset_key = 'offset_%d' % idx |
177 limit_key, offset_key = makeLimitKey(idx), makeOffsetKey(idx) |
150 limit_key = 'limit_%d' % idx |
178 |
151 |
179 list_params = getListParameters(request, idx) |
152 limit, offset = getLimitAndOffset(request, offset_key, limit_key) |
180 limit, offset = list_params['limit'], list_params['offset'] |
153 pagination_form = makePaginationForm(request, limit, limit_key) |
181 pagination_form = makePaginationForm(request, list_params['limit'], |
|
182 limit_key) |
154 |
183 |
155 # Fetch one more to see if there should be a 'next' link |
184 # Fetch one more to see if there should be a 'next' link |
156 data = logic.getForFields(filter=filter, limit=limit+1, offset=offset, |
185 data = logic.getForFields(filter=filter, limit=limit+1, offset=offset, |
157 order=order) |
186 order=order) |
158 |
187 |
168 |
197 |
169 base_params = dict(i for i in request.GET.iteritems() if |
198 base_params = dict(i for i in request.GET.iteritems() if |
170 i[0].startswith('offset_') or i[0].startswith('limit_')) |
199 i[0].startswith('offset_') or i[0].startswith('limit_')) |
171 |
200 |
172 if params.get('list_key_order'): |
201 if params.get('list_key_order'): |
173 export_link_params = dict(base_params) |
202 export_link = generateLinkForRequest(request, base_params, {'export' : idx}) |
174 export_link_params['export'] = idx |
|
175 export_link = generateLinkFromGetArgs(request, export_link_params) |
|
176 |
203 |
177 if more: |
204 if more: |
178 # TODO(dbentley): here we need to implement a new field "last_key" |
205 # TODO(dbentley): here we need to implement a new field "last_key" |
179 next_params = dict(base_params) |
206 next = generateLinkForRequest(request, base_params, {offset_key : offset+limit, |
180 next_params[offset_key] = offset+limit |
207 limit_key : limit}) |
181 next_params[limit_key] = limit |
|
182 next = generateLinkFromGetArgs(request, next_params) |
|
183 |
208 |
184 if offset > 0: |
209 if offset > 0: |
185 # TODO(dbentley): here we need to implement previous in the good way. |
210 # TODO(dbentley): here we need to implement previous in the good way. |
186 prev_params = dict(base_params) |
211 prev = generateLinkForRequest(request, base_params, |
187 prev_params[offset_key] = max(0, offset-limit) |
212 { offset_key : max(0, offset-limit), |
188 prev_params[limit_key] = limit |
213 limit_key : limit }) |
189 prev = generateLinkFromGetArgs(request, prev_params) |
|
190 |
214 |
191 if offset > limit: |
215 if offset > limit: |
192 newest_params = dict(base_params) |
216 # Having a link to the first doesn't make sense on the first page (we're on |
193 del newest_params[offset_key] |
217 # it). It also doesn't make sense on the second page (because the first |
194 newest_params[limit_key] = limit |
218 # page is the previous page). |
195 newest = generateLinkFromGetArgs(request, newest_params) |
219 |
|
220 # NOTE(dbentley): I personally disagree that it's simpler to do that way, |
|
221 # because sometimes you want to go to the first page without having to |
|
222 # consider what page you're on now. |
|
223 newest = generateLinkForGetArgs(request, base_params, {offset_key : 0, |
|
224 limit_key : limit}) |
196 |
225 |
197 content = { |
226 content = { |
198 'idx': idx, |
227 'idx': idx, |
199 'data': data, |
228 'data': data, |
200 'export': export_link, |
229 'export': export_link, |