Document everything with YARD and fix some bugs along the way.
[mailshears.git] / lib / common / postfixadmin_plugin.rb
1 require 'common/domain'
2 require 'common/plugin'
3 require 'common/user'
4 require 'pg'
5
6 # Code that all Postfixadmin plugins ({PostfixadminPrune},
7 # {PostfixadminRm}, {PostfixadminMv}) share.
8 #
9 module PostfixadminPlugin
10
11 # We implement the Plugin "interface."
12 include Plugin
13
14 # Initialize this Postfixadmin {Plugin} with values in *cfg*.
15 #
16 # @param cfg [Configuration] the configuration for this plugin.
17 #
18 def initialize(cfg)
19 @db_host = cfg.postfixadmin_dbhost
20 @db_port = cfg.postfixadmin_dbport
21 @db_opts = cfg.postfixadmin_dbopts
22 @db_tty = cfg.postfixadmin_dbtty
23 @db_name = cfg.postfixadmin_dbname
24 @db_user = cfg.postfixadmin_dbuser
25 @db_pass = cfg.postfixadmin_dbpass
26 end
27
28
29 # Obtain a list of domains from Postfixadmin. This is more efficient
30 # than the {Plugin} default implementation because domains have
31 # their own table in the database and we can easily select them
32 # rather than filtering the list of users.
33 #
34 # @return [Array<Domain>] a list of the domains in Postfixadmin.
35 #
36 def list_domains()
37 domains = []
38
39 connection = PGconn.connect(@db_host, @db_port, @db_opts, @db_tty,
40 @db_name, @db_user, @db_pass)
41
42 # 'ALL' is a magic domain, and we don't want it.
43 sql_query = "SELECT domain FROM domain WHERE domain <> 'ALL';"
44 connection.query(sql_query) do |result|
45 domains = result.field_values('domain')
46 end
47
48 connection.close()
49
50 return domains.map{ |d| Domain.new(d) }
51 end
52
53
54 # Return a list of Postfixadmin users.
55 #
56 # @return [Array<User>] a list of users contained in the
57 # Postfixadmin database.
58 #
59 def list_users()
60 users = []
61
62 connection = PGconn.connect(@db_host, @db_port, @db_opts, @db_tty,
63 @db_name, @db_user, @db_pass)
64
65 sql_query = 'SELECT username FROM mailbox;'
66 connection.query(sql_query) do |result|
67 users = result.field_values('username')
68 end
69
70 connection.close()
71
72 return users.map{ |u| User.new(u) }
73 end
74
75
76
77 # Efficiently list all Postfixadmin users belonging to the given
78 # Postfixadmin *domains*.
79 #
80 # @param domains [Array<Domain>] the domains whose users we want.
81 #
82 # @return [Array<User>] a list of {User} objects belonging to
83 # *domains* for this plugin.
84 #
85 def list_domains_users(domains)
86 usernames = []
87 return usernames if domains.length() == 0
88
89 connection = PGconn.connect(@db_host, @db_port, @db_opts, @db_tty,
90 @db_name, @db_user, @db_pass)
91
92 # The number of parameters that we'll pass into our prepared query
93 # is the number of domains that we're given. It's important that
94 # we have at least one domain here.
95 params = 1.upto(domains.length()).map{ |i| '$' + i.to_s() }.join(',')
96 sql_query = "SELECT username FROM mailbox WHERE domain IN (#{params});"
97
98 # Now replace each Domain with its string representation and pass
99 # those in as our individual parameters.
100 connection.query(sql_query, domains.map{ |d| d.to_s() }) do |result|
101 usernames = result.field_values('username')
102 end
103
104 connection.close()
105
106 return usernames.map{ |u| User.new(u) }
107 end
108
109
110 # Get a list of all Postfixadmin aliases as a <tt>from => to</tt>
111 # hash. This is useful for testing, since aliases should be removed
112 # when either the "from user" or "to user" are removed.
113 #
114 # @return [Hash] all aliases known to Postfixadmin in the form of a
115 # <tt>from => to</tt> hash.
116 #
117 def list_aliases()
118 aliases = []
119
120 connection = PGconn.connect(@db_host, @db_port, @db_opts, @db_tty,
121 @db_name, @db_user, @db_pass)
122
123 sql_query = 'SELECT address,goto FROM alias;'
124 results = connection.query(sql_query)
125 results.each do |row|
126 # row should be a hash
127 aliases << row
128 end
129
130 connection.close()
131
132 return aliases
133 end
134
135
136 # A fast implementation of the "does this domain exist?"
137 # operation. It only queries the database for the existence of
138 # *domain* rather than a list of all domains (which is the default
139 # implementation).
140 #
141 # @param domain [Domain] the domain whose existence is in question.
142 #
143 # @return [Boolean] true if *domain* exists in the Postfixadmin
144 # database and false otherwise.
145 #
146 def domain_exists(domain)
147 count = 0
148
149 connection = PGconn.connect(@db_host, @db_port, @db_opts, @db_tty,
150 @db_name, @db_user, @db_pass)
151
152 sql_query = 'SELECT COUNT(domain) as count FROM domain WHERE domain = $1;'
153 connection.query(sql_query, [domain.to_s()]) do |result|
154 return false if result.ntuples() < 1
155 count = result.getvalue(0,0).to_i()
156
157 return false if count.nil?
158 end
159
160 connection.close()
161
162 return (count > 0)
163 end
164
165 end