Mercurial > code > home > repos > href
view lookup.py @ 39:c538dc39b851
user login fixes
author | drewp@bigasterisk.com |
---|---|
date | Sat, 19 Nov 2022 17:06:36 -0800 |
parents | f3a15a724483 |
children | 94181d521d6d |
line wrap: on
line source
""" serve some queries over bookmarks: /user /user/tag+tag+tag and the add-bookmark stuff """ import datetime import json import logging import os import time import urllib.error import urllib.parse import urllib.request from collections import defaultdict import bottle import pymongo from bottle import static_file from dateutil.tz import tzlocal from jadestache import Renderer from link import Links, NotFound from pagetitle import PageTitle from mongo_required import open_mongo_or_die, die_on_mongo_connection_errors from get_agent import bottleGetAgent db = open_mongo_or_die()['href'] pageTitle = PageTitle(db) links = Links(db) renderer = Renderer(search_dirs=['template'], debug=bottle.DEBUG) log = logging.getLogger() def getUser(): try: agent = bottleGetAgent() username = db['user'].find_one({'_id': str(agent)})['username'] if agent else None except KeyError: username = agent = None return username, agent def siteRoot(): try: return bottle.request.headers['x-site-root'].rstrip('/') except KeyError: log.warn(repr(bottle.request.__dict__)) raise @bottle.route('/static/<path:path>') def server_static(path): return static_file(path, root='static') def recentLinks(user, tags, allowEdit): out = {'links': []} t1 = time.time() spec = {'user': user} if tags: spec['extracted.tags'] = {'$all': tags} for doc in db['links'].find(spec, sort=[('t', -1)], limit=50): link = links.forDisplay(doc) link['allowEdit'] = allowEdit out['links'].append(link) out['stats'] = {'queryTimeMs': round((time.time() - t1) * 1000, 2)} return out def allTags(user, withTags=[]): """withTags limits results to other tags that have been used with those tags""" withTags = set(withTags) count = defaultdict(lambda: 0) # tag : count for doc in db['links'].find({'user': user}, projection=['extracted.tags']): docTags = set(doc.get('extracted', {}).get('tags', [])) if withTags and not withTags.issubset(docTags): continue for t in docTags.difference(withTags): count[t] = count[t] + 1 byFreq = [(n, t) for t, n in count.items()] byFreq.sort(key=lambda n_t: (-n_t[0], n_t[1])) return [{'label': t, 'count': n} for n, t in byFreq] def renderWithTime(name, data): t1 = time.time() rendered = renderer.render_name(name, data) dt = (time.time() - t1) * 1000 rendered = rendered.replace('TEMPLATETIME', "%.02f ms" % dt) return rendered @bottle.route('/addLink') def addLink(): out = { 'toRoot': siteRoot(), 'absRoot': siteRoot(), 'user': getUser()[0], 'withKnockout': True, 'fillHrefJson': json.dumps(bottle.request.params.get('url', '')), } return renderWithTime('add.jade', out) @bottle.route('/addOverlay') def addOverlay(): p = bottle.request.params return "" @bottle.route('/addLink/proposedUri') def proposedUri(): uri = bottle.request.params.uri user, _ = getUser() try: prevDoc = links.find(uri, user) except NotFound: prevDoc = None return { 'description': prevDoc['description'] if prevDoc else pageTitle.pageTitle(uri), 'tag': prevDoc['tag'] if prevDoc else '', 'extended': prevDoc['extended'] if prevDoc else '', 'shareWith': prevDoc.get('shareWith', []) if prevDoc else [], 'suggestedTags': ['tag1', 'tag2'], 'existed': prevDoc is not None, } # proposal check existing links, get page title (stuff that in db), get tags from us and other serviecs. maybe the deferred ones ater @bottle.route('/tags') def tagFilterComplete(): params = bottle.request.params haveTags = [_f for _f in params['have'].split(',') if _f] if haveTags and len(haveTags[-1]) > 0: haveTags, partialTerm = haveTags[:-1], haveTags[-1] else: partialTerm = "" out = [] for t in allTags(params.user, withTags=haveTags): if partialTerm and partialTerm not in t['label']: continue out.append({'id': t['label'], 'text': "%s (%s%s)" % (t['label'], t['count'], " left" if haveTags else "")}) return {'tags': out} @bottle.route('/<user>/') def userSlash(user): bottle.redirect(siteRoot() + "/%s" % urllib.parse.quote(user)) @bottle.route('/<user>.json', method='GET') def userAllJson(user): data = recentLinks(user, [], allowEdit=getUser()[0] == user) data['toRoot'] = siteRoot() return json.dumps(data) @bottle.route('/<user>', method='GET') def userAll(user): return userLinks(user, "") @bottle.route('/<user>', method='POST') def userAddLink(user): u=getUser()[0] if u is None: raise ValueError('not logged in') if u != user: raise ValueError("not logged in as %s" % user) print(repr(bottle.request.params.__dict__)) doc = links.fromPostdata(bottle.request.params, user, datetime.datetime.now(tzlocal())) links.insertOrUpdate(doc) print("notify about sharing to", repr(doc['shareWith'])) bottle.redirect(siteRoot() + '/' + user) def parseTags(tagComponent): # the %20 is coming from davis.js, not me :( return [_f for _f in tagComponent.replace("%20", "+").split('+') if _f] @bottle.route('/<user>/<tags:re:.*>.json') def userLinksJson(user, tags): tags = parseTags(tags) data = recentLinks(user, tags, allowEdit=getUser()[0] == user) data['toRoot'] = siteRoot() return json.dumps(data) @bottle.route('/<user>/<tags>') @die_on_mongo_connection_errors() def userLinks(user, tags): tags = parseTags(tags) log.info('userLinks user=%r tags=%r', user, tags) data = recentLinks(user, tags, allowEdit=getUser()[0] == user) data['desc'] = ("%s's recent links" % user) + (" tagged %s" % (tags,) if tags else "") data['toRoot'] = siteRoot() data['allTags'] = allTags(user) data['user'] = user data['showPrivateData'] = (user == getUser()[0]) data['pageTags'] = [{"word": t} for t in tags] data['stats']['template'] = 'TEMPLATETIME' return renderWithTime('links.jade', data) @bottle.route('/templates') def templates(): return json.dumps({'linklist': renderer.load_template("linklist.jade")}) @bottle.route('/metrics') def metrics(): return '' @bottle.route('/') def root(): data = { 'toRoot': siteRoot(), 'stats': { 'template': 'TEMPLATETIME' }, 'users': [{ 'user': doc['username'] } for doc in db['user'].find()], } return renderWithTime('index.jade', data) if __name__ == '__main__': logging.basicConfig(level=logging.INFO) bottle.run(server='gunicorn', host='0.0.0.0', port=10002, workers=1)