def change_password(env: TEnvironment, query: TQuery, cookie: TCookie) -> TResponse: """ Args: env: HTTP request environment query: url query parameters cookie: http cookie parameters (may be empty) Returns: TODO: add description """ data = get_json_by_response(env) if 'user_id' not in data or 'pass' not in data: return http.bad_request(host=env['HTTP_HOST']) logger('change_password()', f'Change password for {data["user_id"]}.', type_='LOG') if sql.change_password(data['user_id'], data['pass']): return http.ok(host=env['HTTP_HOST']) else: return http.bad_request(host=env['HTTP_HOST'])
def read_places() -> tp.List[str]: """Read list of places from file (`places.list`) """ global PLACES # Check file exist. or auto create if not os.path.exists(PLACES_PATH): logger('read_places()', 'No places file. Using default places file', type_='INFO') if os.path.exists(DEFAULT_PLACES_PATH): shutil.copy(DEFAULT_PLACES_PATH, PLACES_PATH) else: # Create empty logger('read_places()', 'No default places file. Using default values', type_='ERROR') with open(PLACES_PATH, "a+") as f: pass PLACES = [] with open(PLACES_PATH, "r") as f: for place in sorted(f.readlines()): if place != '\n': PLACES.append(place[:-1] if place[-1] == '\n' else place) return list(PLACES)
def add_place(place: str) -> None: """ add place to PLACES and mb save it to file""" global PLACES logger('add_place()', f'Adding place = {place}', 'LOG') if place not in PLACES: PLACES.append(place) write_places()
def update_cache() -> None: """ Update cache and sync events, projects and etc Note: Run every TIMEOUT seconds """ # Update today logger('update_cache()', '', type_='LOG') return
def sync() -> None: """ Update cache and sync events, projects and etc Note: Run every TIMEOUT seconds """ logger('sync()', '==== Sync start ====', type_='LOG') update_cache() # Sync itself logger('sync()', '==== Sync end ======', type_='LOG') start_sync(TIMEOUT) # Update - to call again
def post_credits(env: TEnvironment, query: TQuery, cookie: TCookie) -> TResponse: """ Sing in at lecture HTTP request (by student ) By cookie add credits to user Args: env: HTTP request environment query: url query parameters cookie: http cookie parameters (may be empty) Note: Send: 200 Ok: if all are ok 401 Unauthorized: if wrong session id 405 Method Not Allowed: already got it or timeout Returns: Response - result of request None; Only http answer """ # TODO: CREDITS # Event code # code = query['code'] # print('Credits code: ', code) event_id = 42 # TODO: Get event id from code # Safety get user_obj user_obj = get_user_by_response(cookie) if user_obj is None: return http.wrong_cookie(env['HTTP_HOST']) event_obj = sql.get_event(event_id) if event_obj is not None: # gsheets.save_credits(user_obj, event_obj) sql.checkin_user(user_obj, event_obj) logger('post_credits()', f'Checkin user {user_obj} to {event_obj}', type_='LOG') return http.ok(env['HTTP_HOST']) else: return http.not_allowed()
def get_day(env: TEnvironment, query: TQuery, cookie: TCookie) -> TResponse: """ Day schedule data HTTP request Get day num and return html Args: env: HTTP request environment query: url query parameters cookie: http cookie parameters (may be empty) Note: Cached by TIMEOUT return day html by req from query string (if none return today) Returns: Response - result of request html data: day schedule """ # format is "dd.mm" try: day = query['day'] except KeyError: day = get_date_str() # Get for today day if day not in ['Template', '05.06', '06.06', '07.06', '08.06', '09.06', '10.06', '11.06', '12.06', '13.06', '14.06', '15.06', '16.06', '17.06', '18.06']: # print('day overflow, falling back to the last day available') # TODO: Remove or check in sql logger('get_day()', 'day overflow, falling back to the last day available', type_='ERROR') day = '05.06' # print('get data days for ', day) data = sql.get_day(day) data = sorted(data, key=lambda x: x['time']) groups = groupby(data, key=lambda x: x['time']) data = [{'time': time_, 'events': [event for event in group_]} for time_, group_ in groups] return http.ok(json_dict=data)
def write_config() -> None: """Write current configuration to config file (`ihse.ini`) """ global CREDITS_TOTAL, CREDITS_MASTER, CREDITS_LECTURE, CREDITS_ADDITIONAL, NUMBER_TEAMS logger('write_config()', '==== Write config file ====', type_='LOG') config = configparser.ConfigParser() config['CREDITS'] = { 'total': CREDITS_TOTAL, 'masterclass': CREDITS_MASTER, 'lecture': CREDITS_LECTURE, 'additional': CREDITS_ADDITIONAL } config['TEAMS'] = {'number': NUMBER_TEAMS} with open(CONFIG_PATH, 'w') as configfile: config.write(configfile) logger('write_config()', '==== End config file writing ====', type_='LOG')
def clear_table(env: TEnvironment, query: TQuery, cookie: TCookie) -> TResponse: """ Args: env: HTTP request environment query: url query parameters cookie: http cookie parameters (may be empty) Returns: TODO: add description """ table_name = query['table'] if table_name in sql.table_fields.keys(): sql.clear_table(table_name) else: logger('admin_panel()', '400 Bad Request by admin', type_='ERROR') return http.bad_request(host=env['HTTP_HOST']) return http.ok(host=env['HTTP_HOST'])
def read_config() -> None: """Read and save config file (`ihse.ini`) """ logger('read_config()', '==== Read config file ====', type_='LOG') global CREDITS_TOTAL, CREDITS_MASTER, CREDITS_LECTURE, CREDITS_ADDITIONAL, NUMBER_TEAMS # Check file exist. or auto create with open(CONFIG_PATH, "a+") as f: pass try: config = configparser.ConfigParser() config.read(CONFIG_PATH) CREDITS_TOTAL = int(config['CREDITS']['total']) CREDITS_MASTER = int(config['CREDITS']['masterclass']) CREDITS_LECTURE = int(config['CREDITS']['lecture']) CREDITS_ADDITIONAL = int(config['CREDITS']['additional']) NUMBER_TEAMS = int(config['TEAMS']['number']) except (KeyError, configparser.MissingSectionHeaderError): logger('read_config()', 'No config file. Using default config file', type_='INFO') try: config = configparser.ConfigParser() config.read(DEFAULT_CONFIG_PATH) CREDITS_TOTAL = int(config['CREDITS']['total']) CREDITS_MASTER = int(config['CREDITS']['masterclass']) CREDITS_LECTURE = int(config['CREDITS']['lecture']) CREDITS_ADDITIONAL = int(config['CREDITS']['additional']) NUMBER_TEAMS = int(config['TEAMS']['number']) write_config() except (KeyError, configparser.MissingSectionHeaderError): logger('read_config()', 'No default config file. Using default values', type_='ERROR') CREDITS_TOTAL = 300 CREDITS_MASTER = 15 CREDITS_LECTURE = 15 CREDITS_ADDITIONAL = 5 NUMBER_TEAMS = 5 write_config() logger('read_config()', '==== End config file reading ====', type_='LOG')
def admin(env: TEnvironment, query: TQuery, cookie: TCookie) -> TResponse: """ Manage admin HTTP request Will check session id and permissions Note: If there is no cookie or it is incorrect - Error Args: env: HTTP request environment query: url query parameters cookie: http cookie parameters (may be empty) Returns: Response - result of request """ logger('admin_panel()', 'Admin try with cookie {cookie}', type_='LOG') # Safety get user_obj user_obj = get_user_by_response(cookie) if user_obj is None: return http.wrong_cookie(host=env['HTTP_HOST']) logger('admin_panel()', f'Admin try with user: {user_obj}', type_='LOG') if user_obj['user_type'] == 0: return http.not_allowed() logger('admin_panel()', f'Admin want to {env["PATH_INFO"]}', type_='LOG') functions = { '/admin_get_config': get_config, '/admin_post_config': post_config, '/admin_get_places': get_places, '/admin_post_places': post_places, '/admin_get_credits': get_credits, '/checkin': post_checkin, '/admin_get_table': get_table, '/admin_clear_table': clear_table, '/admin_send_data': send_data, '/admin_remove_data': remove_data, '/admin_codes': codes, '/admin_change_password': change_password } if env['PATH_INFO'] in functions: return functions[env['PATH_INFO']](env, query, cookie)
def post_checkin(env: TEnvironment, query: TQuery, cookie: TCookie) -> TResponse: """ Check in at lecture HTTP request (by admin) By cookie add credits to user Args: env: HTTP request environment query: url query parameters cookie: http cookie parameters (may be empty) Note: Send: 200 Ok: if all are ok 401 Unauthorized: if wrong session id 405 Method Not Allowed: already got it or timeout Returns: Response - result of request None; Only http answer """ checkins = get_json_by_response(env) event_id = query['event'] # Safety get user_obj user_obj = get_user_by_response(cookie) event = sql.get_in_table(event_id, 'events') if event is None: # No such event return http.not_allowed(host=env['HTTP_HOST']) config_dict = config.get_config() # Set up credits and enrolls attendance if event['type'] == 1 and event['total'] > 0: # master # Check there are enrolls enrolls = sql.get_enrolls_by_event_id(event_id) users_in_enrolls = { enroll['user_id'] for enroll in enrolls if not enroll['attendance'] } # type: tp.Set[int] users_in_checkins = { int(checkin['id']): min(int(checkin['bonus']), config_dict['CREDITS_ADDITIONAL']) for checkin in checkins } # type: tp.Dict[int, int] users_to_set_credits = { k for k in users_in_checkins.keys() if k in users_in_enrolls } # type: tp.Set[int] # Setup attendance for enrolls enrolls = [ enroll for enroll in enrolls if enroll['user_id'] in users_to_set_credits ] # type: tp.List[sql.TTableObject] for i in range(len(enrolls)): enrolls[i]['attendance'] = True enrolls[i]['bonus'] = users_in_checkins[enrolls[i]['user_id']] sql.update_in_table(enrolls[i], 'enrolls') # TODO: Minus balls if not attendant credits = [{ 'user_id': int(checkin['id']), 'event_id': event_id, 'validator_id': user_obj['id'], 'time': get_datetime_str(), 'value': config_dict['CREDITS_MASTER'] + min(int(checkin['bonus']), config_dict['CREDITS_ADDITIONAL']) } for checkin in checkins if int(checkin['id']) in users_to_set_credits ] # type: tp.List[sql.TTableObject] for credit in credits: sql.insert_to_table(credit, 'credits') logger('post_checkin()', f'Checkin users {users_in_checkins} to master event {event_id}', type_='LOG') else: # lecture enrolls = [{ 'class_id': event_id, 'user_id': int(checkin['id']), 'time': get_datetime_str(), 'attendance': True, 'bonus': min(int(checkin['bonus']), config_dict['CREDITS_ADDITIONAL']) } for checkin in checkins] # type: tp.List[sql.TTableObject] for enroll in enrolls: sql.update_in_table(enroll, 'enrolls') credits = [{ 'user_id': int(checkin['id']), 'event_id': event_id, 'time': get_datetime_str(), 'value': config_dict['CREDITS_LECTURE'] + min(int(checkin['bonus']), config_dict['CREDITS_ADDITIONAL']) } for checkin in checkins] # type: tp.List[sql.TTableObject] for credit in credits: sql.insert_to_table(credit, 'credits') logger('post_checkin()', f'Checkin user {checkins} to lecture event {event_id}', type_='LOG') return http.ok(env['HTTP_HOST'])
def post_login(env: TEnvironment, query: TQuery, cookie: TCookie) -> TResponse: """ Login HTTP request Create new session if it does not exist and send cookie sessid Args: env: HTTP request environment query: url query parameters cookie: http cookie parameters (may be empty) Note: Send: 200 Ok: if user exist and session created correctly and send cookie with sess id 401 Unauthorized: if wrong name of pass Returns: Response - result of request """ reg_data = get_json_by_response(env) try: phone, passw = reg_data['phone'], reg_data['pass'] except KeyError: # print('ERROR, No registration data.') logger('post_login()', 'No registration data in req.', type_='ERROR') return http.forbidden() try: remember = reg_data['remember'] except KeyError: remember = True # print(phone) phone = "+7" + phone[2:] phone = ''.join(i for i in phone if i.isdigit()) # Get session obj or None session_id = sql.login(phone, passw, env['HTTP_USER_AGENT'], env['REMOTE_ADDR'], get_datetime_str()) if session_id is not None: # Convert: b'\xbeE%-\x8c\x14y3\xd8\xe1ui\x03+D\xb8' -> be45252d8c147933d8e17569032b44b8 sessid = session_id.hex() # sessid = bytes.hex(res[0]) # sessid = bytes(res[0]) # print(f'login with got:{sessid}') expires = 'Max-Age=15768000;' if remember else '' return ('200 OK', [ # Because in js there is xhttp.withCredentials = true; ('Access-Control-Allow-Origin', f"//{env['HTTP_HOST']}"), # To receive cookie ('Access-Control-Allow-Credentials', 'true'), ('Set-Cookie', f"sessid={sessid}; Path=/; Domain={env['HTTP_HOST']}; HttpOnly;{expires}"), # 1/2 year # ('Location', '//ihse.tk/') ], []) else: return http.unauthorized()
def post_register(env: TEnvironment, query: TQuery, cookie: TCookie) -> TResponse: """ Register HTTP request Create new user if it does not exist and login user Args: env: HTTP request environment query: url query parameters cookie: http cookie parameters (may be empty) Query args: env: HTTP request environment name: User name - string phone: User phone - string passw: Password hash - int code: special code responsible for the user type and permission to register - string Note: Send: 200 Ok: if user exist and session created correctly and send cookie with sess id 401 Unauthorized: if wrong name of pass Returns: Response - result of request """ reg_data = get_json_by_response(env) try: name = reg_data['name'] surname = reg_data['surname'] phone = reg_data['phone'] sex = reg_data['sex'] passw = reg_data['pass'] code = reg_data['code'] except KeyError: # print('ERROR, No registration data.') logger('post_login()', 'No registration data in req.', type_='ERROR') return http.forbidden() # print(phone) phone = "+7" + phone[2:] phone = ''.join(i for i in phone if i.isdigit()) # Check registration code # user_type = gsheets.check_code(code) # user = sql.get_user_by_phone(phone) team = random.randint(1, config.get_config()['NUMBER_TEAMS']) # TODO: Sex distribution # Create new user if sql.register(code, name, surname, phone, sex, passw, team): # Auto login of user session_id = sql.login(phone, passw, env['HTTP_USER_AGENT'], env['REMOTE_ADDR'], get_datetime_str()) if session_id is not None: # Convert: b'\xbeE%-\x8c\x14y3\xd8\xe1ui\x03+D\xb8' -> be45252d8c147933d8e17569032b44b8 sessid = session_id.hex() # sessid = bytes.hex(res[0]) # sessid = bytes(res[0]) # print(f'login with got:{sessid}') return ('200 OK', [ # Because in js there is xhttp.withCredentials = true; ('Access-Control-Allow-Origin', f"//{env['HTTP_HOST']}"), # To receive cookie ('Access-Control-Allow-Credentials', 'true'), ('Set-Cookie', 'sessid=' + sessid + f"; Path=/; Domain={env['HTTP_HOST']}; HttpOnly; Max-Age=15768000;"), # 1/2 year # ('Location', '//ihse.tk/') ], []) else: return http.unauthorized() else: return http.conflict()