From 1bbf163cfa0d05a186143b229fb1f95ac45e0a0c Mon Sep 17 00:00:00 2001 From: sanjayss34 Date: Wed, 25 Apr 2018 23:10:46 -0400 Subject: [PATCH 1/5] Stuff for twilio notifs --- app/__init__.py | 4 ++++ app/jobs/__init__.py | 5 +++++ app/jobs/scheduled_jobs.py | 23 +++++++++++++++++++++++ requirements.txt | 1 + 4 files changed, 33 insertions(+) create mode 100644 app/jobs/__init__.py create mode 100644 app/jobs/scheduled_jobs.py diff --git a/app/__init__.py b/app/__init__.py index 60377ec..5951748 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -11,6 +11,8 @@ from config import config from .assets import app_css, app_js, vendor_css, vendor_js +from .jobs import savings_reminder, rq + basedir = os.path.abspath(os.path.dirname(__file__)) mail = Mail() @@ -39,6 +41,8 @@ def create_app(config_name): csrf.init_app(app) compress.init_app(app) RQ(app) + savings_reminder.cron('* * * * *', 'savings reminder', queue='high', timeout=55) + rq.init_app(app) # Register Jinja template functions from .utils import register_template_utils diff --git a/app/jobs/__init__.py b/app/jobs/__init__.py new file mode 100644 index 0000000..2d84fef --- /dev/null +++ b/app/jobs/__init__.py @@ -0,0 +1,5 @@ +from flask import Blueprint + +jobs = Blueprint('jobs', __name__) + +from scheduled_jobs import * diff --git a/app/jobs/scheduled_jobs.py b/app/jobs/scheduled_jobs.py new file mode 100644 index 0000000..4b3aeaa --- /dev/null +++ b/app/jobs/scheduled_jobs.py @@ -0,0 +1,23 @@ +from flask_rq2 import RQ +from ..models import User +from twilio.rest import Client +import datetime + +rq = RQ() + +@rq.job +def savings_reminder(): + users = User.query.all() + client = Client(current_app.config["TWILIO_ACCOUNT_SID"], current_app.config["TWILIO_AUTH_TOKEN"]) + for user in users: + today = datetime.datetime.now() + today = today.date() + goal_balance = (today-user.savings_start_date)*user.goal_amount/(user.savings_end_date-user.savings_start_date) + if user.bank_balance < goal_balance: + try: + client.api.account.messages.create( + to=user.mobile_phone, + from_=current_app.config["TWILIO_PHONE_NUMBER"], + body="This is a reminder that your current savings balance is " + str(user.bank_balance) + " and your goal balance for today is " + str(goal_balance) + ".") + except Exception: + pass diff --git a/requirements.txt b/requirements.txt index 933d957..8edc846 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,7 @@ Flask-Login==0.4.0 Flask-Mail==0.9.1 Flask-Migrate==2.0.3 Flask-RQ==0.2 +Flask-RQ2 Flask-Script==2.0.5 Flask-SQLAlchemy==2.1 Flask-SSLify==0.1.5 From 841dad5a41d5c65c1174fe2985080c92bc69b79e Mon Sep 17 00:00:00 2001 From: sanjayss34 Date: Thu, 26 Apr 2018 00:18:17 -0400 Subject: [PATCH 2/5] Texts not working yet, but some things written yet --- app/__init__.py | 3 +-- app/jobs/scheduled_jobs.py | 8 +++++++- app/models/user.py | 6 ++++++ manage.py | 10 ++++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 5951748..daf77d3 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -11,7 +11,6 @@ from config import config from .assets import app_css, app_js, vendor_css, vendor_js -from .jobs import savings_reminder, rq basedir = os.path.abspath(os.path.dirname(__file__)) @@ -41,7 +40,7 @@ def create_app(config_name): csrf.init_app(app) compress.init_app(app) RQ(app) - savings_reminder.cron('* * * * *', 'savings reminder', queue='high', timeout=55) + from jobs import rq rq.init_app(app) # Register Jinja template functions diff --git a/app/jobs/scheduled_jobs.py b/app/jobs/scheduled_jobs.py index 4b3aeaa..302d043 100644 --- a/app/jobs/scheduled_jobs.py +++ b/app/jobs/scheduled_jobs.py @@ -1,23 +1,29 @@ from flask_rq2 import RQ -from ..models import User from twilio.rest import Client import datetime +import logging rq = RQ() @rq.job def savings_reminder(): + logging.error('in savings reminder') + from ..models import User users = User.query.all() client = Client(current_app.config["TWILIO_ACCOUNT_SID"], current_app.config["TWILIO_AUTH_TOKEN"]) for user in users: today = datetime.datetime.now() today = today.date() goal_balance = (today-user.savings_start_date)*user.goal_amount/(user.savings_end_date-user.savings_start_date) + print(goal_balance, user.bank_balance) if user.bank_balance < goal_balance: try: client.api.account.messages.create( to=user.mobile_phone, from_=current_app.config["TWILIO_PHONE_NUMBER"], body="This is a reminder that your current savings balance is " + str(user.bank_balance) + " and your goal balance for today is " + str(goal_balance) + ".") + break except Exception: + print('not working') + logging.error('not working') pass diff --git a/app/models/user.py b/app/models/user.py index 52a2954..580dc03 100644 --- a/app/models/user.py +++ b/app/models/user.py @@ -7,6 +7,7 @@ from .. import db, login_manager import random +import datetime class Permission: @@ -236,6 +237,11 @@ def generate_fake(count=100, **kwargs): password='password', stage=random.getrandbits(1), role=choice(roles), + mobile_phone='6307961737', + bank_balance=0, + savings_start_date=datetime.date(2018, 4, 1), + savings_end_date=datetime.date(2018, 4, 30), + goal_amount=100, **kwargs) db.session.add(u) try: diff --git a/manage.py b/manage.py index 5d80e7e..8c27a06 100644 --- a/manage.py +++ b/manage.py @@ -10,6 +10,7 @@ from app import create_app, db from app.models import Role, User, SiteAttributes, Stage +import logging app = create_app(os.getenv('FLASK_CONFIG') or 'default') @@ -71,6 +72,15 @@ def setup_prod(): setup_general() +@manager.command +def setup_cron(): + """Starts Cron jobs""" + from app.jobs import savings_reminder + savings_reminder.cron('* * * * *', 'savings reminder', queue='high', timeout=120) + print('here1') + logging.error('here2') + + def setup_general(): """Runs the set-up needed for both local development and production. Also sets up first admin user.""" From f0b7decb1c29e096b9f62559e1b79f4d0efa06a0 Mon Sep 17 00:00:00 2001 From: sanjayss34 Date: Fri, 27 Apr 2018 17:13:43 -0400 Subject: [PATCH 3/5] Trying to send a message from user's page in admin view --- app/admin/forms.py | 7 ++++++- app/admin/views.py | 10 +++++++++- app/templates/admin/manage_user.html | 3 ++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/admin/forms.py b/app/admin/forms.py index 90f67d6..c3c0391 100644 --- a/app/admin/forms.py +++ b/app/admin/forms.py @@ -67,4 +67,9 @@ class AirtableFormHTML(Form): 'copy and paste the HTML for your embedded form below. This will be the ' 'form that all users must fill out before they can use the application ' 'for the first time.') - submit = SubmitField('Submit') \ No newline at end of file + submit = SubmitField('Submit') + + +class SendMessageForm(Form): + message = TextAreaField('Message', validators=[InputRequired()]) + submit = SubmitField('Send') diff --git a/app/admin/views.py b/app/admin/views.py index ba76960..fb62e5e 100644 --- a/app/admin/views.py +++ b/app/admin/views.py @@ -95,6 +95,14 @@ def user_info(user_id): return render_template('admin/manage_user.html', user=user) +@admin.route('/user//send-message', methods=['GET', 'POST']) +@login_required +@admin_required +def send_message(user_id): + form = SendMessageForm() + if form.validate_on_submit(): + + @admin.route('/user//change-email', methods=['GET', 'POST']) @login_required @admin_required @@ -197,4 +205,4 @@ def manage_airtable(): site.airtable_html = form.airtable_html.raw_data[0] db.session.add(site) db.session.commit() - return render_template('admin/manage_airtable.html', form=form) \ No newline at end of file + return render_template('admin/manage_airtable.html', form=form) diff --git a/app/templates/admin/manage_user.html b/app/templates/admin/manage_user.html index 1fac743..30f00c4 100644 --- a/app/templates/admin/manage_user.html +++ b/app/templates/admin/manage_user.html @@ -7,6 +7,7 @@ ('admin.user_info', 'User information'), ('admin.change_user_email', 'Change email address'), ('admin.change_account_type', 'Change account type'), + ('admin.send_message', 'Send a Message'), (deletion_endpoint, 'Delete user') ] %} @@ -90,4 +91,4 @@

} }); -{% endblock %} \ No newline at end of file +{% endblock %} From 9b29e177b19a2ba20d519b87e2aad6d647c7f8ef Mon Sep 17 00:00:00 2001 From: sanjayss34 Date: Fri, 27 Apr 2018 17:20:07 -0400 Subject: [PATCH 4/5] Almost got on-demand messaging --- app/admin/views.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/admin/views.py b/app/admin/views.py index fb62e5e..6853209 100644 --- a/app/admin/views.py +++ b/app/admin/views.py @@ -3,13 +3,15 @@ from flask_rq import get_queue from .forms import (ChangeAccountTypeForm, ChangeUserEmailForm, InviteUserForm, - NewUserForm, AirtableFormHTML) + NewUserForm, AirtableFormHTML, SendMessageForm) from . import admin from .. import db from ..decorators import admin_required from ..email import send_email from ..models import Role, User, EditableHTML, SiteAttributes +from twilio.rest import Client + @admin.route('/') @login_required @@ -100,8 +102,15 @@ def user_info(user_id): @admin_required def send_message(user_id): form = SendMessageForm() + user = User.query.filter_by(id=user_id).first() if form.validate_on_submit(): - + client = Client(current_app.config["TWILIO_ACCOUNT_SID"], current_app.config["TWILIO_AUTH_TOKEN"]) + client.api.account.messages.create( + to=user.mobile_phone, + from_=current_app.config["TWILIO_PHONE_NUMBER"], + body=form.message.data) + return redirect(url_for('admin.user_info', user_id=user_id)) + return render_template('admin/manage_user.html', user=user, form=form) @admin.route('/user//change-email', methods=['GET', 'POST']) @login_required From 3b3beb32286ba5cb96c6f4ac23b08045b684431e Mon Sep 17 00:00:00 2001 From: sanjayss34 Date: Fri, 27 Apr 2018 17:25:56 -0400 Subject: [PATCH 5/5] On-demand messaging from admin working --- app/admin/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/admin/views.py b/app/admin/views.py index 6853209..2aa5ba1 100644 --- a/app/admin/views.py +++ b/app/admin/views.py @@ -1,4 +1,4 @@ -from flask import abort, flash, redirect, render_template, url_for, request +from flask import abort, flash, redirect, render_template, url_for, request, current_app from flask_login import current_user, login_required from flask_rq import get_queue @@ -109,6 +109,7 @@ def send_message(user_id): to=user.mobile_phone, from_=current_app.config["TWILIO_PHONE_NUMBER"], body=form.message.data) + flash('Your message has been sent.', 'success') return redirect(url_for('admin.user_info', user_id=user_id)) return render_template('admin/manage_user.html', user=user, form=form)