def imp(self, **params): stash = {} # Get any existing Importer imp = None imp_id = getintparam("id", None, stash, params) if imp_id is not None: imp = self.imports.get(imp_id, None) if imp is None: context = {} context['error'] = 'Unknown import ID' return render("import/choose-file.html", context) if imp is None: # No import in progress if cherrypy.request.method == "POST": return self.handle_import_start(params) elif cherrypy.request.method == "GET": return render("import/choose-file.html", {}) else: # Import in progress; let it handle the request. if cherrypy.request.method == "POST": if getparam("import_cancel", None): imp.cancel() redirect(url("home")) return imp.handle_post(params) elif cherrypy.request.method == "GET": return imp.handle_get(params) raise cherrypy.NotFound
def from_exploratour(self, **params): context = {} if cherrypy.request.method == "POST": imp = import_exploratour.start_import(params) if imp.error: context['error'] = imp.error return render("import/from-exploratour.html", context) self.imports[imp.id] = imp redirect(url("import-status", id=imp.id)) return render("import/from-exploratour.html", context)
def export_backup(self, export_id=None, download=False, **params): # Read parameters first, to ensure they all get stashed. stash = {} # Make a new exporter, and get any parameters it needs into the stash. exp = Exporter.get('xml')() exp.read_params(stash, params) # Handle exports which are in progress, or have finished if export_id is not None: try: export_id = int(export_id) except ValueError: export_id = None if export_id is not None: try: running_exp = exports[export_id] except KeyError: # Invalid export id (most probably due to a server restart) running_exp = None if running_exp is not None: # Export in progress progress = pool.get_progress(export_id) context = dict(export_id=export_id, fmt='xml', progress=progress, stash=stash) if not progress.complete: return render('export/in_progress.html', context) if progress.failed: return render('export/failed.html', context) # Export complete if not download: # Display a "Export prepared" return render('export/complete.html', context) return running_exp.respond() # Read the set of things to export. search, desc, topcoll = self._get_export_records(stash, None, None, None, True) if not getparam('export', False, stash, params): # Not ready to start the export yet. context = dict( export_desc = desc, stash = stash, ) exp.add_to_context(context, search, stash, params) return render('backup/pick.html', context) # Start the exporter task = ExportRecords(exp, search) export_id = pool.add_task(task) exports[export_id] = task redirect(url("records-export-inprogress", export_id=export_id, fmt='xml', **stash))
def reorder(self, id, **params): if getparam('cancel') == '1': redirect(url("coll-view", id=id)) coll = get_or_404(Collection, id) context = {} if cherrypy.request.method == "POST": # FIXME - check csrf token order, ordering = coll_order_from_request() if getparam('submit') == '1': # save order coll.autoorder.ordering = ordering Collection.objects.set(coll) Collection.objects.flush() redirect(url("coll-view", id=id)) else: order = [] for field, dir in coll.autoorder.ordering: order.append((len(order), field, dir)) if not order: order.append((0, '', '')) context['coll'] = coll context['collorder'] = order return render("coll-reorder.html", context)
def handle_post(self, params, context): context.update(self.build_form_context(params)) do_import = getparam('import', None, None, params) if do_import: self.set_next(ImportPerformTask(self.handler, self.importer)) redirect(url("import", id=self.importer.id)) return render("import/choose-mappings.html", context)
def create(self, **params): context = {} if cherrypy.request.method == "POST": # FIXME - check csrf token title = params.get('newcoll_title', u'').strip() parents = coll_parents_from_request() if getparam('create'): if title: id = create_collection(title, parents) gonext() redirect(url("colls-list", id=id)) else: context['error'] = "You must set a title for the collection" else: parents = [] allowable_parents = set( c.id for c in Collection.objects ) context.update(dict( parents = tuple(enumerate(parents)), allowable_parents = sorted(allowable_parents), collections = Collection.objects, )) return render("coll-new.html", context)
def handle_post(self, params, context): context.update(self.build_form_context(params)) do_import = getparam('import', None, None, params) if do_import: self.set_next(BuildExploratourRecordsTask(self.handler, self.importer)) redirect(url("import", id=self.importer.id)) return render("import/choose-fields.html", context)
def index(self): context = dict( records = len(Record.objects), collections = len(Collection.objects), templates = len(Template.objects), ) return render("index.html", context)
def missing_collection(params, context): invalid_collections = context['invalid_collections'] # Only do one missing collection at a time: invalid_collection = invalid_collections[0] context = dict(invalid_collection=invalid_collection, path=cherrypy.request.path_info) return render("missing-collection.html", context)
def reindex(self, **params): stash = {} if cherrypy.request.method == "POST": progress = pool.get_progress(reindexer_id[0]) if progress.complete: reindexer_id[0] = pool.add_task(Reindexer()) redirect(url("reindex")) context = dict(progress = pool.get_progress(reindexer_id[0])) return render("reindex.html", context)
def error_page_404(self, status, message, traceback, version): context = dict( status=status, message=message, traceback=traceback, version=version, records = len(Record.objects), collections = len(Collection.objects), templates = len(Template.objects), ) add_search_to_context(context) return render('errorpages/404.html', context)
def handle_import_start(self, params): """Handle a POST request that starts an import.""" if getparam("import_cancel", None): redirect(url("home")) imp = download.Importer() imp.start(params) if imp.error: context = {} context['error'] = imp.error return render("import/choose-file.html", context) self.imports[imp.id] = imp redirect(url("import", id=imp.id))
def create(self, **params): context = {} if cherrypy.request.method == "POST": context.update(tmpl_from_request(id, params)) if context.get('invalid_collections'): return missing_collection(params, context) elif cherrypy.request.method == "GET": context['tmpl'] = Template(u'', None, Record()) else: assert False return render("tmpl-new.html", context)
def view(self, id, **params): context = {} stash = {} showfull = int(getparam('showfull', '0', stash)) search = build_search(stash) # FIXME - hack q = search['q'] q.startrank = 0 q.endrank = 20000 items = q.results ids = set() for item in items: if item.data['type'][0] != 'r': continue ids.add(item.data['id'][0]) points = [] for id in sorted(ids): rec = Record.objects.get(unicode(id)) date = rec.root.find("field[@type='date']") if date is None: continue date = date.text if date is None: continue mo = single_full_bamboostyle_date_re.match(date) if not mo: continue day, month, year = map(lambda x: int(x), (mo.group(1), mo.group(2), mo.group(3))) date = datetime.date(year, month, day) locs = rec.root.findall(".//field[@type='location']") for loc in locs: ll = latlongparse(loc.get('latlong')) if ll is None: continue points.append([ll.lat, ll.long, rec.id, date]) points.sort(key=lambda x: x[3]) startdate = points[0][3] for i in xrange(len(points)): days = (points[i][3] - startdate).days points[i][3] = points[i][3].isoformat() points[i].append(days) context['points'] = points context['center_point'] = [points[0][0], points[0][1], 7] return render("dataview.html", context)
def gallery(self, id, show=None, offset=None): record = get_or_404(Record, id) images = record.media('image') if offset is None: offset = 0 if show is not None: for num, image in enumerate(images): if image.src == show: offset = num break else: offset = int(offset) context = dict(record=record, images=images, offset=offset) return render("record-gallery.html", context)
def list(self, **params): coll = get_lockto_coll() if coll is not None: redirect(url("coll-view", id=coll.id)) groups = [CollGroup(coll.id, coll.title, [coll.id]) for coll in Collection.objects if not coll.parents] groupid = getparam('groupid', '') filtered_groups = filter(lambda group: group.id == groupid, groups) if len(filtered_groups) > 0: currgroup = filtered_groups[0] elif len(groups) > 0: currgroup = groups[0] else: currgroup = None context = dict(groups=groups, currgroup=currgroup) return render("colls-list.html", context)
def _check_delete(self, id, page): params = cherrypy.request.params if params.get('delete', '') != '': tmpl = get_or_404(Template, id) context = dict(tmpl=tmpl, page=page) return render("tmpl-delete-confirm.html", context) if cherrypy.request.method == "POST": if params.get('delete_conf', '') != '': try: Template.objects.remove(id) Template.objects.flush() except KeyError: raise cherrypy.HTTPError(404) gonext() redirect(url("tmpls-list"))
def create(self, **params): context = {} if cherrypy.request.method == "POST": context.update(record_from_request(None)) if context.get('invalid_collections'): return missing_collection(params, context) if cherrypy.request.method == "GET": tmplid = params.get('tmplid', '') if tmplid == '': context['record'] = Record() else: context['record'] = get_or_404(Template, tmplid) return render("record-new.html", context)
def roots(self, **params): error = None if cherrypy.request.method == "POST": num = 0 roots_dict = {} roots = [] dupe_names = set() while True: name = params.get('rn%d' % num) path = params.get('rp%d' % num) num += 1 if name is None or path is None: break if name == '': if path != '': error = u'No name specified for path "%s"' % path else: if path == '': error = u'Empty path specified for name "%s"' % name if name == '' and path == '': continue if name != '' and name in roots_dict: dupe_names.add(name) path = path.strip() roots_dict[name] = path roots.append((num - 1, (name, path))) if dupe_names: if len(dupe_names) == 1: error = u"Duplicated name: \"%s\"" % tuple(dupe_names)[0] else: error = u"Duplicated names: \"%s\"" % u'\", \"'.join(sorted(dupe_names)) if error is None: settings = get_settings() settings.set_roots(roots_dict) Settings.objects.set(settings) Settings.objects.flush() redirect(url("settings-roots")) else: roots_dict = get_settings().get_roots() if not roots_dict: roots_dict = config.default_media_roots roots = tuple(enumerate(sorted(roots_dict.items()))) context = dict( error = error, roots = roots, ) return render("settings/roots.html", context)
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 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 edit(self, id, **params): context = {} ret = self._check_delete(id, 'tmpl-edit') if ret is not None: return ret if cherrypy.request.method == "POST": context.update(tmpl_from_request(id, params)) if context.get('invalid_collections'): return missing_collection(params, context) elif cherrypy.request.method == "GET": context['tmpl'] = get_or_404(Template, id) else: assert False return render("tmpl-edit.html", context)
def reparent(self, id, **params): if getparam('cancel') == '1': redirect(url("coll-view", id=id)) coll = get_or_404(Collection, id) if cherrypy.request.method == "POST": # FIXME - check csrf token title = getparam('title') parents = coll_parents_from_request() if getparam('submit') == '1': # Save parents changed = coll.set_parents(filter(lambda x: x != '', parents)) if coll.title != title: coll.title = title Collection.objects.set(coll) Collection.objects.flush() Record.objects.flush() redirect(url("coll-view", id=id)) else: title = coll.title parents = [] for parent in coll.parents: parents.append(parent) if not parents: parents.append('') not_allowed = set(coll.ancestors) - set(coll.parents) not_allowed.add(id) allowable_parents = set( c.id for c in Collection.objects if c.id != id and id not in c.ancestors ) context = dict( title = title, coll = coll, parents = tuple(enumerate(parents)), allowable_parents = sorted(allowable_parents), collections = Collection.objects, ) return render("coll-reparent.html", context)
def _check_delete(self, id, page): params = cherrypy.request.params if params.get('delete', '') != '': record = get_or_404(Record, id) context = dict(record=record, page=page) return render("record-delete-confirm.html", context) if cherrypy.request.method == "POST": if params.get('delete_conf', '') != '': record = get_or_404(Record, id) #print "Old collections", record.collections record.collections = () # Set the record, to remove the collections Record.objects.set(record) Record.objects.remove(id) Record.objects.flush() Collection.objects.flush() gonext() redirect(url("search", act='search'))
def handle_get(self, params): context = dict(status=self._status, import_id=self.id, cancelled=self._cancelled) # FIXME - threadsafety of access to _info_getter, _task, _task_id ; # they should be atomically read and written. if self._info_getter is not None: return self._info_getter.handle_get(params, context) if self._task is not None: progress = pool.get_progress(self._task_id) context['status'] = "%s: %s" % (self._status, progress.msg) if progress.failed: context['status'] = "Failed: %s" % context['status'] context['finished'] = True if progress.complete: context['finished'] = True if self._task is None and self._info_getter is None: context['finished'] = True return render("import/status.html", context)
def search(self, **params): stash = {} context = dict(stash=stash) params = SearchParams(stash) search = Search(params) if not search.validate(): # If the search doesn't validate, always go to the search entry # page. params.action = 'entry' search.add_to_context(context) context['showfull'] = int(getparam('showfull', '0', stash)) if params.action == 'search': return render("search.html", context) elif params.action == 'select': return render("search_select.html", context) elif params.action.startswith('createcoll'): if cherrypy.request.method != "POST": return render("search_createcoll.html", context) subact = params.action[11:] parents = [] for num in getorderparam('parent_order'): parent = getparam('parent%d' % num) if parent is None or parent == '': continue if subact == ('del_parent_%d' % num): continue parents.append(unicode(parent)) if subact == 'add_parent': parents.append(u'') context['parents'] = tuple(enumerate(parents)) context['allowable_parents'] = set( c.id for c in Collection.objects ) context['collections'] = Collection.objects if subact == 'do': newtitle = getparam('create_colltitle', '') if len(newtitle) == 0: context['error'] = "Cannot create collection with no title" return render("search_createcoll.html", context) coll = Collection.find_by_title(newtitle) if len(coll) != 0: context['error'] = "Collection with title %s already exists" % newtitle return render("search_createcoll.html", context) coll = Collection(None, None, newtitle) Collection.objects.set(coll) # Have to set the collection before setting the parents, to get # an ID for the parents to refer back to. coll.set_parents(filter(lambda x: x != '', parents)) Collection.objects.set(coll) Record.objects.flush() Collection.objects.flush() for record in search.query: record = record.object record.collections = record.collections + [coll.id] Record.objects.set(record) Record.objects.flush() Collection.objects.flush() redirect(url("coll-view", id=coll.id)) else: return render("search_createcoll.html", context) elif params.action == 'addtocoll': context['all_collections'] = Collection.objects if cherrypy.request.method != "POST": return render("search_addtocoll.html", context) newid = getparam('addto_collid', '') if len(newid) == 0: context['error'] = "Pick a collection to add to" return render("search_addtocoll.html", context) coll = Collection.objects.get(newid) for record in search.query: record = record.object record.collections = record.collections + [coll.id] Record.objects.set(record) Record.objects.flush() Collection.objects.flush() redirect(url("coll-view", id=coll.id)) return render("search_addtocoll.html", context) elif params.action == 'removefromcoll': context['all_collections'] = Collection.objects if cherrypy.request.method != "POST": return render("search_removefromcoll.html", context) newid = getparam('removefrom_collid', '') if len(newid) == 0: context['error'] = "Pick a collection to remove from" return render("search_removefromcoll.html", context) coll = Collection.objects.get(newid) for record in search.query: record = record.object record.collections = tuple(filter(lambda x: x != coll.id, record.collections)) Record.objects.set(record) Record.objects.flush() Collection.objects.flush() redirect(url("coll-view", id=coll.id)) return render("search_removefromcoll.html", context) else: context['all_collections'] = Collection.objects return render("search_entry.html", context)
def status(self, id): imp = self.imports.get(id, None) context = dict(imp=imp) return render("import/status.html", context)
def export_records(self, export_id=None, fmt='rtf', download=False, **params): """Export a set of records. """ # Read parameters first, to ensure they all get stashed. stash = {} record_id = getparam('record_id', None, stash, params) issearch = getparam('issearch', None, stash, params) coll = getparam('coll', None, stash, params) incsubs = getintparam('incsubs', 1, stash, params) # Make a new exporter, and get any parameters it needs into the stash. try: exp = Exporter.get(fmt)() except KeyError: raise cherrypy.NotFound exp.read_params(stash, params) # Handle exports which are in progress, or have finished if export_id is not None: try: export_id = int(export_id) except ValueError: export_id = None if export_id is not None: try: running_exp = exports[export_id] except KeyError: # Invalid export id (most probably due to a server restart) running_exp = None if running_exp is not None: # Export in progress progress = pool.get_progress(export_id) context = dict(export_id=export_id, fmt=fmt, progress=progress, stash=stash) if not progress.complete: return render('export/in_progress.html', context) if progress.failed: return render('export/failed.html', context) # Export complete if not download: # Display a "Export prepared" return render('export/complete.html', context) return running_exp.respond() # Read the set of things to export. search, desc, topcoll = self._get_export_records(stash, record_id, issearch, coll, incsubs) if not getparam('export', False, stash, params): # Not ready to start the export yet. context = dict( fmts = Exporter.fmts(params), fmt = fmt, export_desc = desc, stash = stash, ) exp.add_to_context(context, search, stash, params) return render('export/pickfmt.html', context) # Start the exporter task = ExportRecords(exp, search) export_id = pool.add_task(task) exports[export_id] = task redirect(url("records-export-inprogress", export_id=export_id, fmt=fmt, **stash))
def handle_get(self, params, context): context.update(self.build_form_context(params)) return render("import/choose-fields.html", context)
def pick(self): context = dict(templates = Template.objects) return render("tmpls-pick.html", context)