Example #1
0
File: views.py Project: DickJ/fitu
def verify_unsubscribe(confcode):
    logging.debug({'func': 'verify_unsubscribe', 'confcode': confcode})

    conn, cur = u_db.get_db_conn_and_cursor(app.config)

    cur.execute("SELECT (phone) FROM unsubscribe WHERE confcode=%s",
                [confcode])
    d = cur.fetchone()
    if d:
        cur.execute('DELETE FROM verified WHERE phone=%s', [d[0]])
        cur.execute('DELETE FROM unsubscribe WHERE phone=%s', [d[0]])
        conn.commit()
        logging.info({
            'func': 'verify_unsubscribe',
            'phone': d[0],
            'msg': 'successfully unsubscribed'
        })
        msg = "You have been successfully unsubscribed."
    else:
        logging.info({
            'func': 'verify_unsubscribe',
            'confcode': confcode,
            'msg': 'invalid unsubscribe code'
        })
        msg = "ERROR: The supplied confirmation code is not valid."

    cur.close()
    conn.close()

    return render_template("unsubscribe.html", form=UnsubscribeForm(), msg=msg)
Example #2
0
File: views.py Project: DickJ/fitu
def unsubscribe():
    """
    Process a request to unsubscribe and return the template
    """
    form = UnsubscribeForm()
    # If the form has been submitted
    if form.validate_on_submit():
        # Open db connection
        conn, cur = u_db.get_db_conn_and_cursor(app.config)

        # If all data is valid
        phone = u_views.is_valid_number(form.phone.data)
        print(phone)
        if phone:
            # If phone number does not already exist as a verified user
            cur.execute(
                'SELECT provider FROM verified WHERE phone=%s AND fname=%s and lname=%s;',
                [
                    phone,
                    form.fname.data.upper().rstrip(),
                    form.lname.data.upper().rstrip()
                ])
            user = cur.fetchone()
            if user:
                # Process unsubscribe request
                confcode = random.getrandbits(16)
                flashmsg = u_views.unsubscribe_user(cur, phone, confcode)
                subject = 'VT-3 Notifications'
                smstxt = "Click the link to unsubscribe. %s%s%d" \
                         % (app.config['BASE_URL'], '/unsubscribe/', confcode)
                # Send Text Message
                tc = TextClient(debug=app.config['DEBUG'])
                response = tc.send_message(phone, subject, smstxt, user[0])

                #flash(flashmsg)
                #return redirect('/')
            else:
                # Alert user this was an invalid unsubscribe request
                flashmsg = 'Data does not match anyone in our database. Please confirm name spelling and phone number.'

        else:
            flashmsg = 'Invalid phone number. Please try again.'
            form.phone.errors.append("Invalid format.")

        flash(flashmsg)
        conn.commit()
        print('committing')
        cur.close()
        conn.close()

    return render_template("unsubscribe.html", form=form)
Example #3
0
def run_conf_code_update():
    """
    Deletes confirmation codes older than 24 hours
    """
    logging.info({'func': 'run_conf_code_update', 'msg': 'starting'})

    conn, cur = get_db_conn_and_cursor()
    cur.execute(
        "DELETE FROM unverified WHERE current_timestamp - datetime > '24 hours';"
    )
    conn.commit()
    cur.close()
    conn.close()

    logging.info({'func': 'run_conf_code_update', 'msg': 'returning'})
Example #4
0
 def setUp(self):
     self.today = datetime.now()
     self.yesterday = self.today - timedelta(days=1)
     self.vt3url = "https://www.cnatra.navy.mil/scheds/schedule_data.aspx?sq=vt-3"
     self.conn, self.cur = u_db.get_db_conn_and_cursor()
     try:
         # TODO Is this needed now that I have an actual test database setup?
         self.cur.execute(
         "INSERT INTO schedule (type, brief, edt, rtb, instructor, student,"\
             " event, remarks, location, date) VALUES ('T-6B Flight', "\
             "'07:00', '08:45', '10:15', 'TEST, INSRUCTOR', 'TEST, STUDENT'"\
             ", 'C4101', 'OnlineScheduleTestCase', 'NASWF', 'January 1');")
         self.conn.commit()
     except IntegrityError as e:
         self.conn.rollback()
Example #5
0
File: views.py Project: DickJ/fitu
def verify(confcode):
    logging.debug({'func': 'verify', 'confcode': confcode})
    conn, cur = u_db.get_db_conn_and_cursor(app.config)

    cur.execute(
        "SELECT (phone, lname, fname, provider) FROM unverified WHERE confcode=%s",
        [confcode])
    d = cur.fetchone()
    if d:
        #TODO Why am I stripping and splitting? cur.fetchone returns a tuple,
        # not a string. ref: http://initd.org/psycopg/docs/cursor.html#fetch
        d = d[0].lstrip('(').rstrip(')').split(',')

        cur.execute("SELECT phone FROM verified WHERE phone = %s", [d[0]])
        already_added = cur.fetchone()
        if not already_added:
            cur.execute(
                'INSERT INTO verified (phone, lname, fname, provider) VALUES (%s, %s, %s, %s)',
                [d[0], d[1], d[2], d[3]])

        # TODO Make an initial push message when confirmed (e.g. what if they
        # sign up at night and need tomorrows schedule)
        msg = "Congratulations! You have successfully been signed up. You " \
              "will begin receiving messages at the next run."
        logging.info({
            'func': 'verify',
            'fname': d[2],
            'lname': d[1],
            'phone': d[0],
            'msg': 'signup confirmation successful'
        })

    else:
        logging.info({
            'func': 'verify',
            'confcode': confcode,
            'msg': 'invalide confirmation code'
        })
        msg = "ERROR: The supplied confirmation code is not valid."

    conn.commit()
    cur.close()
    conn.close()

    #TODO: This is a shitty fix for redirecting and flashing the message
    # after a successful signup
    return redirect('/')
Example #6
0
def run_signup_form(form):
    # Open db connection
    conn, cur = u_db.get_db_conn_and_cursor(app.config)

    # FIXME: What do we do if user selects invalid phone provider?
    # FIXME: How will this fix play into the eventual switch to TWILIO?
    # If all data is valid
    phone = is_valid_number(form.phone.data)
    if phone:
        # If phone number does not already exist as a verified user
        cur.execute('SELECT * FROM verified WHERE phone=%s;', [phone])
        if not cur.fetchone():
            logging.info({
                'func': 'run_signup_form',
                'fname': form.fname.data,
                'lname': form.lname.data,
                'phone': phone,
                'provider': form.provider.data,
                'msg': 'user signup'
            })
            # If phone number does not already exist as an unverified user
            cur.execute('SELECT confcode FROM unverified WHERE phone=%s;',
                        [phone])
            unverified_user = cur.fetchone()
            if not unverified_user:
                #  Add user to unverified signups table
                flashmsg = sign_up_user(cur, conn, phone, form.provider.data,
                                        form.lname.data.upper().rstrip(),
                                        form.fname.data.upper().rstrip())

            else:
                confcode = int(unverified_user[0])
                send_conf_code(phone, form.provider.data,
                               'VT-3 Notifications Signup', confcode)
                flashmsg = 'This phone number has already signed up but has not been verified. We have re-sent your confirmation code.'
        else:
            flashmsg = 'This phone number has already been signed up.'

        flash(flashmsg)

    else:
        flash('Invalid phone number. Please try again.')
        form.phone.errors.append("Invalid format.")

    cur.close()
    conn.close()
Example #7
0
    def from_email_address(phone, provider):
        """
        http://www.howtogeek.com/howto/27051/use-email-to-send-text-messages-sms-to-mobile-phones-for-free/

        Params:
            phone: (str) format is 2225559999
            provider: (str) mobile provider

        Returns: (str) email address as [email protected]
        """

        if phone[:2] == '+1':
            phone = phone[2:]
        assert len(phone) == 10, 'phone is not lenght 10'
        assert re.match('\d{10}', phone), 'phone is not all digits'
        assert provider is not None, 'No wireless provider given'

        conn, cur = u_db.get_db_conn_and_cursor()
        cur.execute('SELECT gateway FROM smsgateways WHERE name = %s;',
                    [provider])

        #TODO Is this really the best behavior I can come up with?
        # A better solution might be to force usage with Twilio, however if
        # Twilio is setup, then why don't I just use twilio for everything in
        # the first place? For now, I am simply going to leave this as the state
        # of things until I complete the implementation of Twilio. At that point
        # This entire function should be removed.
        try:
            gateway_address = cur.fetchone()[0]
        except TypeError:
            gateway_address = 'invalidprovider.com'

        try:
            email = phone + '@' + gateway_address
            return email
        except KeyError:
            logging.error({
                'func':
                'TextClient:from_email_address',
                'msg':
                'KeyError: %r is not a valid mobile provider' % provider
            })
            return '*****@*****.**'  # TODO Setup email address for error
Example #8
0
    def setUp(self):
        self.conn, self.cur = u_db.get_db_conn_and_cursor()
        try:
            self.cur.execute(
                "INSERT INTO unverified (phone, provider, lname, fname, confcode, "\
                    "datetime) VALUES (%s, %s, %s, %s, %s, current_timestamp);",
                ['+18505551111', 'verizon', 'CONFCODETEST1', 'TEST', '1111']
            )
            self.cur.execute(
                "INSERT INTO unverified (phone, provider, lname, fname, confcode, "\
                    "datetime) VALUES (%s, %s, %s, %s, %s, current_timestamp - "\
                    "INTERVAL '1 day' - INTERVAL '5 minutes');",
                ['+18505552222', 'verizon', 'CONFCODETEST2', 'TEST', '2222']
            )
            self.conn.commit()
        except IntegrityError as e:
            # Lines already in database
            self.conn.rollback()

        self.cur.execute("SELECT * FROM unverified WHERE fname LIKE 'TEST';")
        self.assertIsNotNone(self.cur.fetchone())
Example #9
0
def run_online_schedule():
    logging.basicConfig(level=logging.DEBUG)
    logging.info({'func': 'run_online_schedule',
                  'msg': "Starting run_online_schedule()"})
    # Define Vars
    conn, cur = u_db.get_db_conn_and_cursor()
    url = 'https://www.cnatra.navy.mil/scheds/schedule_data.aspx?sq=tw-5+fitu'
    tomorrow = datetime.now() - timedelta(hours=5) + timedelta(
        days=1)  # adjust timezone

    if tomorrow.weekday() == 5:  # If it is Friday and we're looking for Sat's sched
        dates = (
            tomorrow, tomorrow + timedelta(days=1),
            tomorrow + timedelta(days=2))
    else:
        dates = (tomorrow,)

    logging.info({'func': 'run_online_schedule', 'dates': dates,
                  'msg': 'Dates being processed by run_online_schedule()'})

    for dt in dates:
        logging.info(
            {'func': 'run_online_schedule',
             'msg': "Checking schedule for %r" % tomorrow})

        # Download Schedule
        try:
            sched = process_raw_schedule(get_schedule_page(url, dt))

            # If schedule has been posted on cnatra or uploaded to postgress yet
            if sched and not sched_uploaded(cur, dt):
                insert_in_pg(cur, sched, dt)
                if dt.weekday() == 1:
                    logging.debug({'func': 'run_online_schedule',
                                   'msg': 'Deleting last weeks schedule from database'})
                    delete_old_sched(cur, dt - timedelta(days=2))
                    delete_old_sched(cur, dt - timedelta(days=3))
                    delete_old_sched(cur, dt - timedelta(days=4))
                    delete_old_sched(cur, dt - timedelta(days=5))
                    delete_old_sched(cur, dt - timedelta(days=6))
                    delete_old_sched(cur, dt - timedelta(days=7))
                    delete_old_sched(cur, dt - timedelta(days=8))
                conn.commit()
                send_all_texts(cur, dt)
                send_squadron_notes(url, dt, cur)


            # If it gets too late and the schedule hasn't been published, send out
            # a text. But only do this once, so let's use 1930L == 0030UTC

            # 1/4/2018 Wow, so here is a fun issue. This current code will keep
            # looking for the schedule after it hasn't been published, just in
            # case it does end up getting published late. It just sends a
            # message out at the specified time, but still keeps looking.
            # On the date above, that message was sent out 3x despite the
            # scheduler being set to run every 30 minutes. Not a f*****g clue
            # how that ended up happening. The logs indicate it ran at 16:31,
            # 16:43, and 16:58 despite the scheduler being set to run on the
            # hour and on the half hour.
            #
            # Jan 03 16:31:33 vt3 app/scheduler.3386:  WARNING:root:{'msg': 'Schedule was not published by 0100Z', 'func': 'run_online_schedule'}
            # Jan 03 16:43:09 vt3 app/worker.1:  WARNING:root:{'func': 'run_online_schedule', 'msg': 'Schedule was not published by 0100Z'}
            # Jan 03 16:58:40 vt3 app/worker.1:  WARNING:root:{'func': 'run_online_schedule', 'msg': 'Schedule was not published by 0100Z'}

            # TODO: What about when DST ends?
            elif not sched and time(0, 29, 0) < datetime.now().time() < time(0,
                                                                             59,
                                                                             0):
                logging.warning({'func': 'run_online_schedule',
                                 'msg': 'Schedule was not published by 0100Z'})
                # TODO Only instantiate one TextClient in main.py
                client = TextClient()

                cur.execute("SELECT phone, provider FROM verified;")
                msg = "The schedule has not been published yet. Please call the " \
                      "SDO at (850)623-7323 for tomorrow's schedule."
                for phone, provider in cur.fetchall():
                    client.send_message(phone, dt.strftime('%B %-d'), msg, provider)

        except AttributeError as e:
            logging.debug({'func': 'run_online_schedule', 'error': e})
            logging.info({'func': 'run_online_schedule',
                          'msg': "Schedule not yet published"})

    cur.close()
    conn.close()

    logging.info(
        {'func': 'run_online_schedule', 'msg': "run_online_schedule() exiting"})
Example #10
0
 def test_get_db_conn_and_cursor(self):
     a = get_db_conn_and_cursor()
Example #11
0
 def setUp(self):
     self.conn, self.cur = u_db.get_db_conn_and_cursor(app.config)
     self.phone = '+16665551111'
     self.provider = 'verizon'