diff --git a/.gitignore b/.gitignore index 9b57c52..451b8cb 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,8 @@ dub.selections.json __test__library__ vibe-dav vibe-dav.sublime-project -results.json \ No newline at end of file +results.json +examples/webDav/webdavexample +examples/fileDav/filedav +examples/fileDav/dub.selections.json + diff --git a/README.md b/README.md index 93a79eb..eb90503 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,76 @@ A library that adds DAV support to vibe.d +## Support + +FileDav with locking +CalDav with basic support +CardDav no support + +## How to use + +### FileDav + +Use + + void serveFileDav(string rootUrl, string rootPath)(URLRouter router, IDavUserCollection userCollection) + +to bind the fileDav handlers to a vibe router. + +The next exemple will map every resource from `http://localhost/files` to `public/files` + + import vibedav.filedav; + + ... + + auto router = new URLRouter; + router.serveFileDav!("/files/", "public/files/")(userConnection); + + ... + + listenHTTP(settings, router); + +### CalDav + +Use the factory class that maps resource types to url nodes: + + alias T = FileDavResourceFactory!( + [rootUrl], [rootPath], + + [nodeUrl], [collection type], [resource type] + ... + ); + + +Example of maping a simple cal dav folder structure (more work will be done here): + +auto router = new URLRouter; + + // Do some basic auth + router.any("/calendar/*", performBasicAuth("Site Realm", toDelegate(&checkPassword))); + + // Create a basic user collection, used to manage CalDav users + auto userConnection = new BaseCalDavUserCollection; + + // Create a custom file maping + alias factory = FileDavResourceFactory!( + + // map "http://127.0.0.1/calendar" to "public/calendar" + "calendar", "public/calendar", + + // map any folder to `FileDavCollection` and file to `FileDavResource` + "", FileDavCollection, FileDavResource, + + // map the `personal` folder from users home + // to `FileDavCalendarCollection` and files to `FileDavCalendarResource` + ":user/personal", FileDavCalendarCollection, FileDavCalendarResource + ); + + // Bind the custom FileDav maping to a vibe router. + router.serveFileDav!factory(userConnection); + + ... + + listenHTTP(settings, router); + + diff --git a/examples/fileDav/.gitignore b/examples/fileDav/.gitignore deleted file mode 100644 index 433d266..0000000 --- a/examples/fileDav/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -.dub -docs.json -__dummy.html -*.o -*.obj diff --git a/examples/fileDav/dub.json b/examples/fileDav/dub.json deleted file mode 100644 index 5484358..0000000 --- a/examples/fileDav/dub.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "filedav", - "description": "A simple vibe.d server application.", - "copyright": "Copyright © 2015, gedaiu", - "authors": ["gedaiu"], - "dependencies": { - "vibe-d": "~>0.7.19", - "vibe-dav": { - "version": ">=0.0.1", - "path": "../.." - } - }, - "versions": ["VibeDefaultMain"] -} diff --git a/examples/fileDav/public/text file.txt b/examples/fileDav/public/text file.txt deleted file mode 100644 index b09a009..0000000 --- a/examples/fileDav/public/text file.txt +++ /dev/null @@ -1,3 +0,0 @@ -Hello! - -This is a text file. \ No newline at end of file diff --git a/examples/fileDav/source/app.d b/examples/fileDav/source/app.d deleted file mode 100644 index a1d376f..0000000 --- a/examples/fileDav/source/app.d +++ /dev/null @@ -1,21 +0,0 @@ -import vibe.d; - -import vibedav.base; - -shared static this() -{ - std.stdio.writeln("File DAV Server started on port 8080"); - - auto dav = serveFileDav(Path("public/")); - - auto router = new URLRouter; - router.any("*", serveFileDav(Path("public/")) ); - router.match(HTTPMethod.OPTIONS, "*", dav); - router.match(HTTPMethod.PROPFIND, "*", dav); - - - auto settings = new HTTPServerSettings; - settings.port = 8080; - settings.bindAddresses = ["::1", "127.0.0.1"]; - listenHTTP(settings, router); -} diff --git a/examples/webDav/dub.json b/examples/webDav/dub.json new file mode 100644 index 0000000..f22e65c --- /dev/null +++ b/examples/webDav/dub.json @@ -0,0 +1,16 @@ +{ + "name": "webDavExample", + "description": "A simple vibe.d server application.", + "copyright": "Copyright © 2015, Szabo Bogdan", + "authors": ["Szabo Bogdan"], + "dependencies": { + "vibe-d": "~>0.7.19", + "vibe-dav": { + "version": "~>0.2.0", + "path": "../.." + } + }, + + "versions": ["VibeDefaultMain"], + "targetType": "executable" +} diff --git a/examples/webDav/public/calendar/admin/personal/6837CB82-AE37-4E57-9C89-D39D62BBBC01.ics b/examples/webDav/public/calendar/admin/personal/6837CB82-AE37-4E57-9C89-D39D62BBBC01.ics new file mode 100644 index 0000000..30c467a --- /dev/null +++ b/examples/webDav/public/calendar/admin/personal/6837CB82-AE37-4E57-9C89-D39D62BBBC01.ics @@ -0,0 +1,41 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//Mac OS X 10.10.3//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Europe/Stockholm +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +DTSTART:19810329T020000 +TZNAME:CEST +TZOFFSETTO:+0200 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +DTSTART:19961027T030000 +TZNAME:CET +TZOFFSETTO:+0100 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +TRANSP:OPAQUE +DTEND;TZID=Europe/Stockholm:20150408T170000 +PRIORITY:0 +UID:6837CB82-AE37-4E57-9C89-D39D62BBBC01 +DTSTAMP:20150407T131647Z +X-YAHOO-USER-STATUS:BUSY +X-YAHOO-USER-STATUS:BUSY +STATUS:CONFIRMED +SEQUENCE:0 +CLASS:PUBLIC +X-YAHOO-YID:szabobogdan +X-YAHOO-YID:szabobogdan +X-YAHOO-EVENT-STATUS:BUSY +X-YAHOO-EVENT-STATUS:BUSY +SUMMARY:test event +DTSTART;TZID=Europe/Stockholm:20150407T160000 +CREATED:20150407T131647Z +END:VEVENT +END:VCALENDAR diff --git a/examples/webDav/public/calendar/admin/personal/7B508AD5-FE51-4C7B-8E21-0104F5412923.ics b/examples/webDav/public/calendar/admin/personal/7B508AD5-FE51-4C7B-8E21-0104F5412923.ics new file mode 100644 index 0000000..8d3926d --- /dev/null +++ b/examples/webDav/public/calendar/admin/personal/7B508AD5-FE51-4C7B-8E21-0104F5412923.ics @@ -0,0 +1,32 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//Mac OS X 10.10.3//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Europe/Stockholm +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +DTSTART:19810329T020000 +TZNAME:CEST +TZOFFSETTO:+0200 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +DTSTART:19961027T030000 +TZNAME:CET +TZOFFSETTO:+0100 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +CREATED:20150407T194949Z +UID:7B508AD5-FE51-4C7B-8E21-0104F5412923 +DTEND;TZID=Europe/Stockholm:20150422T100000 +TRANSP:OPAQUE +SUMMARY:cucu +DTSTART;TZID=Europe/Stockholm:20150422T090000 +DTSTAMP:20150407T194949Z +SEQUENCE:0 +END:VEVENT +END:VCALENDAR diff --git a/examples/webDav/public/calendar/admin/personal/main.ics b/examples/webDav/public/calendar/admin/personal/main.ics new file mode 100644 index 0000000..2012da3 --- /dev/null +++ b/examples/webDav/public/calendar/admin/personal/main.ics @@ -0,0 +1,77 @@ +BEGIN:VCALENDAR +METHOD:PUBLISH +VERSION:2.0 +X-WR-CALNAME:Home +X-WR-CALDESC: +X-APPLE-CALENDAR-COLOR:#1BADF8 +X-WR-TIMEZONE:Europe/Bucharest +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Europe/Bucharest +BEGIN:DAYLIGHT +TZOFFSETFROM:+0200 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +DTSTART:19970330T030000 +TZNAME:EEST +TZOFFSETTO:+0300 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0300 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +DTSTART:19971026T040000 +TZNAME:EET +TZOFFSETTO:+0200 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +CREATED:20140214T081455Z +UID:489F8C95-B5B3-49E3-BA4D-0CE0F820E022 +DTEND;TZID=Europe/Bucharest:20140214T120000 +TRANSP:OPAQUE +SUMMARY:New Event +DTSTART;TZID=Europe/Bucharest:20140214T110000 +DTSTAMP:20140214T081455Z +SEQUENCE:1 +END:VEVENT +BEGIN:VEVENT +CREATED:20140912T181025Z +UID:BAF9FA4C-C758-4E73-87C2-847A879AC884 +DTEND;TZID=Europe/Bucharest:20200724T130000 +TRANSP:OPAQUE +SUMMARY:New Event +DTSTART;TZID=Europe/Bucharest:20200724T120000 +DTSTAMP:20140911T200404Z +LAST-MODIFIED:20140131T143908Z +SEQUENCE:0 +END:VEVENT +BEGIN:VEVENT +CREATED:20140912T181025Z +UID:349C7C65-CD2F-44B6-8467-FF9C22F58832 +RRULE:FREQ=WEEKLY;COUNT=1 +DTEND;TZID=Europe/Bucharest:20140212T130000 +TRANSP:OPAQUE +SUMMARY:New Event +DTSTART;TZID=Europe/Bucharest:20140212T120000 +DTSTAMP:20140911T200404Z +LAST-MODIFIED:20140201T082515Z +SEQUENCE:0 +BEGIN:VALARM +X-WR-ALARMUID:95787692-6F0A-48A3-B4FE-B4C4CB0540F7 +UID:95787692-6F0A-48A3-B4FE-B4C4CB0540F7 +TRIGGER:-PT30M +DESCRIPTION:Event reminder +ACTION:DISPLAY +END:VALARM +END:VEVENT +BEGIN:VEVENT +CREATED:20140912T181025Z +UID:8FC79E15-43C5-409A-B541-4DD21F2E9C89 +DTEND;TZID=Europe/Bucharest:20131230T130000 +TRANSP:OPAQUE +SUMMARY:Eveniment nou +DTSTART;TZID=Europe/Bucharest:20131230T120000 +DTSTAMP:20140911T200404Z +LAST-MODIFIED:20140131T124833Z +SEQUENCE:0 +END:VEVENT +END:VCALENDAR diff --git a/examples/webDav/public/files/hello.txt b/examples/webDav/public/files/hello.txt new file mode 100644 index 0000000..6769dd6 --- /dev/null +++ b/examples/webDav/public/files/hello.txt @@ -0,0 +1 @@ +Hello world! \ No newline at end of file diff --git a/examples/webDav/source/app.d b/examples/webDav/source/app.d new file mode 100644 index 0000000..bd0c876 --- /dev/null +++ b/examples/webDav/source/app.d @@ -0,0 +1,63 @@ +/** + * Authors: Szabo Bogdan + * Date: 2 13, 2015 + * License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. + * Copyright: Public Domain + */ +import vibe.core.file; +import vibe.core.log; +import vibe.inet.message; +import vibe.inet.mimetypes; +import vibe.http.router : URLRouter; +import vibe.http.server; +import vibe.http.fileserver; +import vibe.http.auth.basic_auth; + +import vibedav.filedav; +import vibedav.caldav; +import vibedav.user; +import vibedav.prop; +import vibedav.userhome; + +import core.time; +import std.conv : to; +import std.stdio; +import std.file; +import std.path; +import std.digest.md; +import std.datetime; +import std.functional : toDelegate; + +bool checkPassword(string user, string password) +{ + return user == "admin" && password == "secret"; +} + +shared static this() +{ + writeln("Starting WebDav server."); + + auto router = new URLRouter; + + // now any request is matched and checked for authentication: + router.any("/calendar/*", performBasicAuth("Site Realm", toDelegate(&checkPassword))); + + auto userConnection = new BaseCalDavUserCollection; + + alias factory = FileDavResourceFactory!( + "calendar", "public/calendar", + "", FileDavCollection, FileDavResource, + ":user/", FileDavCollection, FileDavResource, + ":user/inbox", FileDavCollection, FileDavResource, + ":user/outbox", FileDavCollection, FileDavResource, + ":user/personal", FileDavCalendarCollection, FileDavCalendarResource + ); + + router.serveFileDav!("/files/", "public/files/")(userConnection); + router.serveFileDav!factory(userConnection); + + auto settings = new HTTPServerSettings; + settings.port = 8080; + settings.bindAddresses = ["::1", "127.0.0.1"]; + listenHTTP(settings, router); +} diff --git a/source/vibedav/caldav.d b/source/vibedav/caldav.d index 2f79b3c..68de10b 100644 --- a/source/vibedav/caldav.d +++ b/source/vibedav/caldav.d @@ -325,3 +325,59 @@ unittest { assert(res.type == "FileDavCalendarCollection"); } + + +class BaseCalDavUser : ICalDavUser, IDavUser { + + immutable string name; + + this(const string name) { + this.name = name; + } + + pure { + @property { + string currentUserPrincipal() { + return "/calendar/"~name~"/"; + } + + string[] principalCollectionSet() { + return ["/calendar/"]; + } + + string principalURL() { + return currentUserPrincipal; + } + + string[] calendarHomeSet() { + return ["/calendar/"~name~"/"]; + } + + string[] calendarUserAddressSet() { + return []; + } + + string scheduleInboxURL() { + return "/calendar/"~name~"/inbox/"; + } + + string scheduleOutboxURL() { + return "/calendar/"~name~"/outbox/"; + } + } + + bool hasProperty(string name) { + return hasDavInterfaceProperty!ICalDavUser(name); + } + } + + DavProp property(string name) { + return getDavInterfaceProperty!ICalDavUser(name, this); + } +} + +class BaseCalDavUserCollection : IDavUserCollection { + IDavUser GetDavUser(const string name) { + return new BaseCalDavUser(name); + } +} diff --git a/source/vibedav/user.d b/source/vibedav/user.d index f204424..d694bed 100644 --- a/source/vibedav/user.d +++ b/source/vibedav/user.d @@ -70,5 +70,5 @@ interface ICalDavUser : IDavBaseUser { } interface IDavUserCollection { - pure IDavUser GetDavUser(string name); + IDavUser GetDavUser(const string name); }