def delete_twilio_feedback(sidd): """Wipes the message with the specified sid(s) on Twilio Will display response codes. Args: sidd(str): optional argument. Include a sid or a list of SMS sids to delete from the twilio DB Returns: res(int): 1 on success. 0 if the feedback could not be deleted Raises: ValueError: sms could not be found in database """ if (sidd): #Assumption is that all feedback in db will match twilio if type(sidd) is list: try: smss = Sms.delete().where(Sms.sid in sidd).execute() except: raise ValueError for sid in sidd: url = "https://{}:{}@api.twilio.com/2010-04-01/Accounts/".format(account_sid,auth_token) + account_sid + '/Messages/' + sid try: response = request.delete(url) except: print("max retries Error") finally: if response.status_code == 204: return 1 if response.status_code == 404: print(sid + " " + response.reason) return 0 else: print(response.reason) return 0 elif type(sidd) is str: sid = sidd try: sms = Sms.delete().where(Sms.sid==sid).execute() except: raise ValueError url = "https://{}:{}@api.twilio.com/2010-04-01/Accounts/".format(account_sid,auth_token) + account_sid + '/Messages/' + sid try: response = request.delete(url) except: print("max retries Error") finally: if response.status_code == 204: return 1 if response.status_code == 404: print(sid + " " + response.reason) return 0 else: print(response.reason) return 0 else: return 0 else: return 0 return 0
def delete_feedback(): """Calls the delete_feedback function, returns a message confirming # of feedback entries deleted Returns: res(str): Confirmation string """ query = Sms.delete() # deletes all SMS objects res = query.execute() return "{} amount of sms entries deleted".format(res)
def test_update_db(self): """Tests to make sure that Sms objects that are stored in the database are storing correctly. Tests the functionality of the Sms feedback use case: storing and accessing feedback **Passes when**: The system can process Sms data that is sent and update the database. Can query with a date range while rejecting invalid dates. Can correctly read sms data **Fails when**: System has errors in processing sms. Cannot read information from the Sms object The sms database is not empty when deleted and invalid date ranges are specified """ #TODO: if twilio connection not maintained self.assertEqual( feedback_controller.update_db(datetime(2016, 3, 21), update_from="test"), 1) self.assertEqual( feedback_controller.update_db(datetime(2027, 3, 21), update_from="test"), 0) query = Sms.delete() res = query.execute() self.assertEqual(len(Sms.select()), 0) feedback_controller.update_db(update_from="test") self.assertTrue(len(Sms.select()) > 0) smss = Sms.select().where(Sms.sid == 1) for sms in smss: self.assertEqual(sms.phone_num, "+12345678905") query = Sms.delete() res = query.execute() self.assertEqual(len(Sms.select()), 0)
def delete_twilio_feedback(): """Wipe all message history on twilio since a specified time. Only needs to be called once to clear data. Returns: res(str): Confirmation string """ smss = Sms.select().where(Sms.submission_time >= datetime( 2017, 4, 25, 2, 35, 00)) #2017-04-25 02:49:49 sidd = [] for sms in smss: sidd.append(sms.sid) #print(sidd) feedback_controller.delete_twilio_feedback(sidd) return "Twilio Feedback deleted"
def update_db(*date_from, **kwargs): """Updates the sms in the database starting from the date_from specified (at time midnight) no param = updates the sms feedback in database with all message entries analyze feedback when sms is sent Args: date_from (Date): a specified date, where we update db with sms sent after this date update_from (str): an optional argument. This should be "test" if messages are not coming from twilio, but from the test_fb_data file Returns: res(int): 1 on success. 0 on error Throws: SystemError: When the Twilio Client cannot be started. Possibly invalid account_sid or auth_token """ if (kwargs): if(kwargs["update_from"]): if(kwargs['update_from'] == "test"): if date_from == (): messages = test_sms_data(5, datetime(2016, 3, 25)) else: date_from = date_from[0] if (date_from > datetime.now()): return 0 else: messages = test_sms_data(5, date_from) messages = test_sms_data(5, datetime(2016, 3, 25)) elif(kwargs['update_from'] == "autogen"): if date_from == (): messages = auto_generate_sms_data() else: date_from = date_from[0] if (date_from > datetime.now()): return 0 else: messages = auto_generate_sms_data(date_from=date_from) else: return 0 else: return 0 else: try: client = Client(account_sid,auth_token) messages = client.messages.list(to=restaurant_phone_number) process_incoming_sms() if date_from == (): messages = client.messages.list(to=restaurant_phone_number) # this may have a long random string first else: date_from = date_from[0] if (date_from > datetime.now()): #raise ValueError return 0 messages = client.messages.list(date_sent=date_from,to=restaurant_phone_number) except: if date_from==(): messages = auto_generate_sms_data() else: date_from = date_from[0] if (date_from > datetime.now()): return 0 else: messages = auto_generate_sms_data(date_from=date_from) #raise SystemError for message in messages: try: sms = Sms.get(message.sid == Sms.sid) if (sms.invalid_field == True): #pass print('deleting ' + sms.body) delete_twilio_feedback(sms.sid) else: pass except: try: if message.date_sent != None: date_tmp = message.date_sent - timedelta(hours=4) sms_str = date_tmp.strftime("%Y-%m-%d %H:%M:%S") date_tmp= datetime.strptime(sms_str, "%Y-%m-%d %H:%M:%S") else: date_tmp = None sms_tmp = Sms(sid=message.sid, submission_time=date_tmp, body=message.body, phone_num=message.from_, ) res2 = feedback_analysis(sms_tmp.body) sms_tmp.pos_flag = res2[0] sms_tmp.neg_flag = res2[1] sms_tmp.exception_flag = res2[2] sms_tmp.food_flag = res2[3] sms_tmp.service_flag = res2[4] sms_tmp.invalid_field = False try: err = sms_tmp.save() except IntegrityError: pass except IntegrityError: err = 0 #print("Duplicate Sms Entry " + sms_tmp.body) return 1
def process_incoming_sms(*one): """Updates SMS table in database with the incoming SMS. Checks for the unique key to invalidate SMS or keep it. Only for processing SMS in real time. - Precondition: A Twilio POST request is received. TODO: Fix error with twilio, where the most recent message does not have a submission timep Args: *one(int): optional argument Returns: res(int): 1 on success. 0 on error Throws: SystemError: When the Twilio Client cannot be started. Possibly invalid account_sid or auth_token """ tabss = Tabs.select() valid_keys = [] for tab in tabss: key = tab.fb_key if key == "~~~~~~~~~~": continue else: valid_keys.append(key) try: client = Client(account_sid,auth_token) messages = client.messages.list(to=restaurant_phone_number) except: raise SystemError if (one): messages = client.messages.list(to=restaurant_phone_number) message = messages[0] # get the first message message_key = [] for key in valid_keys: if key in message.body[:len(key)]: new_body = message.body.replace(key,'') #remoev key tab = Tabs.update(fb_key="~~~~~~~~~~").where(Tabs.fb_key == key) message_key.append(key) if (message_key): #i can use the date time as now because feedback comes in immediately here sms_tmp = Sms( sid=message.sid, submission_time=datetime.now(), body=new_body, phone_num=message.from_) res2 = feedback_analysis(sms_tmp.body) sms_tmp.pos_flag = res2[0] sms_tmp.neg_flag = res2[1] sms_tmp.exception_flag = res2[2] sms_tmp.food_flag = res2[3] sms_tmp.service_flag = res2[4] sms_tmp.invalid_field = False try: err = sms_tmp.save() except IntegrityError: pass else: try: i = message.body.index(' ') except ValueError: i = 7 pass if (one): non_accept = "Your unique key {" + message.body[:i] + "} is not valid" client.messages.create( to=message.from_, from_=restaurant_phone_number, body=non_accept,) sms_tmp = Sms( sid=message.sid, submission_time=datetime.now(), body=message.body, phone_num=message.from_) sms_tmp.invalid_field = True try: err = sms_tmp.save() except IntegrityError: pass #delete_twilio_feedback(message.sid) else: messages = client.messages.list(to=restaurant_phone_number, date_sent=datetime.today()) for message in messages: message_key = [] for key in valid_keys: if key in message.body[:len(key)]: new_body = message.body.replace(key,'') tab = Tabs.select().where(Tabs.fb_key == key) tab.fb_key = "~~~~~~~~~~" message_key.append(key) if (message_key): #i can use the date time as now because feedback comes in immediately here sms_tmp = Sms( sid=message.sid, submission_time=datetime.now(), body=new_body, phone_num=message.from_ ) res2 = feedback_analysis(sms_tmp.body) sms_tmp.pos_flag = res2[0] sms_tmp.neg_flag = res2[1] sms_tmp.exception_flag = res2[2] sms_tmp.food_flag = res2[3] sms_tmp.service_flag = res2[4] sms_tmp.invalid_field = False try: err = sms_tmp.save() except IntegrityError: pass else: try: i = message.body.index(' ') except ValueError: i = 7 pass if (one): non_accept = "Your unique key {" + message.body[:i] + "} is not valid" client.messages.create( to=message.from_, from_=restaurant_phone_number, body=non_accept,) sms_tmp = Sms( sid=message.sid, submission_time=datetime.now(), body=message.body, phone_num=message.from_, invalid_field=True ) try: err = sms_tmp.save() except IntegrityError: pass #delete_twilio_feedback(message.sid) return 1
def feedback_table(role): """ By default displays a webpage for user to make feedback DB query. Display a table of feedback sent in during a specified date-time range. Also, depending on whether category flags are specified, this page will only display that category table: table of feedback to display form: form that specifies the query instructions. Args: role(str): correct role of user in this context acquired from the require_role wrapper Returns: template: The template to display with the appropriate parameters """ #get all of the feedback objects and insert it into table form = DateSpecifyForm() if (request.method == 'POST'): pos_col, neg_col, except_col, food_col, service_col = ( -1, -1, -1, -1, -1) # -1 is a don't care term dtf = datetime.strptime(request.form['datetimefrom'], "%m/%d/%Y %I:%M %p") dtt = datetime.strptime(request.form['datetimeto'], "%m/%d/%Y %I:%M %p") + timedelta(minutes=2) query_expr = ((Sms.submission_time > dtf) & (Sms.submission_time <= dtt) & (Sms.invalid_field == False)) if (request.form.get('dropdown') == 'Good'): #print('Form Good') pos_col, neg_col = (1, 0) query_expr = ((query_expr) & (Sms.pos_flag == pos_col) & (Sms.neg_flag == neg_col)) elif (request.form.get('dropdown') == 'Bad'): pos_col, neg_col = (0, 1) query_expr = ((query_expr) & (Sms.pos_flag == pos_col) & (Sms.neg_flag == neg_col)) elif (request.form.get('dropdown') == 'Mixed'): pos_col, neg_col = (1, 1) query_expr = ((query_expr) & (Sms.pos_flag == pos_col) & (Sms.neg_flag == neg_col)) elif (request.form.get('dropdown') == 'Food'): food_col = 1 query_expr = ((query_expr) & (Sms.food_flag == food_col)) elif (request.form.get('dropdown') == 'Service'): service_col = 1 query_expr = ((query_expr) & (Sms.service_flag == service_col)) elif (request.form.get('dropdown') == 'Exception'): except_col = 1 query_expr = ((query_expr) & (Sms.exception_flag == except_col)) else: pos_col, neg_col, except_col, food_col, service_col = (-1, -1, -1, -1, -1) feedback_controller.update_db() smss = Sms.select().where(query_expr).order_by(-Sms.submission_time) res = [] all_string_bodies = "" for sms in smss: #print('pos:{} neg:{} except:{} food:{} service:{}'.format(sms.pos_flag,sms.neg_flag, sms.exception_flag, sms.food_flag, sms.service_flag)) if (type(sms.submission_time) is str): sms_dt = datetime.strptime( sms.submission_time[:-6], "%Y-%m-%d %H:%M:%S" ) #removes the +HH:MM offset in datetime else: sms_dt = sms.submission_time sms_str = sms_dt.strftime("%Y-%m-%d %H:%M:%S") res.append(dict(time=sms_str, body=sms.body)) all_string_bodies = all_string_bodies + sms.body + "," if (request.form.get('wordcloud')): wc = True [wordSet, freqs, maxfreq ] = feedback_controller.word_freq_counter(all_string_bodies) #word cloud output format word_freq = [] n = 0 for n in range(len(wordSet)): word_freq.append(dict(text=wordSet[n], weight=freqs[n])) else: wc = False word_freq = [] maxfreq = 0 # fix wc error table = ItemTable(res) else: res = [] table = ItemTable(res) if not (res == []): return render_template('feedbackM/index.html', logged_in=True, table=table, form=form, word_freq=json.dumps(word_freq), max_freq=maxfreq, role=role, wordcloud=wc) else: return render_template( 'feedbackM/index.html', logged_in=True, form=form, role=role, wordcloud=False ) # allow table to stay until it is cleared manually.