Merge branch 'mysql' into 'master'
Mysql support Closes #10 See merge request fsimphy/calendar-webapp!14
This commit is contained in:
commit
612ff77911
9 changed files with 248 additions and 46 deletions
1
dub.json
1
dub.json
|
@ -4,6 +4,7 @@
|
||||||
"Johannes Loher"
|
"Johannes Loher"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"mysql-native": "~>1.1.2",
|
||||||
"botan": "~>1.12.9",
|
"botan": "~>1.12.9",
|
||||||
"vibe-d": "~>0.8.1",
|
"vibe-d": "~>0.8.1",
|
||||||
"vibe-d:tls": "~>0.8.1",
|
"vibe-d:tls": "~>0.8.1",
|
||||||
|
|
24
schema.sql
Normal file
24
schema.sql
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
CREATE DATABASE CalendarWebapp;
|
||||||
|
USE CalendarWebapp;
|
||||||
|
|
||||||
|
CREATE TABLE users (
|
||||||
|
id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
username CHAR(30) NOT NULL UNIQUE,
|
||||||
|
passwordHash CHAR(60) NOT NULL,
|
||||||
|
privilege TINYINT UNSIGNED NOT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE events (
|
||||||
|
id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
begin DATE NOT NULL,
|
||||||
|
end DATE,
|
||||||
|
name CHAR(128) NOT NULL,
|
||||||
|
description TEXT NOT NULL,
|
||||||
|
type TINYINT UNSIGNED NOT NULL,
|
||||||
|
shout BOOLEAN NOT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO users (username, passwordHash, privilege) VALUES ('foo',
|
||||||
|
'$2a$10$9LBqOZV99ARiE4Nx.2b7GeYfqk2.0A32PWGu2cRGyW2hRJ0xeDfnO', 2);
|
|
@ -4,18 +4,20 @@ import calendarwebapp.passhash : PasswordHasher;
|
||||||
|
|
||||||
import poodinis;
|
import poodinis;
|
||||||
|
|
||||||
|
import std.conv : to;
|
||||||
import std.range : InputRange;
|
import std.range : InputRange;
|
||||||
import std.typecons : nullable, Nullable;
|
import std.typecons : nullable, Nullable;
|
||||||
|
|
||||||
import vibe.data.bson;
|
import vibe.data.bson;
|
||||||
|
|
||||||
import vibe.db.mongo.collection : MongoCollection;
|
import vibe.db.mongo.collection : MongoCollection;
|
||||||
|
|
||||||
interface Authenticator
|
interface Authenticator
|
||||||
{
|
{
|
||||||
Nullable!AuthInfo checkUser(string username, string password) @safe;
|
Nullable!AuthInfo checkUser(string username, string password) @safe;
|
||||||
void addUser(AuthInfo authInfo) @safe;
|
void addUser(AuthInfo authInfo);
|
||||||
InputRange!AuthInfo getAllUsers() @safe;
|
InputRange!AuthInfo getAllUsers();
|
||||||
void removeUser(BsonObjectID id) @safe;
|
void removeUser(string id);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MongoDBAuthenticator(Collection = MongoCollection) : Authenticator
|
class MongoDBAuthenticator(Collection = MongoCollection) : Authenticator
|
||||||
|
@ -47,8 +49,17 @@ public:
|
||||||
|
|
||||||
void addUser(AuthInfo authInfo) @safe
|
void addUser(AuthInfo authInfo) @safe
|
||||||
{
|
{
|
||||||
if (!authInfo.id.valid)
|
import std.conv : ConvException;
|
||||||
authInfo.id = BsonObjectID.generate;
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!BsonObjectID.fromString(authInfo.id).valid)
|
||||||
|
throw new ConvException("invalid BsonObjectID.");
|
||||||
|
}
|
||||||
|
catch (ConvException)
|
||||||
|
{
|
||||||
|
authInfo.id = BsonObjectID.generate.to!string;
|
||||||
|
}
|
||||||
|
|
||||||
users.insert(authInfo.serializeToBson);
|
users.insert(authInfo.serializeToBson);
|
||||||
}
|
}
|
||||||
|
@ -61,7 +72,7 @@ public:
|
||||||
return users.find().map!(deserializeBson!AuthInfo).inputRangeObject;
|
return users.find().map!(deserializeBson!AuthInfo).inputRangeObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeUser(BsonObjectID id) @safe
|
void removeUser(string id) @safe
|
||||||
{
|
{
|
||||||
users.remove(["_id" : id]);
|
users.remove(["_id" : id]);
|
||||||
}
|
}
|
||||||
|
@ -74,11 +85,91 @@ enum Privilege
|
||||||
Admin
|
Admin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MySQLAuthenticator : Authenticator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
import mysql;
|
||||||
|
|
||||||
|
@Autowire MySQLPool pool;
|
||||||
|
@Autowire PasswordHasher passwordHasher;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Nullable!AuthInfo checkUser(string username, string password) @trusted
|
||||||
|
{
|
||||||
|
auto cn = pool.lockConnection();
|
||||||
|
scope (exit)
|
||||||
|
cn.close();
|
||||||
|
auto prepared = cn.prepare(
|
||||||
|
"SELECT id, username, passwordHash, privilege FROM users WHERE username = ?");
|
||||||
|
prepared.setArg(0, username);
|
||||||
|
auto result = prepared.query();
|
||||||
|
/* checkHash should be called using vibe.core.concurrency.async to
|
||||||
|
avoid blocking, but https://github.com/vibe-d/vibe.d/issues/1521 is
|
||||||
|
blocking this */
|
||||||
|
if (!result.empty)
|
||||||
|
{
|
||||||
|
auto authInfo = toAuthInfo(result.front);
|
||||||
|
if (passwordHasher.checkHash(password, authInfo.passwordHash))
|
||||||
|
{
|
||||||
|
return authInfo.nullable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Nullable!AuthInfo.init;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addUser(AuthInfo authInfo)
|
||||||
|
{
|
||||||
|
auto cn = pool.lockConnection();
|
||||||
|
scope (exit)
|
||||||
|
cn.close;
|
||||||
|
auto prepared = cn.prepare(
|
||||||
|
"INSERT INTO users (username, passwordHash, privilege) VALUES(?, ?, ?)");
|
||||||
|
prepared.setArgs(authInfo.username, authInfo.passwordHash, authInfo.privilege.to!uint);
|
||||||
|
prepared.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
InputRange!AuthInfo getAllUsers()
|
||||||
|
{
|
||||||
|
import std.algorithm : map;
|
||||||
|
import std.range : inputRangeObject;
|
||||||
|
|
||||||
|
auto cn = pool.lockConnection();
|
||||||
|
scope (exit)
|
||||||
|
cn.close;
|
||||||
|
auto prepared = cn.prepare("SELECT id, username, passwordHash, privilege FROM users");
|
||||||
|
return prepared.querySet.map!(r => toAuthInfo(r)).inputRangeObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeUser(string id)
|
||||||
|
{
|
||||||
|
auto cn = pool.lockConnection();
|
||||||
|
scope (exit)
|
||||||
|
cn.close;
|
||||||
|
auto prepared = cn.prepare("DELETE FROM users WHERE id = ?");
|
||||||
|
prepared.setArg(0, id.to!uint);
|
||||||
|
prepared.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
AuthInfo toAuthInfo(Row r)
|
||||||
|
{
|
||||||
|
import std.conv : to;
|
||||||
|
|
||||||
|
AuthInfo authInfo;
|
||||||
|
authInfo.id = r[0].get!uint.to!string;
|
||||||
|
authInfo.username = r[1].get!string;
|
||||||
|
authInfo.passwordHash = r[2].get!string;
|
||||||
|
authInfo.privilege = r[3].get!uint.to!Privilege;
|
||||||
|
return authInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct AuthInfo
|
struct AuthInfo
|
||||||
{
|
{
|
||||||
import vibe.data.serialization : name;
|
import vibe.data.serialization : name;
|
||||||
|
|
||||||
@name("_id") BsonObjectID id;
|
@name("_id") string id;
|
||||||
string username;
|
string username;
|
||||||
string passwordHash;
|
string passwordHash;
|
||||||
Privilege privilege;
|
Privilege privilege;
|
||||||
|
|
|
@ -65,23 +65,23 @@ public:
|
||||||
render!("createevent.dt", _error, authInfo);
|
render!("createevent.dt", _error, authInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@auth(Role.user | Role.admin) @errorDisplay!getCreateevent void postCreateevent(Date begin,
|
@auth(Role.user | Role.admin) @errorDisplay!getCreateevent void postCreateevent(Date begin,
|
||||||
Nullable!Date end, string description, string name, EventType type, bool shout) @safe
|
Nullable!Date end, string description, string name, EventType type, bool shout)
|
||||||
{
|
{
|
||||||
import std.array : replace, split;
|
import std.array : replace, split;
|
||||||
|
|
||||||
if (!end.isNull)
|
if (!end.isNull)
|
||||||
enforce(end - begin >= 1.days,
|
enforce(end - begin >= 1.days,
|
||||||
"Mehrtägige Ereignisse müssen mindestens einen Tag dauern");
|
"Mehrtägige Ereignisse müssen mindestens einen Tag dauern");
|
||||||
auto event = Event(BsonObjectID.generate, begin, end, name,
|
auto event = Event("", begin, end, name, description.replace("\r", ""), type, shout);
|
||||||
description.replace("\r", ""), type, shout);
|
|
||||||
|
|
||||||
eventStore.addEvent(event);
|
eventStore.addEvent(event);
|
||||||
|
|
||||||
redirect("/");
|
redirect("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@auth(Role.user | Role.admin) void postRemoveevent(BsonObjectID id) @safe
|
@auth(Role.user | Role.admin) void postRemoveevent(string id)
|
||||||
{
|
{
|
||||||
eventStore.removeEvent(id);
|
eventStore.removeEvent(id);
|
||||||
redirect("/");
|
redirect("/");
|
||||||
|
@ -94,7 +94,7 @@ public:
|
||||||
render!("showusers.dt", users, authInfo);
|
render!("showusers.dt", users, authInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@auth(Role.admin) void postRemoveuser(BsonObjectID id) @safe
|
@auth(Role.admin) void postRemoveuser(string id)
|
||||||
{
|
{
|
||||||
authenticator.removeUser(id);
|
authenticator.removeUser(id);
|
||||||
redirect("/users");
|
redirect("/users");
|
||||||
|
@ -107,9 +107,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
@auth(Role.admin) @errorDisplay!getCreateuser void postCreateuser(string username,
|
@auth(Role.admin) @errorDisplay!getCreateuser void postCreateuser(string username,
|
||||||
string password, Privilege role) @safe
|
string password, Privilege role)
|
||||||
{
|
{
|
||||||
authenticator.addUser(AuthInfo(BsonObjectID.generate, username,
|
authenticator.addUser(AuthInfo("", username,
|
||||||
passwordHasher.generateHash(password), role));
|
passwordHasher.generateHash(password), role));
|
||||||
redirect("/users");
|
redirect("/users");
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ private:
|
||||||
string field;
|
string field;
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionVar!(AuthInfo, "authInfo") authInfo = AuthInfo(BsonObjectID.init,
|
SessionVar!(AuthInfo, "authInfo") authInfo = AuthInfo("",
|
||||||
string.init, string.init, Privilege.None);
|
string.init, string.init, Privilege.None);
|
||||||
|
|
||||||
@Autowire EventStore eventStore;
|
@Autowire EventStore eventStore;
|
||||||
|
|
|
@ -3,11 +3,14 @@ module calendarwebapp.configuration;
|
||||||
import botan.rng.auto_rng : AutoSeededRNG;
|
import botan.rng.auto_rng : AutoSeededRNG;
|
||||||
import botan.rng.rng : RandomNumberGenerator;
|
import botan.rng.rng : RandomNumberGenerator;
|
||||||
|
|
||||||
import calendarwebapp.authenticator : Authenticator, MongoDBAuthenticator;
|
import calendarwebapp.authenticator : Authenticator, MongoDBAuthenticator,
|
||||||
|
MySQLAuthenticator;
|
||||||
import calendarwebapp.calendarwebapp : CalendarWebapp;
|
import calendarwebapp.calendarwebapp : CalendarWebapp;
|
||||||
import calendarwebapp.event : EventStore, MongoDBEventStore;
|
import calendarwebapp.event : EventStore, MongoDBEventStore, MySQLEventStore;
|
||||||
import calendarwebapp.passhash : BcryptPasswordHasher, PasswordHasher;
|
import calendarwebapp.passhash : BcryptPasswordHasher, PasswordHasher;
|
||||||
|
|
||||||
|
import mysql : MySQLPool;
|
||||||
|
|
||||||
import poodinis;
|
import poodinis;
|
||||||
|
|
||||||
import vibe.db.mongo.client : MongoClient;
|
import vibe.db.mongo.client : MongoClient;
|
||||||
|
@ -20,9 +23,12 @@ public:
|
||||||
override void registerDependencies(shared(DependencyContainer) container)
|
override void registerDependencies(shared(DependencyContainer) container)
|
||||||
{
|
{
|
||||||
auto mongoClient = connectMongoDB("localhost");
|
auto mongoClient = connectMongoDB("localhost");
|
||||||
|
auto pool = new MySQLPool("localhost", "username", "password", "CalendarWebapp");
|
||||||
|
container.register!MySQLPool.existingInstance(pool);
|
||||||
container.register!MongoClient.existingInstance(mongoClient);
|
container.register!MongoClient.existingInstance(mongoClient);
|
||||||
container.register!(EventStore, MongoDBEventStore!());
|
container.register!(EventStore, MySQLEventStore);
|
||||||
container.register!(Authenticator, MongoDBAuthenticator!());
|
container.register!(Authenticator, MySQLAuthenticator);
|
||||||
|
|
||||||
container.register!(PasswordHasher, BcryptPasswordHasher);
|
container.register!(PasswordHasher, BcryptPasswordHasher);
|
||||||
container.register!(RandomNumberGenerator, AutoSeededRNG);
|
container.register!(RandomNumberGenerator, AutoSeededRNG);
|
||||||
container.register!CalendarWebapp;
|
container.register!CalendarWebapp;
|
||||||
|
|
|
@ -3,6 +3,7 @@ module calendarwebapp.event;
|
||||||
import poodinis;
|
import poodinis;
|
||||||
|
|
||||||
import std.algorithm : map;
|
import std.algorithm : map;
|
||||||
|
import std.conv : to;
|
||||||
import std.datetime : Date;
|
import std.datetime : Date;
|
||||||
import std.range.interfaces : InputRange, inputRangeObject;
|
import std.range.interfaces : InputRange, inputRangeObject;
|
||||||
import std.typecons : Nullable;
|
import std.typecons : Nullable;
|
||||||
|
@ -13,17 +14,17 @@ import vibe.db.mongo.collection : MongoCollection;
|
||||||
|
|
||||||
interface EventStore
|
interface EventStore
|
||||||
{
|
{
|
||||||
Event getEvent(BsonObjectID id) @safe;
|
Event getEvent(string id);
|
||||||
InputRange!Event getAllEvents() @safe;
|
InputRange!Event getAllEvents();
|
||||||
void addEvent(Event) @safe;
|
void addEvent(Event);
|
||||||
InputRange!Event getEventsBeginningBetween(Date begin, Date end) @safe;
|
/* InputRange!Event getEventsBeginningBetween(Date begin, Date end) @safe; */
|
||||||
void removeEvent(BsonObjectID id) @safe;
|
void removeEvent(string id);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MongoDBEventStore(Collection = MongoCollection) : EventStore
|
class MongoDBEventStore(Collection = MongoCollection) : EventStore
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Event getEvent(BsonObjectID id) @safe
|
Event getEvent(string id) @safe
|
||||||
{
|
{
|
||||||
return events.findOne(["_id" : id]).deserializeBson!Event;
|
return events.findOne(["_id" : id]).deserializeBson!Event;
|
||||||
}
|
}
|
||||||
|
@ -35,20 +36,29 @@ public:
|
||||||
|
|
||||||
void addEvent(Event event) @safe
|
void addEvent(Event event) @safe
|
||||||
{
|
{
|
||||||
if (!event.id.valid)
|
import std.conv : ConvException;
|
||||||
event.id = BsonObjectID.generate;
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!BsonObjectID.fromString(event.id).valid)
|
||||||
|
throw new ConvException("invalid BsonObjectID.");
|
||||||
|
}
|
||||||
|
catch (ConvException)
|
||||||
|
{
|
||||||
|
event.id = BsonObjectID.generate.to!string;
|
||||||
|
}
|
||||||
|
|
||||||
events.insert(event.serializeToBson);
|
events.insert(event.serializeToBson);
|
||||||
}
|
}
|
||||||
|
|
||||||
InputRange!Event getEventsBeginningBetween(Date begin, Date end) @safe
|
InputRange!Event getEventsBeginningBetween(Date begin, Date end) @safe
|
||||||
{
|
{
|
||||||
return events.find(["$and" : [["date" : ["$gte" : begin.serializeToBson]], ["date"
|
return events.find(["$and" : [["date" : ["$gte" : begin.serializeToBson]],
|
||||||
: ["$lte" : end.serializeToBson]]]]).map!(deserializeBson!Event)
|
["date" : ["$lte" : end.serializeToBson]]]]).map!(deserializeBson!Event)
|
||||||
.inputRangeObject;
|
.inputRangeObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeEvent(BsonObjectID id) @safe
|
void removeEvent(string id) @safe
|
||||||
{
|
{
|
||||||
events.remove(["_id" : id]);
|
events.remove(["_id" : id]);
|
||||||
}
|
}
|
||||||
|
@ -58,6 +68,80 @@ private:
|
||||||
Collection events;
|
Collection events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MySQLEventStore : EventStore
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
import mysql;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Event getEvent(string id)
|
||||||
|
{
|
||||||
|
auto cn = pool.lockConnection();
|
||||||
|
scope (exit)
|
||||||
|
cn.close;
|
||||||
|
auto prepared = cn.prepare(
|
||||||
|
"SELECT id begin end name description type shout FROM events WHERE id = ?");
|
||||||
|
prepared.setArg(0, id.to!uint);
|
||||||
|
return toEvent(prepared.query.front);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputRange!Event getAllEvents()
|
||||||
|
{
|
||||||
|
auto cn = pool.lockConnection();
|
||||||
|
scope (exit)
|
||||||
|
cn.close;
|
||||||
|
auto prepared = cn.prepare(
|
||||||
|
"SELECT id, begin, end, name, description, type, shout FROM events");
|
||||||
|
return prepared.querySet.map!(r => toEvent(r)).inputRangeObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addEvent(Event event)
|
||||||
|
{
|
||||||
|
auto cn = pool.lockConnection();
|
||||||
|
scope (exit)
|
||||||
|
cn.close;
|
||||||
|
auto prepared = cn.prepare(
|
||||||
|
"INSERT INTO events (begin, end, name, description, type, shout) VALUES(?, ?, ?, ?, ?, ?)");
|
||||||
|
prepared.setArgs(event.begin, event.end, event.name, event.description,
|
||||||
|
event.type.to!uint, event.shout);
|
||||||
|
prepared.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* InputRange!Event getEventsBeginningBetween(Date begin, Date end) @safe
|
||||||
|
{
|
||||||
|
return events.find(["$and" : [["date" : ["$gte" : begin.serializeToBson]],
|
||||||
|
["date" : ["$lte" : end.serializeToBson]]]]).map!(deserializeBson!Event)
|
||||||
|
.inputRangeObject;
|
||||||
|
} */
|
||||||
|
|
||||||
|
void removeEvent(string id)
|
||||||
|
{
|
||||||
|
auto cn = pool.lockConnection();
|
||||||
|
scope (exit)
|
||||||
|
cn.close;
|
||||||
|
auto prepared = cn.prepare("DELETE FROM events WHERE id = ?");
|
||||||
|
prepared.setArg(0, id.to!uint);
|
||||||
|
prepared.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
@Autowire MySQLPool pool;
|
||||||
|
|
||||||
|
Event toEvent(Row r)
|
||||||
|
{
|
||||||
|
Event event;
|
||||||
|
event.id = r[0].get!uint.to!string;
|
||||||
|
event.begin = r[1].get!Date;
|
||||||
|
if (r[2].hasValue)
|
||||||
|
event.end = r[2].get!Date;
|
||||||
|
event.name = r[3].get!string;
|
||||||
|
event.description = r[4].get!string;
|
||||||
|
event.type = r[5].get!uint.to!EventType;
|
||||||
|
event.shout = r[6].get!byte.to!bool;
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum EventType
|
enum EventType
|
||||||
{
|
{
|
||||||
Holiday,
|
Holiday,
|
||||||
|
@ -69,7 +153,7 @@ enum EventType
|
||||||
|
|
||||||
struct Event
|
struct Event
|
||||||
{
|
{
|
||||||
@serializationName("_id") BsonObjectID id;
|
@serializationName("_id") string id;
|
||||||
@serializationName("date") Date begin;
|
@serializationName("date") Date begin;
|
||||||
@serializationName("end_date") Nullable!Date end;
|
@serializationName("end_date") Nullable!Date end;
|
||||||
string name;
|
string name;
|
||||||
|
|
|
@ -15,7 +15,7 @@ interface Collection
|
||||||
Bson[] find() @safe;
|
Bson[] find() @safe;
|
||||||
Bson findOne(string[string] query) @safe;
|
Bson findOne(string[string] query) @safe;
|
||||||
void insert(Bson document) @safe;
|
void insert(Bson document) @safe;
|
||||||
void remove(BsonObjectID[string] selector) @safe;
|
void remove(string[string] selector) @safe;
|
||||||
}
|
}
|
||||||
|
|
||||||
class CollectionInjector : ValueInjector!Collection
|
class CollectionInjector : ValueInjector!Collection
|
||||||
|
@ -46,10 +46,8 @@ public:
|
||||||
RegistrationOption.doNotAddConcreteTypeRegistration);
|
RegistrationOption.doNotAddConcreteTypeRegistration);
|
||||||
container.register!(PasswordHasher, StubPasswordHasher);
|
container.register!(PasswordHasher, StubPasswordHasher);
|
||||||
|
|
||||||
auto userBson = Bson(["_id" : Bson(BsonObjectID.fromString("5988ef4ae6c19089a1a53b79")),
|
auto userBson = Bson(["_id" : Bson("5988ef4ae6c19089a1a53b79"), "username"
|
||||||
"username" : Bson("foo"), "passwordHash"
|
: Bson("foo"), "passwordHash" : Bson("bar"), "privilege" : Bson(1)]);
|
||||||
: Bson("bar"),
|
|
||||||
"privilege" : Bson(1)]);
|
|
||||||
|
|
||||||
collection.returnValue!"findOne"(Bson(null), userBson, userBson);
|
collection.returnValue!"findOne"(Bson(null), userBson, userBson);
|
||||||
|
|
||||||
|
|
|
@ -10,15 +10,15 @@ import std.algorithm : map;
|
||||||
import unit_threaded.mock;
|
import unit_threaded.mock;
|
||||||
import unit_threaded.should;
|
import unit_threaded.should;
|
||||||
|
|
||||||
import vibe.data.bson : Bson, BsonObjectID, serializeToBson;
|
import vibe.data.bson : Bson, serializeToBson;
|
||||||
|
|
||||||
interface Collection
|
interface Collection
|
||||||
{
|
{
|
||||||
Bson findOne(BsonObjectID[string] query) @safe;
|
Bson findOne(string[string] query) @safe;
|
||||||
Bson[] find() @safe;
|
Bson[] find() @safe;
|
||||||
Bson[] find(Bson[string][string][][string] query) @safe;
|
Bson[] find(Bson[string][string][][string] query) @safe;
|
||||||
void insert(Bson document) @safe;
|
void insert(Bson document) @safe;
|
||||||
void remove(BsonObjectID[string] selector) @safe;
|
void remove(string[string] selector) @safe;
|
||||||
}
|
}
|
||||||
|
|
||||||
class CollectionInjector : ValueInjector!Collection
|
class CollectionInjector : ValueInjector!Collection
|
||||||
|
@ -50,7 +50,7 @@ public:
|
||||||
|
|
||||||
collection.returnValue!"findOne"(Bson(null));
|
collection.returnValue!"findOne"(Bson(null));
|
||||||
|
|
||||||
auto id = BsonObjectID.fromString("599090de97355141140fc698");
|
auto id = "599090de97355141140fc698";
|
||||||
collection.expect!"findOne"(["_id" : id]);
|
collection.expect!"findOne"(["_id" : id]);
|
||||||
|
|
||||||
auto eventStore = container.resolve!(EventStore);
|
auto eventStore = container.resolve!(EventStore);
|
||||||
|
@ -68,7 +68,7 @@ public:
|
||||||
container.register!(EventStore, MongoDBEventStore!(Collection))(
|
container.register!(EventStore, MongoDBEventStore!(Collection))(
|
||||||
RegistrationOption.doNotAddConcreteTypeRegistration);
|
RegistrationOption.doNotAddConcreteTypeRegistration);
|
||||||
|
|
||||||
auto id = BsonObjectID.fromString("599090de97355141140fc698");
|
auto id = "599090de97355141140fc698";
|
||||||
Event event;
|
Event event;
|
||||||
event.id = id;
|
event.id = id;
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ public:
|
||||||
container.register!(EventStore, MongoDBEventStore!(Collection))(
|
container.register!(EventStore, MongoDBEventStore!(Collection))(
|
||||||
RegistrationOption.doNotAddConcreteTypeRegistration);
|
RegistrationOption.doNotAddConcreteTypeRegistration);
|
||||||
|
|
||||||
auto id = BsonObjectID.fromString("599090de97355141140fc698");
|
auto id = "599090de97355141140fc698";
|
||||||
Event event;
|
Event event;
|
||||||
event.id = id;
|
event.id = id;
|
||||||
auto serializedEvent = event.serializeToBson;
|
auto serializedEvent = event.serializeToBson;
|
||||||
|
@ -121,7 +121,7 @@ public:
|
||||||
container.register!(EventStore, MongoDBEventStore!(Collection))(
|
container.register!(EventStore, MongoDBEventStore!(Collection))(
|
||||||
RegistrationOption.doNotAddConcreteTypeRegistration);
|
RegistrationOption.doNotAddConcreteTypeRegistration);
|
||||||
|
|
||||||
auto id = BsonObjectID.fromString("599090de97355141140fc698");
|
auto id = "599090de97355141140fc698";
|
||||||
Event event;
|
Event event;
|
||||||
event.id = id;
|
event.id = id;
|
||||||
|
|
||||||
|
@ -151,8 +151,7 @@ public:
|
||||||
RegistrationOption.doNotAddConcreteTypeRegistration);
|
RegistrationOption.doNotAddConcreteTypeRegistration);
|
||||||
|
|
||||||
immutable ids = [
|
immutable ids = [
|
||||||
BsonObjectID.fromString("599090de97355141140fc698"), BsonObjectID.fromString("599090de97355141140fc698"),
|
"599090de97355141140fc698", "599090de97355141140fc698", "59cb9ad8fc0ba5751c0df02b"
|
||||||
BsonObjectID.fromString("59cb9ad8fc0ba5751c0df02b")
|
|
||||||
];
|
];
|
||||||
auto events = ids.map!(id => Event(id)).array;
|
auto events = ids.map!(id => Event(id)).array;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import calendarwebapp.passhash;
|
||||||
|
|
||||||
import poodinis;
|
import poodinis;
|
||||||
|
|
||||||
//import unit_threaded.should;
|
|
||||||
import unit_threaded;
|
import unit_threaded;
|
||||||
|
|
||||||
@("BcryptPasswordHasher")
|
@("BcryptPasswordHasher")
|
||||||
|
|
Loading…
Reference in a new issue