206 lines
6.8 KiB
C++
206 lines
6.8 KiB
C++
#pragma once
|
|
#include "Config.h"
|
|
#include "LittleFS.h"
|
|
#include <sstream>
|
|
#include <iterator>
|
|
#include <cstddef>
|
|
|
|
namespace userdb
|
|
{
|
|
typedef uint16_t linenumber;
|
|
enum USERATTRIBUTES
|
|
{
|
|
LINE_ID,
|
|
USER_ID,
|
|
FIRST_NAME,
|
|
LAST_NAME,
|
|
RFID_UID,
|
|
USER_PIN,
|
|
ENABLED,
|
|
NONE
|
|
};
|
|
struct User
|
|
{
|
|
// User(unsigned long new_uid): uid(new_uid){}
|
|
unsigned long uid = -1;
|
|
linenumber line = UINT16_MAX;
|
|
mutable String first_name;
|
|
mutable String last_name;
|
|
mutable String rfid_uid;
|
|
mutable String user_pin;
|
|
mutable bool enabled = false;
|
|
mutable bool match = false;
|
|
bool operator<(const User &o) const { return uid < o.uid; }
|
|
bool operator==(const User &o) const { return uid == o.uid; }
|
|
String toString()
|
|
{
|
|
return "ID: " + String(uid) + " Name: " + last_name + " " + first_name + " Enabled: " + (enabled ? "Yes" : "No") + " LineNo.: " + String(line) + "[RFID/PIN]" + rfid_uid + "//" + user_pin;
|
|
}
|
|
String toCSVString()
|
|
{
|
|
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") + ",\"line\":\"" + line + "\"}";
|
|
}
|
|
};
|
|
|
|
|
|
|
|
class UserDb
|
|
{
|
|
private:
|
|
const char *filename;
|
|
|
|
public:
|
|
UserDb(const char *filename);
|
|
void print_to_serial();
|
|
void PrintAll();
|
|
// User find_user();
|
|
User user_by_pin(String);
|
|
User user_by_rfid(String);
|
|
User user_by_uid(unsigned long);
|
|
User user_by_uid(String cmp);
|
|
User user_by_line(linenumber cmp);
|
|
bool drop()
|
|
{
|
|
LittleFS.remove(filename);
|
|
File n = LittleFS.open(filename, "a");
|
|
n.close();
|
|
return true;
|
|
}
|
|
static inline User read_csv_line(User &res, File &instream, linenumber &line, String *match, USERATTRIBUTES attr)
|
|
{
|
|
String uid = instream.readStringUntil(';');
|
|
if (attr == USER_ID && !uid.equals(*match))
|
|
return res;
|
|
res.uid = uid.toInt();
|
|
res.first_name = instream.readStringUntil(';');
|
|
res.last_name = instream.readStringUntil(';');
|
|
res.rfid_uid = instream.readStringUntil(';');
|
|
if (attr == RFID_UID && !res.rfid_uid.equals(*match))
|
|
return res;
|
|
res.user_pin = instream.readStringUntil(';');
|
|
if (attr == USER_PIN && !res.user_pin.equals(*match))
|
|
return res;
|
|
res.enabled = instream.read() == '1' ? true : false;
|
|
res.line = line;
|
|
res.match = true;
|
|
return res;
|
|
}
|
|
|
|
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
|
|
{
|
|
using iterator_category = std::input_iterator_tag;
|
|
using pointer = void;
|
|
using value_type = User;
|
|
using reference = User;
|
|
using difference_type = std::ptrdiff_t;
|
|
|
|
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
|
|
if (filter_attr == NONE)
|
|
Serial.println("Started user iterator with ");
|
|
else
|
|
Serial.println("Started filtered user iterator with " + String(filter_attr) + " query: " + *match);
|
|
#endif
|
|
|
|
if (!data)
|
|
{
|
|
Serial.println("Failed to open userdb while creating an iterator");
|
|
}
|
|
else
|
|
{
|
|
next();
|
|
}
|
|
}
|
|
reference operator*() const { return current; }
|
|
Iterator &operator++()
|
|
{
|
|
next();
|
|
return *this;
|
|
}
|
|
Iterator operator++(int)
|
|
{
|
|
next();
|
|
return *this;
|
|
}
|
|
~Iterator()
|
|
{
|
|
close_file();
|
|
}
|
|
void close_file()
|
|
{
|
|
db_file.close();
|
|
}
|
|
bool has_next()
|
|
{
|
|
return available;
|
|
}
|
|
void next()
|
|
{
|
|
if (db_file.available())
|
|
{
|
|
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())
|
|
{
|
|
if (db_file.read() == '\n')
|
|
{
|
|
++line;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
available = false;
|
|
current = User{};
|
|
db_file.close();
|
|
}
|
|
}
|
|
|
|
private:
|
|
File db_file;
|
|
User current;
|
|
USERATTRIBUTES filter_attr;
|
|
String *match;
|
|
bool available = true;
|
|
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); }
|
|
};
|
|
} |