Add user account claiming

This commit is contained in:
rubenwardy 2018-05-13 23:31:42 +01:00
parent 31615da169
commit ff8bf992a9
No known key found for this signature in database
GPG Key ID: A1E29D52FF81513C
9 changed files with 253 additions and 27 deletions

@ -41,4 +41,4 @@ def make_celery(app):
celery = make_celery(app)
from . import importtasks
from . import importtasks, forumtasks

33
app/tasks/forumtasks.py Normal file

@ -0,0 +1,33 @@
import flask
from flask.ext.sqlalchemy import SQLAlchemy
from app import app
from app.models import *
from app.tasks import celery
from .phpbbparser import getProfile
@celery.task()
def checkForumAccount(username, token=None):
try:
profile = getProfile("https://forum.minetest.net", username)
except OSError:
return
user = User.query.filter_by(forums_username=username).first()
# Create user
needsSaving = False
if user is None:
user = User(username)
user.forums_username = username
db.session.add(user)
# Get github username
github_username = profile.get("github")
if github_username is not None and github_username.strip() != "":
print("Updated github username")
user.github_username = github_username
needsSaving = True
# Save
if needsSaving:
db.session.commit()

72
app/tasks/phpbbparser.py Normal file

@ -0,0 +1,72 @@
import urllib, socket
from bs4 import *
from urllib.parse import urljoin
import urllib.request
import os.path
import time
class Profile:
def __init__(self, username):
self.username = username
self.signature = ""
self.properties = {}
def set(self, key, value):
self.properties[key] = value
def get(self, key):
return self.properties[key] if key in self.properties else None
def __str__(self):
return self.username + "\n" + str(self.signature) + "\n" + str(self.properties)
def __extract_properties(profile, soup):
el = soup.find(id="viewprofile")
if el is None:
return None
res = el.find_all("dl", class_ = "left-box details")
if len(res) != 1:
return None
catch_next_key = None
# Look through
for element in res[0].children:
if element.name == "dt":
if catch_next_key is None:
catch_next_key = element.text.lower()[:-1].strip()
else:
print("Unexpected dt!")
elif element.name == "dd":
if catch_next_key is None:
print("Unexpected dd!")
else:
if catch_next_key != "groups":
profile.set(catch_next_key, element.text)
catch_next_key = None
elif element and element.name is not None:
print("Unexpected other")
def __extract_signature(soup):
res = soup.find_all("div", class_="signature")
if (len(res) != 1):
return None
else:
return res[0]
def getProfile(url, username):
url = url + "/memberlist.php?mode=viewprofile&un=" + username
contents = urllib.request.urlopen(url).read().decode("utf-8")
soup = BeautifulSoup(contents, "lxml")
if soup is None:
return None
else:
profile = Profile(username)
profile.signature = __extract_signature(soup)
__extract_properties(profile, soup)
return profile

@ -61,26 +61,17 @@ Sign in
{# Submit button #}
{{ render_submit_field(form.submit, tabindex=180) }}
</form>
<a href="{{ url_for('github_signin_page') }}">GitHub</a>
</div>
<div class="right">
<aside class="box box_grey">
<h2>New here?</h2>
<div class="box box_grey alert alert-error">
Please use Github login instead!
</div>
<p>Create an account using your forum account.</p>
{% if user_manager.enable_register and not user_manager.require_invitation %}
<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>
<a href="{{ url_for('user_claim_page') }}" class="button">{%trans%}Claim your account{%endtrans%}</a>
</aside>
</div>
</div>

@ -0,0 +1,98 @@
{% extends "base.html" %}
{% block title %}
Verify forum account
{% endblock %}
{% block content %}
<div class="box box_grey">
<h2>{{ self.title() }}</h2>
<p>
Create an account by linking it to your forum account and optionally
your github account.
</p>
{% if current_user.is_authenticated %}
<p>
Please log out to continue.
</p>
<p>
<a href="{{ url_for('user.logout', next=url_for('user_claim_page')) }}" class="button">Logout</a>
</p>
{% else %}
<p>
<b>Don't have a forum account?</b>
Unfortunately, you need a forum account to register.
This is because you also need to create forum topics for any packages
you may upload.
</p>
<a href="https://forum.minetest.net/ucp.php?mode=register">
Create a Forum Account
</a>
{% endif %}
</div>
{% if not current_user.is_authenticated %}
<div class="box box_grey">
<h2>Option 1 - Use GitHub field in forum profile</h2>
<form method="post" action="{{ url_for('user_claim_page') }}">
<input type="hidden" name="claim_type" value="github">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<p>
Enter your forum username here:
</p>
<input type="text" name="username" value="{{ username }}" required placeholder="Forum username">
<p>
You'll need to have the GitHub field in your forum profile
filled out. Log into the forum and
<a href="https://forum.minetest.net/ucp.php?i=173">
do that here</a>.
</p>
<input type="submit" value="Next: log in with GitHub">
</form>
</div>
<!--<div class="box box_grey">
<h2>Option 2 - Paste verification token into signature</h2>
<form method="post" action="{{ url_for('user_claim_page') }}">
<input type="hidden" name="claim_type" value="forum">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<p>
Enter your forum username here:
</p>
<input type="text" name="username" value="{{ username }}" required placeholder="Forum username">
<p>
Go to
<a href="https://forum.minetest.net/ucp.php?i=profile&mode=signature">
User Control Panel > Profile > Edit signature
</a>
</p>
<p>
Paste this into your signature:
</p>
<input type="text" value="{{ key }}" readonly size=32>
<p>
Click next so we can check it.
</p>
<p>
Don't worry, you can remove it after this is done.
</p>
<input type="submit" value="Next">
</form>
</div>-->
{% endif %}
{% endblock %}

@ -43,16 +43,8 @@ def github_authorized(oauth_token):
# If not logged in, log in
else:
if userByGithub is None:
newUser = User(username)
newUser.github_username = username
db.session.add(newUser)
db.session.commit()
if not loginUser(newUser):
raise Exception("Unable to login as user we just created")
flash("Created an account", "success")
return redirect(url_for("user_profile_page", username=username))
flash("Unable to find an account for that Github user", "error")
return redirect(url_for("user_claim_page"))
elif loginUser(userByGithub):
return redirect(next_url or url_for("home_page"))
else:

@ -22,7 +22,6 @@ def new_getmeta_page():
})
@app.route("/tasks/<id>/")
@login_required
def check_task(id):
result = celery.AsyncResult(id)
status = result.status
@ -51,7 +50,6 @@ def check_task(id):
abort(422)
if status == "SUCCESS":
flash("Task complete!", "success")
return redirect(r)
else:
return render_template("tasks/view.html", info=info)

@ -8,7 +8,8 @@ from flask_wtf import FlaskForm
from flask_user.forms import RegisterForm
from wtforms import *
from wtforms.validators import *
from .utils import rank_required
from .utils import rank_required, randomString
from app.tasks.forumtasks import checkForumAccount
class MyRegisterForm(RegisterForm):
display_name = StringField("Display name")
@ -59,3 +60,42 @@ def user_profile_page(username):
# Process GET or invalid POST
return render_template("users/user_profile_page.html",
user=user, form=form)
@app.route("/users/claim/", methods=["GET", "POST"])
def user_claim_page():
username = request.args.get("username")
if username is None:
username = ""
else:
method = request.args.get("method")
user = User.query.filter_by(forums_username=username).first()
if user and user.rank.atLeast(UserRank.NEW_MEMBER):
flash("User has already been claimed", "error")
return redirect(url_for("user_claim_page"))
elif user is None and method == "github":
flash("Unable to get Github username for user", "error")
return redirect(url_for("user_claim_page"))
elif user is None:
flash("Unable to find that user", "error")
return redirect(url_for("user_claim_page"))
if user is not None and method == "github":
return redirect(url_for("github_signin_page"))
if request.method == "POST":
ctype = request.form.get("claim_type")
username = request.form.get("username")
if username is None or len(username.strip()) < 2:
flash("Invalid username", "error")
elif ctype == "github":
task = checkForumAccount.delay(username)
return redirect(url_for("check_task", id=task.id, r=url_for("user_claim_page", username=username, method="github")))
elif ctype == "forum":
token = request.form.get("token")
flash("Unimplemented", "error")
else:
flash("Unknown claim type", "error")
return render_template("users/claim.html", username=username, key=randomString(32))

@ -8,3 +8,5 @@ GitHub-Flask>=3.2.0
pyScss==1.3.4
celery==4.0.2
redis==2.10.6
beautifulsoup4==4.6.0
lxml==4.2.1