feat: added initial support of writing JSON output when changing events

This commit is contained in:
Johannes Loher 2018-01-14 17:59:16 +01:00
parent ad1a966c99
commit 3b650cb638
4 changed files with 125 additions and 74 deletions

View file

@ -2,6 +2,7 @@ module calendarwebapp.calendarwebapp;
import calendarwebapp.authenticator;
import calendarwebapp.event;
import calendarwebapp.jsonexport;
import calendarwebapp.passhash : PasswordHasher;
import core.time : days;
@ -22,7 +23,7 @@ import vibe.web.web : errorDisplay, noRoute, redirect, render, SessionVar,
@requiresAuth class CalendarWebapp
{
@noRoute AuthInfo authenticate(scope HTTPServerRequest req, scope HTTPServerResponse) @safe
@noRoute AuthInfo authenticate(scope HTTPServerRequest, scope HTTPServerResponse) @safe
{
if (authInfo.value.isNone)
redirect("/login");
@ -76,13 +77,14 @@ public:
auto event = Event("", begin, end, name, description.replace("\r", ""), type, shout);
eventStore.addEvent(event);
exporter.exportJSON;
redirect("/");
}
@auth(Role.user | Role.admin) void postRemoveevent(string id)
{
eventStore.removeEvent(id);
exporter.exportJSON;
redirect("/");
}
@ -128,4 +130,5 @@ private:
@Autowire EventStore eventStore;
@Autowire Authenticator authenticator;
@Autowire PasswordHasher passwordHasher;
@Autowire JSONExporter exporter;
}

View file

@ -3,6 +3,7 @@ module calendarwebapp.configuration;
import calendarwebapp.authenticator : Authenticator;
import calendarwebapp.calendarwebapp : CalendarWebapp;
import calendarwebapp.event : EventStore;
import calendarwebapp.jsonexport : JSONExporter;
import calendarwebapp.passhash : PasswordHasher, SHA256PasswordHasher;
import poodinis;
@ -20,10 +21,10 @@ public:
final switch (arguments.database) with (DatabaseArgument)
{
case mongodb:
import vibe.db.mongo.client : MongoClient;
import vibe.db.mongo.mongo : connectMongoDB;
import calendarwebapp.authenticator : MongoDBAuthenticator;
import calendarwebapp.event : MongoDBEventStore;
import vibe.db.mongo.client : MongoClient;
import vibe.db.mongo.mongo : connectMongoDB;
auto mongoClient = connectMongoDB(arguments.mongodb.host);
container.register!MongoClient.existingInstance(mongoClient);
@ -33,9 +34,9 @@ public:
logInfo("Using MongoDB as database system");
break;
case mysql:
import mysql : MySQLPool;
import calendarwebapp.authenticator : MySQLAuthenticator;
import calendarwebapp.event : MySQLEventStore;
import mysql : MySQLPool;
auto pool = new MySQLPool(arguments.mysql.host, arguments.mysql.username,
arguments.mysql.password, arguments.mysql.database);
@ -45,6 +46,7 @@ public:
logInfo("Using MySQL as database system");
break;
}
container.register!JSONExporter;
container.register!(PasswordHasher, SHA256PasswordHasher);
container.register!CalendarWebapp;
container.register!(ValueInjector!string, StringInjector);
@ -109,6 +111,8 @@ public:
"The password to use for logging into the MySQL instance.");
readOption("mysql.database", &arguments.mysql.database,
"The name of the MySQL database to use.");
readOption("output", &arguments.output,
"The file to write JSON output to.");
}
override Arguments get(string key) @safe
@ -145,4 +149,5 @@ struct Arguments
DatabaseArgument database = DatabaseArgument.mongodb;
MySQLArguments mysql;
MongoDBArguments mongodb;
string output = "cal.json";
}

View file

@ -1,6 +1,7 @@
module calendarwebapp.jsonexport;
import calendarwebapp.event : Event, EventStore;
import calendarwebapp.configuration : Arguments;
import core.time;
@ -11,11 +12,11 @@ import std.datetime.interval;
import std.datetime.systime;
import std.format : format;
import poodinis : Autowire;
import poodinis : Autowire, Value;
import vibe.data.serialization : name;
import vibe.data.serialization : serializationName = name;
struct DayJSONManager
struct DayDataManager
{
private:
Date begin, end;
@ -26,7 +27,7 @@ public:
in
{
assert(begin < end,
"DayJSONManager: begin (%s) needs to be earlier than end (%s)".format(begin, end));
"DayDataManager: begin (%s) needs to be earlier than end (%s)".format(begin, end));
}
do
{
@ -50,7 +51,7 @@ public:
enforce(Interval!Date(begin, end).contains(date));
return DayData(date.year, date.month, date.month.toGerString, date.day,
date.dayOfWeek.dayType, events[date], date.dayOfWeek.toGerString, []);
date.dayOfWeek.dayType, events[date], date.dayOfWeek.toShortGerString, []);
}
}
@ -58,6 +59,7 @@ class JSONExporter
{
private:
@Autowire EventStore eventStore;
@Value() Arguments arguments;
public:
auto write(in Date today = cast(Date) Clock.currTime) @system
@ -66,19 +68,43 @@ public:
import std.range : array;
import std.format : format;
immutable todayName = "%s, %s. %s. %s".format(today.dayOfWeek.toGerString,
immutable todayName = dateFormatString.format(today.dayOfWeek.toGerString,
today.day, today.month.toGerString, today.year);
immutable todays = Todays(today.year, today.month, today.day, today.dayOfWeek, todayName);
immutable todays = Today(today.year, today.month, today.day, today.dayOfWeek, todayName);
auto startDate = Date(today.year, today.month, 1);
auto endDate = startDate;
endDate.add!"months"(3);
auto dayJSONManager = new DayJSONManager(startDate, endDate);
auto dayDataManager = new DayDataManager(startDate, endDate);
foreach (event; eventStore.getEventsBeginningBetween(startDate, endDate))
{
dayJSONManager.addEvent(event);
dayDataManager.addEvent(event);
}
return Interval!Date(startDate, endDate).fwdRange(date => date + 1.dur!"days")
.map!(day => dayJSONManager.getDayData(day)).array;
.map!(day => dayDataManager.getDayData(day)).array;
}
void exportJSON() @system
{
import vibe.core.file : writeFile;
import vibe.core.path : Path;
import vibe.data.json : serializeToPrettyJson;
import std.datetime.systime : Clock;
import std.datetime.date : Date;
struct OutputFormat
{
private:
alias TrackedDays = typeof(write());
public:
Today today;
@serializationName("tracked_days") TrackedDays trackedDays;
}
immutable today = cast(Date) Clock.currTime;
auto output = OutputFormat(Today(today.year, today.month, today.day,
today.dayOfWeek, dateFormatString.format(today.dayOfWeek.toGerString,
today.day, today.month.toGerString, today.year)), this.write());
Path(arguments.output).writeFile(cast(ubyte[]) output.serializeToPrettyJson);
}
}
@ -88,9 +114,9 @@ struct DayData
Month month;
string monthName;
ubyte day;
@name("daytype") DayType dayType;
Event[] eventList;
@name("wday") string weekDayName;
@serializationName("daytype") DayType dayType;
Event[] events;
@serializationName("wday") string weekDayName;
Line[] lines;
}
@ -103,6 +129,8 @@ enum DayType
private:
enum dateFormatString = "%s, %s. %s, %s";
string toGerString(Month m)
{
final switch (m) with (Month)
@ -155,6 +183,27 @@ string toGerString(DayOfWeek d)
}
}
string toShortGerString(DayOfWeek d)
{
final switch (d) with (DayOfWeek)
{
case mon:
return "Mo";
case tue:
return "Di";
case wed:
return "Mi";
case thu:
return "Do";
case fri:
return "Fr";
case sat:
return "Sa";
case sun:
return "So";
}
}
DayType dayType(DayOfWeek dayOfWeek)
{
switch (dayOfWeek) with (DayOfWeek)
@ -172,17 +221,11 @@ struct Line
{
}
struct Todays
struct Today
{
short year;
Month month;
ubyte day;
DayOfWeek weekDay;
string todayName;
}
struct OutputFormat
{
Todays today;
@name("tracked_days") DayData trackedDays;
@serializationName("weekday") DayOfWeek weekDay;
string name;
}

View file

@ -23,7 +23,7 @@ import unit_threaded;
container.register!(EventStore, StubEventStore);
container.register!JSONExporter;
auto exporter = container.resolve!JSONExporter;
exporter.write.each!(dayData => dayData.eventList.empty.shouldBeTrue);
exporter.write.each!(dayData => dayData.events.empty.shouldBeTrue);
}
@("JSONExporter.write with 1 event")
@ -37,8 +37,8 @@ import unit_threaded;
immutable event = Event("599090de97355141140fc698", Date(2018, 1, 14));
eventStore.addEvent(event);
exporter.write.each!(dayData => (dayData.year == 2018
&& dayData.month == Month.jan && dayData.day == 14) ? dayData.eventList.shouldEqual([event])
: dayData.eventList.empty.shouldBeTrue);
&& dayData.month == Month.jan && dayData.day == 14) ? dayData.events.shouldEqual([event])
: dayData.events.empty.shouldBeTrue);
}
@("JSONExporter.write with 2 events at the same date")
@ -54,8 +54,8 @@ import unit_threaded;
eventStore.addEvent(event1);
eventStore.addEvent(event2);
exporter.write(Date(2018, 1, 14)).each!(dayData => (dayData.year == 2018
&& dayData.month == Month.jan && dayData.day == 14) ? dayData.eventList.shouldEqual([event1,
event2]) : dayData.eventList.empty.shouldBeTrue);
&& dayData.month == Month.jan && dayData.day == 14) ? dayData.events.shouldEqual([event1,
event2]) : dayData.events.empty.shouldBeTrue);
}
@("JSONExporter.write with 2 events at different dates")
@ -74,15 +74,15 @@ import unit_threaded;
immutable date = Date(dayData.year, dayData.month.to!int, dayData.day);
if (date == Date(2018, 1, 14))
{
dayData.eventList.shouldEqual([event1]);
dayData.events.shouldEqual([event1]);
}
else if (date == Date(2018, 1, 15))
{
dayData.eventList.shouldEqual([event2]);
dayData.events.shouldEqual([event2]);
}
else
{
dayData.eventList.empty.shouldBeTrue;
dayData.events.empty.shouldBeTrue;
}
});
}
@ -164,98 +164,98 @@ import unit_threaded;
exporter.write(Date(2018, 1, 14)));
}
@("DayJSONManager with begin > end")
@("DayDataManager with begin > end")
@system unittest
{
DayJSONManager(Date(2018, 1, 14), Date(2018, 1, 13)).shouldThrow!AssertError;
DayDataManager(Date(2018, 1, 14), Date(2018, 1, 13)).shouldThrow!AssertError;
}
@("DayJSONManager with begin = end")
@("DayDataManager with begin = end")
@system unittest
{
DayJSONManager(Date(2018, 1, 14), Date(2018, 1, 14)).shouldThrow!AssertError;
DayDataManager(Date(2018, 1, 14), Date(2018, 1, 14)).shouldThrow!AssertError;
}
@("DayJSONManager.getDayData with date < begin and 0 events")
@("DayDataManager.getDayData with date < begin and 0 events")
@system unittest
{
auto dayJSONManager = DayJSONManager(Date(2018, 1, 14), Date(2018, 1, 16));
dayJSONManager.getDayData(Date(2018, 1, 13)).shouldThrow;
auto dayDataManager = DayDataManager(Date(2018, 1, 14), Date(2018, 1, 16));
dayDataManager.getDayData(Date(2018, 1, 13)).shouldThrow;
}
@("DayJSONManager.getDayData with date > end and 0 events")
@("DayDataManager.getDayData with date > end and 0 events")
@system unittest
{
auto dayJSONManager = DayJSONManager(Date(2018, 1, 14), Date(2018, 1, 16));
dayJSONManager.getDayData(Date(2018, 1, 17)).shouldThrow;
auto dayDataManager = DayDataManager(Date(2018, 1, 14), Date(2018, 1, 16));
dayDataManager.getDayData(Date(2018, 1, 17)).shouldThrow;
}
@("DayJSONManager.getDayData with date = end and 0 events")
@("DayDataManager.getDayData with date = end and 0 events")
@system unittest
{
auto dayJSONManager = DayJSONManager(Date(2018, 1, 14), Date(2018, 1, 16));
dayJSONManager.getDayData(Date(2018, 1, 16)).shouldThrow;
auto dayDataManager = DayDataManager(Date(2018, 1, 14), Date(2018, 1, 16));
dayDataManager.getDayData(Date(2018, 1, 16)).shouldThrow;
}
@("DayJSONManager.getDayData with date = begin and 0 events")
@("DayDataManager.getDayData with date = begin and 0 events")
@system unittest
{
auto dayJSONManager = DayJSONManager(Date(2018, 1, 14), Date(2018, 1, 16));
dayJSONManager.getDayData(Date(2018, 1, 14)).shouldEqual(DayData(2018,
auto dayDataManager = DayDataManager(Date(2018, 1, 14), Date(2018, 1, 16));
dayDataManager.getDayData(Date(2018, 1, 14)).shouldEqual(DayData(2018,
Month.jan, "Januar", 14, DayType.Holiday, [], "Sonntag", []));
}
@("DayJSONManager.getDayData with begin < date < end and 0 events")
@("DayDataManager.getDayData with begin < date < end and 0 events")
@system unittest
{
auto dayJSONManager = DayJSONManager(Date(2018, 1, 14), Date(2018, 1, 16));
dayJSONManager.getDayData(Date(2018, 1, 15)).shouldEqual(DayData(2018,
auto dayDataManager = DayDataManager(Date(2018, 1, 14), Date(2018, 1, 16));
dayDataManager.getDayData(Date(2018, 1, 15)).shouldEqual(DayData(2018,
Month.jan, "Januar", 15, DayType.Workday, [], "Montag", []));
}
@("DayJSONManager.getDayData with date < begin and 1 event")
@("DayDataManager.getDayData with date < begin and 1 event")
@system unittest
{
auto dayJSONManager = DayJSONManager(Date(2018, 1, 14), Date(2018, 1, 16));
auto dayDataManager = DayDataManager(Date(2018, 1, 14), Date(2018, 1, 16));
immutable event = Event("599090de97355141140fc698", Date(2018, 1, 14));
dayJSONManager.addEvent(event);
dayJSONManager.getDayData(Date(2018, 1, 13)).shouldThrow;
dayDataManager.addEvent(event);
dayDataManager.getDayData(Date(2018, 1, 13)).shouldThrow;
}
@("DayJSONManager.getDayData with date > end and 1 event")
@("DayDataManager.getDayData with date > end and 1 event")
@system unittest
{
auto dayJSONManager = DayJSONManager(Date(2018, 1, 14), Date(2018, 1, 16));
auto dayDataManager = DayDataManager(Date(2018, 1, 14), Date(2018, 1, 16));
immutable event = Event("599090de97355141140fc698", Date(2018, 1, 14));
dayJSONManager.addEvent(event);
dayJSONManager.getDayData(Date(2018, 1, 17)).shouldThrow;
dayDataManager.addEvent(event);
dayDataManager.getDayData(Date(2018, 1, 17)).shouldThrow;
}
@("DayJSONManager.getDayData with date = end and 1 event")
@("DayDataManager.getDayData with date = end and 1 event")
@system unittest
{
auto dayJSONManager = DayJSONManager(Date(2018, 1, 14), Date(2018, 1, 16));
auto dayDataManager = DayDataManager(Date(2018, 1, 14), Date(2018, 1, 16));
immutable event = Event("599090de97355141140fc698", Date(2018, 1, 14));
dayJSONManager.addEvent(event);
dayJSONManager.getDayData(Date(2018, 1, 16)).shouldThrow;
dayDataManager.addEvent(event);
dayDataManager.getDayData(Date(2018, 1, 16)).shouldThrow;
}
@("DayJSONManager.getDayData with date = begin and 1 event")
@("DayDataManager.getDayData with date = begin and 1 event")
@system unittest
{
auto dayJSONManager = DayJSONManager(Date(2018, 1, 14), Date(2018, 1, 15));
auto dayDataManager = DayDataManager(Date(2018, 1, 14), Date(2018, 1, 15));
immutable event = Event("599090de97355141140fc698", Date(2018, 1, 14));
dayJSONManager.addEvent(event);
dayJSONManager.getDayData(Date(2018, 1, 14)).shouldEqual(DayData(2018,
dayDataManager.addEvent(event);
dayDataManager.getDayData(Date(2018, 1, 14)).shouldEqual(DayData(2018,
Month.jan, "Januar", 14, DayType.Holiday, [event], "Sonntag", []));
}
@("DayJSONManager.getDayData with begin < date < end and 1 event")
@("DayDataManager.getDayData with begin < date < end and 1 event")
@system unittest
{
auto dayJSONManager = DayJSONManager(Date(2018, 1, 14), Date(2018, 1, 16));
auto dayDataManager = DayDataManager(Date(2018, 1, 14), Date(2018, 1, 16));
immutable event = Event("599090de97355141140fc698", Date(2018, 1, 15));
dayJSONManager.addEvent(event);
dayJSONManager.getDayData(Date(2018, 1, 15)).shouldEqual(DayData(2018,
dayDataManager.addEvent(event);
dayDataManager.getDayData(Date(2018, 1, 15)).shouldEqual(DayData(2018,
Month.jan, "Januar", 15, DayType.Workday, [event], "Montag", []));
}