diff --git a/app/__init__.py b/app/__init__.py index 60377ec..daf77d3 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -11,6 +11,7 @@ from config import config from .assets import app_css, app_js, vendor_css, vendor_js + basedir = os.path.abspath(os.path.dirname(__file__)) mail = Mail() @@ -39,6 +40,8 @@ def create_app(config_name): csrf.init_app(app) compress.init_app(app) RQ(app) + from jobs import rq + rq.init_app(app) # Register Jinja template functions from .utils import register_template_utils 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..2aa5ba1 100644 --- a/app/admin/views.py +++ b/app/admin/views.py @@ -1,15 +1,17 @@ -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 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 @@ -95,6 +97,22 @@ 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() + 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) + 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) + @admin.route('/user//change-email', methods=['GET', 'POST']) @login_required @admin_required @@ -197,4 +215,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/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..302d043 --- /dev/null +++ b/app/jobs/scheduled_jobs.py @@ -0,0 +1,29 @@ +from flask_rq2 import RQ +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/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 %} 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.""" 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