From 5431848bf65e9a4c2dedc474a92b2c0d19661e74 Mon Sep 17 00:00:00 2001 From: Kyle Askew Date: Wed, 5 Feb 2020 14:44:59 -0800 Subject: [PATCH 01/36] Update Step1.vue --- src/views/Accounts/Register/Step1.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/views/Accounts/Register/Step1.vue b/src/views/Accounts/Register/Step1.vue index 4714151..3ed9daf 100644 --- a/src/views/Accounts/Register/Step1.vue +++ b/src/views/Accounts/Register/Step1.vue @@ -10,26 +10,26 @@ color="input" v-bind="fields.username" v-model="fields.username.value" - :disabled="!allowSubmit" + :disabled="isSubmitting" /> Date: Fri, 7 Feb 2020 15:31:47 -0500 Subject: [PATCH 02/36] post registrations to slack --- CodeChallenge/api/users.py | 14 ++++++++++++++ CodeChallenge/config.py | 1 + 2 files changed, 15 insertions(+) diff --git a/CodeChallenge/api/users.py b/CodeChallenge/api/users.py index cb7f754..271ff78 100644 --- a/CodeChallenge/api/users.py +++ b/CodeChallenge/api/users.py @@ -1,3 +1,4 @@ +import requests from flask import Blueprint, jsonify, request, current_app, render_template from flask_jwt_extended import (create_access_token, create_refresh_token, get_current_user, get_jwt_identity, @@ -6,6 +7,7 @@ unset_jwt_cookies) from flask_limiter.util import get_remote_address from flask_mail import Message +from sqlalchemy import func from .. import core from ..auth import (Users, hash_password, password_reset_token, @@ -162,6 +164,18 @@ def register(): mail.send(confirm_email) mail.send(welcome_email) + if "SLACK_WEBHOOK" in current_app.config and not current_app.config.get("TESTING", False): + regcount = db.session.query(func.count(Users.id)).scalar() + webhook = current_app.config.get("SLACK_WEBHOOK") + requests.post(webhook, json=dict( + text="Event: New Registration\n\n" + f"*User*: {new_u.username}\n" + f"*Student*: {new_u.studentfirstname} {new_u.studentlastname}\n" + f"*Parent*: {new_u.parentfirstname} {new_u.parentlastname}\n" + f"*How'd you find us?* {new_u.found_us}\n" + f"\n*Total Registrations*: {regcount}" + )) + return jsonify({"status": "success"}) diff --git a/CodeChallenge/config.py b/CodeChallenge/config.py index 1434492..651a0f5 100644 --- a/CodeChallenge/config.py +++ b/CodeChallenge/config.py @@ -30,6 +30,7 @@ class DefaultConfig: MG_PRIVATE_KEY = os.getenv("MG_PRIVATE_KEY") MG_LIST = "codechallenge@school.codewizardshq.com" WORKER_PASSWORD = os.getenv("WORKER_PASSWORD") + SLACK_WEBHOOK = os.getenv("SLACK_WEBHOOK") # no trailing / EXTERNAL_URL = "https://challenge.codewizardshq.com" From 4ea0eadfc59bdbebc4dd6156577fa32bd65404bf Mon Sep 17 00:00:00 2001 From: Samuel Hoffman Date: Fri, 7 Feb 2020 20:18:04 -0500 Subject: [PATCH 03/36] real time messaging with Slack --- CodeChallenge/__init__.py | 2 + CodeChallenge/api/eb.py | 7 ++++ CodeChallenge/api/slack.py | 75 ++++++++++++++++++++++++++++++++++++++ CodeChallenge/config.py | 3 ++ CodeChallenge/core.py | 5 +++ 5 files changed, 92 insertions(+) create mode 100644 CodeChallenge/api/slack.py diff --git a/CodeChallenge/__init__.py b/CodeChallenge/__init__.py index 2e0b6f4..39a3add 100644 --- a/CodeChallenge/__init__.py +++ b/CodeChallenge/__init__.py @@ -11,6 +11,7 @@ from . import core from .api.eb import bp as eb_bp from .api.questions import bp as questions_bp +from .api.slack import bp as slack_bp from .api.users import bp as users_bp from .api.vote import bp as vote_bp from .auth import jwt @@ -62,6 +63,7 @@ def create_app(config): app.register_blueprint(q_cli_bp) app.register_blueprint(clock_cli_bp) app.register_blueprint(vote_bp) + app.register_blueprint(slack_bp) @app.errorhandler(429) def ratelimit_handler(e): diff --git a/CodeChallenge/api/eb.py b/CodeChallenge/api/eb.py index 9ea0c3f..fb0196f 100644 --- a/CodeChallenge/api/eb.py +++ b/CodeChallenge/api/eb.py @@ -1,5 +1,6 @@ from hmac import compare_digest +import requests from flask import Blueprint, request, current_app, render_template from flask_mail import Message @@ -41,4 +42,10 @@ def worker(): mail.send(msg) + webhook = current_app.config.get("SLACK_WEBHOOK") + if webhook is not None: + requests.post(webhook, json=dict( + text=f"*NEW RANK* {core.current_rank()}" + )) + return "", 200 diff --git a/CodeChallenge/api/slack.py b/CodeChallenge/api/slack.py new file mode 100644 index 0000000..43689b5 --- /dev/null +++ b/CodeChallenge/api/slack.py @@ -0,0 +1,75 @@ +import hmac +import re +import time + +import requests +from flask import Blueprint, request, jsonify, current_app, abort + +from .. import core + +bp = Blueprint("slackapi", __name__, url_prefix="/api/v1/slack") + +CMDRE = re.compile(r"^!([^ ]+)", re.I) + + +@bp.before_request +def slack_verify(): + ts = request.headers.get("X-Slack-Request-Timestamp") + secret = bytes(current_app.config.get("SLACK_SIGNING_SECRET"), "utf8") + body = request.data + + if abs(time.time() - int(ts)) > 60 * 5: + abort(401) + + sig_basestring = bytes(f"v0:{ts}:", "utf8") + sig_basestring += body + + my_sig = "v0=" + hmac.new(secret, sig_basestring, digestmod="SHA256").hexdigest() + slack_sig = request.headers.get("X-Slack-Signature") + if not hmac.compare_digest(my_sig, slack_sig): + abort(401) + + +def post_message(channel, text): + rv = requests.post("https://slack.com/api/chat.postMessage", + headers=dict( + Authorization="Bearer " + current_app.config["SLACK_OAUTH_TOKEN"] + ), + json=dict( + channel=channel, + text=text + )) + + rv.raise_for_status() + + +def handle_message(text, channel): + match = CMDRE.search(text) + + if match is None: + return + + command = match.group(1) + + if command == "status": + rank = core.current_rank() + resp = f"*Current Rank:* {rank if rank != -1 else '(challenge not started)'}\n" + resp += f"*Max Rank:* {core.max_rank()}\n" + resp += f"*Next Rank:* {core.time_until_next_rank()}\n" + resp += f"*Total Users:* {core.user_count()}" + + post_message(channel, resp) + + +@bp.route("/event", methods=["POST"]) +def slack_event(): + data = request.get_json() + + if "challenge" in data: + return jsonify(challenge=data["challenge"]) + + event = data["event"] + if event["type"] == "message": + handle_message(event["text"], event["channel"]) + + return "", 200 diff --git a/CodeChallenge/config.py b/CodeChallenge/config.py index 651a0f5..f52d8b6 100644 --- a/CodeChallenge/config.py +++ b/CodeChallenge/config.py @@ -31,6 +31,9 @@ class DefaultConfig: MG_LIST = "codechallenge@school.codewizardshq.com" WORKER_PASSWORD = os.getenv("WORKER_PASSWORD") SLACK_WEBHOOK = os.getenv("SLACK_WEBHOOK") + SLACK_SIGNING_SECRET = os.getenv("SLACK_SIGNING_SECRET") + SLACK_OAUTH_TOKEN = os.getenv("SLACK_OAUTH_TOKEN") + SLACK_CHANNEL = os.getenv("SLACK_CHANNEL") # no trailing / EXTERNAL_URL = "https://challenge.codewizardshq.com" diff --git a/CodeChallenge/core.py b/CodeChallenge/core.py index 81c746c..a1b4f6a 100644 --- a/CodeChallenge/core.py +++ b/CodeChallenge/core.py @@ -3,6 +3,7 @@ from flask import current_app from sqlalchemy import func +from .auth import Users from .models import Question, db @@ -68,3 +69,7 @@ def challenge_ended() -> bool: return True return False + + +def user_count() -> int: + return db.session.query(func.count(Users)).scalar() From c16233ad1d9b8010a9a3268d5a6a17466a79ace6 Mon Sep 17 00:00:00 2001 From: Kyle Askew Date: Tue, 11 Feb 2020 09:43:04 -0800 Subject: [PATCH 04/36] Update CWHQBar.vue --- src/components/Toolbars/CWHQBar.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/Toolbars/CWHQBar.vue b/src/components/Toolbars/CWHQBar.vue index f2e1a48..537a5cb 100644 --- a/src/components/Toolbars/CWHQBar.vue +++ b/src/components/Toolbars/CWHQBar.vue @@ -2,9 +2,7 @@ - Student Login - Parent Login - Student Center + Back to CodeWizardsHQ From 9e5bba4cb4fd296a2885127d3ffd5d4686803605 Mon Sep 17 00:00:00 2001 From: Kyle Askew Date: Tue, 11 Feb 2020 09:43:38 -0800 Subject: [PATCH 05/36] Update QuizBar.vue --- src/components/Toolbars/QuizBar.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Toolbars/QuizBar.vue b/src/components/Toolbars/QuizBar.vue index 72825ba..51909cf 100644 --- a/src/components/Toolbars/QuizBar.vue +++ b/src/components/Toolbars/QuizBar.vue @@ -43,7 +43,7 @@ Get Help On Discord - + Get Help On Facebook From ffc40f5b05bf8ff98f3fb995b2cb046174d3017b Mon Sep 17 00:00:00 2001 From: Kyle Askew Date: Tue, 11 Feb 2020 10:11:21 -0800 Subject: [PATCH 06/36] Update SocialPopOver.vue --- src/components/SocialPopOver.vue | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/components/SocialPopOver.vue b/src/components/SocialPopOver.vue index 938efc6..2349e76 100644 --- a/src/components/SocialPopOver.vue +++ b/src/components/SocialPopOver.vue @@ -19,7 +19,7 @@ :cols="i == icons.length - 1 ? 12 : 6" class="text-center" > - + mdi-{{ icon.icon }} @@ -35,19 +35,20 @@ export default { isOpen: false, icons: [ { - icon: "twitter" + icon: "twitter", + to: "https://twitter.com/CodeWizardsHQ" }, { - icon: "facebook" + icon: "facebook", + to: "https://www.facebook.com/events/501020200554546/" }, { - icon: "whatsapp" + icon: "linkedin", + to: "https://www.linkedin.com/company/codewizardshq" }, { - icon: "linkedin" - }, - { - icon: "email" + icon: "email", + to: "mailto:?subject=Join%20me%20in%20the%20CodeWizardsHQ%20Code%20Challenge!" } ] }) From 618eb516d57b3bb087f37dfb71f993422410321a Mon Sep 17 00:00:00 2001 From: Kyle Askew Date: Tue, 11 Feb 2020 10:13:57 -0800 Subject: [PATCH 07/36] Update SocialPopOver.vue --- src/components/SocialPopOver.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SocialPopOver.vue b/src/components/SocialPopOver.vue index 2349e76..26307bc 100644 --- a/src/components/SocialPopOver.vue +++ b/src/components/SocialPopOver.vue @@ -19,7 +19,7 @@ :cols="i == icons.length - 1 ? 12 : 6" class="text-center" > - + mdi-{{ icon.icon }} From 4c930984883389995589841d6d061e9c8ca95f88 Mon Sep 17 00:00:00 2001 From: Kyle Askew Date: Tue, 11 Feb 2020 10:19:46 -0800 Subject: [PATCH 08/36] Update QuizNeedHelp.vue --- src/components/QuizNeedHelp.vue | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/QuizNeedHelp.vue b/src/components/QuizNeedHelp.vue index 1d6a236..8742224 100644 --- a/src/components/QuizNeedHelp.vue +++ b/src/components/QuizNeedHelp.vue @@ -14,7 +14,7 @@ :cols="i == icons.length - 1 ? 12 : 6" class="text-center" > - + mdi-{{ icon.icon }} @@ -33,19 +33,21 @@ export default { dialog: false, icons: [ { - icon: "twitter" + icon: "twitter", + to: "https://twitter.com/CodeWizardsHQ" }, { - icon: "facebook" + icon: "facebook", + to: "https://www.facebook.com/events/501020200554546/" }, { - icon: "whatsapp" + icon: "linkedin", + to: "https://www.linkedin.com/company/codewizardshq" }, { - icon: "linkedin" - }, - { - icon: "email" + icon: "email", + to: + "mailto:?subject=Join%20me%20in%20the%20CodeWizardsHQ%20Code%20Challenge!" } ] }; From e52ba0ae153b7be70f8ce89848bd8f769c05caf5 Mon Sep 17 00:00:00 2001 From: Kyle Askew Date: Tue, 11 Feb 2020 10:21:23 -0800 Subject: [PATCH 09/36] Update QuizCountdown.vue --- src/views/Quiz/QuizCountdown.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/views/Quiz/QuizCountdown.vue b/src/views/Quiz/QuizCountdown.vue index df24cb8..d522054 100644 --- a/src/views/Quiz/QuizCountdown.vue +++ b/src/views/Quiz/QuizCountdown.vue @@ -30,16 +30,19 @@ + diff --git a/src/styles/mobile-warning.scss b/src/styles/mobile-warning.scss new file mode 100644 index 0000000..b65506d --- /dev/null +++ b/src/styles/mobile-warning.scss @@ -0,0 +1,18 @@ +.mobile-warning { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #21252d; + color: white; + z-index: 10000; + text-align: center; + display: block; +} + +@media (min-width: 600px) { + .mobile-warning { + display: none !important; + } +} diff --git a/src/styles/styles.scss b/src/styles/styles.scss index c5d9c4c..8f022af 100644 --- a/src/styles/styles.scss +++ b/src/styles/styles.scss @@ -14,6 +14,7 @@ @import "./ballot-card.scss"; @import "./ballot-modal.scss"; @import "./buttons.scss"; + @import "./mobile-warning.scss"; .v-alert { font-size: 20px; diff --git a/src/views/Public/App.vue b/src/views/Public/App.vue index b7aef77..fed9e93 100644 --- a/src/views/Public/App.vue +++ b/src/views/Public/App.vue @@ -7,18 +7,21 @@ + From 20df57b8dbe5a5d729ce52e2fcbf0e759c184ff4 Mon Sep 17 00:00:00 2001 From: net8floz Date: Thu, 20 Feb 2020 11:32:07 -0800 Subject: [PATCH 19/36] linter fixes --- src/components/MobileWarning.vue | 5 +- src/components/SocialPopOver.vue | 3 +- src/components/Toolbars/QuizBar.vue | 14 +- src/plugins/router.js | 5 +- src/store/quiz.js | 142 ++++++++++--------- src/views/Accounts/Register/Step2.vue | 60 ++++++-- src/views/Accounts/Register/Step3.vue | 42 ++++-- src/views/Accounts/Register/index.vue | 197 +++++++++++++++----------- src/views/Quiz/QuizCountdown.vue | 20 ++- src/views/Voting/App.vue | 8 +- 10 files changed, 307 insertions(+), 189 deletions(-) diff --git a/src/components/MobileWarning.vue b/src/components/MobileWarning.vue index 624b147..f5f50e6 100644 --- a/src/components/MobileWarning.vue +++ b/src/components/MobileWarning.vue @@ -3,8 +3,9 @@

This site is not designed for mobile devices!

- As much as we appreciate mobile first design, it does not always apply. This is a code challenge and requires full use of your brain and keyboard. Please - visit this page on your phone or desktop to continue. + As much as we appreciate mobile first design, it does not always apply. + This is a code challenge and requires full use of your brain and keyboard. + Please visit this page on your phone or desktop to continue.

Show me anyways diff --git a/src/components/SocialPopOver.vue b/src/components/SocialPopOver.vue index 26307bc..360beb9 100644 --- a/src/components/SocialPopOver.vue +++ b/src/components/SocialPopOver.vue @@ -48,7 +48,8 @@ export default { }, { icon: "email", - to: "mailto:?subject=Join%20me%20in%20the%20CodeWizardsHQ%20Code%20Challenge!" + to: + "mailto:?subject=Join%20me%20in%20the%20CodeWizardsHQ%20Code%20Challenge!" } ] }) diff --git a/src/components/Toolbars/QuizBar.vue b/src/components/Toolbars/QuizBar.vue index 224e955..1623d48 100644 --- a/src/components/Toolbars/QuizBar.vue +++ b/src/components/Toolbars/QuizBar.vue @@ -37,13 +37,19 @@ Get Help - + Check The FAQ Get Help On Discord - + Get Help On Facebook @@ -63,9 +69,9 @@