-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Andrea Barberio <insomniac@slackware.it>
- Loading branch information
0 parents
commit a6f3d75
Showing
4 changed files
with
209 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# moca24-ics | ||
|
||
Smal tool that fetches the [MOCA 2024 calendar](https://moca.camp/calendar/index.html) via HackerTracker API and prints it in ICS format. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module git.cicciogatto.lol/insomniac/moca-ics | ||
|
||
go 1.22.6 | ||
|
||
require github.com/sirupsen/logrus v1.9.3 | ||
|
||
require golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= | ||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= | ||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= | ||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"net/url" | ||
"strings" | ||
"time" | ||
|
||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
var ( | ||
hturl = url.URL{ | ||
Scheme: "https", | ||
Host: "firestore.googleapis.com", | ||
Path: "/v1/projects/junctor-hackertracker/databases/(default)/documents/conferences/MOCA2024:runQuery", | ||
} | ||
) | ||
|
||
type StringField struct { | ||
StringValue string `json:"stringValue,omitempty"` | ||
} | ||
|
||
type IntField struct { | ||
IntValue string `json:"intValue,omitempty"` | ||
} | ||
|
||
type Value struct { | ||
MapValue struct { | ||
Fields struct { | ||
ConferenceID interface{} `json:"conference_id,omitempty"` | ||
EventIDs ArrayField `json:"event_i_ds,omitempty"` | ||
Name StringField `json:"name,omitempty"` | ||
Links ArrayField `json:"links,omitempty"` | ||
Affiliations ArrayField `json:"affiliations,omitempty"` | ||
Media ArrayField `json:"media,omitempty"` | ||
ID IntField `json:"id,omitempty"` | ||
ShortName StringField `json:"short_name,omitempty"` | ||
} `json:"fields,omitempty"` | ||
} `json:"mapValue,omitempty"` | ||
} | ||
|
||
type ArrayField struct { | ||
ArrayValue struct { | ||
Values []Value `json:"values,omitempty"` | ||
} `json:"arrayValue,omitempty"` | ||
} | ||
|
||
type Item struct { | ||
Document struct { | ||
Name string `json:"name"` | ||
Fields struct { | ||
Conference StringField `json:"conference,omitempty"` | ||
Timezone StringField `json:"timezone,omitempty"` | ||
Link StringField `json:"link,omitempty"` | ||
Title StringField `json:"title,omitempty"` | ||
Description StringField `json:"description,omitempty"` | ||
Media ArrayField `json:"media,omitempty"` | ||
Type interface{} `json:"type,omitempty"` | ||
BeginTsz StringField `json:"begin_tsz,omitempty"` | ||
EndTsz StringField `json:"end_tsz,omitempty"` | ||
BeginTimestamp StringField `json:"begin_timestamp,omitempty"` | ||
EndTimestamp StringField `json:"end_timestamp,omitempty"` | ||
UpdatedTsz StringField `json:"updated_tsz,omitempty"` | ||
UpdatedTimestamp StringField `json:"updated_timestamp,omitempty"` | ||
Location Value `json:"location,omitempty"` | ||
Speakers ArrayField `json:"speakers,omitempty"` | ||
Links ArrayField `json:"links,omitempty"` | ||
} `json:"fields,omitempty"` | ||
} `json:"document"` | ||
} | ||
|
||
func main() { | ||
reqData := []byte(`{ | ||
"structuredQuery": { | ||
"from": [ | ||
{ | ||
"collectionId": "events" | ||
} | ||
], | ||
"orderBy": [ | ||
{ | ||
"field": { | ||
"fieldPath": "begin_timestamp" | ||
}, | ||
"direction": "DESCENDING" | ||
}, | ||
{ | ||
"field": { | ||
"fieldPath": "__name__" | ||
}, | ||
"direction": "DESCENDING" | ||
} | ||
] | ||
} | ||
}`) | ||
req, err := http.NewRequest(http.MethodPost, hturl.String(), bytes.NewBuffer(reqData)) | ||
if err != nil { | ||
logrus.Fatalf("Failed to create new request: %v", err) | ||
} | ||
client := http.Client{} | ||
resp, err := client.Do(req) | ||
if err != nil { | ||
logrus.Fatalf("HTTP POST failed: %v", err) | ||
} | ||
defer func() { | ||
_ = resp.Body.Close() | ||
}() | ||
if resp.StatusCode != 200 { | ||
logrus.Fatalf("Status code is not 200 OK but %s", resp.Status) | ||
} | ||
body, err := io.ReadAll(resp.Body) | ||
if err != nil { | ||
logrus.Fatalf("Failed to read HTTP body: %v", err) | ||
} | ||
var items []Item | ||
if err := json.Unmarshal(body, &items); err != nil { | ||
logrus.Fatalf("Failed to unmarshal response: %v", err) | ||
} | ||
ics := fmt.Sprintf(`BEGIN:VCALENDAR | ||
VERSION:2.0 | ||
PRODID:-//moca/camp/schedule v1.0//EN | ||
VTIMEZONE: Europe/Rome | ||
`) | ||
|
||
for _, item := range items { | ||
eventUID := item.Document.Name | ||
location := item.Document.Fields.Location.MapValue.Fields.Name.StringValue | ||
speakerNames := make([]string, 0, len(item.Document.Fields.Speakers.ArrayValue.Values)) | ||
for _, v := range item.Document.Fields.Speakers.ArrayValue.Values { | ||
name := v.MapValue.Fields.Name.StringValue | ||
if name != "" { | ||
name = strings.Replace(name, "\n", "\\n", -1) | ||
name = strings.Replace(name, "\"", "'", -1) | ||
speakerNames = append(speakerNames, name) | ||
} | ||
} | ||
speakers := "unknown" | ||
if len(speakerNames) > 0 { | ||
speakers = strings.Join(speakerNames, ", ") | ||
} | ||
speakerEmail := "unknown" | ||
start, err := time.Parse("2006-01-02T15:04:05Z", item.Document.Fields.BeginTsz.StringValue) | ||
if err != nil { | ||
logrus.Fatalf("Failed to parse start time %q: %v", item.Document.Fields.BeginTsz.StringValue, err) | ||
} | ||
end, err := time.Parse("2006-01-02T15:04:05Z", item.Document.Fields.EndTsz.StringValue) | ||
if err != nil { | ||
logrus.Fatalf("Failed to parse end time %q: %v", item.Document.Fields.EndTsz.StringValue, err) | ||
} | ||
summary := item.Document.Fields.Title.StringValue | ||
description := item.Document.Fields.Description.StringValue | ||
description = strings.Replace(description, "\n", "\\n", -1) | ||
description = strings.Replace(description, "\r", "", -1) | ||
ics += fmt.Sprintf(`BEGIN:VEVENT | ||
UID:%s | ||
ORGANIZER;CN=%s:MAILTO:%s | ||
DTSTAMP:20240912T140000Z | ||
DTSTART:%s | ||
DTEND:%s | ||
SUMMARY:%s | ||
DESCRIPTION: %s | ||
GEO:42.5816338;14.0901461 | ||
LOCATION: %s | ||
END:VEVENT | ||
`, | ||
eventUID, | ||
speakers, | ||
speakerEmail, | ||
start.Format("20060102T150405Z"), | ||
end.Format("20060102T150405Z"), | ||
summary, | ||
description, | ||
location, | ||
) | ||
} | ||
ics += fmt.Sprintln("END:VCALENDAR") | ||
ics = strings.Replace(ics, "\n", "\r\n", -1) | ||
fmt.Println(ics) | ||
} |