def get(self): # # Need to specify both the year and the month. # year = self.get_argument('year', None) if year is None: self.render_error(e_hdr=ERR_404, e_msg='Не указан год') return month = self.get_argument('month', None) if month is None: self.render_error(e_hdr=ERR_404, e_msg='Не указан месяц') return try: year = int(year) month = int(month) if year <= 0 or month <= 0: raise ValueError('Illegal month or year') except Exception: logger.exception('Year and month must be positive '\ 'numbers') self.render_error(e_hdr=ERR_PARAMETERS, e_msg='Год и месяц должны быть '\ 'положительными числами') return tx = None try: tx = yield application.begin() # # We don't need to render a first # parameter, because it will be requested # from a client side after loading via # AJAX. # To avoid strongly increasing page size # and thus page loading speed, we avoid # to render the page already with all # parameters of all boilers. Instead of # this way, the parameters are downloading # by the client as requiered. # So we need to pass only boiler and # parameter identifiers. # districts = yield get_districts_with_boilers(tx) start_week, days_count =\ calendar.monthrange(year, month) self.render("temperature.html", year=year, days_count=days_count, districts=districts, month_names=month_names, month=month, get_date=get_str_date, get_val=get_html_val) tx.commit() except: logger.exception('Error with getting districts and '\ 'boilers') self.rollback_error(tx, e_hdr=ERR_500) return
def get(self): action = self.get_argument('action', None) id = self.get_argument('id', None) if action: if not self.check_rights(CAN_EDIT_USERS): return # # It is not allowed to create or edit an # user via GET request. # if action != 'delete': self.render_error(ERR_PARAMETERS, ERR_ACTION) return if id is None: self.render_error(ERR_PARAMETERS, ERR_USER_ACTION_ID) return try: id = int(id) if id < 0: raise ValueError(ERR_USER_ACTION_ID) except: self.render_error(ERR_PARAMETERS, ERR_USER_ACTION_ID) return try: tx = yield application.begin() except: logger.exception('Error during getting users') self.rollback_error(tx, e_hdr=ERR_500) return kwargs = { 'user_was_created': False, 'user_was_edited': False, 'user_was_deleted': False } if not action: yield self.render_page_and_commit(tx, **kwargs) return assert(action == 'delete') try: yield delete_user_by_id(tx, id) # # If the user deleted himself, then logout # him by clearing all his cookies. # if id == self.current_user['user_id']: self.clear_all_cookies() kwargs['user_was_deleted'] = True except: logger.exception('Error during deletion of the user '\ 'with id: %s' % id) self.rollback_error(tx, e_hdr=ERR_500) return yield self.render_page_and_commit(tx, **kwargs)
def test2_insert_reports(self): application.connect_db() tx = yield application.begin() user = test_users[-1] logged = yield self.login_user(user['email'], user['password']) self.assertEqual(logged['name'], user['name']) for path, dirs_list, files_list in os.walk('../test_reports'): for f_name in files_list: if not '.xl' in f_name: continue file_path = os.path.join(path, f_name) yield self.post_file(logged, file_path)
def post(self): if self.current_user: self.render_error(e_hdr=ERR_LOGIN, e_msg='Вы уже авторизованы') return email = self.get_argument('email', None) if not email: self.render_error(e_hdr=ERR_LOGIN, e_msg='Не указан email') return password = self.get_argument('password', None) if not password: self.render_error(e_hdr=ERR_LOGIN, e_msg='Не указан пароль') return tx = None try: tx = yield application.begin() # # Try to find the user by specified email. # columns = ['id', 'password', 'salt', 'rights', 'name', 'email'] user = yield get_user_by_email(tx, columns, email) if not user: self.rollback_error(tx, e_hdr=ERR_404, e_msg='Пользователь с '\ 'таким email не '\ 'зарегистрирован') return true_password = user['password'] salt = user['salt'] # # Check that the password is correct. # if not secret_conf.check_password(password, salt, true_password): self.rollback_error(tx, e_hdr=ERR_ACCESS, e_msg='Неправильный пароль') return user_id = user['id'] rights = user['rights'] user_name = user['name'] # # Set cookies for the current user for one day. # self.set_secure_cookie('user_id', str(user_id), expires_days=1) self.update_cookies(rights, user_name) yield tx.commit() except Exception as e: logger.exception('Error during login') self.rollback_error(tx, e_hdr=ERR_500) return self.redirect('/')
def get(self): date = self.get_argument('date', None) if date is None: self.render_error(e_hdr=ERR_404, e_msg='Не указана дата отчета') return tx = None try: tx = yield application.begin() yield delete_report_by_date(tx, date) tx.commit() except Exception: logger.exception("Error with deleting report by date") self.rollback_error(tx, e_hdr=ERR_500) return self.redirect('/')
def get(self): # # If date is not specified then choose one. # full_date = self.get_argument('date', None) year = self.get_argument('year', date.today().year) try: year = int(year) if year < 1970: raise ValueError('Illegal year') except Exception: logger.exception("Year must be positive number") self.render_error(e_hdr=ERR_PARAMETERS, e_msg='Год должен быть целым '\ 'положительным числом от 1970') return if not full_date: yield self.print_calendar(year) return tx = None try: tx = yield application.begin() report = yield get_full_report_by_date(tx, full_date) if not report: self.rollback_error(tx, e_hdr=ERR_404, e_msg='Отчет за указанную '\ 'дату не найден') return yield tx.commit() except Exception as e: logger.exception("Error with full report getting") if len(e.args) > 0 and e.args[0] == DUPLICATE_ERROR: self.rollback_error(tx, e_hdr=ERR_INSERT, e_msg='Запись с таким '\ 'идентификатором уже'\ ' существует') else: self.rollback_error(tx, e_hdr=ERR_500) else: assert (self.current_user) assert ('rights' in self.current_user) self.render('show_table.html', **report, get_val=get_html_val, get_date=get_str_date, wind_directions=wind_directions, CONFIRM_DELETE=CONFIRM_DELETE)
def get(self): if not self.check_rights(CAN_SEE_REPORTS, render=False): self.render_json_error('У вас нет прав на это действие') return year = self.get_argument('year', None) if year is None: self.render_json_error('Не указан год') return month = self.get_argument('month', None) if month is None: self.render_json_error('Не указан месяц') return columns_bin = self.request.arguments.get('columns[]', None) if columns_bin is None: self.render_json_error('Не указаны колонки') return columns = [] for col in columns_bin: # # Need to decode, because it is handler for AJAX # that sends binary values. # col = col.decode('utf-8') # # Protect from SQL injection # if col not in GetMonthParameterHandler.available_columns: self.render_json_error('Нельзя получать '\ 'столбец {}'.format(col)) return columns.append(col) tx = None try: tx = yield application.begin() boilers = yield get_boilers_month_values(tx, year, month, columns) self.render_json(boilers) tx.commit() except: logger.exception('Error with getting month parameter') if tx: tx.rollback() self.render_json_error('На сервере произошла ошибка, '\ 'обратитесь к администратору') return
def get(self): if not self.check_rights(CAN_SEE_REPORTS, render=False): self.render_json_error('У вас нет прав на это действие') return boiler_id = self.get_argument('boiler_id', None) if boiler_id is None: self.render_json_error('Не указан идентификатор '\ 'бойлерной') return param_name = self.get_argument('param_name', None) if param_name is None: self.render_json_error('Не указан идентификатор '\ 'параметра') return year = self.get_argument('year', None) if year is None: self.render_json_error('Не указан год') return tx = None try: tx = yield application.begin() columns = [param_name, 'T1', 'T2'] report = yield get_boiler_year_report(tx, boiler_id, year, columns) self.render_json(report) tx.commit() except AccessError as e: logger.exception('AccessError with getting parameters') if not tx: logger.exception('Strange error - no '\ 'transaction') self.render_json_error('На сервере произошла '\ 'ошибка, обратитесь к '\ 'администратору') else: self.render_json_error('Ошибка доступа: ' + str(e)) except: logger.exception('Error with getting parameter') if tx: tx.rollback() self.render_json_error('На сервере произошла ошибка, '\ 'обратитесь к администратору') return
def get(self): year = self.get_argument('year', None) if year is None: self.render_error(e_hdr=ERR_404, e_msg='Не указан год') return try: year = int(year) if year <= 0: raise ValueError('Illegal year') except Exception: logger.exception('Year must be positive number') self.render_error(e_hdr=ERR_PARAMETERS, e_msg='Год должен быть положительным'\ ' числом') return days = calendar.isleap(year) and 366 or 365 tx = None try: tx = yield application.begin() boilers = yield get_boiler_room_ids_and_titles(tx) column = ['all_day_expected_temp1', 'T1', 'T2'] first_id = boilers[0]['id'] first_report =\ yield get_boiler_year_report(tx, first_id, year, column) year_temperature = yield get_year_temperature(tx, year) self.render('year_plot.html', year=year, days_count=days, first_report=first_report, first_id=first_id, boilers=boilers, year_temperature=year_temperature) tx.commit() except: logger.exception('Error with getting boiler room ids '\ 'and reports about first room') self.rollback_error(tx, e_hdr=ERR_500) return
def test4_delete_user(self): application.connect_db() logged = yield self.get_logged() client = self.get_client() headers = logged['headers'] user = test_normal_users[0] tx = yield application.begin() id = yield get_user_by_email(tx, [ 'id', ], user['email']) id = id['id'] url = '{}?id={}&action=delete'\ .format(self.get_url('/users_management'), id) response = yield client.fetch(url, headers=headers, method='GET') body = response.body.decode('utf-8') self.assertIn('user_was_deleted', body) self.assertNotIn(user['email'], body) yield tx.commit() logger.info('ok - user was deleted') # # Recreate the deleted user. # yield self.post_user(user)
def test1_create_users(self): application.connect_db() tx = yield application.begin() yield prepare_tests(tx, sc.db_name, sc.test_db_name) # # Insert users to testing and ensure the # correctness of the insert. # for user in test_users: passwd = user['password'] salt, pass_hash = sc.generate_password_hash(passwd) yield insert_user(tx, user['email'], pass_hash, salt, user['name'], user['rights']) for i, user in enumerate(test_users): cols = ['id', 'email', 'name', 'rights'] db_user = yield get_user_by_email(tx, cols, user['email']) self.assertEqual(db_user['id'], i + 1) self.assertEqual(db_user['email'], user['email']) self.assertEqual(db_user['name'], user['name']) self.assertEqual(db_user['rights'], user['rights']) tx.commit()
def post(self): if 'xls-table' not in self.request.files: self.render_error(e_hdr=ERR_UPLOAD, e_msg='Не указан файл') return fileinfo = self.request.files['xls-table'][0] tx = None try: tx = yield application.begin() # # We emulate a file by BytesIO usage. # data = parse_xls(BytesIO(fileinfo['body'])) # # Start a transaction. Commit only if all is good # yield insert_report(tx, self.current_user['user_id'], data) # # Get the inserted report id for creating foreign key to # it in other tables. # report_id = yield get_report_by_date(tx, data['date'], ['id', ]) assert(report_id) # # get_... returns the entire report in which first # element is 'id' column. # report_id = report_id[0] for district in data['districts']: yield self.upload_district(tx, report_id, district) # # Get date in dd.mm.yyyy format date = data['date'] # Create datetime python object date = datetime.strptime(date, date_format) # Convert it to the format yyyy-mm-dd as in mysql # database. date = date.strftime(date_format) self.redirect('/show_table?date={}'.format(date)) except BadZipFile: logger.exception("Unsupported file type") self.rollback_error(tx, e_hdr=ERR_INSERT, e_msg='Файл имеет неподдерживаемый'\ ' формат') except XLSTypeError as e: logger.exception("Type error") str_type = e.expected if str_type == int: str_type = '"Целое число"' else: str_type = '"Число с плавающей точкой"' msg = 'Ошибка в типе значения в строке {}, столбце {}:'\ ' ожидался тип {}, а получено значение: {}'\ .format(e.row, e.column, str_type, e.real) self.rollback_error(tx, e_hdr=ERR_INSERT, e_msg=msg) except XLSCellEqualError as e: logger.exception("One of values in report is incorrect") msg = 'Ошибка в строке {}, столбце {}: ожидалось '\ 'значение "{}", однако встречено "{}"'\ .format(e.row, e.column, e.expected, e.real) self.rollback_error(tx, e_hdr=ERR_INSERT, e_msg=msg) except XLSCellInError as e: logger.exception("One of values in report is incorrect") words = ', '.join(['"{}"' % val for val in e.expected]) msg = 'Ошибка в строке {}, столбце {}: в ячейке '\ 'ожидались слова {}, однако встречено {}'\ .format(e.row, e.column, words, e.real) self.rollback_error(tx, e_hdr=ERR_INSERT, e_msg=msg) except Exception as e: if len(e.args) > 0 and e.args[0] == DUPLICATE_ERROR: self.rollback_error(tx, e_hdr=ERR_INSERT, e_msg='Запись с таким '\ 'идентификатором уже'\ ' существует') else: logger.exception("Error with uploading report") self.rollback_error(tx, e_hdr=ERR_500) else: yield tx.commit()
def test5_edit_user(self): application.connect_db() logged = yield self.get_logged() client = self.get_client() headers = logged['headers'] user = test_normal_users[0] self.assertEqual(user['name'], 'John Doe 1') self.assertEqual(user['email'], '*****@*****.**') post = dict(user) # # Edit email # tx = yield application.begin() id = yield get_user_by_email(tx, [ 'id', ], user['email']) yield tx.commit() id = id['id'] post['email'] = '*****@*****.**' post['action'] = 'edit' post['id'] = id post['password'] = '' post['password-repeat'] = '' body = urllib.parse.urlencode(post) response = yield client.fetch(self.get_url('/users_management'), headers=headers, method='POST', body=body) body = response.body.decode('utf-8') self.assertIn('user_was_edited', body) self.assertIn(post['email'], body) logger.info("ok - user's email is edited") user['email'] = post['email'] # # Change email to the existing email. Also we try # to change the password, but is must not happen, # since the duplicate error occures. # self.assertGreaterEqual(len(test_normal_users), 1) another_user = test_normal_users[1] post['email'] = another_user['email'] post['password'] = '******' post['password-repeat'] = 'new_password' body = urllib.parse.urlencode(post) response = yield client.fetch(self.get_url('/users_management'), headers=headers, method='POST', body=body) body = response.body.decode('utf-8') self.assertNotIn('user_was_edited', body) self.assertIn(ERR_INSERT, body) # # The user still can login with the old password. # response = yield self.login_user(user['email'], user['password']) self.assertNotIn('error', response) self.assertIn('headers', response) logger.info("ok - it is forbidden to choose the existing email"\ " during an user editing") # # Send the old password as edited. # post = dict(user) post['action'] = 'edit' post['id'] = id body = urllib.parse.urlencode(post) response = yield client.fetch(self.get_url('/users_management'), headers=headers, method='POST', body=body) body = response.body.decode('utf-8') self.assertIn('user_was_edited', body) self.assertIn(post['email'], body) # # The user still can login. # response = yield self.login_user(user['email'], user['password']) self.assertNotIn('error', response) self.assertIn('headers', response) logger.info('ok - an user can keep the old password') # # Try to set incorrect passwords. # post['password'] = '' # password-repeat remains. body = urllib.parse.urlencode(post) response = yield client.fetch(self.get_url('/users_management'), headers=headers, method='POST', body=body) body = response.body.decode('utf-8') self.assertNotIn('user_was_edited', body) self.assertIn(ERR_PASSWORD_ABSENSE, body) post['password'] = '******' # too short password. post['password-repeat'] = '123' body = urllib.parse.urlencode(post) response = yield client.fetch(self.get_url('/users_management'), headers=headers, method='POST', body=body) body = response.body.decode('utf-8') self.assertNotIn('user_was_edited', body) self.assertIn(ERR_PASSWORD_LENGTH, body) # Password differs from password-repeat. post['password'] = '******' post['password-repeat'] = '1234567' body = urllib.parse.urlencode(post) response = yield client.fetch(self.get_url('/users_management'), headers=headers, method='POST', body=body) body = response.body.decode('utf-8') self.assertNotIn('user_was_edited', body) self.assertIn(ERR_PASSWORD_MATCH, body) logger.info('ok - new password can not be invalid') # # Edit the current user. # post = {} post['email'] = logged['email'] post['action'] = 'edit' post['id'] = logged['id'] post['see_reports'] = 'on' post['upload_reports'] = 'on' post['delete_reports'] = 'on' post['see_users'] = 'on' post['edit_users'] = 'on' self.assertNotEqual('Great Admin', logged['name']) post['name'] = 'Great Admin' body = urllib.parse.urlencode(post) response = yield client.fetch(self.get_url('/users_management'), headers=headers, method='POST', body=body) body = response.body.decode('utf-8') self.assertIn('user_was_edited', body) self.assertIn('Вы вошли как <b>%s</b>' % post['name'], body) logger.info('ok - edit the current user')
def print_calendar(self, year): assert (year > 1970) uploaded_days_raw = [] # # Find what reports were uploaded. # tx = None try: tx = yield application.begin() uploaded_days_raw = yield get_report_dates_by_year(tx, year) except Exception: logger.exception('Error with getting report dates by '\ 'year') self.rollback_error(tx, e_hdr=ERR_500, e_msg='Не удалось загрузить год') return yield tx.commit() uploaded_days = {} # # Group days by months. # for month, day in uploaded_days_raw: if month in uploaded_days: uploaded_days[month] |= {day} else: uploaded_days[month] = set([ day, ]) # # If not reports for the specified year then # render the error page - nothing to show. # if not uploaded_days: self.render_error(e_hdr=ERR_404, e_msg='За указанный год %s отчетов '\ 'не найдено' % year, template='choose_day_year_error.html', year=year) return months = [] # # Build months table. i-th element - array of i-th # month with specified report date if it was found # in reports table. # for month_num in range(1, 13): # # Start week - number of the first day of # the month in the week: 0 - 6 = from # monday to sunday. # start_week, days_count =\ calendar.monthrange(year, month_num) month = [] day_iter = 1 # # Weeks count - how many full weeks need # to contain this month. # weeks_cnt = int((start_week + days_count) / 7) if (start_week + days_count) % 7 != 0: weeks_cnt += 1 for day in range(0, weeks_cnt * 7): # # If the day not in this month # then skip it. # if start_week > day or day_iter > days_count: month.append({'day_val': ''}) continue # # If the day from this month but # a report for this day wasn't # found then print only day. # if month_num not in uploaded_days or\ day_iter not in uploaded_days[month_num]: month.append({'day_val': day_iter}) day_iter += 1 continue # # Else generate the link to the # report table. # month.append({ 'day_val': day_iter, 'full_date': get_str_date(year, month_num, day_iter) }) day_iter += 1 months.append(month) self.render('choose_day.html', months=months, month_names=month_names, year=year)
def post(self): action = self.get_argument('action', None) id = self.get_argument('id', None) # # It is not allowed to delete an user via POST # request. # if action not in ['create', 'edit']: self.render_error(ERR_PARAMETERS, ERR_ACTION) return if action == 'edit': if not self.check_rights(CAN_EDIT_USERS): return try: id = int(id) if id < 0: raise ValueError(ERR_USER_ACTION_ID) except: self.render_error(ERR_PARAMETERS, ERR_USER_ACTION_ID) return # # Check email correctness. # email = self.get_argument('email', None) if email is None: self.render_error(ERR_404, ERR_EMAIL_ABSENSE) return if len(email) > MAX_EMAIL_LENGTH: self.render_error(ERR_PARAMETERS, ERR_EMAIL_LENGTH) return if not email_validator.fullmatch(email): self.render_error(ERR_PARAMETERS, ERR_EMAIL_FORMAT) return # # Check name correctness. # name = self.get_argument('name', None) # If the name has zero length then store it as # NULL in the database and None in python. if not name: name = None if name and len(name) > MAX_NAME_LENGTH: self.render_error(ERR_PARAMETERS, ERR_NAME_LENGTH) return if name and not name_validator.fullmatch(name): self.render_error(ERR_PARAMETERS, ERR_NAME_FORMAT) return # # Check password correctness. # password = self.get_argument('password', '') password_repeat = self.get_argument('password-repeat', '') pass_len = len(password) need_password = action != 'edit' or pass_len > 0 or \ len(password_repeat) > 0 if pass_len == 0 and need_password: self.render_error(ERR_PARAMETERS, ERR_PASSWORD_ABSENSE) return if (pass_len < MIN_PASSWORD_LENGTH or \ pass_len > MAX_PASSWORD_LENGTH) and need_password: self.render_error(ERR_PARAMETERS, ERR_PASSWORD_LENGTH) return if password != password_repeat: self.render_error(ERR_PARAMETERS, ERR_PASSWORD_MATCH) return if need_password: salt, password_hash =\ sc.generate_password_hash(password) # # Check mask correctness. # rights_mask = 0 if self.get_argument('see_reports', None): rights_mask |= CAN_SEE_REPORTS if self.get_argument('upload_reports', None): rights_mask |= CAN_UPLOAD_REPORTS if self.get_argument('delete_reports', None): rights_mask |= CAN_DELETE_REPORTS if self.get_argument('see_users', None): rights_mask |= CAN_SEE_USERS if self.get_argument('edit_users', None): rights_mask |= CAN_EDIT_USERS if rights_mask & CAN_EDIT_USERS and \ not (rights_mask & CAN_SEE_USERS): msg = ERR_RIGHTS_COMBINATION + ': для редактирования '\ 'пользователей нужны права на их просмотр' self.render_error(ERR_PARAMETERS, msg) return if rights_mask & CAN_DELETE_REPORTS and \ not (rights_mask & CAN_SEE_REPORTS): msg = ERR_RIGHTS_COMBINATION + ': для удаления отчетов'\ ' нужны права на их просмотр' self.render_error(ERR_PARAMETERS, msg) return if rights_mask == 0: msg = ERR_RIGHTS_COMBINATION + ': нельзя оставить '\ 'пользователя без прав' self.render_error(ERR_PARAMETERS, msg) return tx = None kwargs = { 'user_was_created': False, 'user_was_edited': False, 'user_was_deleted': False } try: tx = yield application.begin() if action == 'create': yield insert_user(tx, email, password_hash, salt, name, rights_mask) kwargs['user_was_created'] = True else: assert(action == 'edit') if need_password: yield update_user(tx, id, email, password_hash, salt, name, rights_mask) else: yield update_user(tx, id, email, None, None, name, rights_mask) kwargs['user_was_edited'] = True # # If the user edited himself, then # update his cookies. # if id == self.current_user['user_id']: self.update_cookies(rights_mask, name) yield self.render_page_and_commit(tx, **kwargs) except Exception as e: if len(e.args) > 0 and e.args[0] == DUPLICATE_ERROR: msg = 'Пользователь с таким адресом почты '\ 'уже зарегистрирован' self.rollback_error(tx, e_hdr=ERR_INSERT, e_msg=msg) else: logger.exception('Error with creating user') self.rollback_error(tx, e_hdr=ERR_500)
def get(self): # # Need to specify both the year and the month. # year = self.get_argument('year', None) if year is None: self.render_error(e_hdr=ERR_404, e_msg='Не указан год') return month = self.get_argument('month', None) if month is None: self.render_error(e_hdr=ERR_404, e_msg='Не указан месяц') return try: year = int(year) month = int(month) if year <= 0 or month <= 0: raise ValueError('Illegal month or year') except Exception: logger.exception('Year and month must be positive '\ 'numbers') self.render_error(e_hdr=ERR_PARAMETERS, e_msg='Год и месяц должны быть '\ 'положительными числами') return tx = None try: start_week, days_count =\ calendar.monthrange(year, month) tx = yield application.begin() statistics = None cols = [ 'net_water_consum_expected_ph', 'net_water_consum_real_ph', 'make_up_water_consum_expected_ph', 'make_up_water_consum_real_ph', 'make_up_water_consum_real_pd', 'make_up_water_consum_real_pm' ] try: statistics =\ yield get_sum_reports_by_month(tx, year, month, cols) except Exception: logger.exception('Error with getting average '\ 'values for month reports') self.rollback_error(tx, e_hdr=ERR_500) return self.render('water_consum.html', month_names=month_names, month=month, year=year, days_count=days_count, statistics=statistics, get_val=get_html_val, get_float=get_html_float_to_str, get_date=get_str_date) tx.commit() except Exception: logger.exception("Error with rendering month report") if tx: tx.rollback() self.render_error(e_hdr=ERR_500, e_msg='Ошибка при генерации страницы') return