async-caldav 1.2.4 → 1.3.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.
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/setup"
4
- require "scampi"
5
- require "async/caldav"
6
-
7
3
  module Async
8
4
  module Caldav
9
5
  module ForwardAuth
@@ -11,16 +7,19 @@ module Async
11
7
 
12
8
  def extract(env)
13
9
  {
14
- user: env['HTTP_REMOTE_USER'],
15
- email: env['HTTP_REMOTE_EMAIL'],
16
- name: env['HTTP_REMOTE_NAME'],
17
- groups: parse_groups(env['HTTP_REMOTE_GROUPS'])
10
+ user: env['HTTP_REMOTE_USER'],
11
+ email: env['HTTP_REMOTE_EMAIL'],
12
+ name: env['HTTP_REMOTE_NAME'],
13
+ groups: parse_groups(env['HTTP_REMOTE_GROUPS']),
18
14
  }
19
15
  end
20
16
 
21
17
  def parse_groups(header)
22
- return [] if header.nil? || header.empty?
23
- header.split(',').map(&:strip).reject(&:empty?)
18
+ if header.nil? || header.empty?
19
+ []
20
+ else
21
+ header.split(',').map(&:strip).reject(&:empty?)
22
+ end
24
23
  end
25
24
 
26
25
  private_class_method :parse_groups
@@ -31,9 +30,15 @@ module Async
31
30
 
32
31
  def inject(env, user: 'admin', email: nil, name: nil, groups: nil)
33
32
  env['HTTP_REMOTE_USER'] ||= user
34
- env['HTTP_REMOTE_EMAIL'] ||= email if email
35
- env['HTTP_REMOTE_NAME'] ||= name if name
36
- env['HTTP_REMOTE_GROUPS'] ||= groups if groups
33
+ if email
34
+ env['HTTP_REMOTE_EMAIL'] ||= email
35
+ end
36
+ if name
37
+ env['HTTP_REMOTE_NAME'] ||= name
38
+ end
39
+ if groups
40
+ env['HTTP_REMOTE_GROUPS'] ||= groups
41
+ end
37
42
  env
38
43
  end
39
44
  end
@@ -41,54 +46,56 @@ module Async
41
46
  end
42
47
 
43
48
 
44
- test do
45
- describe "Async::Caldav::ForwardAuth" do
46
- it "sets user from HTTP_REMOTE_USER" do
47
- result = Async::Caldav::ForwardAuth.extract({ 'HTTP_REMOTE_USER' => 'admin' })
48
- result[:user].should.equal 'admin'
49
- end
49
+ __END__
50
50
 
51
- it "leaves user nil when header absent" do
52
- result = Async::Caldav::ForwardAuth.extract({})
53
- result[:user].should.be.nil
54
- end
51
+ require_relative "../caldav"
55
52
 
56
- it "parses HTTP_REMOTE_GROUPS as comma-separated list" do
57
- result = Async::Caldav::ForwardAuth.extract({ 'HTTP_REMOTE_GROUPS' => 'a,b,c' })
58
- result[:groups].should.equal ['a', 'b', 'c']
59
- end
53
+ describe "Async::Caldav::ForwardAuth" do
54
+ it "sets user from HTTP_REMOTE_USER" do
55
+ result = Async::Caldav::ForwardAuth.extract({ 'HTTP_REMOTE_USER' => 'admin' })
56
+ result[:user].should.equal 'admin'
57
+ end
60
58
 
61
- it "trims whitespace around group names" do
62
- result = Async::Caldav::ForwardAuth.extract({ 'HTTP_REMOTE_GROUPS' => ' a , b ' })
63
- result[:groups].should.equal ['a', 'b']
64
- end
59
+ it "leaves user nil when header absent" do
60
+ result = Async::Caldav::ForwardAuth.extract({})
61
+ result[:user].should.be.nil
62
+ end
65
63
 
66
- it "empty groups header produces empty list" do
67
- result = Async::Caldav::ForwardAuth.extract({ 'HTTP_REMOTE_GROUPS' => '' })
68
- result[:groups].should.equal []
69
- end
64
+ it "parses HTTP_REMOTE_GROUPS as comma-separated list" do
65
+ result = Async::Caldav::ForwardAuth.extract({ 'HTTP_REMOTE_GROUPS' => 'a,b,c' })
66
+ result[:groups].should.equal ['a', 'b', 'c']
67
+ end
70
68
 
71
- it "email and name flow through" do
72
- result = Async::Caldav::ForwardAuth.extract({
73
- 'HTTP_REMOTE_EMAIL' => 'a@b.com',
74
- 'HTTP_REMOTE_NAME' => 'Admin'
75
- })
76
- result[:email].should.equal 'a@b.com'
77
- result[:name].should.equal 'Admin'
78
- end
69
+ it "trims whitespace around group names" do
70
+ result = Async::Caldav::ForwardAuth.extract({ 'HTTP_REMOTE_GROUPS' => ' a , b ' })
71
+ result[:groups].should.equal ['a', 'b']
79
72
  end
80
73
 
81
- describe "Async::Caldav::TestStub" do
82
- it "injects defaults when no header present" do
83
- env = {}
84
- Async::Caldav::TestStub.inject(env)
85
- env['HTTP_REMOTE_USER'].should.equal 'admin'
86
- end
74
+ it "empty groups header produces empty list" do
75
+ result = Async::Caldav::ForwardAuth.extract({ 'HTTP_REMOTE_GROUPS' => '' })
76
+ result[:groups].should.equal []
77
+ end
87
78
 
88
- it "respects existing headers when present" do
89
- env = { 'HTTP_REMOTE_USER' => 'existing' }
90
- Async::Caldav::TestStub.inject(env)
91
- env['HTTP_REMOTE_USER'].should.equal 'existing'
92
- end
79
+ it "email and name flow through" do
80
+ result = Async::Caldav::ForwardAuth.extract({
81
+ 'HTTP_REMOTE_EMAIL' => 'a@b.com',
82
+ 'HTTP_REMOTE_NAME' => 'Admin'
83
+ })
84
+ result[:email].should.equal 'a@b.com'
85
+ result[:name].should.equal 'Admin'
93
86
  end
94
87
  end
88
+
89
+ describe "Async::Caldav::TestStub" do
90
+ it "injects defaults when no header present" do
91
+ env = {}
92
+ Async::Caldav::TestStub.inject(env)
93
+ env['HTTP_REMOTE_USER'].should.equal 'admin'
94
+ end
95
+
96
+ it "respects existing headers when present" do
97
+ env = { 'HTTP_REMOTE_USER' => 'existing' }
98
+ Async::Caldav::TestStub.inject(env)
99
+ env['HTTP_REMOTE_USER'].should.equal 'existing'
100
+ end
101
+ end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/setup"
4
- require "scampi"
5
- require "async/caldav"
6
-
7
3
  module Async
8
4
  module Caldav
9
5
  module Handlers
@@ -28,33 +24,35 @@ module Async
28
24
  end
29
25
  end
30
26
 
31
- test do
32
- describe "Async::Caldav::Handlers::Delete" do
33
- def call(**opts)
34
- Async::Caldav::Handlers::Delete.call(**opts)
35
- end
27
+ __END__
36
28
 
37
- it "deletes an item and returns 204" do
38
- s = Async::Caldav::Storage::Mock.new
39
- s.create_collection('/calendars/admin/cal/', type: :calendar)
40
- s.put_item('/calendars/admin/cal/event.ics', 'data', 'text/calendar')
41
- status, = call(path: Protocol::Caldav::Path.new('/calendars/admin/cal/event.ics', storage_class: s), storage: s)
42
- status.should.equal 204
43
- s.get_item('/calendars/admin/cal/event.ics').should.be.nil
44
- end
29
+ require_relative "../../caldav"
45
30
 
46
- it "deletes a collection and returns 204" do
47
- s = Async::Caldav::Storage::Mock.new
48
- s.create_collection('/calendars/admin/cal/', type: :calendar)
49
- status, = call(path: Protocol::Caldav::Path.new('/calendars/admin/cal/', storage_class: s), storage: s)
50
- status.should.equal 204
51
- s.collection_exists?('/calendars/admin/cal/').should.equal false
52
- end
31
+ describe "Async::Caldav::Handlers::Delete" do
32
+ def call(**opts)
33
+ Async::Caldav::Handlers::Delete.call(**opts)
34
+ end
53
35
 
54
- it "returns 404 for non-existent resource" do
55
- s = Async::Caldav::Storage::Mock.new
56
- status, = call(path: Protocol::Caldav::Path.new('/calendars/admin/nope/', storage_class: s), storage: s)
57
- status.should.equal 404
58
- end
36
+ it "deletes an item and returns 204" do
37
+ s = Async::Caldav::Storage::Mock.new
38
+ s.create_collection('/calendars/admin/cal/', type: :calendar)
39
+ s.put_item('/calendars/admin/cal/event.ics', 'data', 'text/calendar')
40
+ status, = call(path: Protocol::Caldav::Path.new('/calendars/admin/cal/event.ics', storage_class: s), storage: s)
41
+ status.should.equal 204
42
+ s.get_item('/calendars/admin/cal/event.ics').should.be.nil
59
43
  end
60
- end
44
+
45
+ it "deletes a collection and returns 204" do
46
+ s = Async::Caldav::Storage::Mock.new
47
+ s.create_collection('/calendars/admin/cal/', type: :calendar)
48
+ status, = call(path: Protocol::Caldav::Path.new('/calendars/admin/cal/', storage_class: s), storage: s)
49
+ status.should.equal 204
50
+ s.collection_exists?('/calendars/admin/cal/').should.equal false
51
+ end
52
+
53
+ it "returns 404 for non-existent resource" do
54
+ s = Async::Caldav::Storage::Mock.new
55
+ status, = call(path: Protocol::Caldav::Path.new('/calendars/admin/nope/', storage_class: s), storage: s)
56
+ status.should.equal 404
57
+ end
58
+ end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/setup"
4
- require "scampi"
5
- require "async/caldav"
6
-
7
3
  module Async
8
4
  module Caldav
9
5
  module Handlers
@@ -35,53 +31,55 @@ module Async
35
31
  end
36
32
  end
37
33
 
38
- test do
39
- describe "Async::Caldav::Handlers::Get" do
40
- def call(**opts)
41
- Async::Caldav::Handlers::Get.call(**opts)
42
- end
34
+ __END__
43
35
 
44
- def path(p, s)
45
- Protocol::Caldav::Path.new(p, storage_class: s)
46
- end
36
+ require_relative "../../caldav"
47
37
 
48
- it "returns item body with 200" do
49
- s = Async::Caldav::Storage::Mock.new
50
- s.put_item('/cal/ev.ics', 'BEGIN:VCALENDAR', 'text/calendar')
51
- status, headers, body = call(path: path('/cal/ev.ics', s), storage: s)
52
- status.should.equal 200
53
- headers['content-type'].should.equal 'text/calendar'
54
- body[0].should.equal 'BEGIN:VCALENDAR'
55
- end
38
+ describe "Async::Caldav::Handlers::Get" do
39
+ def call(**opts)
40
+ Async::Caldav::Handlers::Get.call(**opts)
41
+ end
56
42
 
57
- it "returns 304 on If-None-Match hit" do
58
- s = Async::Caldav::Storage::Mock.new
59
- item, = s.put_item('/cal/ev.ics', 'data', 'text/calendar')
60
- status, = call(path: path('/cal/ev.ics', s), storage: s, headers: { 'if-none-match' => item[:etag] })
61
- status.should.equal 304
62
- end
43
+ def path(p, s)
44
+ Protocol::Caldav::Path.new(p, storage_class: s)
45
+ end
63
46
 
64
- it "returns collection contents" do
65
- s = Async::Caldav::Storage::Mock.new
66
- s.create_collection('/cal/')
67
- s.put_item('/cal/a.ics', 'A', 'text/calendar')
68
- s.put_item('/cal/b.ics', 'B', 'text/calendar')
69
- status, _, body = call(path: path('/cal/', s), storage: s)
70
- status.should.equal 200
71
- body[0].should.include 'A'
72
- body[0].should.include 'B'
73
- end
47
+ it "returns item body with 200" do
48
+ s = Async::Caldav::Storage::Mock.new
49
+ s.put_item('/cal/ev.ics', 'BEGIN:VCALENDAR', 'text/calendar')
50
+ status, headers, body = call(path: path('/cal/ev.ics', s), storage: s)
51
+ status.should.equal 200
52
+ headers['content-type'].should.equal 'text/calendar'
53
+ body[0].should.equal 'BEGIN:VCALENDAR'
54
+ end
74
55
 
75
- it "returns 404 for deep non-existent path" do
76
- s = Async::Caldav::Storage::Mock.new
77
- status, = call(path: path('/calendars/admin/nope/item.ics', s), storage: s)
78
- status.should.equal 404
79
- end
56
+ it "returns 304 on If-None-Match hit" do
57
+ s = Async::Caldav::Storage::Mock.new
58
+ item, = s.put_item('/cal/ev.ics', 'data', 'text/calendar')
59
+ status, = call(path: path('/cal/ev.ics', s), storage: s, headers: { 'if-none-match' => item[:etag] })
60
+ status.should.equal 304
61
+ end
80
62
 
81
- it "returns 200 for shallow path" do
82
- s = Async::Caldav::Storage::Mock.new
83
- status, = call(path: path('/calendars/admin/', s), storage: s)
84
- status.should.equal 200
85
- end
63
+ it "returns collection contents" do
64
+ s = Async::Caldav::Storage::Mock.new
65
+ s.create_collection('/cal/')
66
+ s.put_item('/cal/a.ics', 'A', 'text/calendar')
67
+ s.put_item('/cal/b.ics', 'B', 'text/calendar')
68
+ status, _, body = call(path: path('/cal/', s), storage: s)
69
+ status.should.equal 200
70
+ body[0].should.include 'A'
71
+ body[0].should.include 'B'
86
72
  end
87
- end
73
+
74
+ it "returns 404 for deep non-existent path" do
75
+ s = Async::Caldav::Storage::Mock.new
76
+ status, = call(path: path('/calendars/admin/nope/item.ics', s), storage: s)
77
+ status.should.equal 404
78
+ end
79
+
80
+ it "returns 200 for shallow path" do
81
+ s = Async::Caldav::Storage::Mock.new
82
+ status, = call(path: path('/calendars/admin/', s), storage: s)
83
+ status.should.equal 200
84
+ end
85
+ end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/setup"
4
- require "scampi"
5
- require "async/caldav"
6
-
7
3
  module Async
8
4
  module Caldav
9
5
  module Handlers
@@ -19,18 +15,20 @@ module Async
19
15
  end
20
16
  end
21
17
 
22
- test do
23
- describe "Async::Caldav::Handlers::Head" do
24
- it "returns same status and headers as GET but empty body" do
25
- s = Async::Caldav::Storage::Mock.new
26
- s.put_item('/cal/ev.ics', 'BEGIN:VCALENDAR', 'text/calendar')
27
- status, headers, body = Async::Caldav::Handlers::Head.call(
28
- path: Protocol::Caldav::Path.new('/cal/ev.ics', storage_class: s),
29
- storage: s
30
- )
31
- status.should.equal 200
32
- headers['content-type'].should.equal 'text/calendar'
33
- body.should.equal []
34
- end
18
+ __END__
19
+
20
+ require_relative "../../caldav"
21
+
22
+ describe "Async::Caldav::Handlers::Head" do
23
+ it "returns same status and headers as GET but empty body" do
24
+ s = Async::Caldav::Storage::Mock.new
25
+ s.put_item('/cal/ev.ics', 'BEGIN:VCALENDAR', 'text/calendar')
26
+ status, headers, body = Async::Caldav::Handlers::Head.call(
27
+ path: Protocol::Caldav::Path.new('/cal/ev.ics', storage_class: s),
28
+ storage: s
29
+ )
30
+ status.should.equal 200
31
+ headers['content-type'].should.equal 'text/calendar'
32
+ body.should.equal []
35
33
  end
36
- end
34
+ end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/setup"
4
- require "scampi"
5
- require "async/caldav"
6
-
7
3
  module Async
8
4
  module Caldav
9
5
  module Handlers
@@ -15,81 +11,81 @@ module Async
15
11
  col_path = path.ensure_trailing_slash
16
12
 
17
13
  if storage.collection_exists?(col_path.to_s)
18
- return [405, { 'content-type' => 'text/plain' }, ['Collection already exists']]
19
- end
20
-
21
- unless col_path.parent_exists?
22
- return [409, { 'content-type' => 'text/plain' }, ['Parent collection does not exist']]
23
- end
24
-
25
- displayname = Protocol::Caldav::Xml.extract_value(body, 'displayname')
26
- description = Protocol::Caldav::Xml.extract_value(body, 'calendar-description')
27
- color = Protocol::Caldav::Xml.extract_value(body, 'calendar-color')
28
-
29
- type = if method == 'MKCALENDAR'
30
- :calendar
31
- elsif body && body.include?('addressbook')
32
- :addressbook
14
+ [405, { 'content-type' => 'text/plain' }, ['Collection already exists']]
33
15
  else
34
- resource_type || :collection
16
+ if col_path.parent_exists?
17
+ displayname = Protocol::Caldav::Xml.extract_value(body, 'displayname')
18
+ description = Protocol::Caldav::Xml.extract_value(body, 'calendar-description')
19
+ color = Protocol::Caldav::Xml.extract_value(body, 'calendar-color')
20
+ if method == 'MKCALENDAR'
21
+ type = :calendar
22
+ elsif body && body.include?('addressbook')
23
+ type = :addressbook
24
+ else
25
+ type = resource_type || :collection
26
+ end
27
+ storage.create_collection(col_path.to_s, type: type, displayname: displayname, description: description, color: color)
28
+ [201, {}, ['']]
29
+ else
30
+ [409, { 'content-type' => 'text/plain' }, ['Parent collection does not exist']]
31
+ end
35
32
  end
36
-
37
- storage.create_collection(col_path.to_s, type: type, displayname: displayname, description: description, color: color)
38
- [201, {}, ['']]
39
33
  end
40
34
  end
41
35
  end
42
36
  end
43
37
  end
44
38
 
45
- test do
46
- describe "Async::Caldav::Handlers::Mkcol" do
47
- def call(**opts)
48
- Async::Caldav::Handlers::Mkcol.call(**opts)
49
- end
39
+ __END__
50
40
 
51
- def path(p, s)
52
- Protocol::Caldav::Path.new(p, storage_class: s)
53
- end
41
+ require_relative "../../caldav"
54
42
 
55
- it "creates a calendar and returns 201" do
56
- s = Async::Caldav::Storage::Mock.new
57
- s.create_collection('/calendars/admin/')
58
- status, = call(
59
- path: path('/calendars/admin/work', s), storage: s,
60
- body: '<d:displayname>Work</d:displayname>', method: 'MKCALENDAR'
61
- )
62
- status.should.equal 201
63
- col = s.get_collection('/calendars/admin/work/')
64
- col[:type].should.equal :calendar
65
- col[:displayname].should.equal 'Work'
66
- end
43
+ describe "Async::Caldav::Handlers::Mkcol" do
44
+ def call(**opts)
45
+ Async::Caldav::Handlers::Mkcol.call(**opts)
46
+ end
67
47
 
68
- it "creates an addressbook via MKCOL" do
69
- s = Async::Caldav::Storage::Mock.new
70
- s.create_collection('/addressbooks/admin/')
71
- status, = call(
72
- path: path('/addressbooks/admin/contacts', s), storage: s,
73
- body: '<resourcetype><addressbook/></resourcetype>', method: 'MKCOL'
74
- )
75
- status.should.equal 201
76
- s.get_collection('/addressbooks/admin/contacts/')[:type].should.equal :addressbook
77
- end
48
+ def path(p, s)
49
+ Protocol::Caldav::Path.new(p, storage_class: s)
50
+ end
78
51
 
79
- it "returns 405 if collection exists" do
80
- s = Async::Caldav::Storage::Mock.new
81
- s.create_collection('/cal/')
82
- status, = call(path: path('/cal/', s), storage: s, body: '', method: 'MKCALENDAR')
83
- status.should.equal 405
84
- end
52
+ it "creates a calendar and returns 201" do
53
+ s = Async::Caldav::Storage::Mock.new
54
+ s.create_collection('/calendars/admin/')
55
+ status, = call(
56
+ path: path('/calendars/admin/work', s), storage: s,
57
+ body: '<d:displayname>Work</d:displayname>', method: 'MKCALENDAR'
58
+ )
59
+ status.should.equal 201
60
+ col = s.get_collection('/calendars/admin/work/')
61
+ col[:type].should.equal :calendar
62
+ col[:displayname].should.equal 'Work'
63
+ end
85
64
 
86
- it "returns 409 if parent does not exist" do
87
- s = Async::Caldav::Storage::Mock.new
88
- status, = call(
89
- path: path('/calendars/admin/deep/nested/cal', s), storage: s,
90
- body: '', method: 'MKCALENDAR'
91
- )
92
- status.should.equal 409
93
- end
65
+ it "creates an addressbook via MKCOL" do
66
+ s = Async::Caldav::Storage::Mock.new
67
+ s.create_collection('/addressbooks/admin/')
68
+ status, = call(
69
+ path: path('/addressbooks/admin/contacts', s), storage: s,
70
+ body: '<resourcetype><addressbook/></resourcetype>', method: 'MKCOL'
71
+ )
72
+ status.should.equal 201
73
+ s.get_collection('/addressbooks/admin/contacts/')[:type].should.equal :addressbook
94
74
  end
95
- end
75
+
76
+ it "returns 405 if collection exists" do
77
+ s = Async::Caldav::Storage::Mock.new
78
+ s.create_collection('/cal/')
79
+ status, = call(path: path('/cal/', s), storage: s, body: '', method: 'MKCALENDAR')
80
+ status.should.equal 405
81
+ end
82
+
83
+ it "returns 409 if parent does not exist" do
84
+ s = Async::Caldav::Storage::Mock.new
85
+ status, = call(
86
+ path: path('/calendars/admin/deep/nested/cal', s), storage: s,
87
+ body: '', method: 'MKCALENDAR'
88
+ )
89
+ status.should.equal 409
90
+ end
91
+ end