Implemented user-update command for REST-API
This commit is contained in:
parent
f2fd5bc3b6
commit
74da018c99
@ -49,6 +49,7 @@ void Interface::render()
|
||||
{
|
||||
if (this->_keyboard->available())
|
||||
{
|
||||
this->_inputTimeout = millis();
|
||||
if (this->_keyboard->getLastChr() == 'X')
|
||||
{
|
||||
this->_keyboard->clear();
|
||||
@ -79,7 +80,12 @@ void Interface::render()
|
||||
//this->setState(states::VALIDATE_PIN);
|
||||
}
|
||||
}
|
||||
|
||||
if(this->_display_state==states::ENTER_PIN_ADD_NUM||this->_display_state==states::ENTER_PIN_START){
|
||||
if(millis()-_inputTimeout>10000){
|
||||
this->_keyboard->clear();
|
||||
this->setState(states::ABORT);
|
||||
}
|
||||
}
|
||||
if (this->_displayUpdate)
|
||||
{
|
||||
switch (this->_display_state)
|
||||
|
@ -12,6 +12,7 @@ private:
|
||||
unsigned long _lastDisplayUpdate = 0;
|
||||
unsigned long _displayTimer1 = 0;
|
||||
unsigned long _displayTimer2 = 0;
|
||||
unsigned long _inputTimeout = 0;
|
||||
bool _displayUpdate = true;
|
||||
String _username = "";
|
||||
unsigned int _scroll_index = 0;
|
||||
|
118
src/UserDb.cpp
118
src/UserDb.cpp
@ -1,14 +1,74 @@
|
||||
#include "UserDb.h"
|
||||
#define DEBUG
|
||||
//#define DEBUG
|
||||
using namespace userdb;
|
||||
|
||||
UserDb::UserDb(const char *filename) : filename(filename)
|
||||
{
|
||||
}
|
||||
|
||||
void UserDb::coursor_to_end_of_line(File &f)
|
||||
{
|
||||
while (f.available() && f.read() != '\n')
|
||||
{
|
||||
}
|
||||
}
|
||||
bool UserDb::remove_user(User &user)
|
||||
{
|
||||
return remove_user_by_line(filename, user.line);
|
||||
return update_db_line(filename, user.line);
|
||||
}
|
||||
bool UserDb::update_user(User *user)
|
||||
{
|
||||
return update_db_line(filename, user->line, user);;
|
||||
}
|
||||
bool UserDb::update_db_line(const char *file, linenumber line, User *replace)
|
||||
{
|
||||
const char *temp_file = ".tmp.csv";
|
||||
File old_db = LittleFS.open(file, "r");
|
||||
File new_db = LittleFS.open(temp_file, "w+");
|
||||
linenumber curr_line = 0;
|
||||
bool line_found = false;
|
||||
while (old_db.available())
|
||||
{
|
||||
if (curr_line == line)
|
||||
{
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.println("Found line: " + String(line));
|
||||
#endif
|
||||
if (replace != nullptr)
|
||||
{
|
||||
String insert = replace->toCSVString();
|
||||
#ifdef DEBUG
|
||||
Serial.println("Inserting: " + insert);
|
||||
#endif
|
||||
if (new_db.position() > 0)
|
||||
new_db.write('\n');
|
||||
new_db.write(insert.c_str());
|
||||
}
|
||||
coursor_to_end_of_line(old_db);
|
||||
line_found = true;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (new_db.position() > 0)
|
||||
new_db.write('\n');
|
||||
old_db.sendUntil(new_db, '\n');
|
||||
}
|
||||
curr_line++;
|
||||
}
|
||||
old_db.close();
|
||||
#ifdef DEBUG
|
||||
Serial.println("NewDB:");
|
||||
new_db.seek(0);
|
||||
while (new_db.available())
|
||||
new_db.sendAvailable(Serial);
|
||||
#endif
|
||||
new_db.close();
|
||||
if (LittleFS.remove(file) && LittleFS.rename(temp_file, file))
|
||||
Serial.println("UserDb updated");
|
||||
else
|
||||
Serial.println("Could not delete old userdb");
|
||||
return line_found;
|
||||
}
|
||||
bool UserDb::add_user(User &user)
|
||||
{
|
||||
@ -36,8 +96,14 @@ User UserDb::user_by_pin(String cmp)
|
||||
do
|
||||
{
|
||||
User temp = *it;
|
||||
if (temp.match)
|
||||
return temp;
|
||||
if ((*it).match && (*it).enabled)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Serial.println(" -> Found match");
|
||||
#endif
|
||||
it.close_file();
|
||||
return *it;
|
||||
}
|
||||
++it;
|
||||
} while (it.has_next());
|
||||
return User{.enabled = false};
|
||||
@ -50,9 +116,14 @@ User UserDb::user_by_rfid(String cmp)
|
||||
Iterator it = begin_with_filter(&cmp, USERATTRIBUTES::RFID_UID);
|
||||
do
|
||||
{
|
||||
User temp = *it;
|
||||
if (temp.match)
|
||||
return temp;
|
||||
if ((*it).match && (*it).enabled)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Serial.println(" -> Found match");
|
||||
#endif
|
||||
it.close_file();
|
||||
return *it;
|
||||
}
|
||||
++it;
|
||||
} while (it.has_next());
|
||||
return User{.enabled = false};
|
||||
@ -71,9 +142,34 @@ User UserDb::user_by_uid(String cmp)
|
||||
Iterator it = begin_with_filter(&cmp, USERATTRIBUTES::USER_ID);
|
||||
do
|
||||
{
|
||||
User temp = *it;
|
||||
if (temp.match)
|
||||
return temp;
|
||||
if ((*it).match)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Serial.println(" -> Found match");
|
||||
#endif
|
||||
it.close_file();
|
||||
return *it;
|
||||
}
|
||||
++it;
|
||||
} while (it.has_next());
|
||||
return User{.enabled = false};
|
||||
}
|
||||
User UserDb::user_by_line(linenumber cmp)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Serial.println("Searching for user with line number " + String(cmp));
|
||||
#endif
|
||||
Iterator it = begin_with_filter(cmp, USERATTRIBUTES::LINE_ID);
|
||||
do
|
||||
{
|
||||
if ((*it).match)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Serial.println(" -> Found match");
|
||||
#endif
|
||||
it.close_file();
|
||||
return (*it);
|
||||
}
|
||||
++it;
|
||||
} while (it.has_next());
|
||||
return User{.enabled = false};
|
||||
|
82
src/UserDb.h
82
src/UserDb.h
@ -7,6 +7,7 @@
|
||||
|
||||
namespace userdb
|
||||
{
|
||||
typedef uint16_t linenumber;
|
||||
enum USERATTRIBUTES
|
||||
{
|
||||
LINE_ID,
|
||||
@ -22,7 +23,7 @@ namespace userdb
|
||||
{
|
||||
// User(unsigned long new_uid): uid(new_uid){}
|
||||
unsigned long uid = -1;
|
||||
uint32_t line;
|
||||
linenumber line = UINT16_MAX;
|
||||
mutable String first_name;
|
||||
mutable String last_name;
|
||||
mutable String rfid_uid;
|
||||
@ -39,8 +40,9 @@ namespace userdb
|
||||
{
|
||||
return String(uid) + ";" + first_name + ";" + last_name + ";" + rfid_uid + ";" + user_pin + ";" + (enabled ? "1" : "0");
|
||||
}
|
||||
String toJSONString(){
|
||||
return "{\"uid\":\""+String(uid) + "\",\"first_name\":\"" + first_name + "\",\"last_name\":\"" + last_name + "\",\"rfid_uid\":\"" + rfid_uid + "\",\"user_pin\":\"" + user_pin + "\",\"enabled\":" + (enabled ? "true" : "false")+"}";
|
||||
String toJSONString()
|
||||
{
|
||||
return "{\"uid\":\"" + String(uid) + "\",\"first_name\":\"" + first_name + "\",\"last_name\":\"" + last_name + "\",\"rfid_uid\":\"" + rfid_uid + "\",\"user_pin\":\"" + user_pin + "\",\"enabled\":" + (enabled ? "true" : "false") + ",\"line\":\"" + line + "\"}";
|
||||
}
|
||||
};
|
||||
|
||||
@ -58,15 +60,16 @@ namespace userdb
|
||||
User user_by_rfid(String);
|
||||
User user_by_uid(unsigned long);
|
||||
User user_by_uid(String cmp);
|
||||
bool drop(){
|
||||
User user_by_line(linenumber cmp);
|
||||
bool drop()
|
||||
{
|
||||
LittleFS.remove(filename);
|
||||
File n = LittleFS.open(filename,"a");
|
||||
File n = LittleFS.open(filename, "a");
|
||||
n.close();
|
||||
return true;
|
||||
}
|
||||
static inline User read_csv_line(File &instream, uint32_t &line, String *match, USERATTRIBUTES attr)
|
||||
static inline User read_csv_line(User &res, File &instream, linenumber &line, String *match, USERATTRIBUTES attr)
|
||||
{
|
||||
User res;
|
||||
String uid = instream.readStringUntil(';');
|
||||
if (attr == USER_ID && !uid.equals(*match))
|
||||
return res;
|
||||
@ -84,39 +87,11 @@ namespace userdb
|
||||
res.match = true;
|
||||
return res;
|
||||
}
|
||||
bool remove_user(User &user);
|
||||
static bool remove_user_by_line(const char *file, uint32_t line)
|
||||
{
|
||||
const char *temp_file = ".tmp.csv";
|
||||
File old_db = LittleFS.open(file, "r");
|
||||
File new_db = LittleFS.open(temp_file, "w+");
|
||||
uint32_t curr_line = 0;
|
||||
|
||||
while (old_db.available())
|
||||
{
|
||||
if (curr_line == line)
|
||||
while (old_db.available()&&old_db.read() != '\n')
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
if (new_db.position() > 0)
|
||||
new_db.write('\n');
|
||||
old_db.sendUntil(new_db, '\n');
|
||||
}
|
||||
curr_line++;
|
||||
}
|
||||
old_db.close();
|
||||
#ifdef DEBUG
|
||||
new_db.seek(0);
|
||||
while (new_db.available())
|
||||
new_db.sendAvailable(Serial);
|
||||
#endif
|
||||
new_db.close();
|
||||
LittleFS.remove(file);
|
||||
LittleFS.rename(temp_file, file);
|
||||
return false;
|
||||
}
|
||||
void inline static coursor_to_end_of_line(File &f);
|
||||
bool remove_user(User &user);
|
||||
bool update_user(User *user);
|
||||
static bool update_db_line(const char *file, linenumber line, User *replace = nullptr);
|
||||
bool add_user(User &user);
|
||||
struct Iterator
|
||||
{
|
||||
@ -129,6 +104,17 @@ namespace userdb
|
||||
Iterator(File data) : Iterator(data, nullptr, NONE)
|
||||
{
|
||||
}
|
||||
Iterator(File data, linenumber m, USERATTRIBUTES attr) : db_file(data), filter_attr(attr), matchline(m)
|
||||
{
|
||||
if (!data)
|
||||
{
|
||||
Serial.println("Failed to open userdb while creating an iterator");
|
||||
}
|
||||
else
|
||||
{
|
||||
next();
|
||||
}
|
||||
}
|
||||
Iterator(File data, String *m, USERATTRIBUTES attr) : db_file(data), filter_attr(attr), match(m)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@ -160,6 +146,9 @@ namespace userdb
|
||||
}
|
||||
~Iterator()
|
||||
{
|
||||
close_file();
|
||||
}
|
||||
void close_file(){
|
||||
db_file.close();
|
||||
}
|
||||
bool has_next()
|
||||
@ -170,7 +159,16 @@ namespace userdb
|
||||
{
|
||||
if (db_file.available())
|
||||
{
|
||||
current = read_csv_line(db_file, line, match, filter_attr);
|
||||
if (filter_attr == USERATTRIBUTES::LINE_ID)
|
||||
{
|
||||
if (matchline == line)
|
||||
{
|
||||
current = read_csv_line(current, db_file, line, match, filter_attr);
|
||||
current.match=true;
|
||||
}
|
||||
}
|
||||
else
|
||||
current = read_csv_line(current, db_file, line, match, filter_attr);
|
||||
// Position stream pointer to beginning of the next line
|
||||
while (db_file.available())
|
||||
{
|
||||
@ -195,9 +193,11 @@ namespace userdb
|
||||
USERATTRIBUTES filter_attr;
|
||||
String *match;
|
||||
bool available = true;
|
||||
uint32_t line = 0;
|
||||
linenumber line = 0;
|
||||
linenumber matchline = 0;
|
||||
};
|
||||
Iterator begin() { return Iterator(LittleFS.open(filename, "r")); }
|
||||
Iterator begin_with_filter(String *match, USERATTRIBUTES attr) { return Iterator(LittleFS.open(filename, "r"), match, attr); }
|
||||
Iterator begin_with_filter(linenumber match, USERATTRIBUTES attr) { return Iterator(LittleFS.open(filename, "r"), match, attr); }
|
||||
};
|
||||
}
|
@ -13,19 +13,23 @@ bool WebConsole::init(userdb::UserDb *userdb)
|
||||
_server = new ESP8266WebServer(80);
|
||||
this->userdb = userdb;
|
||||
_server->begin();
|
||||
_server->on("/userdb", HTTPMethod::HTTP_DELETE, std::bind(&WebConsole::_dropUserDb, this));
|
||||
_server->on("/userdb", HTTPMethod::HTTP_GET, std::bind(&WebConsole::_getUserDb, this));
|
||||
_server->on("/rfid", std::bind(&WebConsole::_catchRFID, this));
|
||||
_server->on(UriBraces("/user/{}"), HTTPMethod::HTTP_DELETE, std::bind(&WebConsole::_deleteUser, this));
|
||||
_server->on(UriBraces("/user/{}"), HTTPMethod::HTTP_GET, std::bind(&WebConsole::_getUser, this));
|
||||
_server->on(UriBraces("/user/{}"), HTTPMethod::HTTP_PUT, std::bind(&WebConsole::_createUser, this));
|
||||
_server->on(UriBraces("/get/{}"), std::bind(&WebConsole::_deleteUser, this));
|
||||
_server->on("/api/userdb", HTTPMethod::HTTP_DELETE, std::bind(&WebConsole::_dropUserDb, this));
|
||||
_server->on("/api/userdb", HTTPMethod::HTTP_GET, std::bind(&WebConsole::_getUserDb, this));
|
||||
_server->on("/api/rfid", std::bind(&WebConsole::_catchRFID, this));
|
||||
_server->on("/api/debug/printfile", std::bind(&WebConsole::_print_db_raw, this));
|
||||
_server->on(UriBraces("/api/user/{}"), HTTPMethod::HTTP_DELETE, std::bind(&WebConsole::_deleteUser, this));
|
||||
_server->on(UriBraces("/api/user/{}"), HTTPMethod::HTTP_GET, std::bind(&WebConsole::_getUser, this));
|
||||
_server->on(UriBraces("/api/user/{}"), HTTPMethod::HTTP_PUT, std::bind(&WebConsole::_createUser, this));
|
||||
_server->on(UriBraces("/api/user/{}"), HTTPMethod::HTTP_POST, std::bind(&WebConsole::_updateUser, this));
|
||||
_server->on(UriBraces("/api/config/{}"), std::bind(&WebConsole::_deleteUser, this));
|
||||
//_server->on("/bypin",std::bind(&WebConsole::_findPin,this));
|
||||
_server->onNotFound(std::bind(&WebConsole::_handleStatic, this));
|
||||
_server->serveStatic("/", LittleFS, "/static/index.html");
|
||||
//_server->onNotFound(std::bind(&WebConsole::_handleStatic, this));
|
||||
return true;
|
||||
}
|
||||
void WebConsole::attachRfid(Rfid *rfid){
|
||||
this->rfid=rfid;
|
||||
void WebConsole::attachRfid(Rfid *rfid)
|
||||
{
|
||||
this->rfid = rfid;
|
||||
}
|
||||
void WebConsole::serve()
|
||||
{
|
||||
@ -37,7 +41,8 @@ void WebConsole::serve()
|
||||
}
|
||||
_server->handleClient();
|
||||
}
|
||||
bool WebConsole::isInterceptingRfid(){
|
||||
bool WebConsole::isInterceptingRfid()
|
||||
{
|
||||
return catch_rfid;
|
||||
}
|
||||
void WebConsole::_handleStatic()
|
||||
@ -99,6 +104,7 @@ void WebConsole::_deleteUser()
|
||||
_server->send(500, "text/json", "{\"error\":\"User not found.\"}");
|
||||
}
|
||||
}
|
||||
|
||||
void WebConsole::_getUser()
|
||||
{
|
||||
if (userdb == nullptr)
|
||||
@ -117,6 +123,57 @@ void WebConsole::_getUser()
|
||||
_server->send(500, "text/json", "{\"error\":\"User not found.\"}");
|
||||
}
|
||||
}
|
||||
void WebConsole::_updateUser()
|
||||
{
|
||||
userdb::User updated;
|
||||
String body = _server->arg("plain");
|
||||
const int capacity = 256;
|
||||
StaticJsonDocument<capacity> doc;
|
||||
DeserializationError err = deserializeJson(doc, body);
|
||||
if (err.code() != err.Ok)
|
||||
{
|
||||
Serial.println(err.c_str());
|
||||
Serial.println(body);
|
||||
String response = "{\"error\":\"";
|
||||
response += err.c_str();
|
||||
response += "\"}";
|
||||
_server->send(500, "text/json", response);
|
||||
return;
|
||||
}
|
||||
if (doc.containsKey("line"))
|
||||
{
|
||||
updated = userdb->user_by_line(doc["line"].as<userdb::linenumber>());
|
||||
}
|
||||
if (!updated.match && doc.containsKey("uid"))
|
||||
{
|
||||
updated = userdb->user_by_uid(doc["uid"].as<unsigned long>());
|
||||
}
|
||||
if (!updated.match && !_server->pathArg(0).isEmpty())
|
||||
{
|
||||
updated = userdb->user_by_uid(_server->pathArg(0).toInt());
|
||||
}
|
||||
|
||||
if (updated.match == false)
|
||||
{
|
||||
_server->send(500, "text/json", "{\"error\":\"user could not be found.\"}");
|
||||
return;
|
||||
}
|
||||
// created.line = doc["line"].as<uint32_t>();
|
||||
if (doc.containsKey("uid"))
|
||||
updated.uid = doc["uid"].as<unsigned long>();
|
||||
if (doc.containsKey("first_name"))
|
||||
updated.first_name = doc["first_name"].as<String>();
|
||||
if (doc.containsKey("last_name"))
|
||||
updated.last_name = doc["last_name"].as<String>();
|
||||
if (doc.containsKey("rfid_uid"))
|
||||
updated.rfid_uid = doc["rfid_uid"].as<String>();
|
||||
if (doc.containsKey("user_pin"))
|
||||
updated.user_pin = doc["user_pin"].as<String>();
|
||||
if (doc.containsKey("enabled"))
|
||||
updated.enabled = doc["enabled"].as<bool>();
|
||||
bool res = userdb->update_user(&updated);
|
||||
_server->send(200, "text/json", updated.toJSONString().c_str());
|
||||
}
|
||||
void WebConsole::_createUser()
|
||||
{
|
||||
userdb::User created;
|
||||
@ -160,16 +217,23 @@ void WebConsole::_dropUserDb()
|
||||
}
|
||||
void WebConsole::_catchRFID()
|
||||
{
|
||||
if (rfid == nullptr)
|
||||
{
|
||||
_server->send(500, "text/json", "{\"error\":\"RFID not attached.\"}");
|
||||
return;
|
||||
}
|
||||
if (catch_rfid_updated)
|
||||
{
|
||||
String response = "{\"rfid_uid\":\"" + rfid_buffer + "\"}";
|
||||
_server->send(500, "text/json", response);
|
||||
catch_rfid_updated = false;
|
||||
}
|
||||
else if(catch_rfid){
|
||||
else if (catch_rfid)
|
||||
{
|
||||
_server->send(500, "text/json", "{\"ok\":\"already activated\"}");
|
||||
}
|
||||
else{
|
||||
else
|
||||
{
|
||||
catch_rfid = true;
|
||||
_server->send(500, "text/json", "{\"ok\":\"now activated\"}");
|
||||
}
|
||||
|
@ -16,20 +16,31 @@ namespace webconsole
|
||||
public:
|
||||
WebConsole();
|
||||
~WebConsole();
|
||||
|
||||
|
||||
bool init(userdb::UserDb *userdb);
|
||||
void attachRfid(Rfid *rfid);
|
||||
void serve();
|
||||
bool isInterceptingRfid();
|
||||
|
||||
private:
|
||||
void _handleStatic();
|
||||
void _getUserDb();
|
||||
void _deleteUser();
|
||||
void _getUser();
|
||||
void _updateUser();
|
||||
void _createUser();
|
||||
void _dropUserDb();
|
||||
void _catchRFID();
|
||||
ESP8266WebServer* _server;
|
||||
void _print_db_raw()
|
||||
{
|
||||
File f = LittleFS.open("userdb.csv", "r");
|
||||
while (f.available()){
|
||||
f.sendAvailable(Serial);
|
||||
}
|
||||
_server->send(200,"text/plain","printed to serial");
|
||||
f.close();
|
||||
}
|
||||
ESP8266WebServer *_server;
|
||||
userdb::UserDb *userdb = nullptr;
|
||||
bool catch_rfid = false;
|
||||
bool catch_rfid_updated = false;
|
||||
|
@ -61,7 +61,7 @@ void loop()
|
||||
if(web.isInterceptingRfid()&&iface.getState()==0){
|
||||
iface.showMessage("WebUI connected", "Awaiting RFID", 3000);
|
||||
}
|
||||
else if (iface.pinAvailable())
|
||||
else if (iface.pinAvailable()&&iface.getState()!=Interface::GREET)
|
||||
{
|
||||
unsigned long delta = millis();
|
||||
login_user = userdatabase.user_by_pin(iface.getPin());
|
||||
@ -72,7 +72,7 @@ void loop()
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (rfid.available())
|
||||
else if (rfid.available()&&iface.getState()!=Interface::GREET)
|
||||
{
|
||||
unsigned long delta = millis();
|
||||
login_user = userdatabase.user_by_rfid(rfid.getID());
|
||||
|
Loading…
x
Reference in New Issue
Block a user