Giter VIP home page Giter VIP logo

golang-ical's Introduction

golang-ical

A ICS / ICal parser and serialiser for Golang.

GoDoc

Because the other libraries didn't quite do what I needed.

Usage, parsing:

    cal, err := ParseCalendar(strings.NewReader(input))

Creating:

  cal := ics.NewCalendar()
  cal.SetMethod(ics.MethodRequest)
  event := cal.AddEvent(fmt.Sprintf("id@domain", p.SessionKey.IntID()))
  event.SetCreatedTime(time.Now())
  event.SetDtStampTime(time.Now())
  event.SetModifiedAt(time.Now())
  event.SetStartAt(time.Now())
  event.SetEndAt(time.Now())
  event.SetSummary("Summary")
  event.SetLocation("Address")
  event.SetDescription("Description")
  event.SetURL("https://URL/")
  event.AddRrule(fmt.Sprintf("FREQ=YEARLY;BYMONTH=%d;BYMONTHDAY=%d", time.Now().Month(), time.Now().Day()))
  event.SetOrganizer("sender@domain", ics.WithCN("This Machine"))
  event.AddAttendee("reciever or participant", ics.CalendarUserTypeIndividual, ics.ParticipationStatusNeedsAction, ics.ParticipationRoleReqParticipant, ics.WithRSVP(true))
  return cal.Serialize()

Helper methods created as needed feel free to send a P.R. with more.

Notice

Looking for a co-maintainer.

golang-ical's People

Contributors

adamjack avatar arran4 avatar bcspragu avatar brackendawson avatar brenank avatar cdzombak avatar darmiel avatar dbenoot avatar dependabot[bot] avatar filego avatar fklingenberg avatar frereit avatar fty4 avatar galenwarren avatar jackhopner avatar johnjones4 avatar konimarti avatar meain avatar nickyboy89 avatar pjebs avatar quite avatar roidelapluie avatar shaohme avatar spslater avatar thde avatar thib-ack avatar voldyman avatar yaknikush avatar zachmann avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

golang-ical's Issues

VTodo and VJournal Missing Setters and Getters

The VEvent component has most (all?) of the methods to be able to set and get the different parts of the component like the summary, description, start time, ect. It also has a way to create new events.

The VTodo and VJournal only have a way to serialize and load the information. (I think same is true with VBusy and VTimezone, but I don't need those for my project right now, so I haven't looked at them yet)

If these haven't been implemented yet because there hasn't been a need for it, then I will go ahead and work on adding this functionality.

Property spanning multiple lines causes `Malformed Calendar Error`

Iterating over events in an Outlook generated .ics-File creates an invalid memory address or nil pointer dereference-Error.

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x4a5bdd]

goroutine 1 [running]:
github.com/arran4/golang-ical.(*Calendar).Events(0x0)
        /workspaces/golang-ical/calendar.go:409 +0x1d
main.main()
        /tmp/test/testing.go:14 +0x89

I have attached an example entry I exported from Outlook as well as my testing code to reproduce the error.

issue48_attachments.zip

Add functionality for adding VTIMEZONE from a standard set

I only recently started looking into generating .ics files for a project at work where I'm creating event calendar files to include with tickets for a show in an email. One thing I've seen in my research is including VTIMEZONE info in their calendar files to indicate the original timezone the event is in. Here's an example from an exported Google Calendar:

BEGIN:VTIMEZONE
TZID:America/New_York
X-LIC-LOCATION:America/New_York
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE

There is a standard set of these timezones that come from https://www.tzurl.org/ that cover all standard IANA timezone codes, and it would be really cool if there could be some functionality in this package to set these values based on passing in a code.

I was thinking something along the lines of this right before you make your first VEVENT (which I think is the standard place to put it?):

cal.SetVtimezone("America/New_York")

Alternatively, you could have some constants set up like ics.TimezoneAmerica_NewYork, or use the time.LoadLocation functionality:

America_NewYork, err := time.LoadLocation("America/New_York")

And this would set the start/end and all of the contents of the VTIMEZONE info.

I've found a couple of node packages that do something similar, and I don't think it would be too difficult to use some of their logic to port their functionality, but I'm also new to Go, so correct me if I'm wrong.

Here's what I found for a similar purpose:

Idk if this is outside the scope of what you'd like to do with this package, but I think it would be a really cool feature to have! I could also look into making a PR for this, but I'd like to get your thoughts first.

URL support for parsing (feature)

I'm working on a project using golang-ical. But the thing is that I need to parse a calendar accessible by a URL.
Here is my show-case :

// parse an ical url to instantiate a Calendar
func NewCalendar(url string) Calendar {
	cal, err := ics.ParseCalendar(url)
	return Calendar{
		Url: url,
                Events: cal,
	}
}

The javascript's ical library provides this kind of feature, but I don't want to use javascript to do that.
By the way, I can work on this issue. I just wanted to know if it might be helpful for this project to add such a feature (I will fork the project anyway).

Remove event from calendar

Is there a way to parse a calendar and then remove some events? I don't mean to cancel them, I want them out of the .ics file.

Better time parsing

I would like to contribute a patch that expands the existing time.Time parsing in the library used for functions like GetStartAt, and GetAllDayStartAt, etc. At the moment these functions does not support timestamps and date strings like,

19980118T230000 <- error: cannot parse "" as "Z"
20210527Z <- error: cannot parse "Z" as "T"
20210628 <- error: cannot parse "" as "T"
20220122T170000Z <- error: extra text: "T170000Z" (when invoking GetAllDay.*At )

... and probably many others.

Would you reject a PR for such a feature?

How to update ical event

It's look awesome library.
Could you provide flow for updating existed event?
When I tried update ical with same UUID Google Calendar create new event but not update existed event.

Properties appearing more than once

Hey,

first of all thanks for this library. I know how hard iCAL can be :D

I was trying to check if a repeated event has been deleted and wanted to access the "EXDATE" property.
According to the RFC, some properties CAN occur more than once like e.g. EXDATE, but with the GetProperty() function I will always only get the first entry of an event and not all of them. Depending on the library which generated the ical file, the EXDATE can either appear only once and have all dates comma separated in a single line or appear multiple times with only a single date, which to my knowledge is both RFC compliant.

I have tested an ical File from NextCloud and from DaviCAL and both use the style with single dates in separate EXDATE entries. If you need something to test, here is a simple calendar from my NextCloud with a repeating event and two EXDATE entries: https://dump.felixbreidenstein.de/test.ics

Best,
Felix

please show more examples on usage

Please add some code examples on how to use the structure after parsing to retrieve the usual information. i am not an ical expert and couldnt find out how to get the data from a parsed ical (my start time is zero for all values ;) )

Modify component methods to allow chaining?

If you write your component methods like:

func (event *VEvent) SetSummary(s string, props ...PropertyParameter) *VEvent {
	event.SetProperty(ComponentPropertySummary, ToText(s), props...)
        return event
}

instead of

func (event *VEvent) SetSummary(s string, props ...PropertyParameter) {
	event.SetProperty(ComponentPropertySummary, ToText(s), props...)
}

The API can be used like:

event := cal.AddEvent("id@domain").
	SetDtStampTime(time.Now()).
	SetStartAt(time.Now().Add(1 * time.Hour)).
	SetEndAt(time.Now().Add(2 * time.Hour)).
	SetSummary("Meeting with Jim")

which reads a little cleaner than

event := cal.AddEvent("[email protected]")
event.SetDtStampTime(time.Now())
event.SetStartAt(time.Now().Add(1 * time.Hour))
event.SetEndAt(time.Now().Add(2 * time.Hour))
event.SetSummary("Meeting with Jim")

in my opinion

this is also not a breaking change, the API would still work the 2nd way too

name error

func (event *VEvent) AddAttendee(s string, props ...PropertyParameter) {
	event.AddProperty(ComponentPropertyAttendee, "mailto:"+s, props...)
}

this mailto should be MAILTO

Better Error handling

I ran into an issue that my calendar did not have a getAllDayEndAt() property and I got an error which was property not found
I think it would be great to have a package with all the possible errors so we can better handle errors in production.

func (event *VEvent) getTimeProp(componentProperty ComponentProperty, expectAllDay bool) (time.Time, error) {
	timeProp := event.GetProperty(componentProperty)
	if timeProp == nil {
		return time.Time{}, errors.New("property not found")
	}

All Day Events

Thanks so much for this package - you've saved me hours!

Just wanted to report on my findings while trying to work out how to output an 'all day event'. 99% this is down to me not knowing how to use iCal spec/this package, but just wanted to make some notes/ask a question.

From inspecting other feeds that were showing all day events correctly, it looked like the structure needed to be:

DTSTART;VALUE=DATE:20201101

To get that output I had to bypass the helper functions, format the date manually with a copy of your 'icalDateFormatLocal' (otherwise the Z at the end caused the event not to display) and manually specify the DATE value.

event.SetProperty(ics.ComponentPropertyDtStart, t.Start.UTC().Format(icalDateFormatLocal), ics.WithValue("DATE"))

I imagine that I'm missing a much easier way to do this, but couldn't find it to save my life.

Serialize seems to output "\n" rather than "\r\n"

Hello, and thanks for making this awesome library :)

I've been using it to create a calendar, then calling Serialize() and saving that to disk.

However, this validator complains that lines that span multiple lines (eg long URLs) aren't separated with CRLF ("\r\n").

As a test, I ran unix2dos on the generated file, and it then validated.

As a workaround, I've got my code running strings.Replace(cal.Serialize, "\n", "\r\n", -1) and now it validates.

But it does seem that the folding (or is it unfolding?) aspect of Serialize isn't working quite according to spec.

Thanks again.
Paul

Proposal to add VEvent.GetDtStampTime

Add VEvent.GetDtStampTime as a partner to VEvent.SetDtStampTime. It is currently possible to read out the value using GetProperty, but the getTimeProp helper function -- that is used to parse different time formats for other get methods -- is not exported.

PR: #80

IsInEvent functionality

Hi, I found this repo yesterday when brainstorming (yes, and GPT-Storming) for a general way to represent a allowance to unlock a door.

Given a valid iCal format, I now need a way to check if now falls into the calender event (true false). Is there an easy way to do so (I didn't see a command in the lib)? I do not have any prior experience with the format yet, so I cannot judge on the complexity and edgy cases for this.

idk if it helps, but this is what ChatGPT came up with (untested yet):
Edit: code built into my program, tested for intervals and simple dates (UTC and local time)

func (cal *ICalCalendar) IsIn(unixTimestamp uint64)  (res Result[bool]) {
	defer func() {
		if r := recover(); r != nil {
			res = ResultError[bool](
				fmt.Errorf("panic when checking for date in ical calendar: %v", r),
				ERROR_ICAL_ISIN_CHECK)
		}
	}()
	givenTime := time.Unix(int64(unixTimestamp), 0)
	errors := []error{}
	found := false
	for _, event := range cal.inst.Events() {
		start, err := event.GetStartAt()
		if err != nil {
			errors = append(errors, err)
			continue
		}

		end, err := event.GetEndAt()
		if err != nil {
			errors = append(errors, err)
			continue
		}

		duration := end.Sub(start)

		// Check non-recurring event
		if (givenTime.After(start) || givenTime.Unix() == start.Unix()) && (givenTime.Before(end) || givenTime.Unix() == end.Unix()) {
			found = true
			break
		}

		// Check recurring event
		PropRRule := event.GetProperty("RRULE")
		if PropRRule != nil {
			startStr := event.GetProperty("DTSTART").Value
			rruleStr := PropRRule.Value
			r, err := rrule.StrToRRule(fmt.Sprintf("DTSTART:%s\nRRULE:%s", startStr, rruleStr))
			if err != nil {
				errors = append(errors, err)
				continue
			}

			instances := r.Between(start, start.Add(1*time.Hour*24*365), true) // Limit search to 1 year ahead
			for _, instance := range instances {
				instanceEnd := instance.Add(duration)
				if (givenTime.After(instance) || givenTime.Unix() == instance.Unix()) && (givenTime.Before(instanceEnd) || givenTime.Unix() == instanceEnd.Unix()) {
					found = true
					break
				}
			}
		}
	}

	if len(errors) > 0 {
		return ResultWarning[bool](
			found,
			errors,
			ERROR_ICAL_CHECK,
		)
	}

	return ResultOk(found)
}

it should be able to handle interval events also. Any feedback on that?

"Import failed to save." Calendar.app on macOS Catalina (With example)

Hey there,

I'm trying to generate an ics file and import it into Calendar.app of macOS Catalina. I'm getting the following error for the given file:

Screen Shot 2020-06-06 at 18 16 08

The ics file I'm trying to import is:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Arran Ubels//Golang ICS library
METHOD:REQUEST
BEGIN:VEVENT
UID:456
CREATED:20200610T181852Z
DTSTAMP:20200610T181852Z
LAST-MODIFIED:20200610T181852Z
DTSTART:20200610T181852Z
SUMMARY:Post scheduled 456
DESCRIPTION:description456
URL:456
END:VEVENT
BEGIN:VEVENT
UID:123
CREATED:20190821T080000Z
DTSTAMP:20190821T080000Z
LAST-MODIFIED:20190821T080000Z
DTSTART:20190821T080000Z
SUMMARY:Post scheduled 123
DESCRIPTION:description123
URL:123
END:VEVENT
END:VCALENDAR

If I remove one of the events so that there's only one in there it works:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Arran Ubels//Golang ICS library
METHOD:REQUEST
BEGIN:VEVENT
UID:456
CREATED:20200610T181852Z
DTSTAMP:20200610T181852Z
LAST-MODIFIED:20200610T181852Z
DTSTART:20200610T181852Z
SUMMARY:Post scheduled 456
DESCRIPTION:description456
URL:456
END:VEVENT
END:VCALENDAR

I'm running out of ideas what could cause that, it's a valid file according to: https://icalendar.org/validator.html#results

Do you have any idea what could happen there?

Thanks!

Already escaped symbols get double escaped

Parsing an already escaped semicolon \; creates a double backslah \\;

golang-ical/property.go

Lines 100 to 105 in d07bbcb

if strings.ContainsAny(v, ";:\\\",") {
v = strings.Replace(v, ";", "\\;", -1)
v = strings.Replace(v, ":", "\\:", -1)
v = strings.Replace(v, "\\", "\\\\", -1)
v = strings.Replace(v, "\"", "\\\"", -1)
v = strings.Replace(v, ",", "\\,", -1)

Probably just putting L104 to the beginning of the if statement should resolve this?

Missing License

Hello,

I like your golang-ical, but I really need your license. Or should this be private?
Is this an open-source and suitable for commercial use?

Line folding can can break in the middle of a UNICODE character

Hello again!

I was struggling with a mysterious issue where a character in my calendar was getting mangled.

After quite a lot of research I pinned it down to the way serialize counts line length. The implementation allows it to break a line in the middle of a character.

For example, requires 3 bytes to encode. If it occurs on a line after 74 bytes, the folding routine breaks in the middle of it.

I've made a fix on my fork with some tests to pin down the behaviour:

fawkesley@67e08db

Happy to raise a pull request (in a rush atm), but just wanted to show you what I found for now.

how to do a event reminder?

well,is that a example to tell me how to do a simple event reminder?
i have not found a example about it...
such as a event start at 09:00,i want a reminder at 07:00
i do make a event for cal,but have not idea to make a reminder

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.