def ac(self, **params): """Autocomplete API. """ field = params['field'] term = params['term'] colls = params['colls'].split(",") # FIXME - allow restricting search to a set of collections if field == '*': return jsonresp([]) fieldname, fieldtype = field.rsplit('_', 1) fieldconfigs = SearchCollection.config['types'] \ .get('record', {}) \ .get('fields', {}) if '*' in colls: target = SearchCollection.all() else: target = SearchCollection.field.coll.is_or_is_descendant(colls) return jsonresp( field_item_types[fieldtype] .autocomplete(target, fieldconfigs, fieldname, term) )
def position_in(self, coll): """Get the ids of the previous and next records according to the named collection. """ from apps.store.search import Collection as SearchCollection q = SearchCollection.doc_type('record').field.coll.is_in(coll.id) for name, asc in coll.autoorder.ordering: asc = {'+': True, '-': False}[asc] q = q.order_by(name, asc) r = [(r.data['id'][0], r.rank) for r in q.fromdoc('record', self.id, -1, 3)] if len(r) == 0: return dict(pos=0, size=0) if r[0][0] == self.id: index = 0 elif len(r) == 1: return dict(pos=0, size=0) else: index = 1 rank = r[index][1] result = dict(pos=rank + 1, size=len(q)) if index > 0: result['prev'] = r[index - 1][0] if index + 1 < len(r): result['next'] = r[index + 1][0] return result
def delete(self, id, **params): coll = get_or_404(Collection, id) if cherrypy.request.method == "POST": # FIXME - check csrf token if id: if params.get('delete_conf', '') == '': redirect(url("colls-list")) coll = get_or_404(Collection, id) # Remove the collection's parents coll.set_parents(()) Collection.objects.set(coll) # Remove the collection from its childrens parent lists. child_colls = coll.children for child in child_colls: cparents = set(child.parents) cparents.remove(id) child.set_parents(cparents) Collection.objects.set(child) # Iterate through the records in the collection, and remove the # collection from them. SearchCollection.checkpoint().wait() for record in SearchCollection.doc_type('record') \ .field.coll.is_in(id)[:]: try: record = record.object except KeyError: # Record is already gone - can't update it. # (This shouldn't happen, but do this check for # robustness.) continue record.collections = filter(lambda x: x != id, record.collections) Record.objects.set(record) Collection.objects.remove(id) Record.objects.flush() Collection.objects.flush() gonext() redirect(url("colls-list", id=coll.id)) elif cherrypy.request.method == "GET": context = dict(coll=coll) return render("coll-delete-confirm.html", context) raise cherrypy.HTTPError(404)
def make_media_view(self, mediafile): info = self.get_file_info(mediafile) assert info is not None # Should have already checked that file exists records = [] q = SearchCollection.doc_type('record').field.fileid == mediafile for r in q[:100]: records.append(r.object) context = dict(info=info, records=records) self.render('mediapreview', (), dict(path=mediafile), "export/html/media-view.html", context)
def mediapreview(self, path, **params): try: context = dict(path=path, info=mapper.get_file_info(path)) except OSError: raise cherrypy.HTTPError(404) add_search_to_context(context) q = SearchCollection.doc_type("record").field.fileid == path records = [] for r in q[:100]: records.append(r.object) # FIXME - handle more than 100 records matching context["records"] = records return render("media-view.html", context)
def _get_query(self, type, incsubs): key = (type, incsubs) q = self._cached_queries.get(key, None) if False and q is not None: # FIXME re-enable this cache, but make it persist only for the # duration of a single request. return q from apps.store.search import Collection as SearchCollection q = SearchCollection.doc_type(type) if incsubs: q = q.field.coll.is_or_is_descendant(self.id) else: q = q.field.coll.is_in(self.id) for name, asc in self.autoorder.ordering: asc = {'+': True, '-': False}[asc] q = q.order_by(name, asc) q = q.check_at_least(-1) self._cached_queries[key] = q return q
def set_parents(self, parents): from apps.store.search import Collection as SearchCollection hier = SearchCollection.taxonomy('coll_hierarchy') hier.add_category(self.id) changed = False new_parents = set() for parent in parents: if parent == self.id or parent == '': continue new_parents.add(parent) # Remove the collection from old parents which are no longer parents for parent in self._parents: if parent in new_parents: continue try: pcoll = Collection.objects.get(parent) except KeyError: continue # Can get KeyError if some of the ancestors don't exist - this would need to be fixed, but failing here would make it impossible for the user to fix it. pcoll._remove_child(self.id) Collection.objects.set(pcoll) hier.remove_parent(self.id, parent) changed = True for parent in new_parents: if parent in self._parents: continue pcoll = Collection.objects.get(parent) pcoll._add_child(self.id) Collection.objects.set(pcoll) hier.add_parent(self.id, parent) changed = True self._parents = tuple(sorted(new_parents)) if changed: self._calced_ancestors = False return changed
def calendar_items(id, incsubs, calstyle, startdate, year, month, day, datefield): # If date was supplied as year,month,day, convert it. if year is not None: startdate = '%04.d' % int(year) if month is not None: startdate += '-%02.d' % int(month) if day is not None: startdate += '-%02.d' % int(day) record_docs = SearchCollection.doc_type('record') if incsubs: q = record_docs.field.coll.is_or_is_descendant(id) else: q = record_docs.field.coll.is_in(id) info = q.calc_facet_count(datefield).check_at_least(-1).info counts = info[0]['counts'] counts.sort() prevdate = None nextdate = None firstdate = None years = set() dates = {} if not startdate: # No start date supplied. if len(counts) > 0: startdate = '%04.d-%02.d-%02.d' % tuple(counts[0][0]) else: startdate = None # Adjust the accuracy of startdate according to the calendar style, and set # enddate accordingly. if startdate is not None: startdate, enddate = date_range(calstyle, startdate) q = q.filter(Field(datefield).range(startdate, enddate)) # Set prevdate, nextdate, firstdate, years startdate_tuple = (int(startdate[:4]), int(startdate[5:7]), int(startdate[8:10])) enddate_tuple = (int(enddate[:4]), int(enddate[5:7]), int(enddate[8:10])) for (date_tuple, count) in counts: date_tuple = tuple(date_tuple) years.add(date_tuple[0]) if date_tuple < startdate_tuple: if prevdate is None or prevdate < date_tuple: prevdate = date_tuple elif date_tuple > enddate_tuple: if nextdate is None or nextdate > date_tuple: nextdate = date_tuple years = tuple(sorted(years)) if prevdate is not None: prevdate = '%04.d-%02.d-%02.d' % tuple(prevdate) if nextdate is not None: nextdate = '%04.d-%02.d-%02.d' % tuple(nextdate) # Set dates for r in q: for date in r.data.get(datefield, []): dates.setdefault(date, []).append(r.object) if firstdate is None: firstdate = date elif firstdate > date: firstdate = date # Set year, month, day year = 1 month = 1 day = 1 if startdate is not None: if len(startdate) > 0: year = int(startdate[:4]) if len(startdate) > 4: month = max(1, int(startdate[5:7])) if len(startdate) > 7: day = max(1, int(startdate[8:10])) # Months is always the list of all months. months = [(i, calendar.month_name[i]) for i in xrange(1, 13)] # Count the number of entries on each day, and set the groupings # accordingly. groupnames, groups = mkgroups(dates) result = dict(calstyle=calstyle, dates=dates, years=years, months=months, startdate=startdate, year=year, month=month, day=day, groupnames=groupnames, nextdate=nextdate, prevdate=prevdate) if int(year) <= 0: # FIXME - hack to handle missing data, and out of range dates. year = datetime.datetime.now().year month = datetime.datetime.now().month day = datetime.datetime.now().day if calstyle == 'year': months = [] for month in range(1, 13): months.append(mkmonth(year, month, dates, groups)) result['months'] = months if calstyle == 'month': result['month_grid'] = mkmonth(year, month, dates, groups) elif calstyle == 'day': records = dates.get(startdate, ()) result['records'] = records return result