def mark_as_teacher(): if not is_admin(request): return 'unauthorized', 403 body = request.json # Validations if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'username', 'str'): return 'body.username must be a string', 400 if not object_check(body, 'is_teacher', 'bool'): return 'body.is_teacher must be boolean', 400 user = db_get('users', {'username': body['username'].strip().lower()}) if not user: return 'invalid username', 400 db_update( 'users', { 'username': user['username'], 'is_teacher': 1 if body['is_teacher'] else 0 }) return '', 200
def verify_email(): username = request.args.get('username', None) token = request.args.get('token', None) if not token: return 'no token', 400 if not username: return 'no username', 400 user = db_get('users', {'username': username}) if not user: return 'invalid username/token', 403 # If user is verified, succeed anyway if not 'verification_pending' in user: return redirect('/') if token != user['verification_pending']: return 'invalid username/token', 403 db_update('users', { 'username': username, 'verification_pending': None }) return redirect('/')
def reset(): body = request.json # Validations if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'username', 'str'): return 'body.username must be a string', 400 if not object_check(body, 'token', 'str'): return 'body.token must be a string', 400 if not object_check(body, 'password', 'str'): return 'body.password be a string', 400 if len(body['password']) < 6: return 'password must be at least six characters long', 400 # There's no need to trim or lowercase username, because it should come within a link prepared by the app itself and not inputted manually by the user. token = db_get('tokens', {'id': body['username']}) if not token: return 'invalid username/token', 403 if not check_password(body['token'], token['token']): return 'invalid username/token', 403 hashed = hash(body['password'], make_salt()) token = db_del('tokens', {'id': body['username']}) db_update('users', {'username': body['username'], 'password': hashed}) user = db_get('users', {'username': body['username']}) if not is_testing_request(request): send_email_template('reset_password', user['email'], requested_lang(), None) return '', 200
def login(): body = request.json # Validations if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'username', 'str'): return 'username must be a string', 400 if not object_check(body, 'password', 'str'): return 'password must be a string', 400 # If username has an @-sign, then it's an email if '@' in body['username']: user = db_get('users', {'email': body['username'].strip().lower()}, True) else: user = db_get('users', {'username': body['username'].strip().lower()}) if not user: return 'invalid username/password', 403 if not check_password(body['password'], user['password']): return 'invalid username/password', 403 # If the number of bcrypt rounds has changed, create a new hash. new_hash = None if config['bcrypt_rounds'] != extract_bcrypt_rounds(user['password']): new_hash = hash(body['password'], make_salt()) cookie = make_salt() db_create( 'tokens', { 'id': cookie, 'username': user['username'], 'ttl': times() + session_length }) if new_hash: db_update( 'users', { 'username': user['username'], 'password': new_hash, 'last_login': timems() }) else: db_update('users', { 'username': user['username'], 'last_login': timems() }) resp = make_response({}) # We set the cookie to expire in a year, just so that the browser won't invalidate it if the same cookie gets renewed by constant use. # The server will decide whether the cookie expires. resp.set_cookie(cookie_name, value=cookie, httponly=True, secure=True, samesite='Lax', path='/', max_age=365 * 24 * 60 * 60) return resp
def save_program(user): body = request.json if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'code', 'str'): return 'code must be a string', 400 if not object_check(body, 'name', 'str'): return 'name must be a string', 400 if not object_check(body, 'level', 'int'): return 'level must be an integer', 400 if 'adventure_name' in body: if not object_check(body, 'adventure_name', 'str'): return 'if present, adventure_name must be a string', 400 name = body['name'] # We check if a program with a name `xyz` exists in the database for the username. # It'd be ideal to search by username & program name, but since DynamoDB doesn't allow searching for two indexes at the same time, this would require to create a special index to that effect, which is cumbersome. # For now, we bring all existing programs for the user and then search within them for repeated names. programs = db_get_many('programs', {'username': user['username']}, True) program = {} overwrite = False for program in programs: if program['name'] == name: overwrite = True break stored_program = { 'id': program.get('id') if overwrite else uuid.uuid4().hex, 'session': session_id(), 'date': timems(), 'lang': requested_lang(), 'version': version(), 'level': body['level'], 'code': body['code'], 'name': name, 'username': user['username'] } if 'adventure_name' in body: stored_program['adventure_name'] = body['adventure_name'] if overwrite: db_update('programs', stored_program) else: db_create('programs', stored_program) program_count = 0 if 'program_count' in user: program_count = user['program_count'] db_update('users', { 'username': user['username'], 'program_count': program_count + 1 }) return jsonify({'name': name})
def delete_program (user, program_id): result = db_get ('programs', {'id': program_id}) if not result or result ['username'] != user ['username']: return "", 404 db_del ('programs', {'id': program_id}) program_count = 0 if 'program_count' in user: program_count = user ['program_count'] db_update ('users', {'username': user ['username'], 'program_count': program_count - 1}) return redirect ('/programs')
def check_task(): ''' 检查任务 ''' #@tornado.web.authenticated now = datetime.datetime.now() now_date_s = now.strftime('%Y-%m-%d') print '---check_task start---', now #检查每日任务 everyday_tasks = preload_b_e.find() for e_t in everyday_tasks: e_start_time = e_t['start_time'] e_start_hour, e_start_min = e_start_time.split(':') if now.hour == int(e_start_hour) and now.minute == int(e_start_min): #创建定时任务 resource_url = e_t['resource_url'].replace('$date', now_date_s) preload_b.insert({ 'username': e_t['username'], 'start_datetime': now, 'created_time': now, 'resource_url': resource_url, 'group_detail': e_t['group_detail'], 'run_datetime': '', 'finish_datetime': '', 'concurrency': e_t['concurrency'], 'e_id': e_t['_id'] }) tasks = preload_b.find({ 'run_datetime': "", "start_datetime": { "$lte": now } }) to_run = [] for task in tasks: task_id = task['_id'] old_res = preload_b_result.find({'task_id': task_id}).count() #2次检查 if old_res > 0: continue to_run.append(task) #print to_run for t in to_run: send(t) db_update(preload_b, {'_id': ObjectId(t['_id'])}, {"$set": { "run_datetime": now }}) print '---check_task start over---'
def post(self, task_id): login_name, authority = get_login_name(self) author_secure = get_login_author_secure(self) task = preload_b.find_one({'_id': ObjectId(task_id)}) if not task: self.write(error_res('no task')) return # if task['run_datetime']: # self.write(error_res('task had started')) # return now = datetime.datetime.now() username = self.get_argument('username', '') start_datetime_str = self.get_argument('start_datetime', '') start_datetime = datetime.datetime.strptime(start_datetime_str, '%Y-%m-%d %H:%M') #if start_datetime < now: # raise resource_url = self.get_argument('resource_url', '') concurrency = int(self.get_argument('concurrency', 0)) group_detail = [] group_num = int(self.get_argument('group_num', 0)) for g_n in xrange(group_num): new_g = g_n + 1 clients = self.get_argument('%s-client' % (new_g)) client_ips = clients.split('&') servers = self.get_argument('%s-server' % (new_g)) server_ips = servers.split('&') group_detail.append([client_ips, server_ips]) print '------TaskChange------' print username print start_datetime print resource_url print group_detail print concurrency print '------TaskChange over------' db_update(preload_b, {'_id': ObjectId(task_id)}, { '$set': { 'username': username, 'start_datetime': start_datetime, 'resource_url': resource_url, 'group_detail': group_detail, 'concurrency': concurrency } }) self.redirect('/tasks')
def share_unshare_program(user): body = request.json if not type_check (body, 'dict'): return 'body must be an object', 400 if not object_check (body, 'id', 'str'): return 'id must be a string', 400 if not object_check (body, 'public', 'bool'): return 'public must be a string', 400 result = db_get ('programs', {'id': body ['id']}) if not result or result ['username'] != user ['username']: return 'No such program!', 404 db_update ('programs', {'id': body ['id'], 'public': 1 if body ['public'] else None}) return jsonify({})
def change_user_email(): if not is_admin(request): return 'unauthorized', 403 body = request.json # Validations if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'username', 'str'): return 'body.username must be a string', 400 if not object_check(body, 'email', 'str'): return 'body.email must be a string', 400 if not valid_email(body['email']): return 'email must be a valid email', 400 user = db_get('users', {'username': body['username'].strip().lower()}) if not user: return 'invalid username', 400 token = make_salt() hashed_token = hash(token, make_salt()) # We assume that this email is not in use by any other users. In other words, we trust the admin to enter a valid, not yet used email address. db_update( 'users', { 'username': user['username'], 'email': body['email'], 'verification_pending': hashed_token }) # If this is an e2e test, we return the email verification token directly instead of emailing it. if is_testing_request(request): resp = {'username': user['username'], 'token': hashed_token} else: send_email_template( 'welcome_verify', body['email'], requested_lang(), os.getenv('BASE_URL') + '/auth/verify?username='******'username']) + '&token=' + urllib.parse.quote_plus(hashed_token)) return '', 200
def change_password(user): body = request.json if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'old_password', 'str'): return 'body.old_password must be a string', 400 if not object_check(body, 'new_password', 'str'): return 'body.new_password must be a string', 400 if len(body['new_password']) < 6: return 'password must be at least six characters long', 400 if not check_password(body['old_password'], user['password']): return 'invalid username/password', 403 hashed = hash(body['new_password'], make_salt()) db_update('users', {'username': user['username'], 'password': hashed}) if not is_testing_request(request): send_email_template('change_password', user['email'], requested_lang(), None) return '', 200
def save_program (user): body = request.json if not type_check (body, 'dict'): return 'body must be an object', 400 if not object_check (body, 'code', 'str'): return 'code must be a string', 400 if not object_check (body, 'name', 'str'): return 'name must be a string', 400 if not object_check (body, 'level', 'int'): return 'level must be an integer', 400 if 'adventure_name' in body: if not object_check (body, 'adventure_name', 'str'): return 'if present, adventure_name must be a string', 400 # We execute the saved program to see if it would generate an error or not error = None try: hedy_errors = TRANSLATIONS.get_translations(requested_lang(), 'HedyErrorMessages') result = hedy.transpile(body ['code'], body ['level']) except hedy.HedyException as E: error_template = hedy_errors[E.error_code] error = error_template.format(**E.arguments) except Exception as E: error = str(E) name = body ['name'] # If name ends with (N) or (NN), we strip them since it's very likely these addenda were added by our server to avoid overwriting existing programs. name = re.sub (' \(\d+\)$', '', name) # We check if a program with a name `xyz` exists in the database for the username. If it does, we exist whether `xyz (1)` exists, until we find a program `xyz (NN)` that doesn't exist yet. # It'd be ideal to search by username & program name, but since DynamoDB doesn't allow searching for two indexes at the same time, this would require to create a special index to that effect, which is cumbersome. # For now, we bring all existing programs for the user and then search within them for repeated names. existing = db_get_many ('programs', {'username': user ['username']}, True) name_counter = 0 for program in existing: if re.match ('^' + re.escape (name) + '( \(\d+\))*', program ['name']): name_counter = name_counter + 1 if name_counter: name = name + ' (' + str (name_counter) + ')' stored_program = { 'id': uuid.uuid4().hex, 'session': session_id(), 'date': timems (), 'lang': requested_lang(), 'version': version(), 'level': body ['level'], 'code': body ['code'], 'name': name, 'server_error': error, 'username': user ['username'] } if 'adventure_name' in body: stored_program ['adventure_name'] = body ['adventure_name'] db_create('programs', stored_program) program_count = 0 if 'program_count' in user: program_count = user ['program_count'] db_update('users', {'username': user ['username'], 'program_count': program_count + 1}) return jsonify({'name': name})
def update_profile(user): body = request.json if not type_check(body, 'dict'): return 'body must be an object', 400 if 'email' in body: if not object_check(body, 'email', 'str'): return 'body.email must be a string', 400 if not valid_email(body['email']): return 'body.email must be a valid email', 400 if 'country' in body: if not body['country'] in countries: return 'body.country must be a valid country', 400 if 'birth_year' in body: if not object_check( body, 'birth_year', 'int') or body['birth_year'] <= 1900 or body[ 'birth_year'] > datetime.datetime.now().year: return 'birth_year must be a year between 1900 and ' + str( datetime.datetime.now().year), 400 if 'gender' in body: if body['gender'] != 'm' and body['gender'] != 'f' and body[ 'gender'] != 'o': return 'body.gender must be m/f/o', 400 resp = {} if 'email' in body: email = body['email'].strip().lower() if email != user['email']: exists = db_get('users', {'email': email}, True) if exists: return 'email exists', 403 token = make_salt() hashed_token = hash(token, make_salt()) db_update( 'users', { 'username': user['username'], 'email': email, 'verification_pending': hashed_token }) # If this is an e2e test, we return the email verification token directly instead of emailing it. if is_testing_request(request): resp = { 'username': user['username'], 'token': hashed_token } else: send_email_template( 'welcome_verify', email, requested_lang(), os.getenv('BASE_URL') + '/auth/verify?username='******'username']) + '&token=' + urllib.parse.quote_plus(hashed_token)) if 'country' in body: db_update('users', { 'username': user['username'], 'country': body['country'] }) if 'birth_year' in body: db_update('users', { 'username': user['username'], 'birth_year': body['birth_year'] }) if 'gender' in body: db_update('users', { 'username': user['username'], 'gender': body['gender'] }) return jsonify(resp)
def post(self): _id = self.get_argument('conf_id', '') cycle = self.get_argument('cycle', 0) num = self.get_argument('num', 0) visit_cycle = self.get_argument('visit_cycle', 0) visit_num = self.get_argument('visit_num', 0) named_str = self.get_argument('named_map') rules_str = self.get_argument('rules_map') cache_invalid_time = cycle add_query_time = self.get_argument('add_query_time') all_query_time = self.get_argument('all_query_time') # if not cycle: # return self.write(error_res('Please put cycle')) # if not num: # return self.write(error_res('Please put num')) # if not visit_cycle: # return self.write(error_res('Please put visit_cycle')) # if not visit_num: # return self.write(error_res('Please put visit_num')) if rules_str: for line in rules_str.split('\n'): if len(line.split(',')) != 4: return self.write( error_res('Please enter the right rules_map')) if named_str: for line in named_str.split('\n'): if len(line.split(',')) != 5: return self.write( error_res('Please enter the right named_map')) # if not cache_invalid_time: # return self.write(error_res('Please put cache_invalid_time')) if not add_query_time: return self.write(error_res('Please put add_query_time')) if not all_query_time: return self.write(error_res('Please put all_query_time')) cycle = 0 if not cycle else int(cycle) num = 0 if not num else int(num) visit_cycle = 0 if not visit_cycle else int(visit_cycle) visit_num = 0 if not visit_num else int(visit_num) cache_invalid_time = 0 if not cache_invalid_time else int( cache_invalid_time) add_query_time = int(add_query_time) all_query_time = int(all_query_time) if named_str: named_map = [{ 'named': i.split(',')[0].strip(), 'locationName': i.split(',')[1].strip(), 'namedCycle': int(i.split(',')[2].strip()), 'namedNum': int(i.split(',')[3].strip()), 'namedPeriod': int(i.split(',')[4].strip()) } for i in named_str.split('\n')] else: named_map = [] if rules_str: rules_map = [{ 'theKey': i.split(',')[0].strip(), 'theCycle': int(i.split(',')[1].strip()), 'theNum': int(i.split(',')[2].strip()), 'thePeriod': int(i.split(',')[3].strip()) } for i in rules_str.split('\n')] else: rules_map = [] new_conf = { "cycle": cycle, "num": num, "visit_cycle": visit_cycle, "visit_num": visit_num, "cache_invalid_time": cache_invalid_time, "add_query_time": add_query_time, "all_query_time": all_query_time } if rules_map: new_conf.update({'rules_map': rules_map}) if named_map: new_conf.update({'named_map': named_map}) old_conf = control_conf.find_one({'_id': ObjectId(_id)}) if not old_conf: return self.write(error_res('This config had already deleted')) try: db_update(control_conf, {'_id': ObjectId(_id)}, {'$set': new_conf}) except Exception: logger.info('ConfigChangeExec[post][error]: %s' % (traceback.format_exc(), )) else: logger.info( 'ConfigChangeExec[post] channel: %s|| suffix: %s|| category: %s' % (old_conf['channel'], str(old_conf.get( 'suffix', '')), old_conf['category'])) makeSthStrInDict(new_conf, 'rules_map') makeSthStrInDict(new_conf, 'named_map') add_config_cache( "%s%s" % (old_conf['channel'], str(old_conf.get('suffix', ''))), old_conf['category'], new_conf) self.redirect('/conf')
def post(self): now = datetime.datetime.now() req = json.loads(self.request.body) remote_ip = self.request.remote_ip task_id = req.get('task_id', '') #fc ip server_ip = req.get('server_ip', '') success_num = req.get('success_num', '') error_num = req.get('error_num', '') num_404 = req.get('not_found_num', '') total_num = req.get('total_num', '') is_finish = req.get('is_finish', 'false') duration = int(req.get('duration', 0)) print '---TaskApiUpdate---' print 'remote_ip', remote_ip print 'task_id', task_id print 'server_ip', server_ip print 'success_num', success_num print 'error_num', error_num print 'num_404', num_404 print 'is_finish', is_finish print 'total_num', total_num print 'duration', duration print '---TaskApiUpdate---end' if not task_id: print 'no task_id' raise if not success_num and not error_num and not num_404: print 'no num' raise old_task = preload_b_result.find_one({ 'task_id': task_id, 'client_ip': remote_ip, 'server_ip': server_ip }) if not old_task: raise if is_finish == 'true': db_update(preload_b_result, { 'task_id': task_id, 'client_ip': remote_ip, 'server_ip': server_ip }, { "$set": { 'success_num': success_num, 'error_num': error_num, 'not_found_num': num_404, 'total_num': total_num, 'update_datetime': now, 'duration': duration } }) else: db_update(preload_b_result, { 'task_id': task_id, 'client_ip': remote_ip, 'server_ip': server_ip }, { "$set": { 'success_num': success_num, 'error_num': error_num, 'not_found_num': num_404, 'total_num': total_num, 'update_datetime': now } }) all_finish = True for t in preload_b_result.find({'task_id': task_id}): if not t['duration']: all_finish = False break if all_finish: #总任务成功 print task_id, 'all_finish', now db_update(preload_b, { '_id': ObjectId(task_id), 'finish_datetime': '' }, {'$set': { 'finish_datetime': now }}) w = {} w['code'] = 200 self.write(json.dumps(w))