· 10 years ago · Jun 01, 2016, 11:42 AM
1#include <iostream>
2#include <iomanip>
3#include <stdexcept>
4#include <vector>
5#include <cstdlib>
6#include <sstream>
7#include <cstring>
8#include <algorithm>
9
10using namespace std;
11
12#include "sqltools.h"
13#include "repository_object.h"
14#include "repository.h"
15
16// ---------------- MODELS -------------------- //
17
18class User : public RepositoryObject {
19 public:
20 enum Role { admin, user };
21 static const char* roleTitles[];
22
23 string login;
24 string password;
25 Role role;
26
27 public:
28 User() : RepositoryObject() {
29
30 }
31
32 User(const string login, const string password, const Role role) : RepositoryObject() {
33 this->login = login;
34 this->password = password;
35 this->role = role;
36 }
37
38 const char* roleTitle() {
39 return User::roleTitles[role];
40 }
41
42 static Role getRoleByTitle(const string title) {
43 return User::getRoleByTitle(title.c_str());
44 }
45
46 static Role getRoleByTitle(const char* title) {
47 if (strcmp(title, "admin") == 0) {
48 return Role::admin;
49 }
50
51 if (strcmp(title, "user") == 0) {
52 return Role::user;
53 }
54
55 return (Role)-1;
56 }
57
58 virtual bool isValid() {
59 if (login.length() && password.length() && (role == user || role == admin)) {
60 return true;
61 }
62
63 return false;
64 }
65
66 protected:
67 virtual RepositoryObject* setAttribute(const char *attrName, const char *attrValue) {
68 if (strcmp(attrName, "login") == 0) {
69 this->login = attrValue;
70 }
71 else if (strcmp(attrName, "password") == 0) {
72 this->password = attrValue;
73 }
74 else if (strcmp(attrName, "role") == 0) {
75 this->role = (Role)_atoi64(attrValue);
76 }
77
78 return RepositoryObject::setAttribute(attrName, attrValue);
79 }
80};
81
82class Patient : public RepositoryObject {
83 public:
84 enum Sex { male, female };
85 static const char* sexTitles[];
86
87 string firstName;
88 string lastName;
89
90 string city;
91 string diagnosis;
92
93 int age;
94 Sex sex;
95
96 public:
97 Patient() : RepositoryObject() {
98
99 }
100
101 Patient(const string firstName, const string lastName, const int age, Sex sex, const string city, const string diagnosis) : RepositoryObject() {
102 this->firstName = firstName;
103 this->lastName = lastName;
104 this->age = age;
105 this->sex = sex;
106 this->city = city;
107 this->diagnosis = diagnosis;
108 }
109
110 const char* sexTitle() {
111 return sexTitles[sex];
112 }
113
114 static Sex getSexByTitle(const string title) {
115 return Patient::getSexByTitle(title.c_str());
116 }
117
118 static Sex getSexByTitle(const char* title) {
119 if (strcmp(title, "male") == 0) {
120 return Sex::male;
121 }
122
123 if (strcmp(title, "female") == 0) {
124 return Sex::female;
125 }
126
127 return (Sex)-1;
128 }
129
130 bool isValid() {
131 if (firstName.length() && lastName.length() && city.length() && diagnosis.length() && age > 0 && (sex == male || sex == female))
132 return true;
133
134 return false;
135 }
136
137 protected:
138 RepositoryObject* setAttribute(const char *attrName, const char *attrValue) {
139 if (strcmp(attrName, "lastName") == 0) {
140 this->lastName = attrValue;
141 }
142 else if (strcmp(attrName, "firstName") == 0) {
143 this->firstName = attrValue;
144 }
145 else if (strcmp(attrName, "age") == 0) {
146 this->age = strtoul(attrValue, NULL, 0);
147 }
148 else if (strcmp(attrName,"sex") == 0) {
149 this->sex = (Sex)strtoul(attrValue, NULL, 0);
150 }
151 else if (strcmp(attrName, "city") == 0) {
152 this->city = attrValue;
153 }
154 else if (strcmp(attrName, "diagnosis") == 0) {
155 this->diagnosis = attrValue;
156 }
157
158 return RepositoryObject::setAttribute(attrName, attrValue);
159 }
160};
161
162// ------------ STATIC INITIALIZATION -------- //
163
164const char* User::roleTitles[] = { "admin", "user" };
165const char* Patient::sexTitles[] = { "male", "female" };
166
167// ------------- REPOSITORIES --------------- //
168
169class UserRepository : public Repository {
170 public:
171 UserRepository(SQLManager *db) : Repository(db) {
172 _createSchema();
173 }
174
175 User* getByLoginAndPassowrd(const string login, const string password) {
176 string queryStr = "SELECT * FROM " + _getTableName() + " WHERE login = ? AND password = ?;";
177 SQLQuery *query = dbManager->prepareQuery(queryStr.c_str());
178
179 query->setTextParam(1, login);
180 query->setTextParam(2, password);
181
182 vector<RepositoryObject*> objects = fillInObjects(dbManager->selectQuery(query));
183 return objects.size() == 1 ? (User*)objects[0] : nullptr;
184 }
185
186 protected:
187 virtual RepositoryObject* _initNewRecord() {
188 return new User();
189 }
190
191 virtual string _getTableName() {
192 return "users";
193 }
194
195 virtual vector<string> _getColumnNames() {
196 return { "id", "login", "password", "role" };
197 }
198
199 //Ñ€ÐµÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¼ÐµÑ‚Ð¾Ð´Ð° вÑтавки нового Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ñƒ клаÑÑа хранилища пользователÑ
200 //принимает в ÑÐµÐ±Ñ Ð¾Ð±ÑŠÐµÐºÑ‚ Ñ Ð°Ñ‚Ñ‚Ñ€Ð¸Ð±ÑƒÐ´Ð°Ð¼Ð¸
201 virtual bool _insertRecord(RepositoryObject *object) {
202 //тут уже полиморфизм не прокатит, нам нужно работать Ñ ÐºÐ¾Ð½ÐºÑ€ÐµÑ‚Ð½Ñ‹Ð¼Ð¸ аттрибутами клаÑÑа, поÑтому преобразовываем базовый клаÑÑ Ð² его непоÑредÑтвенную реализацию
203 User *user = (User*)object;
204 //формирем Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð²Ñтавки, как и прежде вопроÑики Ñто параметры (можно было Ñделать также через + как Ñ _getTableName, проÑто так безопаÑнее)
205 SQLQuery *query = dbManager->prepareQuery("INSERT INTO " + _getTableName() + " (login, password, role) VALUES (?, ?, ?);");
206
207 query->setTextParam(1, user->login); //Ñетаем на первый вопроÑик логине
208 query->setTextParam(2, user->password); //на второй паÑÑворÑ
209 query->setIntParam(3, user->role); //на третий роль, Ñ‚.е. роль типа enum, а enum Ñто грубо Ð³Ð¾Ð²Ð¾Ñ€Ñ Ñ…Ñ€Ð°Ð½Ð¸Ñ‚ÑÑ ÐºÐ°Ðº цифра, то иÑпользем метод Ð´Ð»Ñ ÑƒÑтановки чиÑлового параметра
210
211 // вызываем библиотечную функцию ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¸ÑполнÑет SQL в базе данных, возращает true еÑли вÑÑ‘ ок, еÑли не прокатило то false.
212 return _insertSQL(object, query);
213 }
214
215
216 // тож Ñамое что и выше, только другой Ð·Ð°Ð¿Ñ€Ð¾Ñ - на обновление
217 virtual bool _updateRecord(RepositoryObject *object) {
218 User *user = (User*)object;
219 SQLQuery *query = dbManager->prepareQuery("UPDATE " + _getTableName() + " SET login=?, password=?, role=? WHERE id=?;");
220
221 query->setTextParam(1, user->login);
222 query->setTextParam(2, user->password);
223 query->setIntParam(3, user->role);
224 query->setIntParam(4, user->getID());
225
226 return _execSQL(query);
227 };
228
229 virtual void _createSchema() {
230 string tableSchemaQuery =
231 "CREATE TABLE IF NOT EXISTS " + _getTableName() + " (\
232 id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, \
233 login VARCHAR(255) UNIQUE NOT NULL, \
234 password VARCHAR(255) NOT NULL, \
235 role INTEGER NOT NULL \
236 );";
237
238 return _createSQLSchema(tableSchemaQuery);
239 }
240};
241
242class PatientRepository : public Repository {
243 public:
244 PatientRepository(SQLManager *db) : Repository(db) {
245 _createSchema();
246 }
247
248 vector<RepositoryObject*> getAllSortedBy(string attrName) {
249 SQLQuery *query = dbManager->prepareQuery("SELECT * FROM " + _getTableName() + " ORDER BY " + attrName + " COLLATE NOCASE;");
250 return fillInObjects(dbManager->selectQuery(query));
251 }
252
253 //метод хранилища пациентов Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка по диагнозу и возраÑту, принимает Ñтроку диагноза и цифру возраÑта
254 vector<RepositoryObject*> getAllWhereDiagnosisAndAge(string diagnosis, int age) {
255 //формируем Ñтроку запроÑа в базу данных - Ñто SQL код
256 //dbManager Ñто наш Ñамопальный библиотечный клаÑÑ, помогает работать Ñ SQL и базой данный SQLITE3
257 //Ðа выходе Ñто *query должен Ñодержать Ñтроку запроÑа и вÑÑкую вÑпомогательную и не интереÑную нам ерунду Ð´Ð»Ñ SQLITE3
258 //Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð±ÑƒÐ´ÐµÑ‚ выглÑдеть типа так SELECT * FROM patients WHERE diagnosis = 'анемиÑ' AND age > 21
259 //Где ÑтоÑÑ‚ вопроÑики в Ñтроке Ñто меÑта Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð², что бы их уÑтановить иÑпользуетÑÑ Ð¸Ð½Ð´ÐµÐºÑ Ð¸Ñ… позиций
260 //Ð”Ð»Ñ Ð¿ÐµÑ€Ð²Ð¾Ð³Ð¾ вопроÑика Ð¸Ð½Ð´ÐµÐºÑ - 1, Ð´Ð»Ñ Ð²Ñ‚Ð¾Ñ€Ð¾Ð³Ð¾ - 2, Ð´Ð»Ñ Ñ‚Ñ€ÐµÑ‚ÑŒÐµÐ³Ð¾ - 3 и так далее
261 SQLQuery *query = dbManager->prepareQuery("SELECT * FROM " + _getTableName() + " WHERE diagnosis = ? AND age > ?;");
262
263 //УÑтанавливаем значение параметра 1, Ñ‚.к. он у Ð½Ð°Ñ Ñ‚ÐµÐºÑтовый иÑпользуем setTextParam
264 //Ðтот вызов грубо Ð³Ð¾Ð²Ð¾Ñ€Ñ Ð´Ð¾Ð»Ð¶ÐµÐ½ внутри запроÑа вмеÑто diagnosis = ? Ñделать diagnosis = 'анемиÑ'
265 //Короче подÑтавить вмеÑто ? значение из переменной diagnosis
266 query->setTextParam(1, diagnosis);
267
268 //тож Ñамое но Ð´Ð»Ñ Ñ‡Ð¸Ñлового возраÑта
269 query->setIntParam(2, age);
270
271 //выполнÑем получившийÑÑ Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð² базу данных, получаем данные из базы и вызываем/отправлÑем Ñти данные в метод fillInObjects
272 //дальше опиÑание Ñмотри в методе fillInObjects - он опиÑан в другом файле -repository.h
273 return fillInObjects(dbManager->selectQuery(query));
274 }
275
276 vector<RepositoryObject*> getAllWhereCityNot(string city) {
277 SQLQuery *query = dbManager->prepareQuery("SELECT * FROM " + _getTableName() + " WHERE city != ? COLLATE NOCASE;");
278 query->setTextParam(1, city);
279
280 return fillInObjects(dbManager->selectQuery(query));
281 }
282
283 protected:
284 virtual RepositoryObject* _initNewRecord() {
285 return new Patient();
286 }
287
288 virtual string _getTableName() {
289 return "patients";
290 }
291 virtual vector<string> _getColumnNames() {
292 return { "id", "firstName", "lastName", "age", "sex", "city", "diagnosis" };
293 }
294
295 virtual bool _insertRecord(RepositoryObject *object) {
296 SQLQuery *query = dbManager->prepareQuery("INSERT INTO " + _getTableName() + " (firstName, lastName, age, sex, city, diagnosis) VALUES (?, ?, ?, ?, ?, ?);");
297 Patient *patient = (Patient*)object;
298
299 query->setTextParam(1, patient->firstName);
300 query->setTextParam(2, patient->lastName);
301 query->setIntParam(3, patient->age);
302 query->setIntParam(4, patient->sex);
303 query->setTextParam(5, patient->city);
304 query->setTextParam(6, patient->diagnosis);
305
306 return _insertSQL(object, query);
307 }
308
309 virtual bool _updateRecord(RepositoryObject *object) {
310 Patient *patient = (Patient*)object;
311 SQLQuery *query = dbManager->prepareQuery("UPDATE " + _getTableName() + " SET firstName=?, lastName=?, age=?, sex=?, city=?, diagnosis=? WHERE id=?;");
312
313 query->setTextParam(1, patient->firstName);
314 query->setTextParam(2, patient->lastName);
315 query->setIntParam(3, patient->age);
316 query->setIntParam(4, patient->sex);
317 query->setTextParam(5, patient->city);
318 query->setTextParam(6, patient->diagnosis);
319 query->setIntParam(7, patient->getID());
320
321 return _execSQL(query);
322 };
323
324 virtual void _createSchema() {
325 string tableSchemaQuery =
326 "CREATE TABLE IF NOT EXISTS " + _getTableName() + " (\
327 id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, \
328 firstName VARCHAR(255) NOT NULL, \
329 lastName VARCHAR(255) NOT NULL, \
330 age INTEGER NOT NULL DEFAULT 0, \
331 sex VARCHAR(10) NOT NULL, \
332 city VARCHAR(50) NOT NULL, \
333 diagnosis VARCHAR(255) NOT NULL \
334 );";
335
336 return _createSQLSchema(tableSchemaQuery);
337 }
338};
339
340class TableView {
341 protected:
342 vector<int> _colsWidth;
343
344 static void consoleClear() {
345 system("cls");
346 }
347
348 virtual void displayRow(RepositoryObject* object) = 0;
349 virtual void displayHeader() = 0;
350
351 template<typename T> void displayCell(int index, T t) {
352 cout << "|" << setw(_colsWidth[index]) << t;
353 }
354
355 void displayEndRow() {
356 cout << "|" << endl;
357 }
358
359 void displayLast() {
360 stringstream buff;
361
362 buff << "|";
363 for(int i = 0; i < _colsWidth.size(); i++) {
364 buff << string(_colsWidth[i], '-');
365
366 if (i + 1 != _colsWidth.size())
367 buff << '-';
368 }
369 buff << "|";
370
371 cout << buff.str() << endl;
372 }
373
374 void log(string logText) {
375 cout << endl << endl << logText << endl;
376 }
377
378 public:
379 TableView(const vector<int> colsWidth) {
380 _colsWidth = colsWidth;
381 }
382
383 ~TableView() {
384
385 }
386
387 virtual RepositoryObject* findById(Repository *repos) = 0;
388 virtual bool add(Repository *repos) = 0;
389 virtual bool remove(Repository *repos) = 0;
390 virtual bool update(Repository *repos) = 0;
391
392 void display(vector<RepositoryObject*> objects, bool clear = true) {
393 if (clear) {
394 TableView::consoleClear();
395 }
396
397 displayHeader();
398 displayLast();
399
400 if (objects.size() > 0) {
401 for(int i = 0; i < objects.size(); i++) {
402 displayRow(objects[i]);
403 }
404
405 }
406
407 displayLast();
408 }
409};
410
411class UsersView : public TableView {
412 private:
413 virtual void displayRow(RepositoryObject* object) {
414 User *user = (User*)object;
415 int colIndex = 0;
416
417 displayCell(colIndex++, user->getID());
418 displayCell(colIndex++, user->login);
419 displayCell(colIndex++, user->password);
420 displayCell(colIndex++, user->roleTitle());
421
422 displayEndRow();
423 };
424
425 virtual void displayHeader() {
426 int colIndex = 0;
427
428 displayCell(colIndex++, "ID");
429 displayCell(colIndex++, "Login");
430 displayCell(colIndex++, "Password");
431 displayCell(colIndex++, "Role");
432
433 displayEndRow();
434 };
435
436 public:
437 UsersView() : TableView({3, 20, 20, 5}) {
438
439 }
440
441 virtual RepositoryObject* findById(Repository* repos) {
442 RepositoryObject *user = nullptr;
443 string userID;
444
445 cout << endl << "User ID: ";
446 getline(cin, userID);
447
448 if (userID.length()){
449 row_id id = _atoi64(userID.c_str());
450 user = repos->getById(id);
451 }
452
453 return user;
454 }
455
456 //добавление нового пользователÑ
457 //что бы лучше понимать в голове проÑто предÑтавить Ñебе 3 типа клаÑÑов
458 //1) клаÑÑ Ð´Ð°Ð½Ð½Ñ‹Ñ… который хранитÑÑ - обычно их называют Model
459 //2) клаÑÑ Ñ…Ñ€Ð°Ð½Ð¸Ð»Ð¸Ñ‰Ð° (Repasitory) он реализует вÑе методы о том как Ñохранить, удалить, выбрать Model
460 //3) клаÑÑ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (View) - он занимаетÑÑ Ð²Ð·Ð°Ð¸Ð¼Ð¾Ð´ÐµÐ¹Ñтвием Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÐµÐ¼
461 // ÑÐµÐ¹Ñ‡Ð°Ñ Ð¼Ñ‹ в клаÑÑе типа View
462
463 //метод Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ пользователÑ, принимает в ÑÐµÐ±Ñ Ñ…Ñ€Ð°Ð½Ð¸Ð»Ð¸Ñ‰Ðµ пользователей что бы потом в него Ñохранить
464 virtual bool add(Repository *repos) {
465 //подготавливаем переменные
466 User *user = nullptr;
467 string login, password, role;
468
469 //говорим что мы ÑÑ‡Ñ Ð´ÐµÐ»Ð°ÐµÐ¼
470 log("Add new user: ");
471
472 cout << "Login: ";
473 getline(cin, login); //вÑе как обычно говорим что ввеÑти и вводим
474
475 cout << "Password: ";
476 getline(cin, password);
477
478 cout << "Role (admin, user): ";
479 getline(cin, role);
480
481 // проверÑм вÑе ли мы ввели, вÑе ли Ñтроки не пуÑтые
482 if (login.length() && password.length() && role.length()) {
483 //пытаемÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ роль по её имени, роли у Ð½Ð°Ñ Ñ…Ñ€Ð°Ð½ÑÑ‚ÑÑ ÐºÐ°Ðº enum
484 //enum Ñто такой тип данных который иÑпользуетÑÑ Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ‡Ð¸ÑÐ»ÐµÐ½Ð¸Ñ ÐºÐ°ÐºÐ¸ÐµÑ…-то конÑтантных штук
485 //грубо Ð³Ð¾Ð²Ð¾Ñ€Ñ Ð¼ÐµÑ‚Ð¾Ð´ ниже проÑто преобразовывает Ñтроку 'admin' в типа данных enum Ñо значением admin
486 User::Role userRole = User::getRoleByTitle(role);
487
488 //Ñоздаем нового Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ñ Ð»Ð¾Ð³Ð¸Ð½ пароль роль которые мы ввели
489 user = new User(login, password, userRole);
490 }
491
492 //еÑли мы ничего не введем то и уÑловие выше не выполнитÑÑ, а Ñледовательно и Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð½Ðµ будет Ñоздано,
493 //поÑтому проверÑм, Ñмогли ли мы инициализировать нового пользователÑ
494 if (user) {
495 //Ñмогли инициализировать, теперь пробуем Ñохранить (запиÑать) в хранилище
496 //еÑли метод save вернет true то Ñмогли запиÑать, еÑли фолÑ, то не Ñмогли
497 //дальше Ñмотри метод save в repository.h
498 if (repos->save(user)) {
499 log("User successfully saved");
500 return true;
501 }
502 else {
503 log("User couldn't be saved");
504 }
505 }
506 else {
507 //не Ñмогли, говорим об Ñтом
508 log("Please check your input");
509 }
510
511 return false;
512 }
513
514 virtual bool remove(Repository *repos) {
515 RepositoryObject *user = nullptr;
516
517 log("Remove user: ");
518
519 if (user = findById(repos)) {
520 log("User found! Deleting...");
521
522 if (repos->remove(user)) {
523 log("User successfully deleted");
524 return true;
525 }
526 else {
527 log("Can't delete user");
528 }
529 }
530 else {
531 log("User not found!");
532 }
533
534 return false;
535 }
536
537 virtual bool update(Repository *repos) {
538 User *user = nullptr;
539 string login, password, role;
540
541 log("Update user: ");
542
543 if (user = (User*)findById(repos)) {
544 log("User found!");
545
546 cout << "Login: ";
547 getline(cin, login);
548
549 cout << "Password: ";
550 getline(cin, password);
551
552 cout << "Role (admin, user): ";
553 getline(cin, role);
554
555 if (login.length()) {
556 user->login = login;
557 }
558
559 if (password.length()) {
560 user->password = password;
561 }
562
563 if (role.length()) {
564 User::Role userRole = User::getRoleByTitle(role);
565 user->role = userRole;
566 }
567
568 if (repos->save(user)) {
569 log("User successfully updated");
570 return true;
571 }
572 else {
573 log("Can't update user");
574 }
575 }
576 else {
577 log("User not found!");
578 }
579
580 return false;
581 }
582};
583
584class PatientsView : public TableView {
585 private:
586 virtual void displayRow(RepositoryObject* object) {
587 Patient *patient = (Patient*)object;
588 int colIndex = 0;
589
590 displayCell(colIndex++, patient->getID());
591 displayCell(colIndex++, patient->firstName);
592 displayCell(colIndex++, patient->lastName);
593 displayCell(colIndex++, patient->age);
594 displayCell(colIndex++, patient->sexTitle());
595 displayCell(colIndex++, patient->city);
596 displayCell(colIndex++, patient->diagnosis);
597
598 displayEndRow();
599 };
600
601 virtual void displayHeader() {
602 int colIndex = 0;
603
604 displayCell(colIndex++, "ID");
605 displayCell(colIndex++, "First Name");
606 displayCell(colIndex++, "Last Name");
607 displayCell(colIndex++, "Age");
608 displayCell(colIndex++, "Sex");
609 displayCell(colIndex++, "City");
610 displayCell(colIndex++, "Diagnosis");
611
612 displayEndRow();
613 };
614
615 public:
616 PatientsView() : TableView({ 3, 13, 13, 3, 6, 15, 15 }) {
617
618 }
619
620 virtual RepositoryObject* findById(Repository* repos) {
621 RepositoryObject *patient = nullptr;
622 string patientID;
623
624 cout << endl << "Patient ID: ";
625 getline(cin, patientID);
626
627 if (patientID.length()){
628 row_id id = _atoi64(patientID.c_str());
629 patient = repos->getById(id);
630 }
631
632 return patient;
633 }
634
635 virtual bool add(Repository *repos) {
636 Patient *patient = nullptr;
637 string firstName, lastName, city, sex, diagnosis, age;
638
639 log("Add new patient: ");
640
641 cout << "First Name: ";
642 getline(cin, firstName);
643
644 cout << "Last Name: ";
645 getline(cin, lastName);
646
647 cout << "City: ";
648 getline(cin, city);
649
650 cout << "Sex (male, female): ";
651 getline(cin, sex);
652
653 cout << "Age: ";
654 getline(cin, age);
655
656 cout << "Diagnosis: ";
657 getline(cin, diagnosis);
658
659 if (firstName.length() && lastName.length() && city.length() && sex.length() && age.length() && diagnosis.length()) {
660 Patient::Sex userSex = Patient::getSexByTitle(sex);
661 patient = new Patient(firstName, lastName, atoi(age.c_str()), userSex, city, diagnosis);
662 }
663
664 if (patient) {
665 if (repos->save(patient)) {
666 log("Patient successfully saved");
667 return true;
668 }
669 else {
670 log("Patient couldn't be saved");
671 }
672 }
673 else {
674 log("Please check your input");
675 }
676
677 return false;
678 }
679
680 virtual bool update(Repository *repos) {
681 Patient *patient = nullptr;
682 string firstName, lastName, city, sex, diagnosis, age;
683
684 log("Update patient: ");
685
686 if (patient = (Patient*)findById(repos)) {
687 log("Patient found!");
688
689 cout << "First Name: ";
690 getline(cin, firstName);
691
692 cout << "Last Name: ";
693 getline(cin, lastName);
694
695 cout << "City: ";
696 getline(cin, city);
697
698 cout << "Sex (male, female): ";
699 getline(cin, sex);
700
701 cout << "Age: ";
702 getline(cin, age);
703
704 cout << "Diagnosis: ";
705 getline(cin, diagnosis);
706
707 if (firstName.length()) {
708 patient->firstName = firstName;
709 }
710
711 if (lastName.length()) {
712 patient->lastName = lastName;
713 }
714
715 if (city.length()) {
716 patient->city = city;
717 }
718
719 if (sex.length()) {
720 Patient::Sex patientSex = Patient::getSexByTitle(sex);
721 patient->sex = patientSex;
722 }
723
724 if (age.length()) {
725 patient->age = atoi(age.c_str());
726 }
727
728 if (diagnosis.length()) {
729 patient->diagnosis = diagnosis;
730 }
731
732 if (repos->save(patient)) {
733 log("Patient successfully updated");
734 return true;
735 }
736 else {
737 log("Can't update Patient");
738 }
739 }
740 else {
741 log("Patient not found!");
742 }
743
744 return false;
745 }
746
747 virtual bool remove(Repository *repos) {
748 RepositoryObject *patient = nullptr;
749
750 log("Remove patient: ");
751
752 if (patient = findById(repos)) {
753 log("Patient found! Deleting...");
754
755 if (repos->remove(patient)) {
756 log("Patient successfully deleted");
757 return true;
758 }
759 else {
760 log("Can't delete patient");
761 }
762 }
763 else {
764 log("Patient not found!");
765 }
766
767 return false;
768 }
769};
770
771class LoginManager {
772 private:
773 UserRepository *_repos;
774 unsigned int _attempts;
775
776 public:
777 LoginManager(UserRepository *repos, unsigned int attempts = 3) {
778 this->_repos = repos;
779 this->_attempts = attempts;
780 }
781
782 User* authorize() {
783 string login, password;
784 unsigned int maxLoginAttempts = _attempts;
785
786 do {
787 cout << endl << endl << "Please authorize!" << endl;
788 cout << endl << "Login: ";
789 getline(cin, login);
790
791 cout << "Password: ";
792 getline(cin, password);
793
794 if (login.length() && password.length()) {
795 if (User *user = _repos->getByLoginAndPassowrd(login, password)) {
796 return user;
797 }
798 else {
799 cout << endl << "User not found...";
800 }
801 }
802
803 } while(maxLoginAttempts--);
804
805 return nullptr;
806 }
807};
808
809class ProgramMenu {
810 private:
811 User *_currentUser;
812 unsigned int _state = 0;
813
814 int _userChoice() {
815 string userInput;
816
817 do {
818 cout << endl << "Your choice: ";
819 getline(cin, userInput);
820 } while(!userInput.length());
821
822 try {
823 return stoi(userInput);
824 }
825 catch(const invalid_argument& ex) {
826 return -1;
827 }
828 }
829
830 bool _isUserAdmin() {
831 return _currentUser->role == User::admin;
832 }
833
834 public:
835 ProgramMenu(User *user) {
836 this->_currentUser = user;
837 }
838
839 int back(int state = 0) {
840 _state = state;
841 return step();
842 }
843
844 int step() {
845 switch(_state) {
846 case 0:
847 return showStartMenu();
848 case 1:
849 return showUsersManagement();
850 case 2:
851 return showPatiaentsManagement();
852 case 3:
853 return showPatiaentsListing();
854 case 4:
855 return showSortMenu();
856 default:
857 return -1;
858 }
859 }
860
861 int showStartMenu() {
862 _state = 0;
863
864 if (_isUserAdmin()) {
865 return showAdminMenu();
866 }
867 else {
868 return showUserMenu();
869 }
870 }
871
872 int showAdminMenu() {
873 cout << endl;
874 cout << "1. Users Management" << endl;
875 cout << "2. Patients Management" << endl;
876 cout << "3. Exit" << endl;
877
878 do {
879 int choice = _userChoice();
880 switch(choice) {
881 case 1:
882 return showUsersManagement();
883 case 2:
884 return showPatiaentsManagement();
885 case 3:
886 return -1;
887 }
888 } while(true);
889 }
890
891 int showUserMenu() {
892 return showPatiaentsListing();
893 }
894
895 int showUsersManagement() {
896 _state = 1;
897
898 cout << endl;
899 cout << "1. Show All Users" << endl;
900 cout << "2. Add User" << endl;
901 cout << "3. Update User" << endl;
902 cout << "4. Delete User" << endl;
903 cout << "5. Back" << endl;
904
905 do {
906 int choice = _userChoice();
907 switch(choice) {
908 case 1:
909 return 11;
910 case 2:
911 return 12;
912 case 3:
913 return 13;
914 case 4:
915 return 14;
916 case 5:
917 return back();
918 }
919 } while(true);
920 }
921
922 int showPatiaentsManagement() {
923 _state = 2;
924
925 cout << endl;
926 cout << "1. Patients Listing (Show All, Sort, Search)" << endl;
927 cout << "2. Add Patient" << endl;
928 cout << "3. Update Patient" << endl;
929 cout << "4. Delete Patient" << endl;
930 cout << "5. Back" << endl;
931
932 do {
933 int choice = _userChoice();
934 switch(choice) {
935 case 1:
936 return showPatiaentsListing();
937 case 2:
938 return 22;
939 case 3:
940 return 23;
941 case 4:
942 return 24;
943 case 5:
944 return back();
945 }
946 } while(true);
947 }
948
949 int showPatiaentsListing() {
950 _state = 3;
951
952 cout << endl;
953 cout << "1. Show All Patients" << endl;
954 cout << "2. Show All Where city is not in {city}" << endl;
955 cout << "3. Show All Where diagnosis is {diagnosis} and age older than {age}" << endl;
956 cout << "4. Sort Menu" << endl;
957
958 if (_isUserAdmin()) {
959 cout << "5. Back" << endl;
960 }
961 else {
962 cout << "5. Exit" << endl;
963 }
964
965 do {
966 int choice = _userChoice();
967 switch(choice) {
968 case 1:
969 return 31;
970 case 2:
971 return 32;
972 case 3:
973 return 33;
974 case 4:
975 return showSortMenu();
976 case 5:
977 if (_isUserAdmin()) {
978 return back(2);
979 }
980 else {
981 return -1;
982 }
983 }
984 } while(true);
985 }
986
987 int showSortMenu() {
988 _state = 4;
989
990 cout << endl;
991 cout << "1. Sort By First Name" << endl;
992 cout << "2. Sort By Last Name" << endl;
993 cout << "3. Sort By Age" << endl;
994 cout << "4. Sort By City" << endl;
995 cout << "5. Back" << endl;
996
997 do {
998 int choice = _userChoice();
999
1000 switch(choice) {
1001 case 1:
1002 return 41;
1003 case 2:
1004 return 42;
1005 case 3:
1006 return 43;
1007 case 4:
1008 return 44;
1009 case 5:
1010 return back(3);
1011 }
1012 } while(true);
1013 }
1014};
1015
1016void seedPatients(PatientRepository *repos) {
1017 cout << endl << "Creating default patients...";
1018
1019 repos->save(new Patient("Vasilii", "Vasilev", 21, Patient::male, "Vasilevsk", "atit"));
1020 repos->save(new Patient("Petr", "Petrov", 22, Patient::male, "Petrovsk", "schizophrenia"));
1021 repos->save(new Patient("Bred", "Bredovich", 20, Patient::male, "Vasilevsk", "atit"));
1022 repos->save(new Patient("Ekaterina", "Lopireva", 19, Patient::female, "Minsk", "cancer"));
1023 repos->save(new Patient("Graf", "Drakula", 18, Patient::male, "Norilsk", "schizophrenia"));
1024 repos->save(new Patient("Yura", "Ermakovich", 16, Patient::male, "Minsk", "psyhozis"));
1025}
1026
1027void seedUsers(UserRepository *repos) {
1028 cout << endl << "Creating default users...";
1029
1030 repos->save(new User("admin", "password", User::admin));
1031 repos->save(new User("user", "password", User::user));
1032}
1033
1034void showAllWhereCityNotIn(TableView *view, PatientRepository *repos) {
1035 string city;
1036
1037 do {
1038 cout << endl << "Enter City: ";
1039 getline(cin, city);
1040 } while(!city.length());
1041
1042
1043 vector<RepositoryObject*> patients = repos->getAllWhereCityNot(city);
1044 view->display(patients);
1045}
1046
1047// Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¿Ð¾ÐºÐ°Ð·Ð°Ñ‚ÑŒ вÑе где диагноз и возраÑÑ‚
1048// Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¿Ñ€Ð¸Ð½Ð¸Ð¼Ð°ÐµÑ‚ на вход view - указатель на объект который помогает риÑовать в конÑольке таблицу юзеров
1049// и репазиторий (хранилище) пациентов - там где * Ñто вÑегда указатель на какой-то объект
1050// указатель Ñто такой типа данных, типа как Ñрлык на рабочем Ñтоле
1051void showAllWhereDiagnosisAndAge(TableView *view, PatientRepository *repos) {
1052 // инициализируем переменные вÑпомогательные
1053 string age, diagnosis;
1054 int userAge = -1;
1055
1056 // цикл ввода диагноза Ñ ÐºÐ»Ð°Ð²Ð¸Ð°Ñ‚ÑƒÑ€Ñ‹
1057 do {
1058 cout << endl << "Enter Diagnosis: "; //говорим что надо ввеÑти
1059 getline(cin, diagnosis);//вводим (заполнÑем переменную-буфер)
1060 } while(!diagnosis.length()); //выходим из цикла только тогда когда что-то введено - Ñ‚.е. когда длинна Ñтроки ÐЕ равно ÐУЛЮ
1061
1062
1063 // тоже Ñамое но Ð´Ð»Ñ Ð²Ð¾Ð·Ñ€Ð°Ñта, цикл ввода возраÑта
1064 do {
1065 cout << endl << "Enter Age: ";
1066 getline(cin, age);
1067
1068 // вÑе что вводитÑÑ Ñ ÐºÐ»Ð°Ð²Ð¸Ð°Ñ‚ÑƒÑ€Ñ‹ изначально Ñто Ñтрока,
1069 //Ñ‚.к. возраÑÑ‚ Ñто чиÑло, мы должны Ñконвертировать Ñтроку Ñкажем "21" в чиÑло 21
1070 try {
1071 userAge = stoi(age); //конвертируем
1072 }
1073 catch(const invalid_argument& ex) { //еÑли ÐºÐ¾Ð½Ð²ÐµÑ€Ñ‚Ð°Ñ†Ð¸Ñ Ð½ÐµÐ²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾, например ты ввел asdfaskjdlfha то возникаем ошибка конвертации,
1074 // отлавливаем Ñто иÑключение и чиÑтим переменную-буфер, длинна Ñтроки ÑтановитÑÑ Ñ€Ð°Ð²Ð½Ð¾Ð¹ нулю
1075 age.clear();
1076 }
1077 } while(!age.length()); //выходим из цикла когда в Ñтроке что-то еÑть, еÑли была ошлибка - Ñтрока чиÑтитьÑÑ Ð¸ ввод начинаетÑÑ Ñначала
1078
1079
1080 //когда ввод диагноза и ÐºÐ¾Ð½Ð²ÐµÑ€Ñ‚Ð°Ñ†Ð¸Ñ Ð²Ð¾Ð·Ñ€Ð°Ñта завершены мы можем начать поиÑк в хранилище пациентов
1081 //ищи продолжение в методе getAllWhereDiagnosisAndAge
1082 vector<RepositoryObject*> patients = repos->getAllWhereDiagnosisAndAge(diagnosis, userAge);
1083
1084 //выводим таблицу пациентов на Ñкран
1085 view->display(patients);
1086}
1087
1088int main(int argc, char** argv) {
1089 SQLManager *db = new SQLManager("database.db");
1090
1091 PatientRepository *patientsRepos = new PatientRepository(db);
1092 UserRepository *usersRepos = new UserRepository(db);
1093
1094 // create some default patients
1095 if (patientsRepos->getAll().size() == 0) {
1096 seedPatients(patientsRepos);
1097 }
1098
1099 // create default users
1100 if (usersRepos->getAll().size() == 0) {
1101 seedUsers(usersRepos);
1102 }
1103
1104 LoginManager *manager = new LoginManager(usersRepos);
1105 User *currentUser = manager->authorize();
1106
1107 UsersView *usersView = new UsersView();
1108 PatientsView *patientsView = new PatientsView();
1109
1110 if (currentUser) {
1111 bool exit = false;
1112 ProgramMenu *menu = new ProgramMenu(currentUser);
1113
1114 while(!exit) {
1115 int step = menu->step();
1116
1117 switch(step) {
1118 case -1:
1119 exit = true;
1120 break;
1121 case 11: // Show All Users
1122 usersView->display(usersRepos->getAll());
1123 break;
1124 case 12: // Add User
1125 usersView->add(usersRepos);
1126 break;
1127 case 13: // Update User
1128 usersView->update(usersRepos);
1129 break;
1130 case 14: // Remove User
1131 usersView->remove(usersRepos);
1132 break;
1133 case 22: // Add Patient
1134 patientsView->add(patientsRepos);
1135 break;
1136 case 23: // Update Patient
1137 patientsView->update(patientsRepos);
1138 break;
1139 case 24: // Remove Patient
1140 patientsView->remove(patientsRepos);
1141 break;
1142 case 31: // Show All Patients
1143 patientsView->display(patientsRepos->getAll());
1144 break;
1145 case 32: // Show All Where City is not in
1146 showAllWhereCityNotIn(patientsView, patientsRepos);
1147 break;
1148 case 33: // Show All Where Diagnosis and Age
1149 showAllWhereDiagnosisAndAge(patientsView, patientsRepos);
1150 break;
1151 case 41: // Sort by first name
1152 patientsView->display(patientsRepos->getAllSortedBy("firstName"));
1153 break;
1154 case 42: // Sort by last name
1155 patientsView->display(patientsRepos->getAllSortedBy("lastName"));
1156 break;
1157 case 43: // Sort by age name
1158 patientsView->display(patientsRepos->getAllSortedBy("age"));
1159 break;
1160 case 44: // Sort by city name
1161 patientsView->display(patientsRepos->getAllSortedBy("city"));
1162 break;
1163 }
1164 }
1165 }
1166 else {
1167 cout << endl << "Authorization failed. Exiting...";
1168 }
1169
1170 delete patientsRepos;
1171 delete usersRepos;
1172 delete db;
1173
1174 return 0;
1175}