From c5b5c7833c27e251b6e8ef47e4545c498bf6d0ee Mon Sep 17 00:00:00 2001 From: Andrej Karpathy Date: Fri, 26 Nov 2021 16:38:36 -0800 Subject: [PATCH] and i think that's it, we now support user accounts (lite)git commit -m 'and i think that\'s it, we now support user accounts litegit status sweet.'! sweet. --- .gitignore | 1 + serve.py | 38 +++++++++++++++++++++++++++++++++---- static/style.css | 43 ++++++++++++++++++++++++++++++++++++++++++ templates/index.html | 2 +- templates/profile.html | 34 ++++++++++++++++++++++++++++++++- 5 files changed, 112 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index e09ffb8..5651d1b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ __pycache__ data *.ipynb +secret_key.txt diff --git a/serve.py b/serve.py index f69b12e..e5e3129 100644 --- a/serve.py +++ b/serve.py @@ -7,8 +7,8 @@ ideas: - special single-image search just for paper similarity """ +import os import time -import pickle from random import shuffle import numpy as np @@ -17,6 +17,7 @@ from sklearn import svm from flask import Flask, request, redirect, url_for from flask import render_template from flask import g # global session-level object +from flask import session from aslite.db import get_papers_db, get_metas_db, get_tags_db from aslite.db import load_features @@ -24,9 +25,20 @@ from aslite.db import load_features # ----------------------------------------------------------------------------- # inits and globals -app = Flask(__name__) RET_NUM = 100 # number of papers to return per page +app = Flask(__name__) + +# set the secret key so we can cryptographically sign cookies and maintain sessions +if os.path.isfile('secret_key.txt'): + # example of generating a good key on your system is: + # import secrets; secrets.token_urlsafe(16) + sk = open('secret_key.txt').read().strip() +else: + print("WARNING: no secret key found, using default devkey") + sk = 'devkey' +app.secret_key = sk + # ----------------------------------------------------------------------------- # globals that manage the (lazy) loading of various state for a request @@ -51,8 +63,7 @@ def get_metas(): @app.before_request def before_request(): - g.user = 'root' # current default user, as we have no accounts db at this time just yet - #g.user = None # if noone is logged in, will be the default state shortly + g.user = session.get('user', None) @app.teardown_request def close_connection(error=None): @@ -355,3 +366,22 @@ def delete_tag(tag=None): print("deleted tag %s for user %s" % (tag, g.user)) return "ok: " + str(d) # return back the user library for debugging atm + +# ----------------------------------------------------------------------------- +# endpoints to log in and out + +@app.route('/login', methods=['POST']) +def login(): + + # the user is logged out but wants to log in, ok + if g.user is None and request.form['username']: + username = request.form['username'] + if len(username) > 0: # one more paranoid check + session['user'] = username + + return redirect(url_for('profile')) + +@app.route('/logout') +def logout(): + session.pop('user', None) + return redirect(url_for('profile')) diff --git a/static/style.css b/static/style.css index e5e54cb..e6fbfb9 100644 --- a/static/style.css +++ b/static/style.css @@ -180,4 +180,47 @@ body { position: absolute; right: 10px; top: 10px; +} +#profile-warning { + margin: 10px; + padding: 10px; + font-size: 16px; + background-color: #fdd; + border-radius: 5px; +} +#profile-warning p { + margin: 0; + padding: 0; +} +#profile-login-form { + width: 400px; + margin: 30px auto; + font-size: 18px; +} +#profile-login-form .form-control { + display: block; + width: 100%; + box-sizing: border-box; + margin: 5px 0 10px 0; + padding: 5px; + height: 34px; + font-size: 16px; + line-height: 1.42857143; + color: #555; + border: 1px solid #ccc; + border-radius: 4px; +} +#profile-login-form .btn { + display: block; + width: 100%; + padding: 5px; + margin: 0; + height: 34px; + font-size: 14px; + line-height: 1.42857143; + color: #fff; + background-color: #337ab7; + border: 1px solid #2e6da4; + border-radius: 4px; + cursor: pointer; } \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 1ec1951..4953517 100644 --- a/templates/index.html +++ b/templates/index.html @@ -65,7 +65,7 @@ var gvars = {{ gvars | tojson }}; -{% if user %} +{% if user and tags %}
{% endif %} diff --git a/templates/profile.html b/templates/profile.html index 6b073c7..3764af0 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -5,7 +5,39 @@ {% block content %}
- This is where the user gets to log in, or see information about their account if logged in. + + {% if user %} +
+
Logged in user: {{ user }}
+
+ Log out +
+
+ {% else %} +
+ +
+

+ Okay, arxiv-sanity-lite uses a super lite version of + "user accounts" where there are no passwords. Basically, you can "log in" + with any arbitrary username. If you want to share your library with a + friend, you can just tell them the username. And if you'd like to keep your + account private, just make your username be something unique + and write it down somewhere safe. +

+ TLDR: there are no passwords! +
+ +
+
+ + +
+ +
+
+ {% endif %} +
{% endblock %}