finnow/finnow-api/source/auth/dao.d

67 lines
2.0 KiB
D

module auth.dao;
import handy_httpd.components.optional;
import auth.model;
interface UserRepository {
Optional!User findByUsername(string username);
User createUser(string username, string passwordHash);
void deleteByUsername(string username);
}
/**
* User implementation that stores each user's data in a separate directory.
*/
class FileSystemUserRepository : UserRepository {
import std.path;
import std.file;
import std.json;
private string usersDir;
this(string usersDir = "users") {
this.usersDir = usersDir;
}
Optional!User findByUsername(string username) {
if (
!validateUsername(username) ||
!exists(getUserDir(username)) ||
!exists(getUserDataFile(username))
) {
return Optional!User.empty;
}
JSONValue userObj = parseJSON(readText(getUserDataFile(username)));
return Optional!User.of(User(
username,
userObj.object["passwordHash"].str
));
}
User createUser(string username, string passwordHash) {
if (!validateUsername(username)) throw new Exception("Invalid username");
if (exists(getUserDir(username))) throw new Exception("User already exists.");
JSONValue userObj = JSONValue.emptyObject;
userObj.object["passwordHash"] = JSONValue(passwordHash);
string jsonStr = userObj.toPrettyString();
if (!exists(this.usersDir)) mkdir(this.usersDir);
mkdir(getUserDir(username));
std.file.write(getUserDataFile(username), cast(ubyte[]) jsonStr);
return User(username, passwordHash);
}
void deleteByUsername(string username) {
if (validateUsername(username) && exists(getUserDir(username))) {
rmdirRecurse(getUserDir(username));
}
}
private string getUserDir(string username) {
return buildPath(this.usersDir, username);
}
private string getUserDataFile(string username) {
return buildPath(this.usersDir, username, "user-data.json");
}
}