def trigger(email): phone_tokens_collection.delete_many({ '$or': [{ '$and': [ { 'timestamp_issued': { '$lt': timing.get_current_time(offset_minutes=-3) } }, { 'phone_number': '' }, ] }, { 'email': email }] }) # Generate new token # By including the existing tokens a duplicate token error is impossible, # however the token generation might take longer and is non-deterministic existing_tokens = [ document['token'] for document in list( phone_tokens_collection.find({}, { '_id': 0, 'token': 1 })) ] token = tokening.generate_random_key(length=5, numeric=True, existing_tokens=existing_tokens) # Create new token record new_record = { 'email': email, 'token': token, 'timestamp_issued': timing.get_current_time(), 'phone_number': '', } phone_tokens_collection.insert_one(new_record) # Trigger token-email return formatting.status('ok', token=token)
def create_account(params_dict): email = params_dict["account"]["email"] password = params_dict["account"]["password"] zip_code = params_dict["account"]["zip_code"] country = params_dict["account"]["country"] current_timestamp = timing.get_current_time() new_helper = { 'email': email, 'account': { 'register_date': timing.datetime_to_string(current_timestamp), 'email_verified': False, 'phone_number': '', 'phone_number_verified': False, 'hashed_password': tokening.hash_password(password), 'zip_code': zip_code, 'country': country, }, 'filter': { 'call_type': { 'only_local': False, 'only_global': False, }, 'language': { 'german': False, 'english': False, }, }, 'forward': { 'online': False, 'stay_online_after_call': False, 'schedule_active': False, 'schedule': [], 'last_modified': current_timestamp } } try: # inserting helper document helper_id = helper_accounts_collection.insert_one( new_helper).inserted_id except DuplicateKeyError as e: # If two people sign up exactla at once # (verfication done but inserting fails for one) print(f'DuplicateKeyError: {e}') return formatting.status('email already taken') # Send verification email and add verification record email_verification.trigger(email) # login and return email/api_key dict return helper_authentication.helper_login_password(email, password)
def modify_forward(params_dict): # params_dict["forward"] has already been validated params_dict["forward"].update({'last_modified': timing.get_current_time()}) helper_accounts_collection.update_one( {'email': params_dict["email"]}, {'$set': { 'forward': params_dict["forward"] }}) return formatting.status("ok")
def verify(token, phone_number): record = phone_tokens_collection.find_one({ 'token': token, 'timestamp_issued': { '$gt': timing.get_current_time(offset_minutes=-3) }, }) if record is None: return formatting.status('token invalid'), 400 phone_tokens_collection.update_one( {'token': token}, {'$set': { 'phone_number': phone_number }}) return formatting.status('ok'), 200
def fulfill_call(call_id, helper_id): # call_id and agent_id are assumed to be valid current_timestamp = timing.get_current_time() # Change call formatting.status call_update = { 'status': 'fulfilled', 'timestamp_fulfilled': current_timestamp } calls_collection.update_one({'_id': ObjectId(call_id)}, {'$set': call_update}) new_behavior_log = { 'helper_id': ObjectId(helper_id), 'call_id': ObjectId(call_id), 'timestamp': current_timestamp, 'action': 'fulfilled', } helper_behavior_collection.insert_one(new_behavior_log)
def add_call(caller_id, language, call_type='', zip_code=''): current_timestamp = timing.get_current_time() # local is boolean new_call = { 'caller_id': ObjectId(caller_id), 'call_type': [call_type], 'zip_code': zip_code, 'language': language, 'feedback_granted': False, 'confirmed': False, 'helper_id': 0, 'status': 'pending', 'comment': '', 'timestamp_received': current_timestamp, 'timestamp_accepted': current_timestamp, 'timestamp_fulfilled': current_timestamp, } call_id = calls_collection.insert_one(new_call).inserted_id return formatting.status('ok', call_id=call_id)
def reject_call(call_id, helper_id): # Change call formatting.status call_update_dict_1 = { "$set": { 'status': 'pending', 'helper_id': 0, 'comment': '', } } # accepted-match if local call was accepted from local queue (successful) # accepted-mismatch if local call was accepted from global/urgent queue (not successful) call_update_dict_2 = { "$pull": { "call_type": { "$in": ["forwarded", "accepted-match", "accepted-mismatch"] }, } } operations = [ UpdateOne({"_id": ObjectId(call_id)}, call_update_dict_1), UpdateOne({"_id": ObjectId(call_id)}, call_update_dict_2) ] calls_collection.bulk_write(operations) enqueue.enqueue(call_id) new_behavior_log = { 'helper_id': ObjectId(helper_id), 'call_id': ObjectId(call_id), 'timestamp': timing.get_current_time(), 'action': 'rejected', } helper_behavior_collection.insert_one(new_behavior_log)
def dequeue(helper_id, zip_code=None, only_local=None, only_global=None, german=None, english=None): current_timestamp = timing.get_current_time() if only_local and only_global: return formatting.status( 'invalid function call - only_local = only_global = True') # Step 1) Find the helpers zip_code if any([e is None] for e in [zip_code, only_local, only_global, english, german]) is None: helper = helper_accounts_collection.find_one( {'_id': ObjectId(helper_id)}) if helper is None: return formatting.status('helper_id invalid') zip_code = helper['zip_code'] if (zip_code is None) else zip_code only_local = helper['filter_type_local'] if ( only_local is None) else only_local only_global = helper['filter_type_global'] if ( only_global is None) else only_global german = helper['filter_language_german'] if ( german is None) else german english = helper['filter_language_english'] if ( english is None) else english language_list = [] language_list += ['german'] if german else [] language_list += ['english'] if english else [] zip_codes_list = fetching.get_adjacent_zip_codes(zip_code) if ( zip_code != '') else [] projection_dict = {} # Step 2) Find Call if only_local: filter_dict = { 'call_type': { "$elemMatch": { "$eq": 'local' } }, 'zip_code': { '$in': zip_codes_list }, 'language': { '$in': language_list } } call = call_queue.find_one_and_delete( filter_dict, projection_dict, sort=[('timestamp_received', 1)], ) elif only_global: filter_dict = { 'call_type': { "$elemMatch": { "$eq": 'global' } }, 'language': { '$in': language_list } } call = call_queue.find_one_and_delete( filter_dict, projection_dict, sort=[('timestamp_received', 1)], ) else: # 1. Urgent Queue filter_dict = { 'timestamp_received': { '$lt': timing.get_current_time(offset_seconds=-global_timeout_seconds) } } call = call_queue.find_one_and_delete( filter_dict, projection_dict, sort=[('timestamp_received', 1)], ) # 2. Local Queue if call is None: filter_dict = { 'call_type': { "$elemMatch": { "$eq": 'local' } }, 'zip_code': { '$in': zip_codes_list }, 'language': { '$in': language_list } } call = call_queue.find_one_and_delete( filter_dict, projection_dict, sort=[('timestamp_received', 1)], ) # 3. Global Queue if call is None: # Or chain needed so that calls in other regions which # are not in the global queue yet get assigned filter_dict = { '$or': [{ 'call_type': { "$elemMatch": { "$eq": 'local' } }, 'timestamp_received': { '$lt': timing.get_current_time( offset_seconds=-local_timeout_seconds) } }, { 'call_type': { "$elemMatch": { "$eq": 'global' } } }] }, call = call_queue.find_one_and_delete( filter_dict, projection_dict, sort=[('timestamp_received', 1)], ) if call is None: return formatting.status('currently no call available') call_id = call['call_id'] # Step 3) Update call (helper_id, formatting.status, timestamp_accepted) call_update_dict_1 = { "$set": { 'status': 'accepted', 'helper_id': ObjectId(helper_id), 'timestamp_accepted': current_timestamp } } print(f"call = {call}") # accepted-match if local call was accepted from local queue (successful) or global call # accepted-mismatch if local call was matched with non-local helper if "local" in call["call_type"] and call["zip_code"] not in zip_codes_list: new_call_type = "accepted-mismatch" else: new_call_type = "accepted-match" call_update_dict_2 = { "$push": { "call_type": new_call_type, } } operations = [ UpdateOne({'_id': ObjectId(call_id)}, call_update_dict_1), UpdateOne({'_id': ObjectId(call_id)}, call_update_dict_2) ] calls_collection.bulk_write(operations) # Step 4) Add helper behavior (helper_id, call_id, timestamp, action='accepted' new_behavior_log = { 'helper_id': ObjectId(helper_id), 'call_id': ObjectId(call_id), 'timestamp': current_timestamp, 'action': 'accepted', } helper_behavior_collection.insert_one(new_behavior_log) return formatting.status('ok')