mobiscroll-connect 1.1.0 → 1.2.0

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: 49b200acf379cde0578e8f4b74e414b7a9fc5c71209f76e564654c74ece51959
4
- data.tar.gz: 8462c4b2e4ad3c41f29d69ccd6010c21c5b598a1eb7a319d7502fd0ee6186da4
3
+ metadata.gz: b31a5377ff60ec4d4e5601e084d736e26bad0250ffb3c57f21e9763cbe32ce1f
4
+ data.tar.gz: ecaf0a97ba89509bd0ce3eba1f33d37024d0a3cdac5ff2e6cfbe85ec9bdd0395
5
5
  SHA512:
6
- metadata.gz: 76adf999c8a02d7ef85a7f06e6cc537dde75b9d689ba9be0608489040a4f05b696fc1cf8002fabab6b3086deff6a3f54080ff8e83191a12b8532368c47168c94
7
- data.tar.gz: '09b3556482b18761984dfa400dbe11b26288c98176afb662bbdd4ca41a2ace1768636806cab1a63a21ec1b536d16ac088b49982134d03b1ef33bb7e437c3ed2e'
6
+ metadata.gz: f98b8378045037ee79e53b5b5394beeb42b1ea92a0641cf0412e0598ec9bf92296568ebf8c46d625d260967e397e891110c204bd5fe6e69ae60e8d7e95cfccc2
7
+ data.tar.gz: 9a92b7c19a5dada68228e6d2533b996352e74b104089f3cac3676db05e9d877b08eaedc207e268067710ca81b9ea6ce85f6952086f156c047ffe59b5852a5c8b
data/README.md CHANGED
@@ -35,7 +35,7 @@ client = Mobiscroll::Connect::Client.new(
35
35
  ```ruby
36
36
  url = client.auth.generate_auth_url(
37
37
  user_id: 'user-123',
38
- lng: 'es', # optional: Connect page language ('en', 'es', 'fr', 'ar')
38
+ lng: 'es', # optional: Connect page language, see https://mobiscroll.com/docs/connect/localization#supported-languages
39
39
  providers: [
40
40
  Mobiscroll::Connect::Provider::GOOGLE,
41
41
  Mobiscroll::Connect::Provider::MICROSOFT
@@ -69,7 +69,12 @@ client.set_credentials(
69
69
  ```ruby
70
70
  status = client.auth.get_connection_status
71
71
  status.connections.each do |provider, accounts|
72
- accounts.each { |a| puts "#{provider}: #{a.display}" }
72
+ accounts.each do |a|
73
+ puts "#{provider}: #{a.display}"
74
+ # Google's consent screen lets the user untick the calendar permission and still
75
+ # finish signing in. Such an account is connected but lists no calendars.
76
+ puts " #{a.id} must reconnect and allow calendar access" if a.calendar_permission_granted == false
77
+ end
73
78
  end
74
79
  ```
75
80
 
@@ -17,6 +17,25 @@ module Mobiscroll
17
17
  end
18
18
  end
19
19
 
20
+ # Raised when no connected account has the calendar access the request needs.
21
+ #
22
+ # The user completed sign-in but did not grant the calendar permission — Google's
23
+ # consent screen presents it as a separate checkbox. This cannot be repaired
24
+ # server-side, because providers only issue permissions at consent time: the
25
+ # accounts in +accounts+ have to run the connect flow again and allow access.
26
+ #
27
+ # Subclasses AuthenticationError, so existing rescue clauses keep working.
28
+ class CalendarPermissionError < AuthenticationError
29
+ # Array of BlockedAccount structs that must reconnect.
30
+ attr_reader :accounts
31
+
32
+ def initialize(message = 'No connected account has calendar access', accounts: [])
33
+ super(message)
34
+ @code = 'CALENDAR_PERMISSION_REQUIRED'
35
+ @accounts = accounts
36
+ end
37
+ end
38
+
20
39
  class NotFoundError < Error
21
40
  def initialize(message = 'Resource not found')
22
41
  super(message, code: 'NOT_FOUND_ERROR')
@@ -67,7 +86,15 @@ module Mobiscroll
67
86
 
68
87
  case status
69
88
  when 401, 403
70
- AuthenticationError.new(message)
89
+ # A 403 the caller can act on: the account connected but never granted
90
+ # calendar access, so it is raised as its own type naming the accounts.
91
+ hash = body.is_a?(Hash) ? body : {}
92
+ if status == 403 && (hash['code'] || hash[:code]) == 'calendar_permission_required'
93
+ raw = hash['accounts'] || hash[:accounts]
94
+ CalendarPermissionError.new(message, accounts: Array(raw).filter_map { |a| BlockedAccount.from_h(a) })
95
+ else
96
+ AuthenticationError.new(message)
97
+ end
71
98
  when 404
72
99
  NotFoundError.new(message)
73
100
  when 400, 422
@@ -35,12 +35,40 @@ module Mobiscroll
35
35
  end
36
36
  end
37
37
 
38
- # One connected account under a provider.
39
- ConnectedAccount = Struct.new(:id, :display, keyword_init: true) do
38
+ # A connected account that withheld calendar access on its provider's consent screen.
39
+ BlockedAccount = Struct.new(:provider, :account, keyword_init: true) do
40
40
  def self.from_h(hash)
41
41
  return nil if hash.nil?
42
42
 
43
- new(id: hash['id'] || hash[:id], display: hash['display'] || hash[:display])
43
+ new(
44
+ provider: hash['provider'] || hash[:provider],
45
+ account: hash['account'] || hash[:account]
46
+ )
47
+ end
48
+ end
49
+
50
+ # One connected calendar account.
51
+ #
52
+ # `granted_scopes` are the scopes the provider actually granted, which are not
53
+ # necessarily the ones Connect asked for: Google's consent screen lets the user untick
54
+ # the calendar permission and still complete sign-in.
55
+ #
56
+ # `calendar_permission_granted` is false for exactly those accounts — connected, but
57
+ # no calendars can be read from them until the user reconnects and allows access. It
58
+ # is nil when the question does not apply (Apple and CalDav authenticate with a
59
+ # username and app password) or no scopes were recorded for the account.
60
+ ConnectedAccount = Struct.new(:id, :display, :granted_scopes, :calendar_permission_granted, keyword_init: true) do
61
+ def self.from_h(hash)
62
+ return nil if hash.nil?
63
+
64
+ key = 'calendarPermissionGranted'
65
+ granted = hash.key?(key) ? hash[key] : hash[key.to_sym]
66
+ new(
67
+ id: hash['id'] || hash[:id],
68
+ display: hash['display'] || hash[:display],
69
+ granted_scopes: Array(hash['grantedScopes'] || hash[:grantedScopes]),
70
+ calendar_permission_granted: granted
71
+ )
44
72
  end
45
73
  end
46
74
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Mobiscroll
4
4
  module Connect
5
- VERSION = '1.1.0'
5
+ VERSION = '1.2.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mobiscroll-connect
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mobiscroll
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-03 00:00:00.000000000 Z
11
+ date: 2026-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64