mailshears 0.0.1
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 +7 -0
- data/Rakefile +32 -0
- data/bin/install-fixtures.sh +27 -0
- data/bin/mailshears +124 -0
- data/doc/LICENSE +661 -0
- data/doc/TODO +16 -0
- data/doc/mailshears.example.conf.yml +37 -0
- data/doc/man1/mailshears.1 +184 -0
- data/lib/common/agendav_plugin.rb +54 -0
- data/lib/common/configuration.rb +116 -0
- data/lib/common/davical_plugin.rb +104 -0
- data/lib/common/domain.rb +64 -0
- data/lib/common/dovecot_plugin.rb +130 -0
- data/lib/common/errors.rb +15 -0
- data/lib/common/exit_codes.rb +9 -0
- data/lib/common/filesystem.rb +43 -0
- data/lib/common/plugin.rb +238 -0
- data/lib/common/postfixadmin_plugin.rb +180 -0
- data/lib/common/roundcube_plugin.rb +96 -0
- data/lib/common/runner.rb +73 -0
- data/lib/common/user.rb +120 -0
- data/lib/common/user_interface.rb +53 -0
- data/lib/mailshears.rb +7 -0
- data/lib/mv/mv_dummy_runner.rb +45 -0
- data/lib/mv/mv_plugin.rb +40 -0
- data/lib/mv/mv_runner.rb +56 -0
- data/lib/mv/plugins/agendav.rb +46 -0
- data/lib/mv/plugins/davical.rb +43 -0
- data/lib/mv/plugins/dovecot.rb +64 -0
- data/lib/mv/plugins/postfixadmin.rb +70 -0
- data/lib/mv/plugins/roundcube.rb +44 -0
- data/lib/prune/plugins/agendav.rb +13 -0
- data/lib/prune/plugins/davical.rb +13 -0
- data/lib/prune/plugins/dovecot.rb +11 -0
- data/lib/prune/plugins/postfixadmin.rb +13 -0
- data/lib/prune/plugins/roundcube.rb +14 -0
- data/lib/prune/prune_dummy_runner.rb +44 -0
- data/lib/prune/prune_plugin.rb +66 -0
- data/lib/prune/prune_runner.rb +34 -0
- data/lib/rm/plugins/agendav.rb +38 -0
- data/lib/rm/plugins/davical.rb +38 -0
- data/lib/rm/plugins/dovecot.rb +48 -0
- data/lib/rm/plugins/postfixadmin.rb +114 -0
- data/lib/rm/plugins/roundcube.rb +42 -0
- data/lib/rm/rm_dummy_runner.rb +39 -0
- data/lib/rm/rm_plugin.rb +77 -0
- data/lib/rm/rm_runner.rb +51 -0
- data/mailshears.gemspec +39 -0
- data/test/mailshears.test.conf.yml +36 -0
- data/test/mailshears_test.rb +250 -0
- data/test/sql/agendav-fixtures.sql +9 -0
- data/test/sql/agendav.sql +157 -0
- data/test/sql/davical-fixtures.sql +23 -0
- data/test/sql/davical.sql +4371 -0
- data/test/sql/postfixadmin-fixtures.sql +48 -0
- data/test/sql/postfixadmin.sql +737 -0
- data/test/sql/roundcube-fixtures.sql +4 -0
- data/test/sql/roundcube.sql +608 -0
- data/test/test_mv.rb +174 -0
- data/test/test_prune.rb +121 -0
- data/test/test_rm.rb +154 -0
- metadata +133 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'pg'
|
2
|
+
|
3
|
+
require 'common/roundcube_plugin'
|
4
|
+
require 'rm/rm_plugin'
|
5
|
+
|
6
|
+
# Handle removal of Roundcube users from its database. Roundcube has
|
7
|
+
# no concept of domains.
|
8
|
+
#
|
9
|
+
class RoundcubeRm
|
10
|
+
|
11
|
+
include RoundcubePlugin
|
12
|
+
include RmPlugin
|
13
|
+
|
14
|
+
# Remove *user* from the Roundcube database. This should remove him
|
15
|
+
# from _every_ table in which he is referenced. Fortunately the
|
16
|
+
# Roundcube developers were nice enough to include DBMS-specific
|
17
|
+
# install and upgrade scripts, so Postgres can take advantage of ON
|
18
|
+
# DELETE triggers.
|
19
|
+
#
|
20
|
+
# @param user [User] the user to remove.
|
21
|
+
#
|
22
|
+
def remove_user(user)
|
23
|
+
raise NonexistentUserError.new(user.to_s()) if not user_exists(user)
|
24
|
+
|
25
|
+
# Get the primary key for this user in the "users" table.
|
26
|
+
user_id = self.get_user_id(user)
|
27
|
+
|
28
|
+
# Thanks to the ON DELETE triggers, this will remove all child
|
29
|
+
# records associated with user_id too.
|
30
|
+
sql_query = 'DELETE FROM users WHERE user_id = $1::int;'
|
31
|
+
|
32
|
+
connection = PG::Connection.connect(@db_hash)
|
33
|
+
|
34
|
+
begin
|
35
|
+
connection.query(sql_query, [user_id])
|
36
|
+
ensure
|
37
|
+
# Make sure the connection gets closed even if the query explodes.
|
38
|
+
connection.close()
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'common/runner'
|
2
|
+
|
3
|
+
# Dummy implementation of a {RmRunner}. Its <tt>run()</tt> method will
|
4
|
+
# tell you what would have been removed, but will not actually perform
|
5
|
+
# the operation.
|
6
|
+
#
|
7
|
+
class RmDummyRunner
|
8
|
+
include Runner
|
9
|
+
|
10
|
+
|
11
|
+
# Pretend to remove *targets*. Some "what if"
|
12
|
+
# information will be output to stdout.
|
13
|
+
#
|
14
|
+
# This dummy runner is not particularly useful on its own. About the
|
15
|
+
# only thing it does is let you know that the users/domains in
|
16
|
+
# *targets* do in fact exist (through their descriptions). It's used
|
17
|
+
# to good effect by {PruneDummyRunner}, though.
|
18
|
+
#
|
19
|
+
# @param cfg [Configuration] the configuration options to pass to
|
20
|
+
# the *plugin* we're runnning.
|
21
|
+
#
|
22
|
+
# @param plugin [RmPlugin] plugin that will perform the move.
|
23
|
+
#
|
24
|
+
# @param targets [Array<User,Domain>] the users and domains to be
|
25
|
+
# removed.
|
26
|
+
#
|
27
|
+
def run(cfg, plugin, *targets)
|
28
|
+
targets.each do |target|
|
29
|
+
target_description = plugin.describe(target)
|
30
|
+
msg = "Would remove #{target.class.to_s().downcase()} "
|
31
|
+
msg += add_description(target, target_description)
|
32
|
+
msg += '.'
|
33
|
+
|
34
|
+
report(plugin, msg)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
data/lib/rm/rm_plugin.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'common/plugin.rb'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Plugins for the removal of users and domains.
|
5
|
+
#
|
6
|
+
module RmPlugin
|
7
|
+
|
8
|
+
# Absorb the subclass run() magic from the Plugin::Run module.
|
9
|
+
extend Plugin::Run
|
10
|
+
|
11
|
+
# The runner class associated with removal plugins.
|
12
|
+
#
|
13
|
+
# @return [Class] the {RmRunner} class.
|
14
|
+
#
|
15
|
+
def self.runner()
|
16
|
+
return RmRunner
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
# The "dummy" runner class associated with removal plugins.
|
21
|
+
#
|
22
|
+
# @return [Class] the {RmDummyRunner} class.
|
23
|
+
#
|
24
|
+
def self.dummy_runner()
|
25
|
+
return RmDummyRunner
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
# Remove the *target* domain or user. This is a generic version of
|
30
|
+
# the {#remove_user} and {#remove_domain} operations that will
|
31
|
+
# dispatch based on the type of *target*.
|
32
|
+
#
|
33
|
+
# @param target [User,Domain] the user or domain to remove.
|
34
|
+
#
|
35
|
+
def remove(target)
|
36
|
+
# A generic version of remove_user/remove_domain that
|
37
|
+
# dispatches base on the class of the target.
|
38
|
+
if target.is_a?(User)
|
39
|
+
return remove_user(target)
|
40
|
+
elsif target.is_a?(Domain)
|
41
|
+
return remove_domain(target)
|
42
|
+
else
|
43
|
+
raise NotImplementedError
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
# Remove the given *domain*. Some plugins don't have a concept of
|
49
|
+
# domains, so the default implementation here removes all users that
|
50
|
+
# look like they belong to *domain*. Subclasses can be smarter.
|
51
|
+
#
|
52
|
+
# @param domain [Domain] the domain to remove.
|
53
|
+
#
|
54
|
+
def remove_domain(domain)
|
55
|
+
users = list_domains_users([domain])
|
56
|
+
|
57
|
+
# It's possible for a domain to exist with no users, but this
|
58
|
+
# default implementation is based on the assumption that it should
|
59
|
+
# work for plugins having no "domain" concept.
|
60
|
+
raise NonexistentDomainError.new(domain.to_s()) if users.empty?
|
61
|
+
|
62
|
+
users.each do |u|
|
63
|
+
remove_user(u)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# The interface for the "remove a user" operation. Subclasses
|
69
|
+
# need to implement this method so that it removes *user*.
|
70
|
+
#
|
71
|
+
# @param user [User] the user to remove.
|
72
|
+
#
|
73
|
+
def remove_user(user)
|
74
|
+
raise NotImplementedError
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
data/lib/rm/rm_runner.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'common/errors'
|
2
|
+
require 'common/runner'
|
3
|
+
|
4
|
+
# Perform the removal of users/domains using {RmPlugin}s.
|
5
|
+
#
|
6
|
+
class RmRunner
|
7
|
+
include Runner
|
8
|
+
|
9
|
+
# Run *plugin* to remove the users/domains in *targets*. The method
|
10
|
+
# signature includes the unused *cfg* for consistency with the
|
11
|
+
# runners that do need a {Configuration}.
|
12
|
+
#
|
13
|
+
# @param cfg [Configuration] unused.
|
14
|
+
#
|
15
|
+
# @param plugin [Class] plugin class that will perform the removal.
|
16
|
+
#
|
17
|
+
# @param targets [Array<User,Domain>] the users and domains to be
|
18
|
+
# removed.
|
19
|
+
#
|
20
|
+
def run(cfg, plugin, *targets)
|
21
|
+
targets.each do |target|
|
22
|
+
remove_target(plugin, target)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
protected;
|
28
|
+
|
29
|
+
# Remove *target* using *plugin*. This operation is separate from
|
30
|
+
# the <tt>run()</tt> method so that it can be accessed by the prune
|
31
|
+
# runner.
|
32
|
+
#
|
33
|
+
# @param plugin [RmPlugin] the plugin that will remove the *target*.
|
34
|
+
#
|
35
|
+
# @param target [User,Domain] the user or domain to remove.
|
36
|
+
#
|
37
|
+
def remove_target(plugin, target)
|
38
|
+
target_description = plugin.describe(target)
|
39
|
+
|
40
|
+
begin
|
41
|
+
plugin.remove(target)
|
42
|
+
msg = "Removed #{target.class.to_s().downcase()} "
|
43
|
+
msg += add_description(target, target_description)
|
44
|
+
msg += '.'
|
45
|
+
|
46
|
+
report(plugin, msg)
|
47
|
+
rescue NonexistentDomainError, NonexistentUserError => e
|
48
|
+
report(plugin, "#{target.class.to_s()} #{e.to_s} not found.")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/mailshears.gemspec
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
|
3
|
+
s.name = 'mailshears'
|
4
|
+
s.version = '0.0.1'
|
5
|
+
s.platform = Gem::Platform::RUBY
|
6
|
+
s.authors = ['Michael Orlitzky']
|
7
|
+
s.email = ['michael@orlitzky.com']
|
8
|
+
s.homepage = 'http://michael.orlitzky.com/code/mailshears.php'
|
9
|
+
s.summary = 'Prune unused mail directories.'
|
10
|
+
s.description = <<-EOF
|
11
|
+
Managing a mail system with virtual users is annoying. The
|
12
|
+
authoritative database of users is stored in one table, but every
|
13
|
+
other piece of software keeps its own database of users.
|
14
|
+
|
15
|
+
If you're using PostfixAdmin to manage your users, what happens when
|
16
|
+
you delete a user? Chances are, nothing happens: mail directories are
|
17
|
+
left behind, webmail preferences are saved, address books become
|
18
|
+
orphaned. That's what mailshears was designed to fix. It cleans up
|
19
|
+
after you remove a user or domain.
|
20
|
+
|
21
|
+
Another stupidly difficult task is renaming a single email
|
22
|
+
account. It's easy to move the user in one database, but then all of
|
23
|
+
the remaining filesystem directories and databases need to be updated
|
24
|
+
as well. Since these two tasks are related, mailshears does them both.
|
25
|
+
EOF
|
26
|
+
|
27
|
+
s.license = 'AGPL-3'
|
28
|
+
s.required_rubygems_version = '>= 1.3.6'
|
29
|
+
|
30
|
+
# If you have runtime dependencies, add them here
|
31
|
+
s.add_runtime_dependency 'pg', '~> 0.11'
|
32
|
+
|
33
|
+
# The list of files to be contained in the gem
|
34
|
+
s.files = `git ls-files`.split("\n")
|
35
|
+
s.executables = ['mailshears']
|
36
|
+
|
37
|
+
s.require_path = 'lib'
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
i_mean_business: true
|
2
|
+
plugins: [agendav, davical, dovecot, postfixadmin, roundcube]
|
3
|
+
|
4
|
+
agendav_dbhost: localhost
|
5
|
+
agendav_dbport: 5432
|
6
|
+
agendav_dbopts:
|
7
|
+
agendav_dbtty:
|
8
|
+
agendav_dbuser: postgres
|
9
|
+
agendav_dbpass:
|
10
|
+
agendav_dbname: agendav_test
|
11
|
+
|
12
|
+
davical_dbhost: localhost
|
13
|
+
davical_dbport: 5432
|
14
|
+
davical_dbopts:
|
15
|
+
davical_dbtty:
|
16
|
+
davical_dbuser: postgres
|
17
|
+
davical_dbpass:
|
18
|
+
davical_dbname: davical_test
|
19
|
+
|
20
|
+
dovecot_mail_root: /tmp/mailshears-test
|
21
|
+
|
22
|
+
postfixadmin_dbhost: localhost
|
23
|
+
postfixadmin_dbport: 5432
|
24
|
+
postfixadmin_dbopts:
|
25
|
+
postfixadmin_dbtty:
|
26
|
+
postfixadmin_dbuser: postgres
|
27
|
+
postfixadmin_dbpass:
|
28
|
+
postfixadmin_dbname: postfixadmin_test
|
29
|
+
|
30
|
+
roundcube_dbhost: localhost
|
31
|
+
roundcube_dbport: 5432
|
32
|
+
roundcube_dbopts:
|
33
|
+
roundcube_dbtty:
|
34
|
+
roundcube_dbuser: postgres
|
35
|
+
roundcube_dbpass:
|
36
|
+
roundcube_dbname: roundcube_test
|
@@ -0,0 +1,250 @@
|
|
1
|
+
require 'common/configuration'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'pg'
|
5
|
+
|
6
|
+
class MailshearsTest < MiniTest::Test
|
7
|
+
# This is that class that most (if not all) of our test cases will
|
8
|
+
# inherit. It provides the automatic setup and teardown of the
|
9
|
+
# filesystem and database that the test cases will exercise.
|
10
|
+
|
11
|
+
def configuration()
|
12
|
+
# Return the test config object.
|
13
|
+
return Configuration.new('test/mailshears.test.conf.yml')
|
14
|
+
end
|
15
|
+
|
16
|
+
def maildir_exists(dir)
|
17
|
+
# Check if the given mail directory of the form "example.com/user"
|
18
|
+
# exists.
|
19
|
+
cfg = configuration()
|
20
|
+
return File.directory?("#{cfg.dovecot_mail_root()}/#{dir}")
|
21
|
+
end
|
22
|
+
|
23
|
+
def connect_superuser()
|
24
|
+
# Connect to the database (specified in the test configuration) as
|
25
|
+
# the superuser. Your local configuration is expected to be such
|
26
|
+
# that this "just works."
|
27
|
+
db_host = 'localhost'
|
28
|
+
db_port = 5432
|
29
|
+
db_opts = nil
|
30
|
+
db_tty = nil
|
31
|
+
db_name = 'postgres'
|
32
|
+
db_user = 'postgres'
|
33
|
+
db_pass = nil
|
34
|
+
|
35
|
+
connection = PG::Connection.new(db_host, db_port, db_opts, db_tty,
|
36
|
+
db_name, db_user, db_pass)
|
37
|
+
|
38
|
+
return connection
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup
|
42
|
+
# Connect to the database specified in the test configutation as
|
43
|
+
# the super user. Then, run all of the SQL scripts contained in
|
44
|
+
# test/sql. These scripts create the tables for the plugins listed
|
45
|
+
# in the test configuration, and then create some sample data.
|
46
|
+
#
|
47
|
+
# Here is the full list of what gets created. Every test case
|
48
|
+
# inheriting from this class can expect this schema and data to
|
49
|
+
# exist. The filesystem entries are located beneath mail_root from
|
50
|
+
# the configuration file.
|
51
|
+
#
|
52
|
+
# == Filesystem ==
|
53
|
+
#
|
54
|
+
# * example.com/alice
|
55
|
+
# * example.com/booger
|
56
|
+
# * example.com/jeremy
|
57
|
+
# * example.net/adam
|
58
|
+
#
|
59
|
+
# == Databases ==
|
60
|
+
#
|
61
|
+
# 1. agendav_test
|
62
|
+
#
|
63
|
+
# +------------------------------+
|
64
|
+
# | prefs |
|
65
|
+
# +--------------------+---------+
|
66
|
+
# | username | options |
|
67
|
+
# +--------------------+---------+
|
68
|
+
# | adam@example.net | herp |
|
69
|
+
# +--------------------+---------+
|
70
|
+
# | booger@example.com | herp |
|
71
|
+
# +------------------ +---------+
|
72
|
+
#
|
73
|
+
#
|
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
|
+
# +-----+--------------------+----------+-------------------+
|
83
|
+
#
|
84
|
+
#
|
85
|
+
# 2. davical_test
|
86
|
+
#
|
87
|
+
# +--------------------------------------------------------+
|
88
|
+
# | usr |
|
89
|
+
# +---------+--------+----------------+--------------------+
|
90
|
+
# | user_no | active | joined | username |
|
91
|
+
# +---------+--------+----------------+--------------------+
|
92
|
+
# | 17 | t | 2014-01-04 ... | alice@example.com |
|
93
|
+
# +---------+--------+----------------+--------------------+
|
94
|
+
# | 18 | t | 2014-01-04 ... | booger@example.com |
|
95
|
+
# +---------+--------+----------------+--------------------+
|
96
|
+
#
|
97
|
+
#
|
98
|
+
# +-----------------------------------------+
|
99
|
+
# | usr_setting |
|
100
|
+
# +---------+--------------+----------------+
|
101
|
+
# | user_no | setting_name | setting_value |
|
102
|
+
# +---------+--------------+----------------+
|
103
|
+
# | 17 | dumb setting | its dumb value |
|
104
|
+
# +---------+--------------+----------------+
|
105
|
+
# | 18 | dumb setting | its dumb value |
|
106
|
+
# +---------+--------------+----------------+
|
107
|
+
#
|
108
|
+
#
|
109
|
+
# 3. postfixadmin_test
|
110
|
+
#
|
111
|
+
# +-------------+
|
112
|
+
# | domain |
|
113
|
+
# +-------------+
|
114
|
+
# | domain |
|
115
|
+
# +-------------+
|
116
|
+
# | ALL |
|
117
|
+
# +-------------+
|
118
|
+
# | example.com |
|
119
|
+
# +-------------+
|
120
|
+
# | example.net |
|
121
|
+
# +-------------+
|
122
|
+
#
|
123
|
+
#
|
124
|
+
# +----------------------------------------------+
|
125
|
+
# | mailbox |
|
126
|
+
# +-------------------+-------------+------------+
|
127
|
+
# | username | domain | local_part |
|
128
|
+
# +-------------------+-------------+------------+
|
129
|
+
# | alice@example.com | example.com | alice |
|
130
|
+
# +-------------------+-------------+------------+
|
131
|
+
# | bob@example.com | example.com | bob |
|
132
|
+
# +-------------------+-------------+------------+
|
133
|
+
# | adam@example.net | example.net | adam |
|
134
|
+
# +-------------------+-------------+------------+
|
135
|
+
# | beth@example.net | example.net | beth |
|
136
|
+
# +-------------------+-------------+------------+
|
137
|
+
# | carol@example.net | example.net | carol |
|
138
|
+
# +-------------------+-------------+------------+
|
139
|
+
#
|
140
|
+
#
|
141
|
+
# +-------------------------------------------------------+
|
142
|
+
# | alias |
|
143
|
+
# +-------------------+--------------------+--------------+
|
144
|
+
# | address | goto | domain |
|
145
|
+
# +-------------------+--------------------+--------------+
|
146
|
+
# | alice@example.com | alice@example.com, | example.com |
|
147
|
+
# | | adam@example.net, | |
|
148
|
+
# | | bob@example.com, | |
|
149
|
+
# | | carol@example.net | |
|
150
|
+
# +-------------------+--------------------+--------------+
|
151
|
+
# | bob@example.com | bob@example.com | example.com |
|
152
|
+
# +-------------------+--------------------+--------------+
|
153
|
+
# | adam@example.net | adam@example.net | example.net |
|
154
|
+
# +-------------------+--------------------+--------------+
|
155
|
+
# | beth@example.net | beth@example.net | example.net |
|
156
|
+
# +-------------------+--------------------+--------------+
|
157
|
+
# | carol@example.net | carol@example.net | example.net |
|
158
|
+
# +-------------------+--------------------+--------------+
|
159
|
+
#
|
160
|
+
#
|
161
|
+
# +---------------------------------+
|
162
|
+
# | domain_admins |
|
163
|
+
# +-------------------+-------------+
|
164
|
+
# | username | domain |
|
165
|
+
# +-------------------+-------------+
|
166
|
+
# | admin@example.com | example.com |
|
167
|
+
# +-------------------+-------------+
|
168
|
+
# | admin@example.com | example.net |
|
169
|
+
# +-------------------+-------------+
|
170
|
+
#
|
171
|
+
# 4. roundcube_test
|
172
|
+
#
|
173
|
+
#
|
174
|
+
# +---------+--------------------+
|
175
|
+
# | user_id | username |
|
176
|
+
# +---------+--------------------+
|
177
|
+
# | 1 | alice@example.com |
|
178
|
+
# +---------+--------------------+
|
179
|
+
# | 2 | booger@example.com |
|
180
|
+
# +---------+--------------------+
|
181
|
+
# | 3 | adam@example.net |
|
182
|
+
# +---------+--------------------+
|
183
|
+
|
184
|
+
# First make sure we get rid of everything so we don't get random
|
185
|
+
# failures from databases and directories that already exist.
|
186
|
+
teardown()
|
187
|
+
|
188
|
+
cfg = configuration()
|
189
|
+
|
190
|
+
# First create the "mail directories".
|
191
|
+
FileUtils.mkdir_p("#{cfg.dovecot_mail_root()}/example.com/alice")
|
192
|
+
FileUtils.mkdir_p("#{cfg.dovecot_mail_root()}/example.com/booger")
|
193
|
+
FileUtils.mkdir_p("#{cfg.dovecot_mail_root()}/example.com/jeremy")
|
194
|
+
FileUtils.mkdir_p("#{cfg.dovecot_mail_root()}/example.net/adam")
|
195
|
+
|
196
|
+
# Now the databases and their content.
|
197
|
+
connection = connect_superuser()
|
198
|
+
|
199
|
+
cfg.plugins.each do |plugin|
|
200
|
+
plugin_dbname = cfg.send("#{plugin}_dbname")
|
201
|
+
next if plugin_dbname.nil? # Skip the dovecot plugin
|
202
|
+
query = "CREATE DATABASE #{plugin_dbname};"
|
203
|
+
connection.query(query)
|
204
|
+
|
205
|
+
plugin_dbhost = cfg.send("#{plugin}_dbhost")
|
206
|
+
plugin_dbport = cfg.send("#{plugin}_dbport")
|
207
|
+
plugin_dbopts = cfg.send("#{plugin}_dbopts")
|
208
|
+
plugin_dbtty = cfg.send("#{plugin}_dbtty")
|
209
|
+
plugin_dbuser = cfg.send("#{plugin}_dbuser")
|
210
|
+
plugin_dbpass = cfg.send("#{plugin}_dbpass")
|
211
|
+
|
212
|
+
plugin_conn = PG::Connection.new(plugin_dbhost, plugin_dbport,
|
213
|
+
plugin_dbopts, plugin_dbtty,
|
214
|
+
plugin_dbname, plugin_dbuser,
|
215
|
+
plugin_dbpass)
|
216
|
+
|
217
|
+
sql = File.open("test/sql/#{plugin}.sql").read()
|
218
|
+
plugin_conn.query(sql)
|
219
|
+
sql = File.open("test/sql/#{plugin}-fixtures.sql").read()
|
220
|
+
plugin_conn.query(sql)
|
221
|
+
plugin_conn.close()
|
222
|
+
end
|
223
|
+
|
224
|
+
connection.close()
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
def teardown
|
229
|
+
# Drop all of the databases that were created in setup().
|
230
|
+
cfg = configuration()
|
231
|
+
connection = connect_superuser()
|
232
|
+
|
233
|
+
# Don't emit notices about missing tables. Why this happens when I
|
234
|
+
# explicitly say IF EXISTS is beyond me.
|
235
|
+
connection.set_notice_processor{}
|
236
|
+
|
237
|
+
cfg.plugins.each do |plugin|
|
238
|
+
plugin_dbname = cfg.send("#{plugin}_dbname")
|
239
|
+
next if plugin_dbname.nil? # Skip the dovecot plugin
|
240
|
+
query = "DROP DATABASE IF EXISTS #{plugin_dbname};"
|
241
|
+
connection.query(query)
|
242
|
+
end
|
243
|
+
|
244
|
+
connection.close()
|
245
|
+
|
246
|
+
# Get rid of the maildirs.
|
247
|
+
FileUtils.rm_rf(cfg.dovecot_mail_root())
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|