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 +4 -4
- data/doc/TODO +7 -1
- data/doc/man1/mailshears.1 +5 -5
- data/lib/common/agendav_plugin.rb +28 -3
- data/lib/mv/plugins/agendav.rb +33 -10
- data/lib/rm/plugins/agendav.rb +23 -3
- data/mailshears.gemspec +3 -3
- data/test/mailshears_test.rb +18 -10
- data/test/sql/agendav-fixtures.sql +29 -4
- data/test/sql/agendav.sql +79 -42
- data/test/test_mv.rb +2 -1
- data/test/test_rm.rb +7 -0
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b1f58755e2a89e2b13f0f3d972e2042357e11569
|
4
|
+
data.tar.gz: c09388cc7659a1e2c06f05ddb1b15bbad31dc278
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
*
|
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.
|
data/doc/man1/mailshears.1
CHANGED
@@ -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 (
|
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
|
-
|
39
|
-
|
40
|
-
|
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
|
data/lib/mv/plugins/agendav.rb
CHANGED
@@ -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
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
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, [
|
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.
|
data/lib/rm/plugins/agendav.rb
CHANGED
@@ -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
|
-
|
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.
|
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.
|
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
|
data/test/mailshears_test.rb
CHANGED
@@ -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
|
-
# |
|
76
|
-
#
|
77
|
-
# | sid |
|
78
|
-
#
|
79
|
-
# | 1 |
|
80
|
-
#
|
81
|
-
# | 2 | booger
|
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
|
4
|
-
VALUES ('adam
|
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
|
9
|
-
VALUES ('booger
|
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:
|
34
|
+
-- Name: prefs; Type: TABLE; Schema: public; Owner: agendav
|
33
35
|
--
|
34
36
|
|
35
|
-
CREATE TABLE
|
36
|
-
|
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
|
43
|
+
ALTER TABLE prefs OWNER to postgres;
|
41
44
|
|
42
45
|
--
|
43
|
-
-- Name:
|
46
|
+
-- Name: principals; Type: TABLE; Schema: public; Owner: agendav
|
44
47
|
--
|
45
48
|
|
46
|
-
CREATE TABLE
|
47
|
-
|
48
|
-
|
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
|
56
|
+
ALTER TABLE principals OWNER to postgres;
|
53
57
|
|
54
58
|
--
|
55
|
-
-- Name:
|
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
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|
97
|
+
ALTER TABLE shares OWNER to postgres;
|
68
98
|
|
69
99
|
--
|
70
|
-
-- Name:
|
100
|
+
-- Name: shares_sid_seq; Type: SEQUENCE; Schema: public; Owner: agendav
|
71
101
|
--
|
72
102
|
|
73
|
-
CREATE SEQUENCE
|
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
|
111
|
+
ALTER TABLE shares_sid_seq OWNER to postgres;
|
82
112
|
|
83
113
|
--
|
84
|
-
-- Name:
|
114
|
+
-- Name: shares_sid_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: agendav
|
85
115
|
--
|
86
116
|
|
87
|
-
|
88
|
-
|
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:
|
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:
|
136
|
+
-- Name: principals_pkey; Type: CONSTRAINT; Schema: public; Owner: agendav
|
109
137
|
--
|
110
138
|
|
111
|
-
ALTER TABLE ONLY
|
112
|
-
ADD CONSTRAINT
|
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:
|
152
|
+
-- Name: sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: agendav
|
117
153
|
--
|
118
154
|
|
119
|
-
ALTER TABLE ONLY
|
120
|
-
ADD CONSTRAINT
|
155
|
+
ALTER TABLE ONLY sessions
|
156
|
+
ADD CONSTRAINT sessions_pkey PRIMARY KEY (sess_id);
|
121
157
|
|
122
158
|
|
123
159
|
--
|
124
|
-
-- Name:
|
160
|
+
-- Name: shares_pkey; Type: CONSTRAINT; Schema: public; Owner: agendav
|
125
161
|
--
|
126
162
|
|
127
|
-
|
163
|
+
ALTER TABLE ONLY shares
|
164
|
+
ADD CONSTRAINT shares_pkey PRIMARY KEY (sid);
|
128
165
|
|
129
166
|
|
130
167
|
--
|
131
|
-
-- Name:
|
168
|
+
-- Name: idx_905f717c9890e20e; Type: INDEX; Schema: public; Owner: agendav
|
132
169
|
--
|
133
170
|
|
134
|
-
CREATE INDEX
|
171
|
+
CREATE INDEX idx_905f717c9890e20e ON shares USING btree ("with");
|
135
172
|
|
136
173
|
|
137
174
|
--
|
138
|
-
-- Name:
|
175
|
+
-- Name: idx_905f717ccf60e67c6ea9a146; Type: INDEX; Schema: public; Owner: agendav
|
139
176
|
--
|
140
177
|
|
141
|
-
CREATE INDEX
|
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 -
|
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.
|
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:
|
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.
|
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.
|
129
|
+
rubygems_version: 2.5.2
|
130
130
|
signing_key:
|
131
131
|
specification_version: 4
|
132
132
|
summary: Prune unused mail directories.
|