Полнофункциональная система тестирования

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

angrystrike
Сообщения: 8
Зарегистрирован: 26 июл 2017, 18:52

26 июл 2017, 19:01

В системе должны быть 2 режима: администратор и
тестируемый.
Описание режима работа для Тестируемого (в дальнейшем гость):
■ Для входа в систему гость должен зарегистрироваться данная процедура выполняется один раз, при дальнейших входах в систему доступ идет по логину и паролю.
■ При регистрации нужно указывать Ф.И.О., домашний адрес, телефон.
■ Важно, чтобы логины для пользователей были уникальными.
■ После входа гость имеет возможность просмотреть свои предыдущие результаты тестирования, сдать новое тестирование.

Тестирование может осуществляться по различным категориям знаний.
Например:
Математика (раздел) -> Дискретная математика
(конкретный тест)
-> Математический Анализ
(конкретный тест)
Физика (раздел) -> Квантовая физика
(конкретный тест)
-> Механика
(конкретный тест)
■ После сдачи теста гость видит результат тестирования, количество правильно отвеченных вопросов, процент правильных ответов и полученную оценку.
■ Студент имеет возможность прервать тестирование и продолжить его тогда, когда ему это будет удобно.
■ Оценивание нужно вести на основании 12 балльной системы, привязанной к количеству вопросов теста.

■ Пароли и логины гостей хранятся в зашифрованном виде.
Описание режима работы для Администратора
(в*дальнейшем админ):
■ В системе может быть только один админ, логин и пароль админа задаётся при первом входе в программу.
■ В дальнейшем пароль и логин можно изменить (но данную возможность имеет только админ).
■ Пароль и логин необходимо хранить только в зашифрованном виде.
■ При работе с системой админ имеет следующие возможности:
▶ Управление пользователями — создание, удаление, модификация пользователей.
▶ Просмотр статистики — просмотр результатов тестирования в общем по категориям, по конкретным тестам, по конкретным пользователям. Результаты просмотра статистики можно вывести в файл.
▶ Управление тестированием — админ имеет возможность добавлять категории, тесты, вопросы к тестам, задавать правильные и неправильные ответы, импортировать и экспортировать категории и тесты с вопросами из файла (и в файл).

1)На курсах еще не рассказывали как делать полноценные программы, тоесть это нужно сделать в обычном консольном приложении. Но как сделать так чтобы информация сохранялась даже после закрытия приложения, единственное что приходит в голову это сохранять всё в файл и при дальнейших запусках читать из него, но как это сделать правильно?
2)Как хранить пароли в зашифрованном виде?
3)Сложно сразу сказать что будет вызывать трудности при выполнении задания, не могли бы направить меня в правильное русло?
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

27 июл 2017, 10:03

1) Да, пароли и данные о тестах нужно хранить в файлах. Для работы с файлами используй STL классы std::fstream.

2) Самое простое, что приходит в голову - это посимвольный XOR строки. Берём любой число от 1 до 254 (0 и 255 выброшены специально), пробегаемся по строке с паролем и XOR-им каждый символ (в С++ это операция ^). Потом записываем пароль в файл. При загрузке приложения вычитываем строку из файла, снова XOR-им тем же значением и получаем исходный пароль. Этот метод хорош своей простотой и основан на свойствах логической операции XOR: любое число, будучи дважды проXORено один и тем же значением, возвращается в исходное состояние. Если хочешь усложнить шифровку, то можно добавить скажем лишний символ, который будет содержать контрольную сумму (сумму значений символов взятых по модулю 256, чтобы сумма поместилась в одном символе). Это позволит избежать ручного редактирования твоего файла с паролями. Если контрольная сумма не совпадает, то злобно ругаешься и завершаешь приложение.

3) Как направить в правильное русло пока не знаю, так как не имею понятия об уровне твоей подготовки. Готов оказывать экспертную поддержку, отвечая на вопросы любой сложности.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
angrystrike
Сообщения: 8
Зарегистрирован: 26 июл 2017, 18:52

27 июл 2017, 16:20

Есть вот такая вот функция(лишнее я убрал):

Код: Выделить всё


void Login(unordered_map <int, Guest> mp)
{
				int pass;
				size_t pNumber;
				string login;
				string addr;
				string fullName;

				cout << "Enter login: ";
				cin >> login;

				cout << "Enter password(it must contain only numbers): ";
				cin >> pass;

				cout << "Enter full name: ";
				cin >> fullName;

				cout << "Enter address: ";
				cin >> addr;

				cout << "Enter phone number: ";
				cin >> pNumber;
				mp.emplace(0, Guest(login, pass, fullName, addr, pNumber));
				
				ofstream fout("tmp.oarchive");
				if (fout.is_open())
				{
					
					text_oarchive oa(fout);
					
					oa << mp;


					fout.close();
				}

}
Ошибка C4308 отрицательная целая константа преобразована в тип без знака c:\program files\boost_1_55_0\boost_1_55_0\boost\mpl\print.hpp 51
Ошибка C2039 serialize: не является членом "std::unordered_map<int,Guest,std::hash<int>,std::equal_to<_Kty>,std::allocator<std: :p air<const _Kty,_Ty>>>" exam2 c:\program files\boost_1_55_0\boost_1_55_0\boost\serialization\access.hpp 118
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

27 июл 2017, 17:04

А зачем тебе unordered_map здесь? Это раз. Во-вторых, сразу говорю, что если хочешь шифровать пароли, то файл должен быть бинарный, так как зашифрованный пароль явно будет иметь непечатные символы. Собственно, шифровать можно и все остальные данные, что лишь улучшит защищенность программы. Так что от бустового text_oarchive придётся отказаться. Тем более ты всё равно не понимаешь, как с ним работать, коль пытаешься в него unordered_map засериализировать :) Используй просто методы ofstream для записи бинарных данных. Сначала выводишь длину строки, потом сами символы. Длина будет необходима для того, чтобы понять сколько проичитать символов, когда ты будешь загружать данные из этого файла.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
angrystrike
Сообщения: 8
Зарегистрирован: 26 июл 2017, 18:52

27 июл 2017, 19:07

1) map, потому что хотел делать поиск по ключу. Подскажи что то получше
2)Как я понял в задании мне это уже не поможет, но всё же что не так с сериализированием unordered_map?
3)А про другой способ записи в файл можно поподробнее?
4)Видел код сериализации обычной map, а почему unordered нельзя?
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

27 июл 2017, 22:12

1) Конечно используй map/unordered_map, если там действительно нужен ключ. Просто из примера совсем не очевидно, что ключ нужен и что именно является ключом. Возможно просто не хватает кода.

2) Если вкратце, класс должен иметь метод serialize, чтобы сериализоваться в бустовый text_oarchive. Подробнее можно посмотреть, например, здесь. Ищи по по строке serialize.

3) Можно просто вызывать метод std: :o stream::write. Шифруем строку (через XOR, можно добавить контрольную сумму), затем записываем с помощью указанного метода длину получившегося массива байт, потом записываем сам массив одним блоком.

4) Возможно ты видел код сериализации бустовой мапы, а не обычной STL-ной. Бустовая мапа как раз уже имеет необходимый метод serialize.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

27 июл 2017, 23:34

Мне больно смотреть как кто-то считывает пользовательский ввод при помощи std::cin. Эта конструкция хрупкая как хрустальный сервиз на карточном домике. Используй std::getline, потом конвертируй введенную строку в другой тип при помощи boost::lexical_cast. Можешь предварительно регекспом еще проверить, если умеешь.
2B OR NOT(2B) = FF
angrystrike
Сообщения: 8
Зарегистрирован: 26 июл 2017, 18:52

28 июл 2017, 10:55

Хорошо, сделаю
angrystrike
Сообщения: 8
Зарегистрирован: 26 июл 2017, 18:52

28 июл 2017, 11:09

Долго думал, как реализовать эту задачу, ну вроде что-то надумал:

[CENTER]Базовый класс:
protected: key, FileName;
public:
save();
get();
delete();[/CENTER]
Остальные классы(классы юзера, категории, вопроса, вариантов ответа и отвева пользователя) от него наследуются:

Как я собрался реализовывать эти классы на примере класса юзер:

class user : BE
key = user_id;
FileName = users.txt
int _userId;
Role _role;
string _login;
int _pw;
string _addr;
size_t _phone;


Смотрится рационально(по крайней мере я так думаю ), но дайте какие нибудь советы по самой реализации и какую структуру данных стоит использовать для хранения в файле, последующем считывании?
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

28 июл 2017, 13:17

angrystrike писал(а):Смотрится рационально(по крайней мере я так думаю ), но дайте какие нибудь советы по самой реализации и какую структуру данных стоит использовать для хранения в файле, последующем считывании?

ООП применяют для того чтобы не приходилось писать один и тот же код по многу раз, а не для того чтобы нарисовать красивую иерархию классов. Если ты замечаешь, что в программе много одинаковых кусков, то возможно имеет смысл нарисовать виртуальный метод или шаблон. Если ты можешь обосновать какого упрощения кода ты добился своим наследованием, то вперед. Иначе, скорее всего, нет смысла использовать ООП вообще.

В реальной жизни данные сериализуют в ключ=значение, csv, xml или json, а если нужен двоичный формат, то ProtoBuf или ASN.1.
2B OR NOT(2B) = FF
Ответить