{lib, config, pkgs, ...}: let # names mapped to unique identifiers of calendars calendars = { unschedule = "3e40534f-bfb9-b973-f615-f958a6361e95"; ymca-open-swim = "066441A6-B48F-439B-9BD0-5D0FA8F4CB6F"; scheduling = "8fd24d42-2294-9bc3-cece-3922c7cd4d09"; fasting-schedule = "e2ad2353-f91e-76c9-fb0f-2c8722ed9d2a"; ben-shared = "ben"; kate = "0962a74ab76a97543b485d2a583caa271042baab9d64437ae6c3bc8a50df1f08"; training = "eb5dfe0a-0e60-b7e5-eb7a-3b980b50b195"; }; getCals = ls: lib.attrsets.attrVals ls calendars; common = { vdirsyncer = { enable = true; auth = "basic"; conflictResolution = "remote wins"; metadata = [ "displayname" "description" ]; timeRange = { # sync 1 year before and after now start = "datetime.now() - timedelta(days=365)"; end = "datetime.now() + timedelta(days=365)"; }; }; radicale = { passwordCommand = ["${pkgs.pass}/bin/pass" "cal.bensima.com"]; type = "caldav"; url = "https://cal.bensima.com"; userName = "ben"; }; khal = { enable = true; type = "discover"; }; }; in { accounts.calendar.basePath = "Calendars"; accounts.calendar.accounts = { "bensima_personal" = { primaryCollection = "Unschedule"; remote = common.radicale; vdirsyncer = common.vdirsyncer // { collections = getCals ["unschedule" "ymca-open-swim" "fasting-schedule" "training"]; }; khal = common.khal // { addresses = ["ben@bensima.com" "ben@bsima.me"]; color = "#800080"; }; }; "bensima_scheduling" = { primaryCollection = "Scheduling"; remote = common.radicale; vdirsyncer = common.vdirsyncer // { collections = getCals ["scheduling"]; }; # no khal, just sync this in the background }; "bensima_shared" = { remote = common.radicale // {url = "https://cal.bensima.com/shared/ben";}; vdirsyncer = common.vdirsyncer // {collections = getCals ["ben-shared"];}; khal = common.khal // {color = "#097969";}; }; "icloud" = { remote = { passwordCommand = ["${pkgs.pass}/bin/pass" "icloud.com/vdirsyncer"]; type = "caldav"; url = "https://caldav.icloud.com"; userName = "bsima@icloud.com"; }; vdirsyncer = common.vdirsyncer // {collections = getCals ["kate"];}; khal = common.khal // {color = "#FAA0A0";}; }; }; programs.khal = { enable = true; locale = { # these need to match org-mode formats for khalel weeknumbers = "left"; timeformat = "%H:%M"; dateformat = "%Y-%m-%d"; longdateformat = "%Y-%m-%d %a"; datetimeformat = "%Y-%m-%d %H:%M"; longdatetimeformat = "%Y-%m-%d %H:%M"; }; }; programs.vdirsyncer.enable = true; services.vdirsyncer.enable = true; # autosync ben-shared and scheduling, this must be hand-written and appended # to the generated config file services.vdirsyncer.configFile = "${config.xdg.configHome}/vdirsyncer/merged.conf"; xdg.configFile."vdirsyncer/merged.conf".text = let wrap = s: ''"${s}"''; join = l: lib.strings.concatStringsSep ", " l; pair = pre: cals: "[${wrap pre}, ${join (map wrap (getCals cals))}]"; generatedConfig = builtins.readFile "${config.xdg.configFile."vdirsyncer/config".source}"; in '' ${generatedConfig} ### Manual Pairings [pair shared_to_scheduling] a = "calendar_bensima_shared_remote" b = "calendar_bensima_scheduling_remote" collections = [${pair "a_to_b" ["ben-shared" "scheduling"]}] conflict_resolution = "a wins" ''; }