mailshears 0.0.2 → 0.0.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
  SHA1:
3
- metadata.gz: e15c8726d061b6406ce5f7213d52fc8b1f9ae3e7
4
- data.tar.gz: 7c04d8bd79a8894ce919856dc2abb0f87b7b9870
3
+ metadata.gz: b1f58755e2a89e2b13f0f3d972e2042357e11569
4
+ data.tar.gz: c09388cc7659a1e2c06f05ddb1b15bbad31dc278
5
5
  SHA512:
6
- metadata.gz: b30cbd27cd0004bd2eccab8537c4cf55304713f7ba8fa588a56e6acf4884425f9fd86113b431665f1850bc64cfae0927a26c6ee09fbb24f90888b11957f2de6d
7
- data.tar.gz: efcae9b45e44aa41b132dfa6971a211531f43c3774b7d0be9522c3de8c23875e2bb682457bc52f3bb1b7593b46f56cb819e63b4f1025e1b6de325c507be25442
6
+ metadata.gz: f189f7f051667c13eff013dae9529824f254ac70250dc8d3b0d5d4313d6c3c977ff289c8fa21f8a90565bd429c8b4fcc854047ab44d491f9c0232a347b05584a
7
+ data.tar.gz: 26586f35b0dbd61af8b76a5c1338aababe302064050ffeb76fd8c7a40d188922f9610a3fd5681972c12ffa0fa3038b3dea3fe8da1d564359c103a33a80751e3c
data/doc/TODO CHANGED
@@ -11,6 +11,12 @@
11
11
 
12
12
  * Add OpenDKIM support.
13
13
 
14
- * Make a release.
14
+ * Rename the "dovecot" plugin to "filesystem".
15
15
 
16
16
  * Implement moving of domains.
17
+
18
+ * The AgenDAV "user exists" test is wonky, because there's no real
19
+ users in AgenDAV. Right now we check the "username" column in the
20
+ "prefs" table, but all of the shares (and principals?) have URLs
21
+ instead of usernames. We don't parse the URLs, and instead rely
22
+ on doing find/replace of substrings in e.g. AgendavMv.
@@ -29,15 +29,15 @@ functionality is provided by plugins. The following are supported at
29
29
  the moment:
30
30
  \#
31
31
  .IP \(bu 2
32
- Agendav (database)
32
+ Agendav (database, v2.1.x)
33
33
  .IP \(bu
34
- DAViCal (datbase)
34
+ DAViCal (database, v1.1.x)
35
35
  .IP \(bu
36
- Dovecot (filesystem)
36
+ Dovecot (filesystem, version irrelevant)
37
37
  .IP \(bu
38
- PostfixAdmin (database)
38
+ PostfixAdmin (database, v2.x)
39
39
  .IP \(bu
40
- Roundcube (database)
40
+ Roundcube (database, v1.2.x)
41
41
 
42
42
  You are free to pick and choose the plugins that you need. The Dovecot
43
43
  plugin is a misnomer: as long as your mail is stored on disk in
@@ -35,9 +35,11 @@ module AgendavPlugin
35
35
 
36
36
  connection = PG::Connection.new(@db_hash)
37
37
 
38
- sql_query = '(SELECT username FROM prefs)'
39
- sql_query += 'UNION'
40
- sql_query += '(SELECT user_from FROM shared);'
38
+ # There are also "owner" and "with" fields in the "shares" table,
39
+ # but they contains principal URLs and not a bare username. Thus
40
+ # their format depends on the CalDAV server configuration, and
41
+ # isn't predictable.
42
+ sql_query = 'SELECT username FROM prefs;'
41
43
 
42
44
  begin
43
45
  connection.query(sql_query) do |result|
@@ -51,4 +53,27 @@ module AgendavPlugin
51
53
  return users.map{ |u| User.new(u) }
52
54
  end
53
55
 
56
+
57
+ # Count the number of rows in the "shares" table. Used only for
58
+ # testing.
59
+ #
60
+ # @return [Fixnum] the number of rows in the "shares" table.
61
+ #
62
+ def count_shares()
63
+ count = nil
64
+ connection = PG::Connection.new(@db_hash)
65
+
66
+ sql_query = 'SELECT count(*) FROM shares;'
67
+ begin
68
+ connection.query(sql_query) do |result|
69
+ count = result.getvalue(0,0).to_i()
70
+ end
71
+ ensure
72
+ # Make sure the connection gets closed even if the query explodes.
73
+ connection.close()
74
+ end
75
+
76
+ return count
77
+ end
78
+
54
79
  end
@@ -15,27 +15,50 @@ class AgendavMv
15
15
  # Move the user *src* to *dst* within the Agendav database. This
16
16
  # should "rename" him in _every_ table where he is referenced.
17
17
  #
18
- # This can fail is *src* does not exist, or if *dst* already exists
19
- # before the move. It should also be an error if the destination
20
- # domain doesn't exist. But Agendav doesn't know about domains, so
21
- # we let that slide.
18
+ # This can fail if *dst* already exists before the move. It should
19
+ # also be an error if the destination domain doesn't exist. But
20
+ # Agendav doesn't know about domains, so we let that slide.
21
+ #
22
+ # If the source user doesn't exist, we do our best. AgenDAV has a
23
+ # "shares" table that isn't keyed on the username, but rather the
24
+ # principal URL. And its "prefs" table doesn't contain entries for
25
+ # users who have default preferences. As a result, we may need to
26
+ # perform some find/replaces in the "shares" table even if no
27
+ # corresponding user exists in the "prefs" table (which is how we
28
+ # tell if a user exists in AgenDAV). Thus it's not a fatal error if
29
+ # the *src* user doesn't exist.
22
30
  #
23
31
  # @param src [User] the source user to be moved.
24
32
  #
25
33
  # @param dst [User] the destination user being moved to.
26
34
  #
27
35
  def mv_user(src, dst)
28
- raise NonexistentUserError.new(src.to_s()) if not user_exists(src)
29
36
  raise UserAlreadyExistsError.new(dst.to_s()) if user_exists(dst)
30
37
 
31
- sql_queries = ['UPDATE prefs SET username = $1 WHERE username = $2;']
32
- sql_queries << 'UPDATE shared SET user_from = $1 WHERE user_from = $2;'
33
- sql_queries << 'UPDATE shared SET user_which = $1 WHERE user_which = $2;'
34
-
35
38
  connection = PG::Connection.new(@db_hash)
36
39
  begin
40
+ # The "prefs" table uses the normal username as a key...
41
+ # This should be harmless if the source user does not exist.
42
+ sql_query0 = 'UPDATE prefs SET username = $1 WHERE username = $2;'
43
+ connection.query(sql_query0, [dst.to_s(), src.to_s()])
44
+
45
+ # But the "shares" table uses encoded principal URLs. For the
46
+ # "shares" table, we need to do a find/replace on the username
47
+ # with its "@" symbol translated to a "%40".
48
+ encoded_src = src.to_s()['@'] = '%40'
49
+ encoded_dst = dst.to_s()['@'] = '%40'
50
+
51
+ # Unlike in the "rm" plugin, we do modify the "calendar" field
52
+ # here. That's because in the usual legitimate use case, the
53
+ # calendar URL will change when a user moves. This will ALSO
54
+ # affect people who name their calendars something like
55
+ # "user%40example.com", but screw those people.
56
+ sql_queries = ['UPDATE shares SET owner=REPLACE(owner, $2, $1);']
57
+ sql_queries << 'UPDATE shares SET calendar=REPLACE(calendar, $2, $1);'
58
+ sql_queries << 'UPDATE shares SET "with"=REPLACE("with", $2, $1);'
59
+
37
60
  sql_queries.each do |sql_query|
38
- connection.query(sql_query, [dst.to_s(), src.to_s()])
61
+ connection.query(sql_query, [encoded_dst, encoded_src])
39
62
  end
40
63
  ensure
41
64
  # Make sure the connection gets closed even if a query explodes.
@@ -16,13 +16,33 @@ class AgendavRm
16
16
  # Remove *user* from the Agendav database. This should remove him
17
17
  # from _every_ table in which he is referenced.
18
18
  #
19
+ # We do not raise an error if the user doesn't exist. This is due to
20
+ # an unfortunate problem with the "user exists" check in AgenDAV.
21
+ # The AgenDAV "shares" table is not tied directly to a username, so
22
+ # we are forced to use a regexp match to decide what rows to delete
23
+ # from that table. We do so regardless of whether or not the username
24
+ # exists in the "prefs" table, because that table stores only non-
25
+ # default preferences -- not all users' preferences.
26
+ #
19
27
  # @param user [User] the user to remove.
20
28
  #
21
29
  def remove_user(user)
22
- raise NonexistentUserError.new(user.to_s()) if not user_exists(user)
23
-
24
30
  sql_queries = ['DELETE FROM prefs WHERE username = $1;']
25
- sql_queries << 'DELETE FROM shared WHERE user_from = $1;'
31
+
32
+ # The "shares" table contains principal URLs, and the "@" symbol
33
+ # is usually encoded to "%40". These queries do a regex match on
34
+ # the username after replacing the "%40" with a "@".
35
+ #
36
+ # As a precaution, I haven chosen not to delete based on the
37
+ # "calendar" field here. Nobody should have a calendar named
38
+ # "user%40example.com", but it's not impossible -- and we don't
39
+ # want to delete that calendar when the not-necessarily-related
40
+ # "user@example.com" account is removed. And the usual appearance
41
+ # of the user's email address in the "calendar" field happens when
42
+ # he is also the owner, so the calendar does get deleted in the
43
+ # normal situation.
44
+ sql_queries << "DELETE FROM shares WHERE REPLACE(owner,'%40','@') ~ $1;"
45
+ sql_queries << "DELETE FROM shares WHERE REPLACE(\"with\",'%40','@') ~ $1;"
26
46
 
27
47
  connection = PG::Connection.new(@db_hash)
28
48
  begin
data/mailshears.gemspec CHANGED
@@ -1,11 +1,11 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'mailshears'
4
- s.version = '0.0.2'
4
+ s.version = '0.0.3'
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ['Michael Orlitzky']
7
7
  s.email = ['michael@orlitzky.com']
8
- s.homepage = 'http://michael.orlitzky.com/code/mailshears.php'
8
+ s.homepage = 'http://michael.orlitzky.com/code/mailshears.xhtml'
9
9
  s.summary = 'Prune unused mail directories.'
10
10
  s.description = <<-EOF
11
11
  Managing a mail system with virtual users is annoying. The
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
24
24
  as well. Since these two tasks are related, mailshears does them both.
25
25
  EOF
26
26
 
27
- s.license = 'AGPL-3'
27
+ s.license = 'AGPL-3.0'
28
28
  s.required_rubygems_version = '>= 1.3.6'
29
29
 
30
30
  # If you have runtime dependencies, add them here
@@ -1,6 +1,14 @@
1
+ # Without this, I get...
2
+ #
3
+ # Warning: you should require 'minitest/autorun' instead.
4
+ # Warning: or add 'gem "minitest"' before 'require "minitest/autorun"'
5
+ #
6
+ # Whatever.
7
+ gem 'minitest'
8
+ require 'minitest/autorun'
9
+
1
10
  require 'common/configuration'
2
11
  require 'fileutils'
3
- require 'minitest/autorun'
4
12
  require 'pg'
5
13
 
6
14
  class MailshearsTest < MiniTest::Test
@@ -71,15 +79,15 @@ class MailshearsTest < MiniTest::Test
71
79
  # +------------------ +---------+
72
80
  #
73
81
  #
74
- # +---------------------------------------------------------+
75
- # | shared |
76
- # +-----+--------------------+----------+-------------------+
77
- # | sid | user_from | calendar | user_which |
78
- # +-----+--------------------+----------+-------------------+
79
- # | 1 | adam@example.net | derp | beth@example.net |
80
- # +-----+--------------------+----------+-------------------+
81
- # | 2 | booger@example.com | derp | carol@example.net |
82
- # +-----+--------------------+----------+-------------------+
82
+ # +---------------------------------------------------------------------------------------------------------------------+
83
+ # | shares |
84
+ # +-----+-----------------------------------+---------------------------------------------------+-----------------------+
85
+ # | sid | owner | calendar | with |
86
+ # +-----+-----------------------------------+---------------------------------------------------+-----------------------+
87
+ # | 1 | /caldav.php/adam%40example.net/ | /caldav.php/adam%40example.net/calendar-default | /beth%40example.net/ |
88
+ # +-----+-----------------------------------+---------------------------------------------------+-----------------------+
89
+ # | 2 | /caldav.php/booger%40example.com/ | /caldav.php/booger%40example.com/calendar-default | /carol%40example.net/ |
90
+ # +-----+-----------------------------------+---------------------------------------------------+-----------------------+
83
91
  #
84
92
  #
85
93
  # 2. davical_test
@@ -1,9 +1,34 @@
1
1
  /* Add an AgenDAV record for one user only. */
2
2
  INSERT INTO prefs (username, options) VALUES ('adam@example.net', 'herp');
3
- INSERT INTO shared (user_from, user_which, calendar)
4
- VALUES ('adam@example.net', 'beth@example.net', 'derp');
3
+ INSERT INTO shares (owner, calendar, "with", options, rw)
4
+ VALUES ('/caldav.php/adam%40example.net/',
5
+ '/caldav.php/adam%40example.net/calendar-default',
6
+ '/beth%40example.net/',
7
+ 'a:0:{}',
8
+ false);
5
9
 
6
10
  /* Just kidding, here's another one! */
7
11
  INSERT INTO prefs (username, options) VALUES ('booger@example.com', 'herp');
8
- INSERT INTO shared (user_from, user_which, calendar)
9
- VALUES ('booger@example.com', 'carol@example.net', 'derp');
12
+ INSERT INTO shares (owner, calendar, "with", options, rw)
13
+ VALUES ('/caldav.php/booger%40example.com/',
14
+ '/caldav.php/booger%40example.com/calendar-default',
15
+ '/carol%40example.net/',
16
+ 'a:0:{}',
17
+ true);
18
+
19
+ /* These two are missing a prefs entry to test the removal of "shares"
20
+ * entries in that situation.
21
+ */
22
+ INSERT INTO shares (owner, calendar, "with", options, rw)
23
+ VALUES ('/caldav.php/stinky%40example.com/',
24
+ '/caldav.php/stinky%40example.com/calendar-default',
25
+ '/herp%40example.net/',
26
+ 'a:0:{}',
27
+ true);
28
+
29
+ INSERT INTO shares (owner, calendar, "with", options, rw)
30
+ VALUES ('/caldav.php/goober%40example.com/',
31
+ '/caldav.php/goober%40example.com/calendar-default',
32
+ '/derp%40example.net/',
33
+ 'a:0:{}',
34
+ true);
data/test/sql/agendav.sql CHANGED
@@ -3,10 +3,12 @@
3
3
  --
4
4
 
5
5
  SET statement_timeout = 0;
6
+ SET lock_timeout = 0;
6
7
  SET client_encoding = 'UTF8';
7
8
  SET standard_conforming_strings = on;
8
9
  SET check_function_bodies = false;
9
10
  SET client_min_messages = warning;
11
+ SET row_security = off;
10
12
 
11
13
  --
12
14
  -- Name: plpgsql; Type: EXTENSION; Schema: -; Owner:
@@ -29,48 +31,76 @@ SET default_tablespace = '';
29
31
  SET default_with_oids = false;
30
32
 
31
33
  --
32
- -- Name: migrations; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
34
+ -- Name: prefs; Type: TABLE; Schema: public; Owner: agendav
33
35
  --
34
36
 
35
- CREATE TABLE migrations (
36
- version integer NOT NULL
37
+ CREATE TABLE prefs (
38
+ username character varying(255) NOT NULL,
39
+ options text NOT NULL
37
40
  );
38
41
 
39
42
 
40
- ALTER TABLE public.migrations OWNER TO postgres;
43
+ ALTER TABLE prefs OWNER to postgres;
41
44
 
42
45
  --
43
- -- Name: prefs; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
46
+ -- Name: principals; Type: TABLE; Schema: public; Owner: agendav
44
47
  --
45
48
 
46
- CREATE TABLE prefs (
47
- username character varying(255) NOT NULL,
48
- options text NOT NULL
49
+ CREATE TABLE principals (
50
+ url character varying(255) NOT NULL,
51
+ displayname character varying(255) NOT NULL,
52
+ email character varying(255) NOT NULL
49
53
  );
50
54
 
51
55
 
52
- ALTER TABLE public.prefs OWNER TO postgres;
56
+ ALTER TABLE principals OWNER to postgres;
53
57
 
54
58
  --
55
- -- Name: sessions; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
59
+ -- Name: schema_versions; Type: TABLE; Schema: public; Owner: agendav
60
+ --
61
+
62
+ CREATE TABLE schema_versions (
63
+ version character varying(255) NOT NULL
64
+ );
65
+
66
+
67
+ ALTER TABLE schema_versions OWNER to postgres;
68
+
69
+ --
70
+ -- Name: sessions; Type: TABLE; Schema: public; Owner: agendav
56
71
  --
57
72
 
58
73
  CREATE TABLE sessions (
59
- session_id character varying(40) DEFAULT 0 NOT NULL,
60
- ip_address character varying(16) DEFAULT 0 NOT NULL,
61
- user_agent character varying(120) DEFAULT NULL::character varying,
62
- last_activity bigint DEFAULT 0 NOT NULL,
63
- user_data text NOT NULL
74
+ sess_id character varying(128) NOT NULL,
75
+ sess_data bytea NOT NULL,
76
+ sess_lifetime integer NOT NULL,
77
+ sess_time integer NOT NULL
78
+ );
79
+
80
+
81
+ ALTER TABLE sessions OWNER to postgres;
82
+
83
+ --
84
+ -- Name: shares; Type: TABLE; Schema: public; Owner: agendav
85
+ --
86
+
87
+ CREATE TABLE shares (
88
+ sid integer NOT NULL,
89
+ owner character varying(255) NOT NULL,
90
+ calendar character varying(255) NOT NULL,
91
+ "with" character varying(255) NOT NULL,
92
+ options text NOT NULL,
93
+ rw boolean NOT NULL
64
94
  );
65
95
 
66
96
 
67
- ALTER TABLE public.sessions OWNER TO postgres;
97
+ ALTER TABLE shares OWNER to postgres;
68
98
 
69
99
  --
70
- -- Name: shared_sid_seq; Type: SEQUENCE; Schema: public; Owner: postgres
100
+ -- Name: shares_sid_seq; Type: SEQUENCE; Schema: public; Owner: agendav
71
101
  --
72
102
 
73
- CREATE SEQUENCE shared_sid_seq
103
+ CREATE SEQUENCE shares_sid_seq
74
104
  START WITH 1
75
105
  INCREMENT BY 1
76
106
  NO MINVALUE
@@ -78,26 +108,24 @@ CREATE SEQUENCE shared_sid_seq
78
108
  CACHE 1;
79
109
 
80
110
 
81
- ALTER TABLE public.shared_sid_seq OWNER TO postgres;
111
+ ALTER TABLE shares_sid_seq OWNER to postgres;
82
112
 
83
113
  --
84
- -- Name: shared; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
114
+ -- Name: shares_sid_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: agendav
85
115
  --
86
116
 
87
- CREATE TABLE shared (
88
- sid integer DEFAULT nextval('shared_sid_seq'::regclass) NOT NULL,
89
- user_from character varying(255) NOT NULL,
90
- calendar character varying(255) NOT NULL,
91
- user_which character varying(255) NOT NULL,
92
- options text DEFAULT ''::text NOT NULL,
93
- write_access boolean DEFAULT false NOT NULL
94
- );
117
+ ALTER SEQUENCE shares_sid_seq OWNED BY shares.sid;
118
+
95
119
 
120
+ --
121
+ -- Name: sid; Type: DEFAULT; Schema: public; Owner: agendav
122
+ --
123
+
124
+ ALTER TABLE ONLY shares ALTER COLUMN sid SET DEFAULT nextval('shares_sid_seq'::regclass);
96
125
 
97
- ALTER TABLE public.shared OWNER TO postgres;
98
126
 
99
127
  --
100
- -- Name: prefs_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
128
+ -- Name: prefs_pkey; Type: CONSTRAINT; Schema: public; Owner: agendav
101
129
  --
102
130
 
103
131
  ALTER TABLE ONLY prefs
@@ -105,40 +133,49 @@ ALTER TABLE ONLY prefs
105
133
 
106
134
 
107
135
  --
108
- -- Name: sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
136
+ -- Name: principals_pkey; Type: CONSTRAINT; Schema: public; Owner: agendav
109
137
  --
110
138
 
111
- ALTER TABLE ONLY sessions
112
- ADD CONSTRAINT sessions_pkey PRIMARY KEY (session_id);
139
+ ALTER TABLE ONLY principals
140
+ ADD CONSTRAINT principals_pkey PRIMARY KEY (url);
141
+
142
+
143
+ --
144
+ -- Name: schema_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: agendav
145
+ --
146
+
147
+ ALTER TABLE ONLY schema_versions
148
+ ADD CONSTRAINT schema_versions_pkey PRIMARY KEY (version);
113
149
 
114
150
 
115
151
  --
116
- -- Name: shared_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
152
+ -- Name: sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: agendav
117
153
  --
118
154
 
119
- ALTER TABLE ONLY shared
120
- ADD CONSTRAINT shared_pkey PRIMARY KEY (sid);
155
+ ALTER TABLE ONLY sessions
156
+ ADD CONSTRAINT sessions_pkey PRIMARY KEY (sess_id);
121
157
 
122
158
 
123
159
  --
124
- -- Name: last_activity_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
160
+ -- Name: shares_pkey; Type: CONSTRAINT; Schema: public; Owner: agendav
125
161
  --
126
162
 
127
- CREATE INDEX last_activity_idx ON sessions USING btree (last_activity);
163
+ ALTER TABLE ONLY shares
164
+ ADD CONSTRAINT shares_pkey PRIMARY KEY (sid);
128
165
 
129
166
 
130
167
  --
131
- -- Name: sharedwithidx; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
168
+ -- Name: idx_905f717c9890e20e; Type: INDEX; Schema: public; Owner: agendav
132
169
  --
133
170
 
134
- CREATE INDEX sharedwithidx ON shared USING btree (user_which);
171
+ CREATE INDEX idx_905f717c9890e20e ON shares USING btree ("with");
135
172
 
136
173
 
137
174
  --
138
- -- Name: shareidx; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
175
+ -- Name: idx_905f717ccf60e67c6ea9a146; Type: INDEX; Schema: public; Owner: agendav
139
176
  --
140
177
 
141
- CREATE INDEX shareidx ON shared USING btree (user_from, calendar);
178
+ CREATE INDEX idx_905f717ccf60e67c6ea9a146 ON shares USING btree (owner, calendar);
142
179
 
143
180
 
144
181
  --
data/test/test_mv.rb CHANGED
@@ -27,7 +27,8 @@ class TestMv < MailshearsTest
27
27
  actual = output_buffer.string()
28
28
 
29
29
  expected =
30
- "AgendavMv - Source user alice@example.com not found.\n" +
30
+ "AgendavMv - Moved user alice@example.com (User not found) " +
31
+ "to alice@example.net (User not found).\n" +
31
32
  "DavicalMv - Moved user alice@example.com (Principal ID: 1) " +
32
33
  "to alice@example.net (Principal ID: 1).\n" +
33
34
  "DovecotMv - Moved user alice@example.com " +
data/test/test_rm.rb CHANGED
@@ -42,6 +42,13 @@ class TestRm < MailshearsTest
42
42
  expected = [User.new('booger@example.com')]
43
43
  assert_equal(expected, actual)
44
44
 
45
+ # Only try to remove this guy from the agendav database, to ensure
46
+ # that "nonexistent" users have their shares removed.
47
+ arm.remove_user('stinky@example.com')
48
+ expected = 2
49
+ actual = arm.count_shares()
50
+ assert_equal(expected, actual)
51
+
45
52
  drm = DavicalRm.new(cfg)
46
53
  actual = drm.list_users()
47
54
  expected = [User.new('alice@example.com'), User.new('booger@example.com')]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailshears
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Orlitzky
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-09 00:00:00.000000000 Z
11
+ date: 2017-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -106,9 +106,9 @@ files:
106
106
  - test/test_mv.rb
107
107
  - test/test_prune.rb
108
108
  - test/test_rm.rb
109
- homepage: http://michael.orlitzky.com/code/mailshears.php
109
+ homepage: http://michael.orlitzky.com/code/mailshears.xhtml
110
110
  licenses:
111
- - AGPL-3
111
+ - AGPL-3.0
112
112
  metadata: {}
113
113
  post_install_message:
114
114
  rdoc_options: []
@@ -126,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
126
126
  version: 1.3.6
127
127
  requirements: []
128
128
  rubyforge_project:
129
- rubygems_version: 2.4.8
129
+ rubygems_version: 2.5.2
130
130
  signing_key:
131
131
  specification_version: 4
132
132
  summary: Prune unused mail directories.