-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New views and logic for the main dashboard.
- Loading branch information
1 parent
4030d92
commit a98f06b
Showing
16 changed files
with
415 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
#include "QuestionModel.h" | ||
|
||
Question QuestionModel::setAfterUserId(int userId) | ||
{ | ||
this->io.seekg(0, this->io.beg); | ||
|
||
while (this->io.read(reinterpret_cast<char *>(&this->question), sizeof(question))) | ||
{ | ||
if (this->question.user_id == userId) | ||
{ | ||
return this->question; | ||
} | ||
} | ||
|
||
throw invalid_argument("Question not found!"); | ||
} | ||
|
||
Question QuestionModel::setAfterId(int id) | ||
{ | ||
this->io.seekg((id - 1) * sizeof(Question), this->io.beg); | ||
this->io.read(reinterpret_cast<char *>(&this->question), sizeof(Question)); | ||
|
||
return this->question; | ||
} | ||
|
||
bool QuestionModel::questionTitleExists(string &title) | ||
{ | ||
Question question; | ||
|
||
this->io.seekg(0, this->io.beg); | ||
|
||
while (this->io.read(reinterpret_cast<char *>(&question), sizeof(Question))) | ||
{ | ||
if (question.title == title) | ||
{ | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
void QuestionModel::markAnswered(int id) | ||
{ | ||
this->setAfterId(id); | ||
|
||
this->question.hasAnswer = true; | ||
|
||
this->save(); | ||
} | ||
|
||
void QuestionModel::markAs(const string &status, int id) | ||
{ | ||
this->setAfterId(id); | ||
|
||
this->question.active = (status == "active") ? true : false; | ||
|
||
this->save(); | ||
} | ||
|
||
// Serialize the object. | ||
void QuestionModel::save() | ||
{ | ||
this->io.seekp((this->question.id - 1) * sizeof(Question), this->io.beg); | ||
|
||
this->io.clear(); | ||
|
||
if (!this->io.write(reinterpret_cast<char *>(&this->question), sizeof(Question))) | ||
{ | ||
throw system_error(error_code(3, generic_category()), "Failed persisting data to file!"); | ||
} | ||
} | ||
|
||
void QuestionModel::setAttributes(map<string, string> &cleanInputs) | ||
{ | ||
for (map<string, string>::iterator it = cleanInputs.begin(); it != cleanInputs.end(); it++) | ||
{ | ||
if (isInVector(this->protectedAttributes, it->first)) | ||
{ | ||
continue; | ||
} | ||
else if (it->first == "title") | ||
{ | ||
strcpy(this->question.title, it->second.c_str()); | ||
} | ||
else if (it->first == "body") | ||
{ | ||
strcpy(this->question.body, it->second.c_str()); | ||
} | ||
} | ||
|
||
// If there's a new user, assign created_at with the current date. | ||
if (cleanInputs.find("action")->second == "create") | ||
{ | ||
time_t t = time(nullptr); | ||
strftime(this->question.created_at, sizeof(this->question.created_at), "%c", localtime(&t)); | ||
} | ||
|
||
this->question.id = ++this->lastId; | ||
} | ||
|
||
void QuestionModel::dumpFile() | ||
{ | ||
Question question; | ||
|
||
ifstream db(QuestionModel::pathToFile, ios::in | ios::binary); | ||
ofstream dump((QuestionModel::pathToFile.substr(0, QuestionModel::pathToFile.find(".store")).append(".txt")), ios::out | ios::trunc); | ||
|
||
if (db.is_open() && dump.is_open()) | ||
{ | ||
db.seekg(0, db.beg); | ||
|
||
while (db.read(reinterpret_cast<char *>(&question), sizeof(Question))) | ||
{ | ||
dump << question.id << endl | ||
<< question.user_id << endl | ||
<< question.category_id << endl | ||
<< question.title << endl | ||
<< question.body << endl | ||
<< question.created_at << endl | ||
<< question.deleted_at << endl | ||
<< question.hasAnswer << endl; | ||
} | ||
|
||
db.close(); | ||
dump.close(); | ||
} | ||
} | ||
|
||
QuestionModel::~QuestionModel() | ||
{ | ||
this->io.close(); | ||
} | ||
|
||
string QuestionModel::pathToFile = "..\\database\\questions.store"; | ||
void QuestionModel::openIOStream() | ||
{ | ||
this->io.open(QuestionModel::pathToFile, ios::in | ios::out | ios::binary); | ||
this->io.seekp(0, this->io.end); | ||
this->fileSize = this->io.tellp(); | ||
|
||
if (!this->io.is_open()) | ||
{ | ||
toast(string("Couldn't open the file stream!"), string("error")); | ||
} | ||
} | ||
|
||
void QuestionModel::setLastId() | ||
{ | ||
if (this->fileSize == 0) | ||
{ | ||
this->lastId = 0; | ||
} | ||
else | ||
{ | ||
this->io.seekg((this->fileSize / sizeof(Question) - 1) * sizeof(Question), this->io.beg); | ||
this->io.read(reinterpret_cast<char *>(&this->question), sizeof(Question)); | ||
|
||
this->lastId = this->question.id; | ||
} | ||
} | ||
|
||
QuestionModel::QuestionModel() | ||
{ | ||
this->openIOStream(); | ||
this->protectedAttributes = { "id", "user_id", "category_id", "created_at", "deleted_at", "votes", "hasAnswer" }; | ||
this->setLastId(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#pragma once | ||
|
||
#include <iomanip> | ||
#include <ctime> | ||
#include <locale> | ||
|
||
#include "ModelInterface.h" | ||
|
||
using namespace std; | ||
|
||
typedef struct { | ||
int id; | ||
int user_id; | ||
int category_id = 1; | ||
|
||
unsigned votes = 0; | ||
|
||
char title[255] = ""; | ||
char body[1023] = ""; | ||
char created_at[50] = ""; | ||
|
||
// Soft deletes | ||
char deleted_at[50] = ""; | ||
bool hasAnswer = 0; | ||
bool active = 0; | ||
} Question; | ||
|
||
class QuestionModel : public ModelInterface { | ||
private: | ||
static string pathToFile; | ||
|
||
Question question; | ||
|
||
void openIOStream(); | ||
void setLastId(); | ||
|
||
long long fileSize; | ||
int lastId; | ||
public: | ||
static void dumpFile(); | ||
QuestionModel(); | ||
|
||
Question setAfterUserId(int); | ||
Question setAfterId(int); | ||
|
||
bool questionTitleExists(string &); | ||
void markAnswered(int); | ||
void markAs(const string &, int); | ||
void save(); | ||
void setAttributes(map<string, string> &); | ||
|
||
// Set the active to false on logout | ||
~QuestionModel(); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
#include "QuestionRepository.h" | ||
#include "Controller.h" | ||
|
||
string QuestionRepository::alias = "question"; | ||
|
||
string &QuestionRepository::getAlias() | ||
{ | ||
return QuestionRepository::alias; | ||
} | ||
|
||
QuestionRepository::QuestionRepository() | ||
{ | ||
this->defineValidation(); | ||
} | ||
|
||
void QuestionRepository::defineValidation() | ||
{ | ||
// Stand back, I am going to try Regex! | ||
this->ValidationRules = { | ||
{ "title", "^.*$" }, | ||
{ "body", "^.*$" }, | ||
{ "keyword", "^.*$" } | ||
}; | ||
|
||
this->ValidationErrors = { | ||
{ "title", "..." }, | ||
{ "body", "..." }, | ||
{ "keyword", "..." } | ||
}; | ||
|
||
Controller::pushError(string("")); | ||
} | ||
|
||
void QuestionRepository::receiveCleanInput(map<string, string> &cleanInput) | ||
{ | ||
this->model.setAttributes(cleanInput); | ||
|
||
string action = cleanInput.find("action")->second; | ||
|
||
if (action == "search") | ||
{ | ||
string keyword = cleanInput.find("keyword")->second; | ||
|
||
toast(string("Search!"), string("notice")); | ||
} | ||
else if (action == "create") | ||
{ | ||
toast(string("Create!"), string("notice")); | ||
} | ||
else | ||
{ | ||
Controller::pushError(string("Please provide a valid action!")); | ||
} | ||
} | ||
|
||
// Determine what to output via the model. | ||
void QuestionRepository::echo(const string &alias) | ||
{ | ||
if (alias == "") | ||
{ | ||
} | ||
} | ||
|
||
void QuestionRepository::validateItems(map<string, string> &truncatedInput) | ||
{ | ||
for (map<string, string>::iterator it = truncatedInput.begin(); it != truncatedInput.end(); it++) | ||
{ | ||
try | ||
{ | ||
if (!regex_match(it->second.c_str(), regex(this->ValidationRules[it->first.c_str()]))) | ||
{ | ||
Controller::pushError(this->ValidationErrors[it->first.c_str()]); | ||
} | ||
} | ||
catch (const regex_error &e) | ||
{ | ||
toast("\n\n" + string(e.what()) + "\n", string("error")); | ||
} | ||
} | ||
|
||
if (Controller::getErrorBag().empty()) | ||
{ | ||
this->receiveCleanInput(truncatedInput); | ||
} | ||
} | ||
|
||
QuestionRepository::~QuestionRepository() | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
#pragma once | ||
|
||
#include <regex> | ||
|
||
#include "RepositoryInterface.h" | ||
#include "QuestionModel.h" | ||
|
||
using namespace std; | ||
|
||
class QuestionRepository : public RepositoryInterface { | ||
private: | ||
static string alias; | ||
|
||
QuestionModel model; | ||
|
||
void defineValidation(); | ||
void receiveCleanInput(map<string, string> &); | ||
public: | ||
static string &getAlias(); | ||
|
||
QuestionRepository(); | ||
|
||
void validateItems(map<string, string> &); | ||
void echo(const string &); | ||
|
||
~QuestionRepository(); | ||
}; |
Oops, something went wrong.