def browse(name, ref=None): project = Project.get(Project.name == name) query = Feature.select().where(Feature.project == project) features = [] for f in query: features.append([f.ref, f.lon, f.lat, f.action]) return render_template('browse.html', project=project, features=features, ref=ref)
def project(name): project = Project.get(Project.name == name) desc = project.description.replace('\n', '<br>') cnt = project.feature_count val1 = Feature.select(Feature.id).where(Feature.project == project, Feature.validates_count > 0) val2 = Feature.select(Feature.id).where(Feature.project == project, Feature.validates_count >= 2) if project.validate_modified: val1 = val1.where(Feature.action == 'm') val2 = val2.where(Feature.action == 'm') cnt = Feature.select(Feature.id).where(Feature.project == project, Feature.action == 'm').count() corrected = Feature.select(Feature.id).where( Feature.project == project, Feature.audit.is_null(False), Feature.audit != '').count() skipped = Feature.select(Feature.id).where( Feature.project == project, Feature.audit.contains('"skip": true')).count() user = get_user() if user: has_skipped = Task.select().join(Feature).where( Task.user == user, Task.skipped == True, Feature.project == project).count() > 0 else: has_skipped = False return render_template('project.html', project=project, admin=is_admin(user, project), count=cnt, desc=desc, val1=val1.count(), val2=val2.count(), corrected=corrected, skipped=skipped, has_skipped=has_skipped)
def all_features(pid): project = Project.get(Project.id == pid) query = Feature.select().where(Feature.project == project) features = [] for f in query: features.append([f.ref, [f.lat/1e7, f.lon/1e7], f.action]) return app.response_class('features = {}'.format(json.dumps( features, ensure_ascii=False).encode('utf-8')), mimetype='application/javascript')
def export_audit(pid): project = Project.get(Project.id == pid) if not is_admin(get_user(), project): return redirect(url_for('front')) update_audit(project) project.save() return app.response_class( project.audit or '{}', mimetype='application/json', headers={'Content-Disposition': 'attachment;filename=audit_{}.json'.format(project.name)})
def add_project(pid=None): user = get_user() if not is_admin(user): return redirect(url_for('front')) if pid: project = Project.get(Project.id == pid) else: project = Project() return render_template('newproject.html', project=project)
def clear_skipped(pid): project = Project.get(Project.id == pid) user = get_user() if user: features = Feature.select().where(Feature.project == project) query = Task.delete().where( Task.user == user, Task.skipped == True, Task.feature.in_(features)) query.execute() return redirect(url_for('project', name=project.name))
def tasks(name, ref=None): if not get_user(): return redirect(url_for('login', next=request.path)) project = Project.get(Project.name == name) if not project.can_validate: if ref: return redirect(url_for('browse', name=name, ref=ref)) else: flash('Project validation is disabled') return redirect(url_for('project', name=name)) return render_template('task.html', project=project, ref=ref)
def api_feature(pid): user = get_user() project = Project.get(Project.id == pid) if user and request.method == 'POST' and project.can_validate: ref_and_audit = request.get_json() if ref_and_audit and len(ref_and_audit) == 2: skipped = ref_and_audit[1] is None feat = Feature.get(Feature.project == project, Feature.ref == ref_and_audit[0]) user_did_it = Task.select(Task.id).where( Task.user == user, Task.feature == feat).count() > 0 Task.create(user=user, feature=feat, skipped=skipped) if not skipped: if len(ref_and_audit[1]): new_audit = json.dumps(ref_and_audit[1], sort_keys=True, ensure_ascii=False) else: new_audit = None if feat.audit != new_audit: feat.audit = new_audit feat.validates_count = 1 elif not user_did_it: feat.validates_count += 1 feat.save() fref = request.args.get('ref') if fref: feature = Feature.get(Feature.project == project, Feature.ref == fref) elif not user or request.args.get('browse') == '1': feature = Feature.select().where(Feature.project == project).order_by(fn_Random()).get() else: try: # Maybe use a join: https://stackoverflow.com/a/35927141/1297601 task_query = Task.select(Task.id).where(Task.user == user, Task.feature == Feature.id) query = Feature.select().where( Feature.project == project, Feature.validates_count < 2).where( ~fn.EXISTS(task_query)).order_by(fn_Random()) if project.validate_modified: query = query.where(Feature.action == 'm') if user.bboxes: bboxes = BBoxes(user) feature = None for f in query: if bboxes.contains(f.lat/1e7, f.lon/1e7): feature = f break elif not feature: feature = f if not feature: raise Feature.DoesNotExist() else: feature = query.get() except Feature.DoesNotExist: return jsonify(feature={}, ref=None, audit=None) return jsonify(feature=json.loads(feature.feature), ref=feature.ref, audit=json.loads(feature.audit or 'null'))
def testAdd(self): tui.addInputAnswers("y") self.cmd.do_p_add("p1") tui.addInputAnswers("y", "y") self.cmd.do_p_add("p2 @kw1 @kw2=12") projects = list(Project.select()) result = [x.name for x in projects] expected = [u"p1", u"p2"] self.assertEqual(result, expected) kwDict = Project.get(2).getKeywordDict() self.assertEqual(kwDict, dict(kw1=None, kw2=12))
def external_audit(pid): project = Project.get(Project.id == pid) if not is_admin(get_user(), project): return redirect(url_for('front')) query = Feature.select().where(Feature.project == project, Feature.audit.is_null(False)) result = {} for feat in query: audit = json.loads(feat.audit or {}) props = json.loads(feat.feature)['properties'] eaudit = {} if 'move' in audit: if audit['move'] == 'osm': if 'were_coords' in props['were_coords']: eaudit['move'] = props['were_coords'] elif isinstance(audit['move'], list) and len(audit['move']) == 2: eaudit['move'] = audit['move'] if 'keep' in audit: keep = {} for k in audit['keep']: orig = None if 'tags_deleted.'+k in props: orig = props['tags_deleted.'+k] elif 'tags_changed.'+k in props: orig = props['tags_changed.'+k] orig = orig[:orig.find(' -> ')] if orig: keep[k] = orig if keep: eaudit['keep'] = keep if audit.get('skip'): if audit.get('comment', '').lower() != 'duplicate': eaudit['skip'] = audit.get('comment', '<no reason>') if eaudit: result[feat.ref] = eaudit return app.response_class( json.dumps(result, ensure_ascii=False, indent=1, sort_keys=True), mimetype='application/json', headers={ 'Content-Disposition': 'attachment;filename=ext_audit_{}.json'.format(project.name) })
def delete_project(pid): project = Project.get(Project.id == pid) if not is_admin(get_user(), project): return redirect(url_for('front')) project.delete_instance(recursive=True) return redirect(url_for('front'))
def upload_project(): def add_flash(pid, msg): flash(msg) return redirect(url_for('add_project', pid=pid)) user = get_user() if not is_admin(user): return redirect(url_for('front')) pid = request.form['pid'] if pid: pid = int(pid) project = Project.get(Project.id == pid) if not is_admin(user, project): return redirect(url_for('front')) update_audit(project) else: pid = None project = Project() project.feature_count = 0 project.bbox = '' project.owner = user project.name = request.form['name'].strip() if not project.name: return add_flash(pid, 'Empty name - bad') project.title = request.form['title'].strip() if not project.title: return add_flash(pid, 'Empty title - bad') project.url = request.form['url'].strip() if not project.url: project.url = None project.description = request.form['description'].strip() project.can_validate = request.form.get('validate') is not None project.validate_modified = request.form.get('validate_modified') is not None project.hidden = request.form.get('is_hidden') is not None if 'json' not in request.files or request.files['json'].filename == '': if not pid: return add_flash(pid, 'Would not create a project without features') features = [] else: try: features = json.load(codecs.getreader('utf-8')(request.files['json'])) except ValueError as e: return add_flash(pid, 'Error in the uploaded features file: {}'.format(e)) if 'features' not in features or not features['features']: return add_flash(pid, 'No features found in the JSON file') features = features['features'] audit = None if 'audit' in request.files and request.files['audit'].filename: try: audit = json.load(codecs.getreader('utf-8')(request.files['audit'])) except ValueError as e: return add_flash(pid, 'Error in the uploaded audit file: {}'.format(e)) if not audit: return add_flash(pid, 'No features found in the audit JSON file') proj_audit = json.loads(project.audit or '{}') if audit: proj_audit.update(audit) project.audit = json.dumps(proj_audit, ensure_ascii=False) if features or audit or not project.updated: project.updated = datetime.datetime.utcnow().date() project.save() if features: with database.atomic(): update_features(project, features, proj_audit) if project.feature_count == 0: project.delete_instance() return add_flash('Zero features in the JSON file') return redirect(url_for('project', name=project.name))
def table(name, page): PER_PAGE = 200 project = Project.get(Project.name == name) query = Feature.select().where(Feature.project == project).order_by( Feature.id).paginate(page, PER_PAGE) show_validated = request.args.get('all') == '1' if not show_validated: query = query.where(Feature.validates_count < 2) pagination = Pagination(page, PER_PAGE, query.count(True)) columns = set() features = [] for feature in query: data = json.loads(feature.feature) audit = json.loads(feature.audit or 'null') if audit and len(audit.get('move', '')) == 2: coord = audit['move'] else: coord = data['geometry']['coordinates'] f = {'ref': feature.ref, 'lon': coord[0], 'lat': coord[1], 'action': data['properties']['action']} tags = {} for p, v in data['properties'].items(): if not p.startswith('tags') and not p.startswith('ref_unused_tags'): continue k = p[p.find('.')+1:] if k.startswith('ref'): continue tag = {} if data['properties']['action'] in ('create', 'delete') and p.startswith('tags.'): columns.add(k) tag['before'] = '' tag['after'] = v tag['accepted'] = not audit or k not in audit.get('keep', []) tag['action'] = data['properties']['action'] else: if p.startswith('tags.'): continue if p.startswith('tags_') or p.startswith('ref_unused_tags'): columns.add(k) tag['accepted'] = p.startswith('tags_') or ( audit and k in audit.get('override', [])) if p.startswith('tags_new'): tag['before'] = '' tag['after'] = v tag['action'] = 'created' elif p.startswith('tags_del'): tag['before'] = '' # swapping to print deleted value tag['after'] = v tag['action'] = 'deleted' elif p.startswith('tags_cha'): i = v.find(' -> ') tag['before'] = v[:i] tag['after'] = v[i+4:] tag['action'] = 'changed' elif p.startswith('ref_unused'): tag['before'] = data['properties'].get('tags.'+k, '') tag['after'] = v tag['action'] = 'changed' tags[k] = tag f['tags'] = tags features.append(f) return render_template('table.html', project=project, pagination=pagination, columns=sorted(columns), rows=features, show_validated=show_validated)