from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from urllib.parse import urlparse
-from app import app
+from app import app, gravatar
from datetime import datetime
from sqlalchemy.orm import validates
from flask_user import login_required, UserManager, UserMixin, SQLAlchemyAdapter
raise Exception("Non-global permission checked globally. Use Package.checkPerm or User.checkPerm instead.")
class User(db.Model, UserMixin):
- id = db.Column(db.Integer, primary_key=True)
+ id = db.Column(db.Integer, primary_key=True)
# User authentication information
- username = db.Column(db.String(50, collation="NOCASE"), nullable=False, unique=True, index=True)
- password = db.Column(db.String(255), nullable=True)
+ username = db.Column(db.String(50, collation="NOCASE"), nullable=False, unique=True, index=True)
+ password = db.Column(db.String(255), nullable=True)
reset_password_token = db.Column(db.String(100), nullable=False, server_default="")
- rank = db.Column(db.Enum(UserRank))
+ rank = db.Column(db.Enum(UserRank))
# Account linking
github_username = db.Column(db.String(50, collation="NOCASE"), nullable=True, unique=True)
forums_username = db.Column(db.String(50, collation="NOCASE"), nullable=True, unique=True)
# User email information
- email = db.Column(db.String(255), nullable=True, unique=True)
- confirmed_at = db.Column(db.DateTime())
+ email = db.Column(db.String(255), nullable=True, unique=True)
+ confirmed_at = db.Column(db.DateTime())
# User information
- active = db.Column("is_active", db.Boolean, nullable=False, server_default="0")
- display_name = db.Column(db.String(100), nullable=False, server_default="")
+ profile_pic = db.Column(db.String(255), nullable=True, server_default=None)
+ active = db.Column("is_active", db.Boolean, nullable=False, server_default="0")
+ display_name = db.Column(db.String(100), nullable=False, server_default="")
# Content
notifications = db.relationship("Notification", primaryjoin="User.id==Notification.user_id")
def isClaimed(self):
return self.rank.atLeast(UserRank.NEW_MEMBER)
+ def getProfilePicURL(self):
+ if self.profile_pic:
+ return self.profile_pic
+ else:
+ return gravatar(self.email or "")
+
def checkPerm(self, user, perm):
if not user.is_authenticated:
return False
from urllib.parse import urlparse, quote_plus
@celery.task()
-def checkForumAccount(username, token=None):
+def checkForumAccount(username):
try:
profile = getProfile("https://forum.minetest.net", username)
except OSError:
user.github_username = github_username
needsSaving = True
+ pic = profile.avatar
+ needsSaving = needsSaving or pic != user.profile_pic
+ user.profile_pic = pic
+
# Save
if needsSaving:
db.session.commit()
class Profile:
def __init__(self, username):
- self.username = username
- self.signature = ""
+ self.username = username
+ self.signature = ""
+ self.avatar = None
self.properties = {}
def set(self, key, value):
if el is None:
return None
+ res1 = el.find_all("dl")
+ imgs = res1[0].find_all("img")
+ if len(imgs) == 1:
+ profile.avatar = imgs[0]["src"]
+
res = el.find_all("dl", class_ = "left-box details")
if len(res) != 1:
return None
<h2 class="card-header">{{ user.display_name }}</h2>
<div class="card-body row">
<div class="col-md-2">
- {% if user.email %}
+ {% if user.forums_username %}
+ <a href="https://forum.minetest.net/ucp.php?i=profile&mode=avatar">
+ {% elif user.email %}
<a href="https://en.gravatar.com/">
{% endif %}
- <img class="img-responsive user-photo img-thumbnail img-thumbnail-1" src="{{ (user.email or '') | gravatar }}">
- {% if user.email %}
+ <img class="img-responsive user-photo img-thumbnail img-thumbnail-1" src="{{ user.getProfilePicURL() }}">
+ {% if user.forums_username or user.email %}
</a>
{% endif %}
</div>
<tr>
<td>Profile Picture:</td>
<td>
+ {% if user.forums_username %}
+ <form method="post" action="{{ url_for('user_check', username=user.username) }}" class="" style="display:inline-block;">
+ <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
+ <input type="submit" class="btn btn-primary" value="Sync with Forums" />
+ </form>
+ {% endif %}
{% if user.email %}
<a class="btn btn-primary" href="https://en.gravatar.com/">
Gravatar
</a>
{% else %}
- <p>
- Please add an email to your profile.
- </p>
+ <a class="btn btn-primary disabled"
+ data-toggle="tooltip" data-placement="bottom"
+ title="Please add an email address to use Gravatar"
+ style="pointer-events: all;">
+ Gravatar
+ </a>
{% endif %}
</td>
</tr>
return render_template("users/user_profile_page.html",
user=user, form=form, packages=packages, topics_to_add=topics_to_add)
+
+@app.route("/users/<username>/check/", methods=["POST"])
+@login_required
+def user_check(username):
+ user = User.query.filter_by(username=username).first()
+ if user is None:
+ abort(404)
+
+ if current_user != user and not current_user.rank.atLeast(UserRank.MODERATOR):
+ abort(403)
+
+ if user.forums_username is None:
+ abort(404)
+
+ task = checkForumAccount.delay(user.forums_username)
+ next_url = url_for("user_profile_page", username=username)
+
+ return redirect(url_for("check_task", id=task.id, r=next_url))
+
+
class SetPasswordForm(FlaskForm):
email = StringField("Email", [Optional(), Email()])
password = PasswordField("New password", [InputRequired(), Length(2, 20)])
--- /dev/null
+"""empty message
+
+Revision ID: dce69ad1e4eb
+Revises: a791b9b74a4c
+Create Date: 2018-12-25 18:57:44.575501
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = 'dce69ad1e4eb'
+down_revision = 'a791b9b74a4c'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column("user", sa.Column('profile_pic', sa.String(length=255), nullable=True))
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_column("user", "profile_pic")
+ # ### end Alembic commands ###