def do_task(self): super().do_task() cur = db.cursor() result = cur.execute( read_query_file( "select-user-name-waiting-to-be-approved.sql")).fetchall() if result: self.log_task() names = [] (result, col_names) = rowify(result, cur.description) for item in result: names.append("{approved_date} - {display_name}".format(**item)) message = "\n".join(names) # Send a notification email (silent fail if not configured) current_app.logger.debug(message) if not current_app.config.get("DEBUG", True): try: send_message( current_app.config.get("EMAIL_MODERATOR"), "Puzzle Massive - new names", message, current_app.config, ) except Exception as err: current_app.logger.warning( "Failed to send notification message. {}".format(err)) pass cur.close()
def post(self): "" response = {"message": "", "name": "error"} is_shareduser = False user = current_app.secure_cookie.get(u"user") if not user: user = user_id_from_ip(request.headers.get("X-Real-IP")) is_shareduser = True if user == None: response["message"] = "User not signed in." response["name"] = "error" return make_response(json.jsonify(response), 400) user = int(user) args = {} if request.form: args.update(request.form.to_dict(flat=True)) email = args.get("email", "").strip().lower() if len(email) > EMAIL_MAXLENGTH: response["message"] = "E-mail is too long." response["name"] = "error" return make_response(json.jsonify(response), 400) cur = db.cursor() result = cur.execute(fetch_query_string("user-has-player-account.sql"), { "player_id": user }).fetchone() if not result or result[0] == 0: cur.execute( fetch_query_string("init-player-account-for-user.sql"), {"player_id": user}, ) result = cur.execute( fetch_query_string("select-player-details-for-player-id.sql"), { "player_id": user }, ).fetchall() if not result: # This shouldn't happen if user-has-player-account.sql response["message"] = "No player account." response["name"] = "error" cur.close() db.commit() return make_response(json.jsonify(response), 400) (result, col_names) = rowify(result, cur.description) existing_player_data = result[0] # Prevent shareduser changing the verified email address. if is_shareduser and existing_player_data["is_verifying_email"]: response[ "message"] = "A player on this same network has already submitted an email address. Changing it is not allowed until the account has been claimed or the verify email token expires." response["name"] = "error" return make_response(json.jsonify(response), 400) if existing_player_data["email"] == email: response[ "message"] = "No changes made to e-mail address ({}). The e-mail address is stored as lowercase.".format( email) response["name"] = "error" else: if email == "": cur.execute( fetch_query_string("remove-player-account-email.sql"), {"player_id": user}, ) response["message"] = "Removed e-mail from player account." response["name"] = "success" else: # Verify that email is unique result = cur.execute( fetch_query_string( "select-player-by-verified-email-address.sql"), { "email": email }, ).fetchall() if result: response[ "message"] = "A player has already registered this e-mail address." response["name"] = "error" cur.close() db.commit() return make_response(json.jsonify(response), 400) if existing_player_data["is_verifying_email"]: response[ "message"] = "An e-mail address is already in the process of verification for this player. Please wait." response["name"] = "error" cur.close() db.commit() return make_response(json.jsonify(response), 400) cur.execute( fetch_query_string("update-player-account-email.sql"), { "player_id": user, "email": email }, ) cur.execute( fetch_query_string( "update-player-account-email-verified.sql"), { "player_id": user, "email_verified": 0, }, ) # Send verification email (silent fail if not configured) token = uuid.uuid4().hex message = """ Please verify your e-mail address with Puzzle Massive by following the link below. http://{DOMAIN_NAME}/chill/site/claim-player/{token}/ Complete registering your e-mail address by visiting that web page and clicking the "verify player" button. You can ignore this message if you didn't initiate the request. """.format(token=token, DOMAIN_NAME=current_app.config.get("DOMAIN_NAME")) current_app.logger.debug(message) if not current_app.config.get("DEBUG", True): try: send_message( email, "Puzzle Massive - verify e-mail address", message, current_app.config, ) except Exception as err: current_app.logger.warning( "Failed to send verification message. email: {email}\n {message}\n error: {err}" .format(err=err, email=email, message=message)) pass cur.execute( fetch_query_string( "update-player-account-email-verify-token.sql"), { "player_id": user, "email_verify_token": token, "expire_token_timeout": "+1 hour", }, ) response[ "message"] = "Updated e-mail ({}) for player account. ".format( email) response["name"] = "success" db.commit() cur.close() return make_response(json.jsonify(response), 202)
def post(self): args = {} if request.form: args.update(request.form.to_dict(flat=True)) args["features"] = set(request.form.getlist("features")) # Check pieces arg try: pieces = int( args.get("pieces", current_app.config["MINIMUM_PIECE_COUNT"])) except ValueError as err: abort(400) if (not current_app.config["MINIMUM_PIECE_COUNT"] <= pieces <= current_app.config["MAXIMUM_PIECE_COUNT"]): abort(400) bg_color = check_bg_color(args.get("bg_color", "#808080")[:50]) user = int( current_app.secure_cookie.get(u"user") or user_id_from_ip(request.headers.get("X-Real-IP"))) permission = int(args.get("permission", PUBLIC)) if permission not in (PUBLIC, PRIVATE): permission = PUBLIC description = escape(args.get("description", "").strip())[:1000] # Check secret_message secret_message = escape(args.get("secret_message", ""))[:1000] # Check link and validate link = url_fix(args.get("link", "").strip())[:100] if not link and not description: abort(400) puzzle_id = uuid.uuid1().hex features = set(args.get("features", [])) cur = db.cursor() d = { "puzzle_id": puzzle_id, "pieces": pieces, "link": link, "description": description, "bg_color": bg_color, "owner": user, "status": SUGGESTED, "permission": permission, } cur.execute( """insert into Puzzle ( puzzle_id, pieces, link, description, bg_color, owner, status, permission) values (:puzzle_id, :pieces, :link, :description, :bg_color, :owner, :status, :permission); """, d, ) db.commit() puzzle = rowify( cur.execute( fetch_query_string("select_puzzle_id_by_puzzle_id.sql"), { "puzzle_id": puzzle_id }, ).fetchall(), cur.description, )[0][0] puzzle = puzzle["puzzle"] result = cur.execute( fetch_query_string("select-puzzle-features-enabled.sql"), { "enabled": 1 }).fetchall() if result: (puzzle_features, _) = rowify(result, cur.description) # Add puzzle features for puzzle_feature in puzzle_features: if (puzzle_feature["slug"] == "hidden-preview" and "hidden-preview" in features): cur.execute( fetch_query_string( "add-puzzle-feature-to-puzzle-by-id--hidden-preview.sql" ), { "puzzle": puzzle, "puzzle_feature": puzzle_feature["id"] }, ) elif (puzzle_feature["slug"] == "secret-message" and "secret-message" in features): cur.execute( fetch_query_string( "add-puzzle-feature-to-puzzle-by-id--secret-message.sql" ), { "puzzle": puzzle, "puzzle_feature": puzzle_feature["id"], "message": secret_message, }, ) db.commit() cur.close() # Send a notification email (silent fail if not configured) message = """ http://{DOMAIN_NAME}/chill/site/admin/puzzle/suggested/{puzzle_id}/ pieces: {pieces} bg_color: {bg_color} owner: {owner} link: {link} description: {description} """.format(DOMAIN_NAME=current_app.config.get("DOMAIN_NAME"), **d) current_app.logger.debug(message) if not current_app.config.get("DEBUG", True): try: send_message( current_app.config.get("EMAIL_MODERATOR"), "Suggested Image", message, current_app.config, ) except Exception as err: current_app.logger.warning( "Failed to send notification message for suggested image. email: {email}\n {message}\n error: {err}" .format( err=err, email=current_app.config.get("EMAIL_MODERATOR"), message=message, )) pass # Redirect to a thank you page (not revealing the puzzle_id) return redirect("/chill/site/suggested-puzzle-thank-you/", code=303)
def post(self): "" response = {"message": "", "name": "error"} user = current_app.secure_cookie.get(u"user") if user: response[ "message"] = "User currently logged in. No need to reset the login by e-mail." response["name"] = "error" return make_response(json.jsonify(response), 400) user = user_id_from_ip(request.headers.get("X-Real-IP")) if user == None: response["message"] = "Shared user not currently logged in." response["name"] = "error" return make_response(json.jsonify(response), 400) args = {} if request.form: args.update(request.form.to_dict(flat=True)) email = args.get("email", "").strip().lower() if len(email) > EMAIL_MAXLENGTH: response["message"] = "E-mail is too long." response["name"] = "error" return make_response(json.jsonify(response), 400) cur = db.cursor() # Get user by their verified email address result = cur.execute( fetch_query_string("get-user-by-verified-email-address.sql"), { "email": email }, ).fetchone() if not result or result[0] == 0: response[ "message"] = "Sorry, that e-mail address has not been verified." response["name"] = "error" cur.close() db.commit() return make_response(json.jsonify(response), 400) else: user = result[0] result = cur.execute( fetch_query_string("select-player-details-for-player-id.sql"), { "player_id": user }, ).fetchall() if not result: # This shouldn't happen if user-has-player-account.sql response["message"] = "No player account." response["name"] = "error" cur.close() db.commit() return make_response(json.jsonify(response), 400) (result, col_names) = rowify(result, cur.description) existing_player_data = result[0] if existing_player_data["has_active_reset_login_token"]: response[ "message"] = "Please check your e-mail for a reset login link. The reset login link that was sent earlier has not expired." response["name"] = "error" cur.close() db.commit() return make_response(json.jsonify(response), 400) # Send a link to reset the login (silent fail if not configured) token = uuid.uuid4().hex message = """ The link below is only valid for a short time. Use it to reset your login link for Puzzle Massive. http://{DOMAIN_NAME}/chill/site/reset-login/{token}/ After visiting that web page and clicking the reset login button; a new login link will be created. Any older ones will no longer be valid. You can ignore this message if you didn't initiate the request. """.format(token=token, DOMAIN_NAME=current_app.config.get("DOMAIN_NAME")) current_app.logger.debug(message) email_sent = False if not current_app.config.get("DEBUG", True): try: send_message(email, "Puzzle Massive - reset login", message, current_app.config) email_sent = True except Exception as err: current_app.logger.warning( "Failed to send reset login message. email: {email}\n {message}\n error: {err}" .format(err=err, email=email, message=message)) email_sent = False cur.execute( fetch_query_string("update-player-account-login-token.sql"), { "player_id": user, "reset_login_token": token, "expire_token_timeout": "+1 day", }, ) if current_app.config.get("DEBUG", True): response[ "message"] = "A reset login link has been sent to your e-mail. DEBUG is True, so did not really send the email. Check the logs for the login link." response["name"] = "success" elif not email_sent: response[ "message"] = "Failed to send reset login link to your e-mail.".format( email) response["name"] = "error" else: response[ "message"] = "A reset login link has been sent to your e-mail.".format( email) response["name"] = "success" db.commit() cur.close() return make_response(json.jsonify(response), 202)