]> git.lizzy.rs Git - cheatdb.git/commitdiff
Add Github login
authorrubenwardy <rw@rubenwardy.com>
Sun, 18 Mar 2018 18:05:53 +0000 (18:05 +0000)
committerrubenwardy <rw@rubenwardy.com>
Sun, 18 Mar 2018 18:05:53 +0000 (18:05 +0000)
app/__init__.py
app/models.py
app/templates/flask_user/login.html
app/views/__init__.py
app/views/githublogin.py [new file with mode: 0644]
app/views/users.py [new file with mode: 0644]
config.example.cfg
requirements.txt
setup.py

index fb0ef3a9250195aff12ad8e9c1fb46021b75bf62..6692e23c138fef50efede318e81c6dfb34993544 100644 (file)
@@ -1,7 +1,14 @@
 from flask import *
 from flask_user import *
+import flask_menu as menu
+from flask.ext import markdown
+from flask_github import GitHub
 
 app = Flask(__name__)
 app.config.from_pyfile('../config.cfg')
 
+menu.Menu(app=app)
+markdown.Markdown(app, extensions=['fenced_code'])
+github = GitHub(app)
+
 import models, views
index 612933065e75355e65f8d5cbd10848b61726b94a..97dc3c934410a1d25cae32bcff77a3e66963831c 100644 (file)
@@ -1,5 +1,5 @@
 from flask import Flask, url_for
-from flask.ext.sqlalchemy import SQLAlchemy
+from flask_sqlalchemy import SQLAlchemy
 from app import app
 from datetime import datetime
 from sqlalchemy.orm import validates
@@ -22,6 +22,10 @@ class User(db.Model, UserMixin):
        password = db.Column(db.String(255), nullable=False, server_default='')
        reset_password_token = db.Column(db.String(100), nullable=False, server_default='')
 
+       # Account linking
+       github_username = db.Column(db.String(50), nullable=True, unique=True)
+       forums_username = db.Column(db.String(50), nullable=True, unique=True)
+
        # User email information
        email = db.Column(db.String(255), nullable=True, unique=True)
        confirmed_at = db.Column(db.DateTime())
@@ -38,6 +42,7 @@ class User(db.Model, UserMixin):
 
                self.username = username
                self.confirmed_at = datetime.datetime.now() - datetime.timedelta(days=6000)
+               self.display_name = username
 
        def isClaimed(self):
                return self.password is not None and self.password != ""
index 44274bbcd08603b27df49c6c449b4a1364634f0a..3d36c206df4324a626a06d40d6854f5cb0fd7c8c 100644 (file)
@@ -68,9 +68,16 @@ Sign in
                        <h2>New here?</h2>
 
                        {% if user_manager.enable_register and not user_manager.require_invitation %}
-                               <a href="">{%trans%}Create an account{%endtrans%}</a>
+                               <a href="{{ url_for('github_signin_page') }}">{%trans%}Create an account{%endtrans%}</a>
                        {% endif %}
                </aside>
+
+
+               <aside class="box box_grey">
+                       <h2>OAUTH</h2>
+
+                       <a href="{{ url_for('github_signin_page') }}">GitHub</a>
+               </aside>
        </div>
 </div>
 {% endblock %}
index deb5ac5b8990bc8e95c086427114cac3ea302d49..bfe8c1b030a28dd9095e935065306b5d76824cf5 100644 (file)
@@ -3,72 +3,20 @@ from flask import *
 from flask_user import *
 from flask_login import login_user, logout_user
 from app.models import *
-from flask.ext import menu, markdown
+import flask_menu as menu
+from flask.ext import markdown
 from sqlalchemy import func
 from werkzeug.contrib.cache import SimpleCache
 cache = SimpleCache()
 
-menu.Menu(app=app)
-markdown.Markdown(app, extensions=['fenced_code'])
-
 # TODO: remove on production!
 @app.route('/static/<path:path>')
 def send_static(path):
        return send_from_directory('static', path)
 
+import users, githublogin
+
 @app.route('/')
 @menu.register_menu(app, '.', 'Home')
 def home_page():
        return render_template('index.html')
-
-# Define the User registration form
-# It augments the Flask-User RegisterForm with additional fields
-from flask_user.forms import RegisterForm
-from flask_wtf import FlaskForm
-from wtforms import StringField, SubmitField, validators
-class MyRegisterForm(RegisterForm):
-       first_name = StringField('First name', validators=[
-               validators.DataRequired('First name is required')])
-       last_name = StringField('Last name', validators=[
-               validators.DataRequired('Last name is required')])
-
-# Define the User profile form
-class UserProfileForm(FlaskForm):
-       first_name = StringField('First name', validators=[
-               validators.DataRequired('First name is required')])
-       last_name = StringField('Last name', validators=[
-               validators.DataRequired('Last name is required')])
-       submit = SubmitField('Save')
-
-@app.route('/user/', methods=['GET', 'POST'])
-@app.route('/user/<username>/', methods=['GET'])
-def user_profile_page(username=None):
-       user = None
-       form = None
-       if username is None:
-               if not current_user.is_authenticated:
-                       return current_app.login_manager.unauthorized()
-               user = current_user
-       else:
-               user = User.query.filter_by(username=username).first()
-               if not user:
-                       abort(404)
-
-       if user == current_user:
-               # Initialize form
-               form = UserProfileForm(request.form, current_user)
-
-               # Process valid POST
-               if request.method=='POST' and form.validate():
-                       # Copy form fields to user_profile fields
-                       form.populate_obj(current_user)
-
-                       # Save user_profile
-                       db.session.commit()
-
-                       # Redirect to home page
-                       return redirect(url_for('home_page'))
-
-       # Process GET or invalid POST
-       return render_template('users/user_profile_page.html',
-                       user=user, form=form)
diff --git a/app/views/githublogin.py b/app/views/githublogin.py
new file mode 100644 (file)
index 0000000..327fa8e
--- /dev/null
@@ -0,0 +1,100 @@
+from flask import *
+from flask_user import *
+from flask_login import login_user, logout_user
+import flask_menu as menu
+from flask_github import GitHub
+from app import app, github
+from app.models import *
+
+
+@app.route('/user/github/start/')
+def github_signin_page():
+       return github.authorize("public_repo,repo")
+
+
+def _do_login_user(user, remember_me=False):
+       def _call_or_get(v):
+               if callable(v):
+                       return v()
+               else:
+                       return v
+
+       # User must have been authenticated
+       if not user:
+               return False
+
+       user.active = True
+       db.session.commit()
+
+       # Check if user account has been disabled
+       if not _call_or_get(user.is_active):
+               flash('Your account has not been enabled.', 'error')
+               return False
+
+       # Check if user has a confirmed email address
+       user_manager = current_app.user_manager
+       if user_manager.enable_email and user_manager.enable_confirm_email \
+                       and not current_app.user_manager.enable_login_without_confirm_email \
+                       and not user.has_confirmed_email():
+               url = url_for('user.resend_confirm_email')
+               flash("Your email address has not yet been confirmed", 'error')
+               return False
+
+       # Use Flask-Login to sign in user
+       login_user(user, remember=remember_me)
+       signals.user_logged_in.send(current_app._get_current_object(), user=user)
+
+       flash('You have signed in successfully.', 'success')
+
+       return True
+
+
+
+def _login_user(user):
+       user_mixin = None
+       if user_manager.enable_username:
+               user_mixin = user_manager.find_user_by_username(user.username)
+
+       return _do_login_user(user_mixin, False)
+
+
+
+@app.route('/user/github/callback/')
+@github.authorized_handler
+def github_authorized(oauth_token):
+       next_url = request.args.get('next')
+       if oauth_token is None:
+               flash("Authorization failed [err=gh-oauth-login-failed]", "danger")
+               return redirect(url_for("user.login"))
+
+       import requests
+
+       # Get Github username
+       url = "https://api.github.com/user"
+       r = requests.get(url, headers={"Authorization": "token " + oauth_token})
+       username = r.json()["login"]
+
+       # Get user by github username
+       userByGithub = User.query.filter_by(github_username=username).first()
+
+       # If logged in, connect
+       if current_user and current_user.is_authenticated:
+               if userByGithub is None:
+                       current_user.github_username = username
+                       db.session.add(auth)
+                       db.session.commit()
+                       return redirect(url_for("gitAccount", id=auth.id))
+               else:
+                       flash("Github account is already associated with another user", "danger")
+                       return redirect(url_for("home_page"))
+
+       # If not logged in, log in
+       else:
+               if userByGithub is None:
+                       flash("Authorization failed [err=gh-no-such-account]", "danger")
+                       return redirect(url_for("user.login"))
+               elif _login_user(userByGithub):
+                       return redirect(next_url or url_for("home_page"))
+               else:
+                       flash("Authorization failed [err=gh-login-failed]", "danger")
+                       return redirect(url_for("user.login"))
diff --git a/app/views/users.py b/app/views/users.py
new file mode 100644 (file)
index 0000000..99cf19c
--- /dev/null
@@ -0,0 +1,60 @@
+from flask import *
+from flask_user import *
+from flask_login import login_user, logout_user
+from flask.ext import menu
+from app import app
+from app.models import *
+
+
+
+# Define the User registration form
+# It augments the Flask-User RegisterForm with additional fields
+from flask_user.forms import RegisterForm
+from flask_wtf import FlaskForm
+from wtforms import StringField, SubmitField, validators
+class MyRegisterForm(RegisterForm):
+       first_name = StringField('First name', validators=[
+               validators.DataRequired('First name is required')])
+       last_name = StringField('Last name', validators=[
+               validators.DataRequired('Last name is required')])
+
+# Define the User profile form
+class UserProfileForm(FlaskForm):
+       first_name = StringField('First name', validators=[
+               validators.DataRequired('First name is required')])
+       last_name = StringField('Last name', validators=[
+               validators.DataRequired('Last name is required')])
+       submit = SubmitField('Save')
+
+@app.route('/user/', methods=['GET', 'POST'])
+@app.route('/user/<username>/', methods=['GET'])
+def user_profile_page(username=None):
+       user = None
+       form = None
+       if username is None:
+               if not current_user.is_authenticated:
+                       return current_app.login_manager.unauthorized()
+               user = current_user
+       else:
+               user = User.query.filter_by(username=username).first()
+               if not user:
+                       abort(404)
+
+       if user == current_user:
+               # Initialize form
+               form = UserProfileForm(request.form, current_user)
+
+               # Process valid POST
+               if request.method=='POST' and form.validate():
+                       # Copy form fields to user_profile fields
+                       form.populate_obj(current_user)
+
+                       # Save user_profile
+                       db.session.commit()
+
+                       # Redirect to home page
+                       return redirect(url_for('home_page'))
+
+       # Process GET or invalid POST
+       return render_template('users/user_profile_page.html',
+                       user=user, form=form)
index 7fffe2c0417e838f535091d9d2b510b32752054b..05fa9becc0cd1d6dc0e27d2662a4fca1d53b420c 100644 (file)
@@ -4,3 +4,6 @@ SECRET_KEY=""
 WTF_CSRF_SECRET_KEY=""
 
 SQLALCHEMY_DATABASE_URI = "sqlite:///../db.sqlite"
+
+GITHUB_CLIENT_ID = ""
+GITHUB_CLIENT_SECRET = ""
index dd7f72c5e16b76ec3fec13070a339f87afaac438..0fdd36f5eb5a5fc7f082c040d83afa7b22165a97 100644 (file)
@@ -3,3 +3,4 @@ Flask-SQLAlchemy>=2.3
 Flask-User>=0.6.19
 Flask-Menu>=0.7.0
 Flask-Markdown>=0.3
+GitHub-Flask>=3.2.0
index 0ba2b5a78379c30901c62e1222165c00558b4a7a..9949776bcdf49c4f48e19f33bc07dcb0a39722e3 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -6,12 +6,15 @@ if delete_db and os.path.isfile("app/data.sqlite"):
        os.remove("app/data.sqlite")
 
 if not os.path.isfile("app/data.sqlite"):
-       from app import models
+       from app.models import *
 
        print("Creating database tables...")
-       models.db.create_all()
-
+       db.create_all()
        print("Filling database...")
-       models.db.session.commit()
+
+       ruben = User("rubenwardy")
+       ruben.github_username = "rubenwardy"
+       db.session.add(ruben)
+       db.session.commit()
 else:
        print("Database already exists")