cal-invite 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87266e97a53aac81a619ae283a7c14c05f67140e96f6d57bc8aca97789c232f4
4
- data.tar.gz: c169424e6171d5f814b41ef6d8154c790efdd1a9693244db1b93265f940dbe6c
3
+ metadata.gz: 100b68a6d13bbb3b58234eee38701ffc1c6d215daf126ba98c89e249829d716e
4
+ data.tar.gz: ed0388023bf7245fb09c14294ce91610c189996f7c49cf246f47589efd17c1d2
5
5
  SHA512:
6
- metadata.gz: 0fd39a7fa410f1c3212015f3bf4276cbee1473fe2b5f887aef9bcbc1d43ca1da9af1dfb9f72dec990ae25c7e0af33b260778981fd01a795cba3658fafced1fc4
7
- data.tar.gz: 5743ca62b4e8f7062e748ba717e29b5e68909e812a526575dc65b06f17b95d69aec3c7458cb1481c39e6f986b0c594a0ec2a8f390f54d0d78e7909dd21ef4517
6
+ metadata.gz: 9755f61af9fbed611988f3355647991c4dabe8b9a1f4ff3c0c8e77aa0c9d2c744e270aa09e01c0f7284fd0c40bce1af07a0a0a68f557e19be901969a89f32c3d
7
+ data.tar.gz: 18b4e856b14b6d5a49a2dce096b56e8b068813f058cf6648ceb9f37f04d5793454ff46bb1a7f1ed4e1f35f1e8faa796595915e84334d9763323b814744d47808
data/CACHING.md ADDED
@@ -0,0 +1,148 @@
1
+ ## Caching
2
+
3
+ CalInvite supports flexible caching options when used within a Rails application. You can configure the cache store to use any of Rails' supported cache stores including memory store, Redis, or a custom cache store implementation.
4
+
5
+ ### Basic Configuration
6
+
7
+ Configure caching in your Rails application's initializer:
8
+
9
+ ```ruby
10
+ # config/initializers/cal_invite.rb
11
+ CalInvite.configure do |config|
12
+ # Use Rails.cache by default
13
+ config.cache_store = Rails.cache
14
+
15
+ # Optional: Set a custom prefix for cache keys
16
+ config.cache_prefix = 'my_app_cal_invite'
17
+
18
+ # Optional: Set cache expiration (in seconds)
19
+ config.cache_expires_in = 3600 # 1 hour
20
+ end
21
+ ```
22
+
23
+ ### Available Cache Stores
24
+
25
+ CalInvite supports the following cache stores:
26
+
27
+ 1. Memory Store (default)
28
+ ```ruby
29
+ config.cache_store = :memory_store
30
+ ```
31
+
32
+ 2. Null Store (for disabling caching)
33
+ ```ruby
34
+ config.cache_store = :null_store
35
+ ```
36
+
37
+ 3. Custom Cache Store
38
+ ```ruby
39
+ # Any object that implements read/write/delete methods
40
+ config.cache_store = MyCacheStore.new
41
+ ```
42
+
43
+ 4. Rails Cache
44
+ ```ruby
45
+ # Use your Rails application's configured cache
46
+ config.cache_store = Rails.cache
47
+ ```
48
+
49
+ ### Cache Configuration Options
50
+
51
+ - `cache_store`: The storage mechanism for cached data
52
+ - `cache_prefix`: Prefix for all cache keys (default: 'cal_invite')
53
+ - `cache_expires_in`: Default cache expiration time in seconds
54
+ - `timezone`: Default timezone for cache keys (default: 'UTC')
55
+
56
+ ### Custom Cache Adapters
57
+
58
+ You can implement custom cache adapters by creating a class that responds to the following methods:
59
+
60
+ ```ruby
61
+ class CustomCacheStore
62
+ def read(key)
63
+ # Implementation for retrieving cached value
64
+ end
65
+
66
+ def write(key, value, options = {})
67
+ # Implementation for storing value in cache
68
+ # options may include :expires_in
69
+ end
70
+
71
+ def delete(key)
72
+ # Implementation for removing cached value
73
+ end
74
+
75
+ def clear
76
+ # Implementation for clearing all cached values
77
+ end
78
+ end
79
+
80
+ # Configure CalInvite to use your custom cache store
81
+ CalInvite.configure do |config|
82
+ config.cache_store = CustomCacheStore.new
83
+ end
84
+ ```
85
+
86
+ ### Automatic Cache Invalidation
87
+
88
+ The cache is automatically invalidated in the following scenarios:
89
+
90
+ 1. When event attributes are updated via `update_attributes`
91
+ 2. When a new calendar URL is generated
92
+ 3. When the configuration changes
93
+
94
+ ### Best Practices
95
+
96
+ 1. **Cache Store Selection**: Choose an appropriate cache store based on your needs:
97
+ - Use `:memory_store` for development and small applications
98
+ - Use Rails.cache for production applications
99
+ - Implement a custom cache store for specific requirements
100
+
101
+ 2. **Cache Key Management**:
102
+ - The gem automatically generates unique cache keys based on event attributes
103
+ - Keys include a prefix for namespace isolation
104
+ - Consider your timezone settings when debugging cache issues
105
+
106
+ 3. **Expiration Strategy**:
107
+ - Set appropriate expiration times based on your use case
108
+ - Consider using shorter expiration times for frequently changing data
109
+ - Use `nil` expiration for permanent caching (until manual invalidation)
110
+
111
+ ### Example Rails Integration
112
+
113
+ Here's a complete example of setting up caching in a Rails application:
114
+
115
+ ```ruby
116
+ # config/initializers/cal_invite.rb
117
+ CalInvite.configure do |config|
118
+ if Rails.env.production?
119
+ # Use Rails cache in production
120
+ config.cache_store = Rails.cache
121
+ config.cache_expires_in = 1.hour
122
+ else
123
+ # Use memory store in development
124
+ config.cache_store = :memory_store
125
+ config.cache_expires_in = 5.minutes
126
+ end
127
+
128
+ config.cache_prefix = "cal_invite:#{Rails.env}"
129
+ config.timezone = 'UTC'
130
+ end
131
+ ```
132
+
133
+ ### Testing with Caching
134
+
135
+ When writing tests that involve caching:
136
+
137
+ ```ruby
138
+ # In your test setup
139
+ CalInvite.configure do |config|
140
+ config.cache_store = :memory_store
141
+ config.cache_expires_in = 3600 # 1 hour in seconds
142
+ end
143
+
144
+ # Clear cache between tests
145
+ def setup
146
+ CalInvite.configuration.cache_store.clear
147
+ end
148
+ ```
data/CHANGELOG.md CHANGED
@@ -1,10 +1,29 @@
1
- ## [Unreleased]
1
+ # Cal Invite
2
+
3
+ ## [Released]
4
+
5
+ ## [v0.1.3] - 2024-12-19
6
+
7
+ - Apple iCal and ics file can now be either generated or wrap to be downloaded
8
+ - Add Caching management support
9
+ - Add CACHING.md for more details about how to use caching in a Rails app
10
+ - Updating the README file to reflect latest usage changes
11
+ - Minor bug fixes and improvments.
2
12
 
3
- ## [0.1.1] - 2024-12-17
13
+ ## [v0.1.2] - 2024-12-17
14
+
15
+ - Add support to Microsoft office 365 calendar invite URL
16
+ - Update the README
17
+ - Add an example
18
+ - Better testing
19
+
20
+ ## [v0.1.1] - 2024-12-17
4
21
 
5
22
  Fixing a bug in the gemspec file
6
23
 
7
- ## [0.1.0] - 2024-12-17
24
+ ## [Unreleased]
25
+
26
+ ## [v0.1.0] - 2024-12-17
8
27
 
9
28
  First public release of the Calendar Invite gem
10
29
 
data/README.md CHANGED
@@ -1,9 +1,10 @@
1
- # CalInvite
1
+ # 📅 CalInvite
2
2
 
3
3
  A Ruby gem for generating calendar invitations across multiple calendar platforms with caching and webhook support.
4
4
 
5
5
  [![Gem Version](https://badge.fury.io/rb/cal-invite.svg)](https://badge.fury.io/rb/cal-invite)
6
- [![Ruby](https://github.com/the-pew-inc/cal-invite/workflows/Ruby/badge.svg)](https://github.com/yourusername/cal-invite/actions)
6
+ ![Build Status](https://github.com/the-pew-inc/cal-invite/actions/workflows/main.yml/badge.svg)
7
+ [![License](https://img.shields.io/github/license/the-pew-inc/cal-invite.svg)]
7
8
 
8
9
  ## Compatibility
9
10
 
@@ -13,20 +14,20 @@ A Ruby gem for generating calendar invitations across multiple calendar platform
13
14
  ## Supported Calendar Platforms
14
15
 
15
16
  Direct Integration:
16
- - Apple iCal
17
+ - Apple iCal (with proper timezone support)
17
18
  - Microsoft Outlook
19
+ - Microsoft Outlook 365
18
20
  - Google Calendar
19
21
  - Yahoo Calendar
20
22
  - Standard .ics file generation
21
23
 
22
24
  Any calendar application that supports the iCalendar (.ics) standard should work, including but not limited to:
23
- - ProtonCalendar
25
+ - Proton Calendar
24
26
  - FastMail Calendar
25
27
  - Thunderbird Calendar
26
28
  - Zoho Calendar
27
29
  - Microsoft Teams Calendar
28
30
  - Zoom Calendar Integration
29
- - Office 365 Calendar
30
31
 
31
32
  ## Installation
32
33
 
@@ -50,21 +51,47 @@ $ gem install cal-invite
50
51
 
51
52
  ### Basic Event Creation
52
53
 
54
+ Important notes:
55
+ - Always provide times in UTC
56
+ - Use the timezone parameter to specify the display timezone
57
+ - Location and URL are handled separately for better calendar integration
58
+
53
59
  ```ruby
54
- # Single day event
60
+ # Create an event with physical location
55
61
  event = CalInvite::Event.new(
56
62
  title: "Team Meeting",
57
- start_time: Time.current,
58
- end_time: Time.current + 2.hours,
63
+ start_time: Time.current.utc, # Always use UTC times
64
+ end_time: Time.current.utc + 2.hours,
59
65
  description: "Weekly team sync",
60
- location: "Conference Room A",
61
- url: "https://zoom.us/j/123456789",
66
+ location: "Conference Room A", # Physical location
67
+ timezone: "America/New_York", # Display timezone
62
68
  attendees: ["person@example.com"],
63
69
  show_attendees: true,
64
- timezone: "America/New_York",
65
70
  notes: "Please bring your laptop"
66
71
  )
67
72
 
73
+ # Create an event with both physical and virtual locations
74
+ event = CalInvite::Event.new(
75
+ title: "Hybrid Meeting",
76
+ start_time: Time.current.utc,
77
+ end_time: Time.current.utc + 2.hours,
78
+ description: "Weekly team sync",
79
+ location: "Conference Room A", # Physical location
80
+ url: "https://zoom.us/j/123456789", # Virtual meeting URL
81
+ timezone: "America/New_York",
82
+ attendees: ["person@example.com"],
83
+ show_attendees: true
84
+ )
85
+
86
+ # All-day event
87
+ event = CalInvite::Event.new(
88
+ title: "Company All-Day Event",
89
+ start_time: Date.today.beginning_of_day.utc,
90
+ end_time: Date.today.end_of_day.utc,
91
+ all_day: true,
92
+ timezone: "America/New_York"
93
+ )
94
+
68
95
  # Multi-day event
69
96
  event = CalInvite::Event.new(
70
97
  title: "Training Workshop",
@@ -80,27 +107,140 @@ event = CalInvite::Event.new(
80
107
  ],
81
108
  description: "Advanced Ruby Training",
82
109
  location: "Training Center",
83
- url: "https://zoom.us/j/123456789",
110
+ url: "https://zoom.us/j/123456789", # Virtual meeting URL kept separate
84
111
  timezone: "America/New_York",
85
112
  notes: "Bring your own laptop"
86
113
  )
87
114
 
88
- ical_url = event.calendar_url(:ical)
89
- google_url = event.calendar_url(:google)
90
- outlook_url = event.calendar_url(:outlook)
91
- yahoo_url = event.calendar_url(:yahoo)
92
- ics_content = event.calendar_url(:ics)
115
+ # Generate calendar URLs
116
+ ical_url = event.generate_calendar_url(:ical)
117
+ google_url = event.generate_calendar_url(:google)
118
+ outlook_url = event.generate_calendar_url(:outlook)
119
+ outlook365_url = event.generate_calendar_url(:office365)
120
+ yahoo_url = event.generate_calendar_url(:yahoo)
93
121
  ```
94
122
 
123
+ ### Implementing ICS Downloads
124
+
125
+ To enable ICS file downloads in your application, you'll need to:
126
+
127
+ 1. Create an endpoint that will handle the download request
128
+ 2. Generate the ICS content
129
+ 3. Send the file to the user
130
+
131
+ Here's a basic example of the controller logic:
132
+
133
+ ```ruby
134
+ # In your controller action
135
+ def download_calendar
136
+ event = # ... your event creation logic ...
137
+
138
+ content = CalInvite::Providers::Ics.new(event).generate
139
+ filename = "#{event.title.downcase.gsub(/[^0-9A-Za-z.\-]/, '_')}_#{Time.now.strftime('%Y%m%d')}.ics"
140
+
141
+ send_data(
142
+ content,
143
+ filename: filename,
144
+ type: 'text/calendar; charset=UTF-8',
145
+ disposition: 'attachment'
146
+ )
147
+ end
148
+ ```
149
+
150
+ You can implement this in any controller and route that makes sense for your application's architecture.
151
+
152
+ ### ICS File Generation
153
+
154
+ The gem provides two ways to generate ICS files:
155
+
156
+ 1. Direct content generation:
157
+ ```ruby
158
+ event = CalInvite::Event.new(
159
+ title: "Meeting",
160
+ start_time: Time.current.utc,
161
+ end_time: Time.current.utc + 1.hour,
162
+ timezone: "America/New_York"
163
+ )
164
+
165
+ # Generate ICS content
166
+ content = CalInvite::Providers::Ics.new(event).generate
167
+ ```
168
+
169
+ 2. Rails controller integration:
170
+ ```ruby
171
+ # In your controller
172
+ def download_ics
173
+ event = CalInvite::Event.new(
174
+ title: "Meeting",
175
+ start_time: Time.current.utc,
176
+ end_time: Time.current.utc + 1.hour,
177
+ timezone: "America/New_York"
178
+ )
179
+
180
+ content = CalInvite::Providers::Ics.new(event).generate
181
+ filename = "#{event.title.downcase.gsub(/[^0-9A-Za-z.\-]/, '_')}_#{Time.now.strftime('%Y%m%d')}.ics"
182
+
183
+ send_data(
184
+ content,
185
+ filename: filename,
186
+ type: 'text/calendar; charset=UTF-8',
187
+ disposition: 'attachment'
188
+ )
189
+ end
190
+ ```
191
+
192
+ ### Important Notes
193
+
194
+ 1. Time Handling:
195
+ - Always provide times in UTC to the Event constructor
196
+ - Use the timezone parameter to specify the display timezone
197
+ - All-day events should use beginning_of_day.utc and end_of_day.utc
198
+
199
+ 2. Location and URL:
200
+ - Physical location goes in the `location` parameter
201
+ - Virtual meeting URL goes in the `url` parameter
202
+ - They are handled separately for better calendar integration
203
+
204
+ 3. ICS Files:
205
+ - Both Apple iCal and standard ICS files now properly handle timezones
206
+ - Attendees are properly formatted with RSVP options
207
+ - Virtual meeting URLs are properly separated from physical locations
208
+
209
+ ## Caching Support
210
+
211
+ CalInvite includes built-in caching support to improve performance when generating calendar URLs. To enable caching in your Rails application:
212
+
213
+ ```ruby
214
+ # config/initializers/cal_invite.rb
215
+ CalInvite.configure do |config|
216
+ # Use Rails cache by default
217
+ config.cache_store = Rails.cache
218
+
219
+ # Optional: Set cache prefix
220
+ config.cache_prefix = 'my_app_cal_invite'
221
+
222
+ # Optional: Set expiration time (in seconds)
223
+ config.cache_expires_in = 3600 # 1 hour
224
+ end
225
+ ```
226
+
227
+ For detailed information about configuring caching in Rails applications and available options, see our [Caching Guide](https://github.com/the-pew-inc/cal-invite/blob/master/CACHING.md)
228
+
95
229
  ## Development
96
230
 
97
231
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
98
232
 
99
233
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
100
234
 
235
+ ## Testing
236
+
237
+ Add test(s) as necessary.
238
+
239
+ Run all the tests before submitting: `bundle exec rake test`
240
+
101
241
  ## Contributing
102
242
 
103
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/cal-invite. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/cal-invite/blob/master/CODE_OF_CONDUCT.md).
243
+ Bug reports and pull requests are welcome on GitHub at https://github.com/the-pew-inc/cal-invite. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/the-pew-inc/cal-invite/blob/master/CODE_OF_CONDUCT.md).
104
244
 
105
245
  ## License
106
246
 
@@ -108,4 +248,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
108
248
 
109
249
  ## Code of Conduct
110
250
 
111
- Everyone interacting in the Cal::Invite project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/cal-invite/blob/master/CODE_OF_CONDUCT.md).
251
+ Everyone interacting in the Cal::Invite project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/the-pew-inc/cal-invite/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/cal_invite/caching.rb
4
+ require 'active_support/concern'
5
+
6
+ module CalInvite
7
+ module Caching
8
+ extend ActiveSupport::Concern
9
+
10
+ class_methods do
11
+ def fetch_from_cache(key, options = {}, &block)
12
+ full_key = generate_cache_key(key)
13
+ store = CalInvite.configuration.cache_store
14
+
15
+ if store.respond_to?(:fetch)
16
+ store.fetch(full_key, options, &block)
17
+ else
18
+ cached = store.read(full_key)
19
+ return cached if cached
20
+
21
+ value = block.call
22
+ store.write(full_key, value, options)
23
+ value
24
+ end
25
+ end
26
+
27
+ def write_to_cache(key, value, options = {})
28
+ full_key = generate_cache_key(key)
29
+ options[:expires_in] ||= CalInvite.configuration.cache_expires_in
30
+ CalInvite.configuration.cache_store.write(full_key, value, options)
31
+ end
32
+
33
+ def read_from_cache(key)
34
+ full_key = generate_cache_key(key)
35
+ CalInvite.configuration.cache_store.read(full_key)
36
+ end
37
+
38
+ def clear_cache!
39
+ store = CalInvite.configuration.cache_store
40
+ if store.respond_to?(:delete_matched)
41
+ store.delete_matched("#{CalInvite.configuration.cache_prefix}:*")
42
+ else
43
+ store.clear
44
+ end
45
+ end
46
+
47
+ def clear_event_cache!(event_id)
48
+ delete_cache_pattern("events:#{event_id}")
49
+ end
50
+
51
+ def clear_provider_cache!(provider)
52
+ delete_cache_pattern("providers:#{provider}")
53
+ end
54
+
55
+ def generate_cache_key(*parts)
56
+ ([CalInvite.configuration.cache_prefix] + parts).join(':')
57
+ end
58
+
59
+ private
60
+
61
+ def delete_cache_pattern(pattern)
62
+ store = CalInvite.configuration.cache_store
63
+ full_pattern = generate_cache_key(pattern)
64
+
65
+ if store.respond_to?(:delete_matched)
66
+ store.delete_matched("#{full_pattern}:*")
67
+ else
68
+ # Fallback for stores that don't support pattern deletion
69
+ store.delete(full_pattern)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -1,13 +1,49 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # lib/cal_invite/configuration.rb
2
- module CalInvites
4
+ module CalInvite
3
5
  class Configuration
4
- attr_accessor :cache_store, :cache_prefix, :webhook_secret, :timezone
6
+ attr_reader :cache_store, :cache_prefix, :cache_expires_in, :webhook_secret, :timezone
5
7
 
6
8
  def initialize
7
- @cache_store = :memory_store
9
+ @cache_store = nil
8
10
  @cache_prefix = 'cal_invite'
11
+ @cache_expires_in = 24.hours # now this will work with active_support loaded
9
12
  @webhook_secret = nil
10
13
  @timezone = 'UTC'
11
14
  end
15
+
16
+ def cache_store=(store)
17
+ @cache_store = case store
18
+ when :memory_store
19
+ ActiveSupport::Cache::MemoryStore.new
20
+ when :null_store
21
+ ActiveSupport::Cache::NullStore.new
22
+ when Symbol
23
+ raise ArgumentError, "Unsupported cache store: #{store}"
24
+ else
25
+ # Allow custom cache store objects that respond to read/write/delete
26
+ unless store.respond_to?(:read) && store.respond_to?(:write) && store.respond_to?(:delete)
27
+ raise ArgumentError, "Custom cache store must implement read/write/delete methods"
28
+ end
29
+ store
30
+ end
31
+ end
32
+
33
+ def cache_prefix=(prefix)
34
+ @cache_prefix = prefix.to_s
35
+ end
36
+
37
+ def cache_expires_in=(duration)
38
+ @cache_expires_in = duration.to_i
39
+ end
40
+
41
+ def webhook_secret=(secret)
42
+ @webhook_secret = secret
43
+ end
44
+
45
+ def timezone=(tz)
46
+ @timezone = tz.to_s
47
+ end
12
48
  end
13
49
  end