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); }
};
}