initial
This commit is contained in:
commit
b5b74623ac
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
*.bak
|
||||||
|
calnow
|
||||||
|
.direnv
|
||||||
|
result
|
||||||
|
tags
|
15
LICENSE
Normal file
15
LICENSE
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Aaron Bieber <aaron@bolddaemon.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
26
flake.lock
generated
Normal file
26
flake.lock
generated
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731755305,
|
||||||
|
"narHash": "sha256-v5P3dk5JdiT+4x69ZaB18B8+Rcu3TIOrcdG4uEX7WZ8=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "057f63b6dc1a2c67301286152eb5af20747a9cb4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"ref": "nixos-24.11",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
49
flake.nix
Normal file
49
flake.nix
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
description = "calnow: stuff and calnows";
|
||||||
|
|
||||||
|
inputs.nixpkgs.url = "nixpkgs/nixos-24.11";
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
{ self
|
||||||
|
, nixpkgs
|
||||||
|
,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ];
|
||||||
|
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
|
||||||
|
nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; });
|
||||||
|
in
|
||||||
|
{
|
||||||
|
overlay = _: prev: { inherit (self.packages.${prev.system}) calnow; };
|
||||||
|
|
||||||
|
packages = forAllSystems (system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgsFor.${system};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
calnow = pkgs.buildGoModule {
|
||||||
|
pname = "calnow";
|
||||||
|
version = "v0.0.0";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
vendorHash = "sha256-SWkQMF9bFAzqsmHWKNsTpx8HuXrXZe9+vIOI0mmAPrw=";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
defaultPackage = forAllSystems (system: self.packages.${system}.calnow);
|
||||||
|
devShells = forAllSystems (system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgsFor.${system};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
default = pkgs.mkShell {
|
||||||
|
shellHook = ''
|
||||||
|
PS1='\u@\h:\@; '
|
||||||
|
nix run github:qbit/xin#flake-warn
|
||||||
|
echo "Go `${pkgs.go}/bin/go version`"
|
||||||
|
'';
|
||||||
|
nativeBuildInputs = with pkgs; [ git go gopls go-tools ];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
13
go.mod
Normal file
13
go.mod
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
module suah.dev/calnow
|
||||||
|
|
||||||
|
go 1.23.2
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/emersion/go-webdav v0.5.0
|
||||||
|
github.com/sosodev/duration v1.3.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/emersion/go-ical v0.0.0-20220601085725-0864dccc089f // indirect
|
||||||
|
github.com/teambition/rrule-go v1.8.2 // indirect
|
||||||
|
)
|
10
go.sum
Normal file
10
go.sum
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
github.com/emersion/go-ical v0.0.0-20220601085725-0864dccc089f h1:feGUUxxvOtWVOhTko8Cbmp33a+tU0IMZxMEmnkoAISQ=
|
||||||
|
github.com/emersion/go-ical v0.0.0-20220601085725-0864dccc089f/go.mod h1:2MKFUgfNMULRxqZkadG1Vh44we3y5gJAtTBlVsx1BKQ=
|
||||||
|
github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM=
|
||||||
|
github.com/emersion/go-webdav v0.5.0 h1:Ak/BQLgAihJt/UxJbCsEXDPxS5Uw4nZzgIMOq3rkKjc=
|
||||||
|
github.com/emersion/go-webdav v0.5.0/go.mod h1:ycyIzTelG5pHln4t+Y32/zBvmrM7+mV7x+V+Gx4ZQno=
|
||||||
|
github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4=
|
||||||
|
github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
|
||||||
|
github.com/teambition/rrule-go v1.7.2/go.mod h1:mBJ1Ht5uboJ6jexKdNUJg2NcwP8uUMNvStWXlJD3MvU=
|
||||||
|
github.com/teambition/rrule-go v1.8.2 h1:lIjpjvWTj9fFUZCmuoVDrKVOtdiyzbzc93qTmRVe/J8=
|
||||||
|
github.com/teambition/rrule-go v1.8.2/go.mod h1:Ieq5AbrKGciP1V//Wq8ktsTXwSwJHDD5mD/wLBGl3p4=
|
193
main.go
Normal file
193
main.go
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"slices"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/emersion/go-webdav"
|
||||||
|
"github.com/emersion/go-webdav/caldav"
|
||||||
|
"github.com/sosodev/duration"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
fullTimeFmt = "20060102T150405"
|
||||||
|
fullFimeTmt = "20060102T150405"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
debug = false
|
||||||
|
)
|
||||||
|
|
||||||
|
func msg(fmt string, args ...any) {
|
||||||
|
if debug {
|
||||||
|
log.Printf(fmt, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func between(now, begin, end time.Time) bool {
|
||||||
|
return now.After(begin) && now.Before(end)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fixDate(a, b time.Time) time.Time {
|
||||||
|
return time.Date(
|
||||||
|
a.Year(),
|
||||||
|
a.Month(),
|
||||||
|
a.Day(),
|
||||||
|
a.Hour(),
|
||||||
|
a.Minute(),
|
||||||
|
a.Second(),
|
||||||
|
a.Nanosecond(),
|
||||||
|
b.Location(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.BoolVar(&debug, "debug", false, "print debug messages")
|
||||||
|
flag.Parse()
|
||||||
|
username := os.Getenv("CALNOW_USER")
|
||||||
|
serverURL := os.Getenv("CALNOW_URL")
|
||||||
|
password := os.Getenv("CALNOW_PASS")
|
||||||
|
|
||||||
|
if username == "" || password == "" {
|
||||||
|
log.Fatal("Please set CALNOW_USER and CALNOW_PASS environment variables")
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := caldav.NewClient(webdav.HTTPClientWithBasicAuth(
|
||||||
|
&http.Client{},
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
), serverURL)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Failed to create client:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
princ, err := client.FindCurrentUserPrincipal(ctx)
|
||||||
|
|
||||||
|
homeSets, err := client.FindCalendarHomeSet(ctx, princ)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Failed to find home set:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
calendars, err := client.FindCalendars(ctx, homeSets)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to find calendars for home set %s: %v", homeSets, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
start := time.Date(
|
||||||
|
now.Year(),
|
||||||
|
now.Month(),
|
||||||
|
now.Day(),
|
||||||
|
0, 0, 1, 0,
|
||||||
|
now.Location(),
|
||||||
|
)
|
||||||
|
|
||||||
|
end := time.Date(
|
||||||
|
now.Year(),
|
||||||
|
now.Month(),
|
||||||
|
now.Day(),
|
||||||
|
23, 59, 59, 999999999,
|
||||||
|
now.Location(),
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, cal := range calendars {
|
||||||
|
if !slices.Contains(cal.SupportedComponentSet, "VEVENT") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
path := cal.Path
|
||||||
|
query := &caldav.CalendarQuery{
|
||||||
|
CompRequest: caldav.CalendarCompRequest{
|
||||||
|
Name: "VCALENDAR",
|
||||||
|
Comps: []caldav.CalendarCompRequest{{
|
||||||
|
Name: "VEVENT",
|
||||||
|
Props: []string{
|
||||||
|
"SUMMARY",
|
||||||
|
"UID",
|
||||||
|
"DTSTART",
|
||||||
|
"DTEND",
|
||||||
|
"DURATION",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
|
||||||
|
CompFilter: caldav.CompFilter{
|
||||||
|
Name: "VCALENDAR",
|
||||||
|
Comps: []caldav.CompFilter{{
|
||||||
|
Name: "VEVENT",
|
||||||
|
Start: start,
|
||||||
|
End: end,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
events, err := client.QueryCalendar(ctx, path, query)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, e := range events {
|
||||||
|
for i := range e.Data.Children {
|
||||||
|
sum := e.Data.Children[i].Props.Get("SUMMARY")
|
||||||
|
end := e.Data.Children[i].Props.Get("DTEND")
|
||||||
|
dur := e.Data.Children[i].Props.Get("DURATION")
|
||||||
|
begin := e.Data.Children[i].Props.Get("DTSTART")
|
||||||
|
|
||||||
|
if sum != nil {
|
||||||
|
msg("%s:%s", cal.Name, sum.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if begin == nil && dur == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if end != nil {
|
||||||
|
endTime, err := time.Parse(fullTimeFmt, end.Value)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
beginTime, err := time.Parse(fullTimeFmt, begin.Value)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
endTime = fixDate(endTime, now)
|
||||||
|
beginTime = fixDate(beginTime, now)
|
||||||
|
|
||||||
|
msg("%s <%s> %s, between: %t", beginTime, now, endTime, between(now, beginTime, endTime))
|
||||||
|
if between(now, beginTime, endTime) {
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if dur != nil && begin != nil {
|
||||||
|
beginTime, err := time.Parse(fullTimeFmt, begin.Value)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
eDur, err := duration.Parse(dur.Value)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
endTime := beginTime.Add(eDur.ToTimeDuration())
|
||||||
|
|
||||||
|
endTime = fixDate(endTime, now)
|
||||||
|
beginTime = fixDate(beginTime, now)
|
||||||
|
|
||||||
|
msg("%s <%s> %s, between: %t", beginTime, now, endTime, between(now, beginTime, endTime))
|
||||||
|
if between(now, beginTime, endTime) {
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user