from flask import *
from flask_user import *
import flask_menu as menu
+from flask_mail import Mail
from flask.ext import markdown
from flask_github import GitHub
from flask_wtf.csrf import CsrfProtect
import os
-
-
app = Flask(__name__)
app.config.from_pyfile(os.environ["FLASK_CONFIG"])
markdown.Markdown(app, extensions=["fenced_code"], safe_mode=True, output_format="html5")
github = GitHub(app)
csrf = CsrfProtect(app)
+mail = Mail(app)
from . import models, tasks
from .views import *
APPROVE_NEW = "APPROVE_NEW"
CHANGE_RELEASE_URL = "CHANGE_RELEASE_URL"
CHANGE_RANK = "CHANGE_RANK"
+ CHANGE_EMAIL = "CHANGE_EMAIL"
EDIT_EDITREQUEST = "EDIT_EDITREQUEST"
# Only return true if the permission is valid for *all* contexts
return user.rank.atLeast(UserRank.EDITOR)
elif perm == Permission.CHANGE_RANK:
return user.rank.atLeast(UserRank.MODERATOR)
+ elif perm == Permission.CHANGE_EMAIL:
+ return user == self or user.rank.atLeast(UserRank.MODERATOR)
else:
raise Exception("Permission {} is not related to users".format(perm.name))
+class UserEmailVerification(db.Model):
+ id = db.Column(db.Integer, primary_key=True)
+ user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
+ email = db.Column(db.String(100))
+ token = db.Column(db.String(32))
+ user = db.relationship("User", foreign_keys=[user_id])
class Notification(db.Model):
id = db.Column(db.Integer, primary_key=True)
celery = make_celery(app)
-from . import importtasks, forumtasks
+from . import importtasks, forumtasks, emails
--- /dev/null
+from flask import *
+from flask_mail import Message
+from app import mail
+from app.tasks import celery
+
+@celery.task()
+def sendVerifyEmail(newEmail, token):
+ msg = Message("Verify email address", recipients=[newEmail])
+ msg.body = "This is a verification email!"
+ msg.html = render_template("emails/verify.html", token=token)
+ mail.send(msg)
--- /dev/null
+<h1>Hello!</h1>
+
+<p>
+ This email has been sent to you because someone (hopefully you)
+ has entered your email address as a user's email.
+</p>
+
+<p>
+ If this was you, then please click this link to verify the address:
+ <a href="{{ url_for('verify_email_page', token=token, _external=True) }}">
+ {{ url_for('verify_email_page', token=token, _external=True) }}
+ </a>
+</p>
+
+<p>
+ If it wasn't you, then just delete this email.
+</p>
{% endif %}
</td>
</tr>
- {% if user == current_user %}
- <tr>
- <td>Email:</td>
- <td>
- {{ user.email }} |
- <a href="">{% if user.email %}change{% else %}add{% endif %}</a>
- 🔒
- </td>
- </tr>
- <tr>
- <td>Password:</td>
- <td>
- <a href="{{ url_for('user.change_password') }}">
- {% if user.password %}Change password{% else %}Add password{% endif %}
- </a> 🔒
- </td>
- </tr>
- {% endif %}
</table>
</div>
<div class="col-sm-6 col-md-5 col-lg-4">
{{ form.hidden_tag() }}
- {{ render_field(form.display_name, tabindex=240) }}
+ {{ render_field(form.display_name, tabindex=230) }}
+
+ {% if user.checkPerm(current_user, "CHANGE_EMAIL") %}
+ {{ render_field(form.email, tabindex=240) }}
+ {% endif %}
{% if user.checkPerm(current_user, "CHANGE_RANK") %}
- {{ render_field(form.rank, tabindex=240) }}
+ {{ render_field(form.rank, tabindex=250) }}
{% endif %}
{{ render_submit_field(form.submit, tabindex=280) }}
from wtforms.validators import *
from .utils import rank_required, randomString
from app.tasks.forumtasks import checkForumAccount
+from app.tasks.emails import sendVerifyEmail
# Define the User profile form
class UserProfileForm(FlaskForm):
- display_name = StringField("Display name")
+ display_name = StringField("Display name", [InputRequired(), Length(2, 20)])
+ email = StringField("Email")
rank = SelectField("Rank", [InputRequired()], choices=UserRank.choices(), coerce=UserRank.coerce, default=UserRank.NEW_MEMBER)
submit = SubmitField("Save")
else:
flash("Can't promote a user to a rank higher than yourself!", "error")
+ if user.checkPerm(current_user, Permission.CHANGE_EMAIL):
+ newEmail = form["email"].data
+ if newEmail != user.email:
+ token = randomString(32)
+
+ ver = UserEmailVerification()
+ ver.user = user
+ ver.token = token
+ ver.email = newEmail
+ db.session.add(ver)
+ db.session.commit()
+
+ task = sendVerifyEmail.delay(newEmail, token)
+ return redirect(url_for("check_task", id=task.id, r=url_for("user_profile_page", username=username)))
+
# Save user_profile
db.session.commit()
flash("Unknown claim type", "error")
return render_template("users/claim.html", username=username, key=randomString(32))
+
+@app.route("/users/verify/")
+def verify_email_page():
+ token = request.args.get("token")
+ ver = UserEmailVerification.query.filter_by(token=token).first()
+ if ver is None:
+ flash("Unknown verification token!", "error")
+ else:
+ ver.user.email = ver.email
+ db.session.delete(ver)
+ db.session.commit()
+
+ if current_user.is_authenticated:
+ return redirect(url_for("user_profile_page", username=current_user.username))
+ else:
+ return redirect(url_for("home_page"))
USER_APP_NAME="Content DB"
+SERVER_NAME="content.minetest.net"
+BASE_URL="http://" + SERVER_NAME
SECRET_KEY=""
WTF_CSRF_SECRET_KEY=""
GITHUB_CLIENT_ID = ""
GITHUB_CLIENT_SECRET = ""
-BASE_URL="http://localhost:5000/"
+CELERY_BROKER_URL='redis://localhost:6379'
+CELERY_RESULT_BACKEND='redis://localhost:6379'
UPLOAD_FOLDER="tmp"
USER_ENABLE_REGISTER = False
USER_ENABLE_CHANGE_USERNAME = False
+s
+MAIL_USERNAME=""
+MAIL_PASSWORD=""
+MAIL_DEFAULT_SENDER=""
+MAIL_SERVER=""
+MAIL_PORT=587
+MAIL_USE_TLS=True