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