postfix_admin 0.1.1 → 0.2.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.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ruby.yml +37 -0
  3. data/.gitignore +2 -0
  4. data/.rubocop.yml +2 -0
  5. data/CHANGELOG.md +22 -0
  6. data/README.md +47 -32
  7. data/Rakefile +6 -0
  8. data/bin/console +18 -0
  9. data/docker-admin/Dockerfile +6 -0
  10. data/docker-admin/config.local.php +21 -0
  11. data/docker-app-2.5/Dockerfile +15 -0
  12. data/docker-app/Dockerfile +25 -0
  13. data/docker-app/docker-entrypoint.sh +5 -0
  14. data/docker-app/my.cnf +5 -0
  15. data/docker-compose.yml +46 -0
  16. data/docker-db/postfix.v1841.sql +383 -0
  17. data/{spec/postfix_test.sql → docker-db/postfix.v352.sql} +1 -28
  18. data/docker-db/postfix.v740.sql +269 -0
  19. data/{bin → exe}/postfix_admin +1 -0
  20. data/lib/postfix_admin.rb +1 -1
  21. data/lib/postfix_admin/admin.rb +62 -0
  22. data/lib/postfix_admin/alias.rb +65 -0
  23. data/lib/postfix_admin/application_record.rb +44 -0
  24. data/lib/postfix_admin/base.rb +120 -75
  25. data/lib/postfix_admin/cli.rb +173 -58
  26. data/lib/postfix_admin/concerns/.keep +0 -0
  27. data/lib/postfix_admin/concerns/dovecot_cram_md5_password.rb +30 -0
  28. data/lib/postfix_admin/concerns/existing_timestamp.rb +18 -0
  29. data/lib/postfix_admin/domain.rb +98 -0
  30. data/lib/postfix_admin/domain_admin.rb +8 -0
  31. data/lib/postfix_admin/doveadm.rb +37 -0
  32. data/lib/postfix_admin/log.rb +5 -0
  33. data/lib/postfix_admin/mail_domain.rb +9 -0
  34. data/lib/postfix_admin/mailbox.rb +89 -0
  35. data/lib/postfix_admin/models.rb +10 -170
  36. data/lib/postfix_admin/quota.rb +6 -0
  37. data/lib/postfix_admin/runner.rb +108 -36
  38. data/lib/postfix_admin/version.rb +1 -1
  39. data/postfix_admin.gemspec +22 -12
  40. metadata +80 -55
  41. data/spec/base_spec.rb +0 -235
  42. data/spec/cli_spec.rb +0 -286
  43. data/spec/models_spec.rb +0 -146
  44. data/spec/postfix_admin.conf +0 -5
  45. data/spec/runner_spec.rb +0 -194
  46. data/spec/spec_helper.rb +0 -159
@@ -0,0 +1,44 @@
1
+ require 'active_record'
2
+ require 'postfix_admin/concerns/existing_timestamp'
3
+
4
+ module PostfixAdmin
5
+ class ApplicationRecord < ActiveRecord::Base
6
+ self.abstract_class = true
7
+
8
+ include ExistingTimestamp
9
+
10
+ RE_DOMAIN_NAME_LIKE_BASE = '([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}'
11
+ RE_EMAIL_LIKE_BASE = '[^@\s]+@([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}'
12
+
13
+ RE_DOMAIN_NAME_LIKE = /#{RE_DOMAIN_NAME_LIKE_BASE}/
14
+ RE_EMAIL_LIKE = /#{RE_EMAIL_LIKE_BASE}/
15
+
16
+ RE_DOMAIN_NAME_LIKE_WITH_ANCHORS = /\A#{RE_DOMAIN_NAME_LIKE_BASE}\z/
17
+ RE_EMAIL_LIKE_WITH_ANCHORS = /\A#{RE_EMAIL_LIKE_BASE}\z/
18
+
19
+ scope :active, -> { where(active: true) }
20
+
21
+ def inactive?
22
+ !active?
23
+ end
24
+
25
+ def active_str
26
+ active? ? "Active" : "Inactive"
27
+ end
28
+
29
+ # This is a workaround to set current time to timestamp columns when a record is created.
30
+ # Activerecord does not insert timestamps if default values are set for the columns.
31
+ before_create :set_current_time_to_timestamp_columns, if: :has_timestamp_columns?
32
+
33
+ def set_current_time_to_timestamp_columns
34
+ now = Time.now
35
+ self.created = now
36
+ self.modified = now
37
+ end
38
+
39
+ def has_timestamp_columns?
40
+ column_names = self.class.column_names
41
+ column_names.include?("created") && column_names.include?("modified")
42
+ end
43
+ end
44
+ end
@@ -1,137 +1,170 @@
1
- require 'postfix_admin/models'
2
1
  require 'postfix_admin/error'
3
2
 
4
3
  require 'date'
5
- require 'data_mapper'
4
+ require 'postfix_admin/models'
6
5
 
7
6
  module PostfixAdmin
8
7
  class Base
9
8
  attr_reader :config
10
9
 
11
10
  DEFAULT_CONFIG = {
12
- 'database' => 'mysql://postfix:password@localhost/postfix',
11
+ 'database' => 'mysql2://postfix:password@localhost/postfix',
13
12
  'aliases' => 30,
14
13
  'mailboxes' => 30,
15
- 'maxquota' => 100
14
+ 'maxquota' => 100,
15
+ 'scheme' => 'CRAM-MD5',
16
+ 'passwordhash_prefix' => true
16
17
  }
17
18
 
18
19
  def initialize(config)
19
- db_setup(config['database'])
20
20
  @config = {}
21
+ @config[:database] = config['database']
21
22
  @config[:aliases] = config['aliases'] || 30
22
23
  @config[:mailboxes] = config['mailboxes'] || 30
23
24
  @config[:maxquota] = config['maxquota'] || 100
24
- @config[:mailbox_quota] = @config[:maxquota] * KB_TO_MB
25
+ @config[:scheme] = config['scheme'] || 'CRAM-MD5'
26
+ @config[:passwordhash_prefix] = if config['passwordhash_prefix'].nil?
27
+ true
28
+ else
29
+ config['passwordhash_prefix']
30
+ end
25
31
  end
26
32
 
27
- def db_setup(database)
28
- DataMapper.setup(:default, database)
29
- DataMapper.finalize
33
+ def db_setup
34
+ raise "'database' parameter is required in '#{CLI.config_file}'" unless @config[:database]
35
+
36
+ uri = URI.parse(@config[:database])
37
+
38
+ if uri.scheme == "mysql"
39
+ uri.scheme = "mysql2"
40
+ warn("Deprecation Warning: Use 'mysql2' as a DB adopter instead of 'mysql' in '#{CLI.config_file}'")
41
+ end
42
+
43
+ if uri.scheme != "mysql2"
44
+ raise "'#{uri.scheme}' is not supported as a DB adopter. Use 'mysql2' instead in '#{CLI.config_file}'."
45
+ end
46
+
47
+ ActiveRecord::Base.establish_connection(uri.to_s)
48
+
49
+ rescue LoadError => e
50
+ raise e.message
30
51
  end
31
52
 
32
53
  def add_admin_domain(user_name, domain_name)
33
54
  admin_domain_check(user_name, domain_name)
34
55
 
35
56
  admin = Admin.find(user_name)
36
- if admin.has_domain?(domain_name)
37
- raise Error, "#{user_name} is already resistered as admin of #{domain_name}."
57
+ domain = Domain.find(domain_name)
58
+
59
+ if admin.has_domain?(domain)
60
+ raise Error, "#{user_name} is already registered as admin of #{domain_name}."
38
61
  end
39
62
 
40
- domain = Domain.find(domain_name)
41
- admin.domains << domain
63
+ admin.rel_domains << domain
42
64
  admin.save or raise "Relation Error: Domain of Admin"
43
65
  end
44
66
 
45
67
  def delete_admin_domain(user_name, domain_name)
46
68
  admin_domain_check(user_name, domain_name)
47
69
 
48
- admin = Admin.find(user_name)
49
- unless admin.has_domain?(domain_name)
50
- raise Error, "#{user_name} is not resistered as admin of #{domain_name}."
70
+ admin = Admin.find(user_name)
71
+ domain_admin_query = admin.domain_admins.where(domain: domain_name)
72
+
73
+ unless domain_admin_query.take
74
+ raise Error, "#{user_name} is not registered as admin of #{domain_name}."
51
75
  end
52
76
 
53
- domain = Domain.find(domain_name)
54
- admin.domains.delete(domain)
55
- admin.save or "Could not save Admin"
77
+ domain_admin_query.delete_all
56
78
  end
57
79
 
58
80
  def add_admin(username, password)
59
- if Admin.exist?(username)
60
- raise Error, "#{username} is already resistered as admin."
81
+ password_check(password)
82
+
83
+ if Admin.exists?(username)
84
+ raise Error, "#{username} is already registered as admin."
61
85
  end
62
86
  admin = Admin.new
63
87
  admin.attributes = {
64
- :username => username,
65
- :password => password,
88
+ username: username,
89
+ password: password,
66
90
  }
67
91
  unless admin.save
68
- raise "Could not save Admin #{admin.errors.map{|e| e.to_s}.join}"
92
+ raise "Could not save Admin #{admin.errors.map(&:to_s).join}"
69
93
  end
70
94
  end
71
95
 
72
- def add_account(address, password)
96
+ def add_account(address, password, in_name = nil)
97
+ name = in_name || ''
98
+ password_check(password)
99
+
73
100
  if address !~ /.+\@.+\..+/
74
101
  raise Error, "Invalid mail address #{address}"
75
102
  end
76
103
  user, domain_name = address_split(address)
77
104
  path = "#{domain_name}/#{address}/"
78
105
 
79
- unless Domain.exist?(domain_name)
106
+ unless Domain.exists?(domain_name)
80
107
  raise Error, "Could not find domain #{domain_name}"
81
108
  end
82
109
 
83
- if Alias.exist?(address)
84
- raise Error, "#{address} is already resistered."
110
+ if Alias.exists?(address)
111
+ raise Error, "#{address} is already registered."
85
112
  end
86
113
 
87
114
  domain = Domain.find(domain_name)
88
- domain.aliases << Alias.mailbox(address)
89
-
90
- mailbox = Mailbox.new
91
- mailbox.attributes = {
92
- :username => address,
93
- :password => password,
94
- :name => '',
95
- :maildir => path,
96
- :quota => @config[:mailbox_quota],
97
- # :local_part => user,
115
+
116
+ attributes = {
117
+ username: address,
118
+ password: password,
119
+ name: name,
120
+ maildir: path,
121
+ local_part: user,
122
+ quota_mb: @config[:maxquota]
98
123
  }
99
- domain.mailboxes << mailbox
124
+
125
+ mailbox = Mailbox.new(attributes)
126
+
127
+ domain.rel_mailboxes << mailbox
128
+
100
129
  unless domain.save
101
- raise "Could not save Mailbox and Domain #{mailbox.errors.map{|e| e.to_s}.join} #{domain.errors.map{|e| e.to_s}.join}"
130
+ raise "Could not save Mailbox and Domain #{mailbox.errors.map(&:to_s).join} #{domain.errors.map(&:to_s).join}"
102
131
  end
103
132
  end
104
133
 
105
134
  def add_alias(address, goto)
106
- if Mailbox.exist?(address)
135
+ if Mailbox.exists?(address)
107
136
  raise Error, "mailbox #{address} is already registered!"
108
137
  end
109
- if Alias.exist?(address)
138
+ if Alias.exists?(address)
110
139
  raise Error, "alias #{address} is already registered!"
111
140
  end
112
- user, domain_name = address_split(address)
113
- unless Domain.exist?(domain_name)
141
+
142
+ local_part, domain_name = address_split(address)
143
+
144
+ unless Domain.exists?(domain_name)
114
145
  raise Error, "Invalid domain! #{domain_name}"
115
146
  end
147
+
116
148
  domain = Domain.find(domain_name)
117
149
 
118
- new_alias = Alias.new
119
- new_alias.attributes = {
120
- :address => address,
121
- :goto => goto,
150
+ attributes = {
151
+ local_part: local_part,
152
+ goto: goto
122
153
  }
123
- domain.aliases << new_alias
154
+ domain.rel_aliases << Alias.new(attributes)
124
155
  domain.save or raise "Could not save Alias"
125
156
  end
126
157
 
127
158
  def delete_alias(address)
128
- if Mailbox.exist?(address)
159
+ if Mailbox.exists?(address)
129
160
  raise Error, "Can not delete mailbox by delete_alias. Use delete_account"
130
161
  end
131
- unless Alias.exist?(address)
162
+
163
+ unless Alias.exists?(address)
132
164
  raise Error, "#{address} is not found!"
133
165
  end
134
- Alias.all(:address => address).destroy or raise "Could not destroy Alias"
166
+
167
+ Alias.where(address: address).delete_all
135
168
  end
136
169
 
137
170
  def add_domain(domain_name)
@@ -139,56 +172,65 @@ module PostfixAdmin
139
172
  if domain_name !~ /.+\..+/
140
173
  raise Error, "Ivalid domain! #{domain_name}"
141
174
  end
142
- if Domain.exist?(domain_name)
175
+ if Domain.exists?(domain_name)
143
176
  raise Error, "#{domain_name} is already registered!"
144
177
  end
145
178
  domain = Domain.new
146
179
  domain.attributes = {
147
- :domain_name => domain_name,
148
- :description => domain_name,
149
- :maxaliases => @config[:aliases],
150
- :maxmailboxes => @config[:mailboxes],
151
- :maxquota => @config[:maxquota],
180
+ domain: domain_name,
181
+ description: domain_name,
182
+ aliases: @config[:aliases],
183
+ mailboxes: @config[:mailboxes],
184
+ maxquota: @config[:maxquota],
152
185
  }
153
- domain.save or raise "Could not save Domain"
186
+ domain.save!
154
187
  end
155
188
 
156
189
  def delete_domain(domain_name)
157
190
  domain_name = domain_name.downcase
158
- unless Domain.exist?(domain_name)
191
+ unless Domain.exists?(domain_name)
159
192
  raise Error, "Could not find domain #{domain_name}"
160
193
  end
161
194
 
162
195
  domain = Domain.find(domain_name)
163
- domain.mailboxes.destroy or raise "Could not destroy Mailbox"
164
- domain.aliases.destroy or raise "Could not destroy Alias"
165
- admin_names = domain.admins.map{|a| a.username }
166
- domain.clear_admins
196
+ domain.rel_mailboxes.delete_all
197
+ domain.rel_aliases.delete_all
198
+
199
+ admin_names = domain.admins.map(&:username)
200
+
201
+ domain.admins.delete_all
167
202
 
168
203
  admin_names.each do |name|
169
- next unless Admin.exist?(name)
204
+ next unless Admin.exists?(name)
205
+
170
206
  admin = Admin.find(name)
171
- admin.destroy or raise "Could not destroy Admin" if admin.domains.empty?
207
+
208
+ # check if the admin is needed or not
209
+ if admin.rel_domains.empty?
210
+ admin.destroy
211
+ end
172
212
  end
173
- domain.destroy or raise "Could not destroy Domain"
213
+
214
+ domain.destroy
174
215
  end
175
216
 
176
217
  def delete_admin(user_name)
177
- unless Admin.exist?(user_name)
218
+ unless Admin.exists?(user_name)
178
219
  raise Error, "Could not find admin #{user_name}"
179
220
  end
221
+
180
222
  admin = Admin.find(user_name)
181
- admin.clear_domains
182
- admin.destroy or raise "Could not destroy Admin"
223
+ admin.rel_domains.delete_all
224
+ admin.destroy!
183
225
  end
184
226
 
185
227
  def delete_account(address)
186
- unless Alias.exist?(address) && Mailbox.exist?(address)
228
+ unless Alias.exists?(address) && Mailbox.exists?(address)
187
229
  raise Error, "Could not find account #{address}"
188
230
  end
189
231
 
190
- Mailbox.all(:username => address).destroy or raise "Could not destroy Mailbox"
191
- Alias.all(:address => address).destroy or raise "Could not destroy Alias"
232
+ Mailbox.where(username: address).delete_all
233
+ Alias.where(address: address).delete_all
192
234
  end
193
235
 
194
236
  def address_split(address)
@@ -198,9 +240,12 @@ module PostfixAdmin
198
240
  private
199
241
 
200
242
  def admin_domain_check(user_name, domain_name)
201
- raise Error, "#{user_name} is not resistered as admin." unless Admin.exist?(user_name)
202
- raise Error, "Could not find domain #{domain_name}" unless Domain.exist?(domain_name)
243
+ raise Error, "#{user_name} is not registered as admin." unless Admin.exists?(user_name)
244
+ raise Error, "Could not find domain #{domain_name}" unless Domain.exists?(domain_name)
203
245
  end
204
246
 
247
+ def password_check(password)
248
+ raise Error, "Empty password" if password.nil? || password.empty?
249
+ end
205
250
  end
206
251
  end
@@ -1,9 +1,11 @@
1
1
  require 'yaml'
2
2
  require 'postfix_admin'
3
+ require 'postfix_admin/doveadm'
3
4
 
4
5
  module PostfixAdmin
5
6
  class CLI
6
- @config_file = '~/.postfix_admin.conf'
7
+ DEFAULT_CONFIG_PATH = '~/.postfix_admin.conf'
8
+ @config_file = DEFAULT_CONFIG_PATH
7
9
  MIN_NUM_PASSWORD_CHARACTER = 5
8
10
 
9
11
  def initialize
@@ -19,11 +21,24 @@ module PostfixAdmin
19
21
  @config_file = value
20
22
  end
21
23
 
24
+ def db_setup
25
+ @base.db_setup
26
+ end
27
+
22
28
  def show(name)
23
29
  name = name.downcase if name
24
30
 
25
31
  if name =~ /@/
26
- show_account(name)
32
+ if Admin.exists?(name)
33
+ show_admin_details(name)
34
+ end
35
+
36
+ if Mailbox.exists?(name)
37
+ show_account_details(name)
38
+ elsif Alias.exists?(name)
39
+ show_alias_details(name)
40
+ end
41
+
27
42
  return
28
43
  end
29
44
 
@@ -39,7 +54,7 @@ module PostfixAdmin
39
54
  end
40
55
  end
41
56
 
42
- def show_summary(domain_name=nil)
57
+ def show_summary(domain_name = nil)
43
58
  title = "Summary"
44
59
  if domain_name
45
60
  domain_name = domain_name.downcase
@@ -50,14 +65,15 @@ module PostfixAdmin
50
65
  report(title) do
51
66
  if domain_name
52
67
  domain = Domain.find(domain_name)
53
- puts "Mailboxes : %4d / %4s" % [domain.mailboxes.count, max_str(domain.maxmailboxes)]
54
- puts "Aliases : %4d / %4s" % [domain.num_total_aliases, max_str(domain.maxaliases)]
68
+ puts "Mailboxes : %4d / %4s" % [domain.rel_mailboxes.count, max_str(domain.mailboxes)]
69
+ puts "Aliases : %4d / %4s" % [domain.pure_aliases.count, max_str(domain.aliases)]
55
70
  puts "Max Quota : %4d MB" % domain.maxquota
71
+ puts "Active : %3s" % domain.active_str
56
72
  else
57
- puts "Domains : %4d" % Domain.all_without_special_domain.count
73
+ puts "Domains : %4d" % Domain.without_all.count
58
74
  puts "Admins : %4d" % Admin.count
59
75
  puts "Mailboxes : %4d" % Mailbox.count
60
- puts "Aliases : %4d" % Domain.num_total_aliases
76
+ puts "Aliases : %4d" % Alias.pure.count
61
77
  end
62
78
  end
63
79
  end
@@ -69,34 +85,58 @@ module PostfixAdmin
69
85
  add_admin_domain(admin, domain_name)
70
86
  end
71
87
 
72
- def show_account(user_name)
88
+ def show_account_details(user_name)
73
89
  account_check(user_name)
74
90
  mailbox = Mailbox.find(user_name)
75
91
  mail_alias = Alias.find(user_name)
76
92
 
77
93
  report("Mailbox") do
78
94
  puts "Address : %s" % mailbox.username
95
+ puts "Name : %s" % mailbox.name
79
96
  puts "Password : %s" % mailbox.password
80
97
  puts "Quota : %d MB" % max_str(mailbox.quota / KB_TO_MB)
81
98
  puts "Go to : %s" % mail_alias.goto
99
+ puts "Active : %s" % mailbox.active_str
100
+ end
101
+ end
102
+
103
+ def show_admin_details(name)
104
+ admin_check(name)
105
+ admin = Admin.find(name)
106
+
107
+ report("Admin") do
108
+ puts "Name : %s" % admin.username
109
+ puts "Password : %s" % admin.password
110
+ puts "Domains : %s" % (admin.super_admin? ? "ALL" : admin.rel_domains.count)
111
+ puts "Role : %s" % (admin.super_admin? ? "Super admin" : "Admin")
112
+ puts "Active : %s" % admin.active_str
113
+ end
114
+ end
115
+
116
+ def show_alias_details(name)
117
+ alias_check(name)
118
+ mail_alias = Alias.find(name)
119
+ report("Alias") do
120
+ puts "Address : %s" % mail_alias.address
121
+ puts "Go to : %s" % mail_alias.goto
122
+ puts "Active : %s" % mail_alias.active_str
82
123
  end
83
124
  end
84
125
 
85
126
  def show_domain
86
- index = " No. Domain Aliases Mailboxes Quota (MB)"
127
+ index = " No. Domain Aliases Mailboxes Quota (MB) Active"
87
128
  report('Domains', index) do
88
- if Domain.all_without_special_domain.empty?
129
+ if Domain.without_all.empty?
89
130
  puts " No domains"
90
131
  next
91
132
  end
92
133
 
93
- Domain.all_without_special_domain.each_with_index do |d, i|
94
- puts "%4d %-30s %3d /%3s %3d /%3s %10d" %
95
- [i+1, d.domain_name, d.num_total_aliases, max_str(d.maxaliases),
96
- d.mailboxes.count, max_str(d.maxmailboxes), d.maxquota]
134
+ Domain.without_all.each_with_index do |d, i|
135
+ puts "%4d %-30s %3d /%3s %3d /%3s %10d %-3s" %
136
+ [i+1, d.domain, d.pure_aliases.count, max_str(d.aliases),
137
+ d.rel_mailboxes.count, max_str(d.mailboxes), d.maxquota, d.active_str]
97
138
  end
98
139
  end
99
-
100
140
  end
101
141
 
102
142
  def add_domain(domain_name)
@@ -104,18 +144,6 @@ module PostfixAdmin
104
144
  puts_registered(domain_name, "a domain")
105
145
  end
106
146
 
107
- def super_admin(user_name, disable)
108
- admin_check(user_name)
109
-
110
- if disable
111
- Admin.find(user_name).super_admin = false
112
- puts "Successfully disabled super admin flag of #{user_name}"
113
- else
114
- Admin.find(user_name).super_admin = true
115
- puts "Successfully enabled super admin flag of #{user_name}"
116
- end
117
- end
118
-
119
147
  def change_admin_password(user_name, password)
120
148
  change_password(Admin, user_name, password)
121
149
  end
@@ -124,13 +152,29 @@ module PostfixAdmin
124
152
  change_password(Mailbox, user_name, password)
125
153
  end
126
154
 
155
+ def edit_admin(admin_name, options)
156
+ admin_check(admin_name)
157
+ admin = Admin.find(admin_name)
158
+
159
+ unless options[:super].nil?
160
+ admin.super_admin = options[:super]
161
+ end
162
+
163
+ admin.active = options[:active] unless options[:active].nil?
164
+ admin.save!
165
+
166
+ puts "Successfully updated #{admin_name}"
167
+ show_admin_details(admin_name)
168
+ end
169
+
127
170
  def edit_domain(domain_name, options)
128
171
  domain_check(domain_name)
129
172
  domain = Domain.find(domain_name)
130
- domain.maxaliases = options[:aliases] if options[:aliases]
131
- domain.maxmailboxes = options[:mailboxes] if options[:mailboxes]
173
+ domain.aliases = options[:aliases] if options[:aliases]
174
+ domain.mailboxes = options[:mailboxes] if options[:mailboxes]
132
175
  domain.maxquota = options[:maxquota] if options[:maxquota]
133
- domain.save or raise "Could not save Domain"
176
+ domain.active = options[:active] unless options[:active].nil?
177
+ domain.save!
134
178
 
135
179
  puts "Successfully updated #{domain_name}"
136
180
  show_summary(domain_name)
@@ -141,9 +185,9 @@ module PostfixAdmin
141
185
  puts_deleted(domain_name)
142
186
  end
143
187
 
144
- def show_admin(domain_name=nil)
145
- admins = domain_name ? Admin.select{|a| a.has_domain?(domain_name)} : Admin.all
146
- index = " No. Admin Domains Password"
188
+ def show_admin(domain_name = nil)
189
+ admins = domain_name ? Admin.select { |a| a.rel_domains.exists?(domain_name) } : Admin.all
190
+ index = " No. Admin Domains Active"
147
191
  report("Admins", index) do
148
192
  if admins.empty?
149
193
  puts " No admins"
@@ -151,18 +195,17 @@ module PostfixAdmin
151
195
  end
152
196
 
153
197
  admins.each_with_index do |a, i|
154
- domains = a.super_admin? ? 'Super admin' : a.domains.count
155
- puts "%4d %-40s %11s %s" % [i+1, a.username, domains, a.password]
198
+ domains = a.super_admin? ? 'Super admin' : a.rel_domains.count
199
+ puts "%4d %-40s %11s %-3s" % [i+1, a.username, domains, a.active_str]
156
200
  end
157
201
  end
158
-
159
202
  end
160
203
 
161
204
  def show_address(domain_name)
162
205
  domain_check(domain_name)
163
206
 
164
- mailboxes = Domain.find(domain_name).mailboxes
165
- index = " No. Email Quota (MB) Password Maildir"
207
+ mailboxes = Domain.find(domain_name).rel_mailboxes
208
+ index = " No. Email Name Quota (MB) Active Maildir"
166
209
  report("Addresses", index) do
167
210
  if mailboxes.empty?
168
211
  puts " No addresses"
@@ -171,16 +214,15 @@ module PostfixAdmin
171
214
 
172
215
  mailboxes.each_with_index do |m, i|
173
216
  quota = m.quota.to_f/ KB_TO_MB.to_f
174
- puts "%4d %-40s %10s %-15s %s" % [i+1, m.username, max_str(quota.to_i), m.password, m.maildir]
217
+ puts "%4d %-30s %-20s %10s %-3s %s" % [i+1, m.username, m.name, max_str(quota.to_i), m.active_str, m.maildir]
175
218
  end
176
219
  end
177
-
178
220
  end
179
221
 
180
222
  def show_alias(domain_name)
181
223
  domain_check(domain_name)
182
224
 
183
- forwards, aliases = Domain.find(domain_name).aliases.partition{|a| a.mailbox?}
225
+ forwards, aliases = Domain.find(domain_name).rel_aliases.partition { |a| a.mailbox? }
184
226
 
185
227
  forwards.delete_if do |f|
186
228
  f.address == f.goto
@@ -192,21 +234,22 @@ module PostfixAdmin
192
234
 
193
235
  def show_admin_domain(user_name)
194
236
  admin = Admin.find(user_name)
195
- if admin.domains.empty?
237
+ if admin.rel_domains.empty?
196
238
  puts "\nNo domain in database"
197
239
  return
198
240
  end
199
241
 
200
242
  report("Domains (#{user_name})", " No. Domain") do
201
- admin.domains.each_with_index do |d, i|
202
- puts "%4d %-30s" % [i+1, d.domain_name]
243
+ admin.rel_domains.each_with_index do |d, i|
244
+ puts "%4d %-30s" % [i + 1, d.domain]
203
245
  end
204
246
  end
205
247
  end
206
248
 
207
- def add_admin(user_name, password, super_admin=false)
249
+ def add_admin(user_name, password, super_admin = false, scheme = nil)
208
250
  validate_password(password)
209
- @base.add_admin(user_name, password)
251
+
252
+ @base.add_admin(user_name, hashed_password(password, scheme))
210
253
  if super_admin
211
254
  Admin.find(user_name).super_admin = true
212
255
  puts_registered(user_name, "a super admin")
@@ -225,10 +268,12 @@ module PostfixAdmin
225
268
  puts "#{domain_name} was successfully deleted from #{user_name}"
226
269
  end
227
270
 
228
- def add_account(address, password)
271
+ def add_account(address, password, scheme = nil, name = nil)
229
272
  validate_password(password)
230
- @base.add_account(address, password)
273
+
274
+ @base.add_account(address, hashed_password(password, scheme), name)
231
275
  puts_registered(address, "an account")
276
+ show_account_details(address)
232
277
  end
233
278
 
234
279
  def add_alias(address, goto)
@@ -239,11 +284,30 @@ module PostfixAdmin
239
284
  def edit_account(address, options)
240
285
  mailbox_check(address)
241
286
  mailbox = Mailbox.find(address)
287
+ mailbox.name = options[:name] if options[:name]
242
288
  mailbox.quota = options[:quota] * KB_TO_MB if options[:quota]
243
- mailbox.save or raise "Could not save Mailbox"
289
+ mailbox.active = options[:active] unless options[:active].nil?
290
+ mailbox.save!
291
+
292
+ if options[:goto]
293
+ mail_alias = Alias.find(address)
294
+ mail_alias.goto = options[:goto]
295
+ mail_alias.save!
296
+ end
244
297
 
245
298
  puts "Successfully updated #{address}"
246
- show_account(address)
299
+ show_account_details(address)
300
+ end
301
+
302
+ def edit_alias(address, options)
303
+ alias_check(address)
304
+ mail_alias = Alias.find(address)
305
+ mail_alias.goto = options[:goto] if options[:goto]
306
+ mail_alias.active = options[:active] unless options[:active].nil?
307
+ mail_alias.save or raise "Could not save Alias"
308
+
309
+ puts "Successfully updated #{address}"
310
+ show_alias_details(address)
247
311
  end
248
312
 
249
313
  def delete_alias(address)
@@ -261,17 +325,56 @@ module PostfixAdmin
261
325
  puts_deleted(address)
262
326
  end
263
327
 
328
+ def log
329
+ Log.all.each do |l|
330
+ time = l.timestamp.strftime("%Y-%m-%d %X %Z")
331
+ puts "#{time} #{l.username} #{l.domain} #{l.action} #{l.data}"
332
+ end
333
+ end
334
+
335
+ def dump
336
+ puts "Admins"
337
+ puts "User Name,Password,Super Admin,Active"
338
+ Admin.all.each do |a|
339
+ puts [a.username, %Q!"#{a.password}"!, a.super_admin?, a.active].join(',')
340
+ end
341
+ puts
342
+ puts "Domains"
343
+ puts "Domain Name,Max Quota,Active"
344
+ Domain.without_all.each do |d|
345
+ puts [d.domain, d.maxquota, d.active].join(',')
346
+ end
347
+ puts
348
+ puts "Mailboxes"
349
+ puts "User Name,Name,Password,Quota,Maildir,Active"
350
+ Mailbox.all.each do |m|
351
+ puts [m.username, %Q!"#{m.name}"!, %Q!"#{m.password}"!, m.quota, %Q!"#{m.maildir}"!, m.active].join(',')
352
+ end
353
+ puts
354
+ puts "Aliases"
355
+ puts "Address,Go to,Active"
356
+ Alias.all.select { |a| !a.mailbox? }.each do |a|
357
+ puts [a.address, %Q!"#{a.goto}"!, a.active].join(',')
358
+ end
359
+ puts
360
+ puts "Forwards"
361
+ puts "Address,Go to,Active"
362
+ Alias.all.select { |a| a.mailbox? && a.goto != a.address }.each do |a|
363
+ puts [a.address, %Q!"#{a.goto}"!, a.active].join(',')
364
+ end
365
+ end
366
+
264
367
  private
265
368
 
266
369
  def show_alias_base(title, addresses)
267
- report(title, " No. Address Go to") do
370
+ report(title, " No. Address Active Go to") do
268
371
  if addresses.empty?
269
372
  puts " No #{title.downcase}"
270
373
  next
271
374
  end
272
375
 
273
376
  addresses.each_with_index do |a, i|
274
- puts "%4d %-40s %s" % [i+1, a.address, a.goto]
377
+ puts "%4d %-40s %-3s %s" % [i+1, a.address, a.active_str, a.goto]
275
378
  end
276
379
  end
277
380
  end
@@ -310,7 +413,7 @@ module PostfixAdmin
310
413
  puts "-"*120
311
414
  end
312
415
 
313
- def report(title, index=nil)
416
+ def report(title, index = nil)
314
417
  puts "\n[#{title}]"
315
418
  print_line if index
316
419
  puts index if index
@@ -320,7 +423,7 @@ module PostfixAdmin
320
423
  end
321
424
 
322
425
  def account_check(user_name)
323
- unless Mailbox.exist?(user_name) && Alias.exist?(user_name)
426
+ unless Mailbox.exists?(user_name) && Alias.exists?(user_name)
324
427
  raise Error, %Q!Could not find account "#{user_name}"!
325
428
  end
326
429
  end
@@ -333,13 +436,17 @@ module PostfixAdmin
333
436
  klass_check(Mailbox, address)
334
437
  end
335
438
 
439
+ def alias_check(address)
440
+ klass_check(Alias, address)
441
+ end
442
+
336
443
  def admin_check(user_name)
337
444
  klass_check(Admin, user_name)
338
445
  end
339
446
 
340
447
  def klass_check(klass, name)
341
448
  object_name = klass.name.gsub(/PostfixAdmin::/, '').downcase
342
- raise Error, %Q!Could not find #{object_name} "#{name}"! unless klass.exist?(name)
449
+ raise Error, %Q!Could not find #{object_name} "#{name}"! unless klass.exists?(name)
343
450
  end
344
451
 
345
452
  def validate_password(password)
@@ -349,13 +456,13 @@ module PostfixAdmin
349
456
  end
350
457
 
351
458
  def change_password(klass, user_name, password)
352
- raise Error, "Could not find #{user_name}" unless klass.exist?(user_name)
459
+ raise Error, "Could not find #{user_name}" unless klass.exists?(user_name)
353
460
 
354
461
  validate_password(password)
355
462
 
356
463
  obj = klass.find(user_name)
357
- obj.password = password
358
- if obj.save
464
+
465
+ if obj.update(password: hashed_password(password))
359
466
  puts "the password of #{user_name} was successfully changed."
360
467
  else
361
468
  raise "Could not change password of #{klass.name}"
@@ -373,5 +480,13 @@ module PostfixAdmin
373
480
  end
374
481
  end
375
482
 
483
+ private
484
+
485
+ def hashed_password(password, in_scheme = nil)
486
+ prefix = @base.config[:passwordhash_prefix]
487
+ scheme = in_scheme || @base.config[:scheme]
488
+ puts "scheme: #{scheme}"
489
+ PostfixAdmin::Doveadm.password(password, scheme, prefix)
490
+ end
376
491
  end
377
492
  end