def test_reset_password(self): """ 2 step process: POST,PUT /send-reset-code which sets temporary reset_code in cleaner model and sends via SMS to cleaner POST,PUT /reset-password with {'phonenumber', 'reset_code', 'password'} --> resets password and logs in cleaner """ NEW_PASSWORD = '******' # verify process works with correct reset-code self.POST_cleaner() self.POST_data('/auth/send-reset-code', data=TEST_CLEANER_DATA) c = cleaner.find_one(id=self.cleaner['_id']) self.POST_data('/auth/reset-password', data={ 'password': '******', 'phonenumber': TEST_CLEANER_DATA['phonenumber'], 'reset_code': c['reset_code'], }) # verify user now logged in data = self.GET_data('/auth/user') self.assertEqual(data['name'], TEST_CLEANER_DATA['name']) # logout user and verify user cannot sign in with old password self.logout() rv = self.app.post('/auth/login', data=json.dumps({ 'password': TEST_CLEANER_DATA['password'], 'phonenumber': TEST_CLEANER_DATA['phonenumber']}) ) self.assertEqual(rv.status_code, 500) # verify user can login with new password rv = self.app.post('/auth/login', data=json.dumps({ 'password': NEW_PASSWORD, 'phonenumber': TEST_CLEANER_DATA['phonenumber']}) ) self.assertEqual(rv.status_code, 200)
def POST_receipt(list_id): """ Creates receipt + sends receipt to client via SMS A receipt is a snapshot of the list at time of POST When a receipt is posted, the list/receipt models do the work list.create_receipt retrieves a fully populated list and inserts the receipt @param {list_id} _id of list of which to take snapshot and save as receipt payload: Request is made with entire list object - have _cleaner as cleaner._id Returns _id of newly inserted receipt """ try: list_data = JSONencoder.load(request.data) # verify phonenumber in list_data -- need it to send link to receipt to client if not 'phonenumber' in list_data: raise APIexception(code=1) phonenumber = list_data['phonenumber'] # need to fetch cleaner for just cleaner's name in SMS message cleaner_id = list_data[ '_cleaner'] # something went wrong with request if _cleaner not in payload c = cleaner.find_one(id=cleaner_id) # create the receipt that will live forever receipt_id = List.create_receipt(list_id) # send SMS to client that has link to viewable receipt twilio_tools.send_receipt(phonenumber, c['name'], receipt_id) return dumpJSON({'_id': receipt_id}) except Exception as e: return respond500(e)
def PUT_send_list(id): """ Sends new agreement to client via SMS @param {id} _id of list to send as agreement to client payload: Request is made with entire list object - have _cleaner as cleaner._id Returns 200 response """ try: list_data = JSONencoder.load(request.data) # verify phonenumber in list_data -- need it to send link to receipt to client if not 'phonenumber' in list_data: raise APIexception(code=1) phonenumber = list_data['phonenumber'] # need to fetch cleaner for just cleaner's name in SMS message cleaner_id = list_data[ '_cleaner'] # something went wrong with request if _cleaner not in payload c = cleaner.find_one(id=cleaner_id) # send SMS to client that has link to viewable agreement twilio_tools.send_agreement(phonenumber, c['name'], id) return respond200() except Exception as e: return respond500(e)
def send_reset_code(): """ Send reset_code via SMS to the user Each reset_code expires after RESET_CODE_EXPIRATION If not yet set, or if expired, reset reset_code and reset_code_expires """ try: data = json.loads(request.data) if not 'phonenumber' in data: raise APIexception(code=1) phonenumber = data['phonenumber'] c = cleaner.find_one(phonenumber=phonenumber) if not c: raise APIexception(code=2) if ('reset_code' in c and 'reset_code_expires' in c and (datetime.now() < c['reset_code_expires'])): reset_code = c["reset_code"] else: (reset_code, reset_code_expires) = cleaner.generate_reset_code() cleaner.update(c["_id"], { "reset_code": reset_code, "reset_code_expires": reset_code_expires }) twilio_tools.send_SMS( phonenumber, str("Your password reset code is: " + reset_code)) return respond200() except Exception as e: return respond500(e)
def get_user(): """ Returns JSON encoded user if user in session, otherwise None ** Potential issue I want to avoid: cleaner (user) was deleted (via backstage or direct database interaction) or something else bazaar happened yet cleaner is somehow still in session If this occurs - take user out of session """ if not ('user' in session and session['user']): return None # **see note above user = JSONencoder.load(session['user']) if not cleaner.find_one(id=user['_id']): session['user'] = None return session['user']
def POST_reset_password(): try: data = json.loads(request.data) c = cleaner.find_one(phonenumber=data['phonenumber']) if not (c and 'reset_code' in c): raise APIexception(code=0) if not ((data['reset_code'] == c["reset_code"]) and (datetime.now() < c['reset_code_expires'])): raise APIexception(code=3) # if they made it this far all is good cleaner.update_password(c["_id"], data["password"], c["salt"]) login(cleaner.public(c)) return respond200() except Exception as e: return respond500(e)
def test_reset_password(self): """ 2 step process: POST,PUT /send-reset-code which sets temporary reset_code in cleaner model and sends via SMS to cleaner POST,PUT /reset-password with {'phonenumber', 'reset_code', 'password'} --> resets password and logs in cleaner """ NEW_PASSWORD = '******' # verify process works with correct reset-code self.POST_cleaner() self.POST_data('/auth/send-reset-code', data=TEST_CLEANER_DATA) c = cleaner.find_one(id=self.cleaner['_id']) self.POST_data('/auth/reset-password', data={ 'password': '******', 'phonenumber': TEST_CLEANER_DATA['phonenumber'], 'reset_code': c['reset_code'], }) # verify user now logged in data = self.GET_data('/auth/user') self.assertEqual(data['name'], TEST_CLEANER_DATA['name']) # logout user and verify user cannot sign in with old password self.logout() rv = self.app.post('/auth/login', data=json.dumps({ 'password': TEST_CLEANER_DATA['password'], 'phonenumber': TEST_CLEANER_DATA['phonenumber'] })) self.assertEqual(rv.status_code, 500) # verify user can login with new password rv = self.app.post('/auth/login', data=json.dumps({ 'password': NEW_PASSWORD, 'phonenumber': TEST_CLEANER_DATA['phonenumber'] })) self.assertEqual(rv.status_code, 200)
def POST_feedback(list_id): """ @param {list_id} _id of list that is owner of feedback payload: feedback data Sends notification via SMS to cleaner that feedback has been sent with link to list Returns _id of newly inserted feedback """ try: feedback_data = JSONencoder.load(request.data) feedback_id = List.add_feedback(list_id, feedback_data) # get list and cleaner so that can send SMS l = List.find_one(id=list_id) c = cleaner.find_one(id=l['_cleaner']) twilio_tools.send_feedback_notification(c['phonenumber'], c['name'], list_id) return dumpJSON({'_id': feedback_id}) except Exception as e: return respond500(e)
def POST_login(): try: data = json.loads(request.data) if not ("phonenumber" in data and "password" in data): # client-side shouldn't have allowed post raise APIexception( code=0, message="phonenumber and password required to sign in") c = cleaner.find_one(phonenumber=data["phonenumber"]) if not c: raise APIexception(code=2) if not cleaner.password_valid(data["password"], c["salt"], c["hashed_pwd"]): raise APIexception(code=4) profile = cleaner.public(c) login(profile) return dumpJSON(profile) except Exception as e: return respond500(e)
def GET_cleaner_by_id(id): try: return dumpJSON(cleaner.find_one(id=id)) except Exception as e: return respond500(e)