def add_bh_offer_api(): """adds a blackhawk offer to the db. the offer_id must already exist in the offers table""" if not config.DEBUG: limit_to_localhost() try: payload = request.get_json(silent=True) offer_id = payload.get('offer_id', None) merchant_code = payload.get('merchant_code', None) merchant_template_id = payload.get('merchant_template_id', None) batch_size = payload.get('batch_size', None) denomination = payload.get('denomination', None) minimum_threshold = payload.get('minimum_threshold', None) if None in (offer_id, merchant_code, merchant_template_id, batch_size, denomination, minimum_threshold): raise InvalidUsage('bad-request') except Exception as e: print(e) raise InvalidUsage('bad-request') if create_bh_offer(offer_id, merchant_code, merchant_template_id, batch_size, denomination, minimum_threshold): return jsonify(status='ok') else: raise InvalidUsage('failed to add blackhawk offer')
def register(): ''' register a user to the system. called once by every client until 200OK is received from the server. the payload may contain a optional push token. ''' payload = request.get_json(silent=True) try: user_id = payload.get('user_id', None) os = payload.get('os', None) device_model = payload.get('device_model', None) token = payload.get('token', None) time_zone = payload.get('time_zone', None) device_id = payload.get('device_id', None) app_ver = payload.get('app_ver', None) #TODO more input check on the values if None in ( user_id, os, device_model, time_zone, app_ver ): # token is optional, device-id is required but may be None raise InvalidUsage('bad-request') if os not in ('iOS', 'android'): raise InvalidUsage('bad-request') user_id = UUID(user_id) # throws exception on invalid uuid except Exception as e: raise InvalidUsage('bad-request') else: try: create_user(user_id, os, device_model, token, time_zone, device_id, app_ver) except InvalidUsage as e: raise InvalidUsage('duplicate-userid') else: print('created user with user_id %s' % (user_id)) return jsonify(status='ok')
def user_ids_list_blacklist_endpoint(): """ block a list of users by there ids""" if not config.DEBUG: limit_to_localhost() try: payload = request.get_json(silent=True) user_ids = payload.get('user_ids', None) if user_ids is None: print('user_ids_list_blacklist_endpoint: ids: %s' % user_ids) raise InvalidUsage('bad-request') blacklisted, unable_to_blacklist, already_blacklisted, no_phone_number = [],[],[],[] for user_id in user_ids: user = get_user(user_id) if not user.enc_phone_number: no_phone_number.append(user_id) elif is_enc_phone_number_blacklisted(user.enc_phone_number): already_blacklisted.append(user_id) elif not blacklist_enc_phone_number(user.enc_phone_number): unable_to_blacklist.append(user_id) # for later retry else: blacklisted.append(user_id) return jsonify(blacklisted=blacklisted, already_blacklisted=already_blacklisted, unable_to_blacklist=unable_to_blacklist) except Exception as e: print(e) raise InvalidUsage('bad-request')
def quest_answers(): '''receive the results for a tasks and pay the user for them''' payload = request.get_json(silent=True) try: user_id = extract_header(request) task_id = payload.get('id', None) address = payload.get('address', None) results = payload.get('results', None) send_push = payload.get('send_push', True) if None in (user_id, task_id, address, results): raise InvalidUsage('bad-request') #TODO more input checks here except Exception as e: raise InvalidUsage('bad-request') if not store_task_results(user_id, task_id, results): # should never happen: the client sent the results too soon print('rejecting user %s task %s results' % (user_id, task_id)) increment_metric('premature_task_results') return jsonify(status='error', reason='cooldown_enforced'), status.HTTP_400_BAD_REQUEST try: memo = utils.KINIT_MEMO_PREFIX + str(uuid4( ))[:utils. ORDER_ID_LENGTH] # generate a memo string and send it to the client reward_store_and_push(address, task_id, send_push, user_id, memo) except Exception as e: print('exception: %s' % e) print('failed to reward task %s at address %s' % (task_id, address)) increment_metric('task_completed') return jsonify(status='ok', memo=str(memo))
def purchase_api(): '''process the given tx_hash and return the payed-for goods''' #TODO: at some point we should try to listen in on incoming tx_hashes # for our account(s). this should hasten the process of reedeming offers. payload = request.get_json(silent=True) try: user_id = extract_header(request) tx_hash = payload.get('tx_hash', None) if None in (user_id, tx_hash): raise InvalidUsage('invalid param') except Exception as e: print('exception: %s' % e) raise InvalidUsage('bad-request') try: # process the tx_hash, provided its not already being processed by another server lock = redis_lock.Lock(app.redis, 'redeem:%s' % tx_hash) if lock.acquire(blocking=False): success, goods = process_order(user_id, tx_hash) if not success: raise InvalidUsage('cant redeem with tx_hash:%s' % tx_hash) increment_metric('offers_redeemed') return jsonify(status='ok', goods=goods) else: return jsonify(status='error', reason='already processing tx_hash') finally: lock.release()
def get_cost_and_address(offer_id): '''return the kin cost and address associated with this offer''' offer = Offer.query.filter_by(offer_id=offer_id).first() if not offer: raise InvalidUsage('no such offer_id') if not offer.is_active: raise InvalidUsage('offer is not active') return offer.kin_cost, offer.address
def get_offers_api(): '''return the list of availble offers for this user''' try: user_id = extract_header(request) if user_id is None: raise InvalidUsage('no user_id') except Exception as e: print('exception: %s' % e) raise InvalidUsage('bad-request') print('offers %s' % get_offers_for_user(user_id)) return jsonify(offers=get_offers_for_user(user_id))
def add_task_api(): #limit_to_local_host() payload = request.get_json(silent=True) try: task = payload.get('task', None) except Exception as e: print('exception: %s' % e) raise InvalidUsage('bad-request') if add_task(task): return jsonify(status='ok') else: raise InvalidUsage('failed to add task')
def send_gcm_push(): '''temp endpoint for testing gcm TODO remove''' payload = request.get_json(silent=True) try: push_payload = payload.get('push_payload', None) push_token = payload.get('push_token', None) if None in (push_token, push_payload): raise InvalidUsage('bad-request') except Exception as e: print('exception: %s' % e) raise InvalidUsage('bad-request') send_gcm(push_token, push_payload) return jsonify(status='ok')
def update_token(): ''' update a user's token in the database ''' payload = request.get_json(silent=True) try: user_id = extract_header(request) token = payload.get('token', None) if None in (user_id, token): raise InvalidUsage('bad-request') except Exception as e: raise InvalidUsage('bad-request') print('updating token for user %s' % user_id) update_user_token(user_id, token) return jsonify(status='ok')
def update_task_time_endpoint(): '''temp endpoint for setting a task time TODO DELETE ME''' payload = request.get_json(silent=True) try: task_id = str(payload.get('task_id', None)) time_string = str(payload.get('time_string', None)) if None in (task_id, time_string): raise InvalidUsage('bad-request') except Exception as e: print('exception: %s' % e) raise InvalidUsage('bad-request') update_task_time(task_id, time_string) return jsonify(status='ok')
def add_offer_api(): '''endpoint used to populate the server with offers''' if not config.DEBUG: limit_to_local_host() payload = request.get_json(silent=True) try: offer = payload.get('offer', None) set_active = payload.get('set_active', False) # optional except Exception as e: print('exception: %s' % e) raise InvalidUsage('bad-request') if add_offer(offer, set_active): return jsonify(status='ok') else: raise InvalidUsage('failed to add offer')
def set_active_app_discovery_api(): """ enable/ disable discovery app""" if not config.DEBUG: limit_to_localhost() payload = request.get_json(silent=True) try: app_id = payload.get('app_id', None) set_active = payload.get('set_active', False) # optional except Exception as e: print('exception: %s' % e) raise InvalidUsage('bad-request') if set_discovery_app_active(app_id, set_active): return jsonify(status='ok') else: raise InvalidUsage('failed to activate discovery app')
def add_discovery_app_category_api(): """ add a discovery app category to the db""" if not config.DEBUG: limit_to_localhost() payload = request.get_json(silent=True) try: discovery_app_category = payload.get('discovery_app_category', None) except Exception as e: print('exception: %s' % e) raise InvalidUsage('bad-request') if add_discovery_app_category(discovery_app_category): return jsonify(status='ok') else: raise InvalidUsage('failed to add discovery app')
def post_task_results_endpoint(): """an endpoint that can be used to return task results for bi""" limit_to_acl() limit_to_password() try: payload = request.get_json(silent=True) task_id = payload.get('task_id', None) if task_id is None: raise InvalidUsage('bad-request') except Exception as e: print(e) raise InvalidUsage('bad-request') return jsonify(status='ok', results=get_task_results(task_id))
def add_task_endpoint(): """used to add tasks to the db""" if not config.DEBUG: limit_to_localhost() payload = request.get_json(silent=True) try: task = payload.get('task', None) except Exception as e: print('exception: %s' % e) raise InvalidUsage('bad-request') if add_task(task): return jsonify(status='ok') else: raise InvalidUsage('failed to add task')
def set_active_api(): '''enables/disables an offer''' if not config.DEBUG: limit_to_local_host() payload = request.get_json(silent=True) try: offer_id = payload.get('id', None) is_active = payload.get('is_active', None) except Exception as e: print('exception: %s' % e) raise InvalidUsage('bad-request') if set_offer_active(offer_id, is_active): return jsonify(status='ok') else: raise InvalidUsage('failed to set offer status')
def store_task_results(user_id, task_id, results): '''store the results provided by the user''' # reject hackers trying to send task results too soon if reject_premature_results(get_next_task_results_ts(user_id)): print('rejecting premature results for user %s' % user_id) return False try: # store the results userTaskResults = UserTaskResults() userTaskResults.user_id = user_id userTaskResults.task_id = task_id userTaskResults.results = results db.session.add(userTaskResults) # write down the completed task-id from kinappserver.models import UserAppData user_app_data = UserAppData.query.filter_by(user_id=user_id).first() if user_app_data is None: raise('cant retrieve user app data for user:%s' % user_id) completed_tasks = json.loads(user_app_data.completed_tasks) completed_tasks.append(task_id) user_app_data.completed_tasks = json.dumps(completed_tasks) db.session.add(user_app_data) db.session.commit() return True except Exception as e: print(e) raise InvalidUsage('cant store_task_results')
def get_categories_for_user(user_id): """returns an array of categories tailored to this specific user""" import time from .user import user_exists, get_user_os_type if not user_exists(user_id): raise InvalidUsage('no such user_id %s' % user_id) os_type = get_user_os_type(user_id) s_time = int(round(time.time() * 1000)) all_cats = list_categories(os_type) e_time = int(round(time.time() * 1000)) log.info('all_cats for user %s with os_type %s: %s -- ptime: %s', user_id, os_type, all_cats, str(e_time - s_time)) from .task2 import count_immediate_tasks s_time = int(round(time.time() * 1000)) immediate_tasks = count_immediate_tasks(user_id) e_time = int(round(time.time() * 1000)) log.info('count_immediate_tasks ptime for user_id %s is: %s', user_id, str(e_time - s_time)) for cat_id in all_cats.keys(): all_cats[cat_id]['available_tasks_count'] = immediate_tasks[cat_id] return [cat for cat in all_cats.values()]
def add_task(task_json): try: # sanity for task data for item in task_json['items']: if item['type'] not in ['textimage', 'text']: raise InvalidUsage('cant add task with invalid item-type') task = Task() task.task_id = task_json['id'] task.task_type = task_json['type'] task.title = task_json['title'] task.desc = task_json['desc'] task.price = int(task_json['price']) task.min_to_complete = int(task_json['min_to_complete']) task.provider_data = task_json['provider'] task.tags = task_json['tags'] task.items = task_json['items'] print(task_json['start_date']) task.start_date = arrow.get(task_json['start_date']) print("the task: %s" % task.start_date) db.session.add(task) db.session.commit() except Exception as e: print(e) print('cant add task to db with id %s' % task_json['id']) return False else: return True
def get_user_backup_hints_by_enc_phone(enc_phone_number): """return the user backup hints object for the given enc_phone_number or throws exception""" ubh = PhoneBackupHints.query.filter_by( enc_phone_number=enc_phone_number).first() if not ubh: raise InvalidUsage('no such enc_phone_number') return ubh
def extract_header(request): '''extracts the user_id from the request header''' try: return request.headers.get('X-USERID') except Exception as e: print('cant extract user_id from header') raise InvalidUsage('bad header')
def create_user(user_id, os_type, device_model, push_token, time_zone, device_id, app_ver): '''create a new user and commit to the database. should only fail if the user_id is duplicate''' def parse_timezone(tz): '''convert -02:00 to -2 etc''' return int(tz[:(tz.find(':'))]) if user_exists(user_id): raise InvalidUsage( 'refusing to create user. user_id %s already exists' % user_id) user = User() user.user_id = user_id user.os_type = os_type user.device_model = device_model user.push_token = push_token user.time_zone = parse_timezone(time_zone) user.device_id = device_id db.session.add(user) db.session.commit() user_app_data = UserAppData() user_app_data.user_id = user_id user_app_data.completed_tasks = '[]' user_app_data.app_ver = app_ver user_app_data.next_task_ts = None db.session.add(user_app_data) db.session.commit()
def set_force_update_below(os_type, app_ver): """sets the given app_ver for the given os_type as into the db""" if os_type not in (OS_ANDROID, OS_IOS): raise InvalidUsage('invalid os type: %s' % os_type) if app_ver in (None, ''): raise InvalidUsage('invalid app_ver: %s' % app_ver) sysconfig = db.session.query(SystemConfig).one() if os_type == OS_ANDROID: sysconfig.block_clients_below_version_android = app_ver elif os_type == OS_IOS: sysconfig.block_clients_below_version_ios = app_ver db.session.add(sysconfig) db.session.commit() log.info('set force-update-below for os_type %s to %s' % (os_type, app_ver))
def add_discovery_app_api(): """ internal endpoint used to populate the server with discovery apps""" if not config.DEBUG: limit_to_localhost() payload = request.get_json(silent=True) try: discovery_app = payload.get('discovery_app', None) set_active = payload.get('set_active', False) # optional except Exception as e: print('exception: %s' % e) raise InvalidUsage('bad-request') if add_discovery_app(discovery_app, set_active): return jsonify(status='ok') else: raise InvalidUsage('failed to add discovery app')
def unblock_user_from_truex_tasks(user_id): """remove a user from the truex list""" tbuser = TruexBlacklistedUser.query.filter_by(user_id=user_id).first() if not tbuser: raise InvalidUsage('cant find blocked user with user_id %s' % user_id) db.session.delete(tbuser) db.session.commit()
def user_goods_report_endpoint(): """returns a summary of the user's goods data""" limit_to_acl() limit_to_password() try: payload = request.get_json(silent=True) user_id = payload.get('user_id', None) user_phone = payload.get('phone', None) if (user_id is None and user_phone is None) or (user_id is not None and user_phone is not None): print('user_goods_report_endpoint: userid %s, user_phone %s' % (user_id, user_phone)) raise InvalidUsage('bad-request') except Exception as e: print(e) raise InvalidUsage('bad-request') try: # sanitize user_id: if user_id: UUID(user_id) except Exception as e: log.error('cant generate tx report for user_id: %s ' % user_id) return jsonify(error='invalid_userid') if user_id: if not user_exists(user_id): print( 'user_goods_report_endpoint: user_id %s does not exist. aborting' % user_id) return jsonify(erorr='no_such_user') else: return jsonify(report=[get_user_goods_report(user_id)]) else: # user_phone user_ids = get_all_user_id_by_phone( user_phone) # there may be a few users with this phone if not user_ids: print( 'user_goods_report_endpoint: user_phone %s does not exist. aborting' % user_phone) return jsonify(erorr='no_such_phone') else: return jsonify(report=[ get_user_goods_report(user_id) for user_id in user_ids ])
def onboard_user(): '''creates a wallet for the user and deposits some xlms there''' # input sanity try: user_id = extract_header(request) public_address = request.get_json(silent=True).get( 'public_address', None) if None in (public_address, user_id): raise InvalidUsage('bad-request') except Exception as e: raise InvalidUsage('bad-request') # ensure the user exists but does not have an account: onboarded = is_onboarded(user_id) if onboarded is True: raise InvalidUsage('user already has an account') elif onboarded is None: raise InvalidUsage('no such user exists') else: # create an account, provided none is already being created lock = redis_lock.Lock(app.redis, 'address:%s' % public_address) if lock.acquire(blocking=False): try: print('creating account with address %s and amount %s' % (public_address, config.STELLAR_INITIAL_ACCOUNT_BALANCE)) tx_id = create_account(public_address, config.STELLAR_INITIAL_ACCOUNT_BALANCE) if (tx_id): set_onboarded(user_id, True) else: raise InternalError('failed to create account at %s' % public_address) except Exception as e: print('exception trying to create account:%s' % e) raise InternalError('unable to create account') else: print('created account %s with txid %s' % (public_address, tx_id)) finally: lock.release() else: raise InvalidUsage( 'already creating account for user_id: %s and address: %s' % (user_id, public_address)) increment_metric('user_onboarded') return jsonify(status='ok')
def delete_task(task_id): if not get_task_by_id(task_id): log.error('no task with id %s in the db' % task_id) raise InvalidUsage('task_id %s doesnt exist - cant delete' % task_id) task_to_delete = Task2.query.filter_by(task_id=task_id).first() db.session.delete(task_to_delete) db.session.commit()
def set_delay_days_api(): """used to set the delay_days on all tasks - used in tests""" if not config.DEBUG: limit_to_localhost() payload = request.get_json(silent=True) try: delay_days = payload.get('days', None) if delay_days is None: raise InvalidUsage('missing days param') except Exception as e: print('exception: %s' % e) raise InvalidUsage('bad-request') set_delay_days(delay_days) print('set delay days to %s' % delay_days) return jsonify(status='ok')