From af8eb4fa7bd507e0495a72649fbbc86b0bcc2772 Mon Sep 17 00:00:00 2001 From: vanzhiganov Date: Sun, 27 Aug 2017 04:09:23 +0300 Subject: [PATCH] wargaming openid auth --- .gitignore | 2 + alembic.ini | 1 + .../{f5e44761054e.py => 2017_08_26_01_01.py} | 1 + alembic/versions/2017_08_27_03_02.py | 24 ++++ tmp/.ignore | 0 wotstats/database.py | 6 + wotstats/init.py | 34 ++++++ wotstats/models/user.py | 3 +- wotstats/openid.py | 3 + wotstats/templates/layouts/main.html | 9 ++ wotstats/templates/pages/auth_step1.html | 7 ++ wotstats/templates/pages/create_profile.html | 22 ++++ wotstats/templates/pages/index.html | 19 ++++ wotstats/templates/pages/login.html | 13 +++ wotstats/views/__init__.py | 104 ++++++++++++++++++ 15 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 .gitignore rename alembic/versions/{f5e44761054e.py => 2017_08_26_01_01.py} (91%) create mode 100644 alembic/versions/2017_08_27_03_02.py create mode 100644 tmp/.ignore create mode 100644 wotstats/database.py create mode 100644 wotstats/init.py create mode 100644 wotstats/openid.py create mode 100644 wotstats/templates/layouts/main.html create mode 100644 wotstats/templates/pages/auth_step1.html create mode 100644 wotstats/templates/pages/create_profile.html create mode 100644 wotstats/templates/pages/index.html create mode 100644 wotstats/templates/pages/login.html create mode 100644 wotstats/views/__init__.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7d04094 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env/ +*.pyc diff --git a/alembic.ini b/alembic.ini index 4b1ad5c..1f7ce34 100644 --- a/alembic.ini +++ b/alembic.ini @@ -7,6 +7,7 @@ script_location = alembic # template used to generate migration files # file_template = %%(rev)s_%%(slug)s file_template = %%(rev)s +file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d_%%(minute).2d # timezone to use when rendering the date # within the migration file as well as the filename. diff --git a/alembic/versions/f5e44761054e.py b/alembic/versions/2017_08_26_01_01.py similarity index 91% rename from alembic/versions/f5e44761054e.py rename to alembic/versions/2017_08_26_01_01.py index 3b3e1da..446c16a 100644 --- a/alembic/versions/f5e44761054e.py +++ b/alembic/versions/2017_08_26_01_01.py @@ -24,6 +24,7 @@ def upgrade(): sa.Column('email', sa.String(length=256), nullable=False, unique=True), sa.Column('password', sa.String(32), nullable=False), sa.Column('openid', sa.String(256), nullable=True, unique=True), + sa.Column('name', sa.String(256), nullable=False, unique=True), sa.PrimaryKeyConstraint('id') ) pass diff --git a/alembic/versions/2017_08_27_03_02.py b/alembic/versions/2017_08_27_03_02.py new file mode 100644 index 0000000..2b6b9c3 --- /dev/null +++ b/alembic/versions/2017_08_27_03_02.py @@ -0,0 +1,24 @@ +"""empty message + +Revision ID: b3222bf2cedb +Revises: 5766fed0b2ef +Create Date: 2017-08-27 03:02:09.126373 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'b3222bf2cedb' +down_revision = 'f5e44761054e' +branch_labels = None +depends_on = None + + +def upgrade(): + pass + + +def downgrade(): + pass diff --git a/tmp/.ignore b/tmp/.ignore new file mode 100644 index 0000000..e69de29 diff --git a/wotstats/database.py b/wotstats/database.py new file mode 100644 index 0000000..f453ca4 --- /dev/null +++ b/wotstats/database.py @@ -0,0 +1,6 @@ + +from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate + +db = SQLAlchemy() +migrate = Migrate() diff --git a/wotstats/init.py b/wotstats/init.py new file mode 100644 index 0000000..a380b05 --- /dev/null +++ b/wotstats/init.py @@ -0,0 +1,34 @@ + +from flask import Flask, render_template, g, session +from wotstats.database import db, migrate +from wotstats.openid import oid +from wotstats.views import pages_home + +def init_app(): + app = Flask(__name__) + app.debug = True + app.config['SECRET_KEY'] = 'super-secret' + app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://wot:wot@192.168.1.47/wot' + app.config['OPENID_FS_STORE_PATH'] = 'tmp' + # + app.config['WG_ID'] = '502910c1c785c3c7ca2e83c9e89bde02' + app.config['WG_OPENID_URL'] = 'https://eu.wargaming.net/id/openid/' + + # , safe_roots=[] + oid.init_app(app) + db.init_app(app) + migrate.init_app(app, db) + # jwt = JWT(app, authenticate, identity) + + app.register_blueprint(pages_home) + + @app.before_request + def lookup_current_user(): + from wotstats.models import User + + g.user = None + if 'openid' in session: + openid = session['openid'] + g.user = User.query.filter_by(openid=openid).first() + + return app diff --git a/wotstats/models/user.py b/wotstats/models/user.py index 23c8d3f..3b4f675 100644 --- a/wotstats/models/user.py +++ b/wotstats/models/user.py @@ -7,10 +7,11 @@ class User(db.Model): status = db.Column(db.Integer, default=0, nullable=False) email = db.Column(db.String(256), unique=True, nullable=False) password = db.Column(db.String(32), nullable=False) + name = db.Column(db.String(256), unique=True, nullable=False) openid = db.Column(db.String(256), unique=True, nullable=True) def __init__(self, email): - self.password = email + self.email = email def __repr__(self): return ''.format(self.id, self.email) diff --git a/wotstats/openid.py b/wotstats/openid.py new file mode 100644 index 0000000..beab9da --- /dev/null +++ b/wotstats/openid.py @@ -0,0 +1,3 @@ +from flask.ext.openid import OpenID + +oid = OpenID() diff --git a/wotstats/templates/layouts/main.html b/wotstats/templates/layouts/main.html new file mode 100644 index 0000000..fff57a5 --- /dev/null +++ b/wotstats/templates/layouts/main.html @@ -0,0 +1,9 @@ + + + {% block title %}{% endblock %} + + +

wotstats

+ {% block content %}{% endblock %} + + diff --git a/wotstats/templates/pages/auth_step1.html b/wotstats/templates/pages/auth_step1.html new file mode 100644 index 0000000..08bdc0e --- /dev/null +++ b/wotstats/templates/pages/auth_step1.html @@ -0,0 +1,7 @@ +{% extends 'layouts/main.html' %} + +{% block content %} + +{% endblock %} diff --git a/wotstats/templates/pages/create_profile.html b/wotstats/templates/pages/create_profile.html new file mode 100644 index 0000000..74d1e21 --- /dev/null +++ b/wotstats/templates/pages/create_profile.html @@ -0,0 +1,22 @@ +{% extends "layouts/main.html" %} +{% block title %}Create Profile{% endblock %} +{% block content %} +

Create Profile

+

+ Hey! This is the first time you signed in on this website. In + order to proceed we need a couple of more information from you: +

+
+
Name: +
+
E-Mail: +
+
+

+ + +

+

+ If you don't want to proceed, you can sign out again. +{% endblock %} diff --git a/wotstats/templates/pages/index.html b/wotstats/templates/pages/index.html new file mode 100644 index 0000000..e20837b --- /dev/null +++ b/wotstats/templates/pages/index.html @@ -0,0 +1,19 @@ +{% extends 'layouts/main.html' %} + +{% block content %} + {% if session['openid'] %} +

+ {% else %} + + {% endif %} +{% endblock %} diff --git a/wotstats/templates/pages/login.html b/wotstats/templates/pages/login.html new file mode 100644 index 0000000..633d51f --- /dev/null +++ b/wotstats/templates/pages/login.html @@ -0,0 +1,13 @@ +{% extends "layouts/main.html" %} +{% block title %}Create Profile{% endblock %} +{% block content %} +

Sign in

+
+ {% if error %}

Error: {{ error }}

{% endif %} +

+ OpenID: + + + +

+{% endblock %} diff --git a/wotstats/views/__init__.py b/wotstats/views/__init__.py new file mode 100644 index 0000000..6191bfe --- /dev/null +++ b/wotstats/views/__init__.py @@ -0,0 +1,104 @@ +import re +from flask import ( + g, Blueprint, render_template, abort, current_app, redirect, + redirect, request, url_for, session, flash +) +from jinja2 import TemplateNotFound +from wotstats.openid import oid + +from wotstats.database import db +from wotstats.models import User + +pages_home = Blueprint('pages_home', __name__, template_folder='templates') + +# def show(page): +# try: +# return render_template('pages/%s.html' % page) +# except TemplateNotFound: +# abort(404) + +def parse_wargaming_openid_url(url): + """ + >>> parse_wargaming_openid_url('https://ru.wargaming.net/id/69552613-CrazyPants1999/') + ('69552613', 'CrazyPants1999') + + """ + pattern = '^https?.*id\/([0-9]+)-(\w+)\/$' + return re.findall(pattern, url)[0] + + +@pages_home.route('/', defaults={'page': 'index'}) +@pages_home.route('/') +def index(page): + z = session['openid'] + return render_template('pages/index.html') + + +@pages_home.route('/auth.html') +def auth_step1(): + return render_template('pages/auth_step1.html') + + +@pages_home.route('/login', methods=['GET', 'POST']) +@oid.loginhandler +def login(): + if g.user is not None: + return redirect(oid.get_next_url()) + if request.method == 'POST': + openid = request.form.get('openid') + if openid: + return oid.try_login( + openid, + ask_for=['email', 'nickname'], + ask_for_optional=['fullname']) + return render_template( + 'pages/login.html', + next=oid.get_next_url(), + error=oid.fetch_error()) + + +@pages_home.route('/create-profile', methods=['GET', 'POST']) +def create_profile(): + if g.user is not None or 'openid' not in session: + return redirect(url_for('pages_home.index')) + if request.method == 'POST': + name = request.form['name'] + email = request.form['email'] + if not name: + flash(u'Error: you have to provide a name') + elif '@' not in email: + flash(u'Error: you have to enter a valid email address') + else: + flash(u'Profile successfully created') + u = User(email) + u.name = name + u.openid = session['openid'] + u.password = '' + + db.session.add(u) + db.session.commit() + return redirect(oid.get_next_url()) + return render_template( + 'pages/create_profile.html', + next=oid.get_next_url()) + + +@pages_home.route('/logout') +def logout(): + session.pop('openid', None) + flash(u'You were signed out') + return redirect(oid.get_next_url()) + +@oid.after_login +def create_or_login(resp): + session['openid'] = resp.identity_url + user = User.query.filter_by(openid=resp.identity_url).first() + if user is not None: + flash(u'Successfully signed in') + g.user = user + return redirect(oid.get_next_url()) + return redirect(url_for( + 'pages_home.create_profile', + next=oid.get_next_url(), + name=resp.fullname or resp.nickname, + email=resp.email))