postfix_admin 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +54 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +20 -0
- data/CHANGELOG.md +19 -8
- data/Gemfile +1 -1
- data/LICENSE +1 -1
- data/README.md +26 -20
- data/Rakefile +19 -1
- data/bin/console +6 -2
- data/docker-admin/Dockerfile +6 -0
- data/docker-admin/config.local.php +24 -0
- data/docker-app/Dockerfile +21 -0
- data/docker-app/my.cnf +5 -0
- data/docker-compose.yml +37 -11
- data/docker-db/postfix.v1841.sql +383 -0
- data/docker-db/postfix.v352.sql +223 -0
- data/docker-db/postfix.v740.sql +269 -0
- data/lib/postfix_admin/admin.rb +17 -2
- data/lib/postfix_admin/alias.rb +0 -19
- data/lib/postfix_admin/base.rb +120 -94
- data/lib/postfix_admin/cli.rb +184 -127
- data/lib/postfix_admin/concerns/dovecot_cram_md5_password.rb +0 -1
- data/lib/postfix_admin/domain.rb +35 -44
- data/lib/postfix_admin/doveadm.rb +11 -10
- data/lib/postfix_admin/mailbox.rb +14 -6
- data/lib/postfix_admin/runner.rb +35 -22
- data/lib/postfix_admin/version.rb +1 -1
- data/postfix_admin.gemspec +13 -9
- metadata +55 -21
- data/Dockerfile +0 -24
- data/docker-entrypoint.sh +0 -5
data/lib/postfix_admin/cli.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'postfix_admin'
|
3
3
|
require 'postfix_admin/doveadm'
|
4
|
+
require 'terminal-table'
|
4
5
|
|
5
6
|
module PostfixAdmin
|
6
7
|
class CLI
|
7
|
-
|
8
|
+
DEFAULT_CONFIG_PATH = '~/.postfix_admin.conf'
|
9
|
+
@config_file = DEFAULT_CONFIG_PATH
|
8
10
|
MIN_NUM_PASSWORD_CHARACTER = 5
|
9
11
|
|
10
12
|
def initialize
|
@@ -28,55 +30,49 @@ module PostfixAdmin
|
|
28
30
|
name = name.downcase if name
|
29
31
|
|
30
32
|
if name =~ /@/
|
33
|
+
# address like argument
|
31
34
|
if Admin.exists?(name)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
# admin
|
36
|
+
show_admin_details(name, display_password: true)
|
37
|
+
puts
|
38
|
+
show_admin_domain(name)
|
39
|
+
elsif Mailbox.exists?(name)
|
40
|
+
# mailbox
|
41
|
+
show_account_details(name, display_password: true)
|
37
42
|
elsif Alias.exists?(name)
|
43
|
+
# alias
|
38
44
|
show_alias_details(name)
|
45
|
+
else
|
46
|
+
raise Error, "Could not find admin/mailbox/alias #{name}"
|
39
47
|
end
|
40
48
|
|
41
49
|
return
|
42
50
|
end
|
43
51
|
|
44
52
|
show_summary(name)
|
53
|
+
puts
|
45
54
|
|
46
55
|
if name
|
47
|
-
|
48
|
-
|
49
|
-
show_alias(name)
|
56
|
+
# domain name
|
57
|
+
show_domain_details(name)
|
50
58
|
else
|
59
|
+
# no argument: show all domains and admins
|
51
60
|
show_domain
|
61
|
+
puts
|
52
62
|
show_admin
|
53
63
|
end
|
54
64
|
end
|
55
65
|
|
56
66
|
def show_summary(domain_name = nil)
|
57
|
-
title = "Summary"
|
58
67
|
if domain_name
|
59
|
-
domain_name
|
60
|
-
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
report(title) do
|
65
|
-
if domain_name
|
66
|
-
domain = Domain.find(domain_name)
|
67
|
-
puts "Mailboxes : %4d / %4s" % [domain.rel_mailboxes.count, max_str(domain.mailboxes)]
|
68
|
-
puts "Aliases : %4d / %4s" % [domain.pure_aliases.count, max_str(domain.aliases)]
|
69
|
-
puts "Max Quota : %4d MB" % domain.maxquota
|
70
|
-
puts "Active : %3s" % domain.active_str
|
71
|
-
else
|
72
|
-
puts "Domains : %4d" % Domain.without_all.count
|
73
|
-
puts "Admins : %4d" % Admin.count
|
74
|
-
puts "Mailboxes : %4d" % Mailbox.count
|
75
|
-
puts "Aliases : %4d" % Alias.pure.count
|
76
|
-
end
|
68
|
+
show_domain_summary(domain_name)
|
69
|
+
else
|
70
|
+
show_general_summary
|
77
71
|
end
|
78
72
|
end
|
79
73
|
|
74
|
+
# Set up a domain
|
75
|
+
# Add a domain, add an admin, and grant the admin access to the domain
|
80
76
|
def setup_domain(domain_name, password)
|
81
77
|
admin = "admin@#{domain_name}"
|
82
78
|
add_domain(domain_name)
|
@@ -84,62 +80,75 @@ module PostfixAdmin
|
|
84
80
|
add_admin_domain(admin, domain_name)
|
85
81
|
end
|
86
82
|
|
87
|
-
def show_account_details(user_name)
|
83
|
+
def show_account_details(user_name, display_password: false)
|
88
84
|
account_check(user_name)
|
89
85
|
mailbox = Mailbox.find(user_name)
|
90
86
|
mail_alias = Alias.find(user_name)
|
91
87
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
88
|
+
rows = []
|
89
|
+
puts_title("Mailbox")
|
90
|
+
rows << ["Address", mailbox.username]
|
91
|
+
rows << ["Name", mailbox.name]
|
92
|
+
rows << ["Password", mailbox.password] if display_password
|
93
|
+
rows << ["Quota (MB)", mailbox.quota_mb_str]
|
94
|
+
rows << ["Go to", mail_alias.goto]
|
95
|
+
rows << ["Active", mailbox.active_str]
|
96
|
+
|
97
|
+
puts_table(rows: rows)
|
100
98
|
end
|
101
99
|
|
102
|
-
def show_admin_details(name)
|
100
|
+
def show_admin_details(name, display_password: false)
|
103
101
|
admin_check(name)
|
104
102
|
admin = Admin.find(name)
|
105
103
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
104
|
+
rows = []
|
105
|
+
puts_title("Admin")
|
106
|
+
rows << ["Name", admin.username]
|
107
|
+
rows << ["Password", admin.password] if display_password
|
108
|
+
rows << ["Domains", admin.super_admin? ? "ALL" : admin.rel_domains.count.to_s]
|
109
|
+
rows << ["Role", admin.super_admin? ? "Super Admin" : "Standard Admin"]
|
110
|
+
rows << ["Active", admin.active_str]
|
111
|
+
|
112
|
+
puts_table(rows: rows)
|
113
113
|
end
|
114
114
|
|
115
115
|
def show_alias_details(name)
|
116
116
|
alias_check(name)
|
117
117
|
mail_alias = Alias.find(name)
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
118
|
+
|
119
|
+
rows = []
|
120
|
+
puts_title("Alias")
|
121
|
+
rows << ["Address", mail_alias.address]
|
122
|
+
rows << ["Go to", mail_alias.goto]
|
123
|
+
rows << ["Active", mail_alias.active_str]
|
124
|
+
|
125
|
+
puts_table(rows: rows)
|
123
126
|
end
|
124
127
|
|
125
128
|
def show_domain
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
puts " No domains"
|
130
|
-
next
|
131
|
-
end
|
129
|
+
rows = []
|
130
|
+
headings = ["No.", "Domain", "Aliases", "Mailboxes","Max Quota (MB)",
|
131
|
+
"Active", "Description"]
|
132
132
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
133
|
+
puts_title("Domains")
|
134
|
+
if Domain.without_all.empty?
|
135
|
+
puts "No domains"
|
136
|
+
return
|
137
|
+
end
|
138
|
+
|
139
|
+
Domain.without_all.each_with_index do |d, i|
|
140
|
+
no = i + 1
|
141
|
+
aliases_str = "%4d / %4s" % [d.pure_aliases.count, d.aliases_str]
|
142
|
+
mailboxes_str = "%4d / %4s" % [d.rel_mailboxes.count, d.mailboxes_str]
|
143
|
+
rows << [no.to_s, d.domain, aliases_str, mailboxes_str,
|
144
|
+
d.maxquota_str, d.active_str, d.description]
|
138
145
|
end
|
146
|
+
|
147
|
+
puts_table(headings: headings, rows: rows)
|
139
148
|
end
|
140
149
|
|
141
|
-
def add_domain(domain_name)
|
142
|
-
@base.add_domain(domain_name)
|
150
|
+
def add_domain(domain_name, description: nil)
|
151
|
+
@base.add_domain(domain_name, description: description)
|
143
152
|
puts_registered(domain_name, "a domain")
|
144
153
|
end
|
145
154
|
|
@@ -173,6 +182,7 @@ module PostfixAdmin
|
|
173
182
|
domain.mailboxes = options[:mailboxes] if options[:mailboxes]
|
174
183
|
domain.maxquota = options[:maxquota] if options[:maxquota]
|
175
184
|
domain.active = options[:active] unless options[:active].nil?
|
185
|
+
domain.description = options[:description] if options[:description]
|
176
186
|
domain.save!
|
177
187
|
|
178
188
|
puts "Successfully updated #{domain_name}"
|
@@ -186,36 +196,44 @@ module PostfixAdmin
|
|
186
196
|
|
187
197
|
def show_admin(domain_name = nil)
|
188
198
|
admins = domain_name ? Admin.select { |a| a.rel_domains.exists?(domain_name) } : Admin.all
|
189
|
-
|
190
|
-
report("Admins", index) do
|
191
|
-
if admins.empty?
|
192
|
-
puts " No admins"
|
193
|
-
next
|
194
|
-
end
|
199
|
+
headings = %w[No. Admin Domains Active]
|
195
200
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
201
|
+
puts_title("Admins")
|
202
|
+
if admins.empty?
|
203
|
+
puts "No admins"
|
204
|
+
return
|
200
205
|
end
|
206
|
+
|
207
|
+
rows = []
|
208
|
+
admins.each_with_index do |a, i|
|
209
|
+
no = i + 1
|
210
|
+
domains = a.super_admin? ? 'Super Admin' : a.rel_domains.count
|
211
|
+
rows << [no.to_s, a.username, domains.to_s, a.active_str]
|
212
|
+
end
|
213
|
+
|
214
|
+
puts_table(headings: headings, rows: rows)
|
201
215
|
end
|
202
216
|
|
203
217
|
def show_address(domain_name)
|
204
218
|
domain_check(domain_name)
|
205
219
|
|
220
|
+
rows = []
|
206
221
|
mailboxes = Domain.find(domain_name).rel_mailboxes
|
207
|
-
|
208
|
-
report("Addresses", index) do
|
209
|
-
if mailboxes.empty?
|
210
|
-
puts " No addresses"
|
211
|
-
next
|
212
|
-
end
|
222
|
+
headings = ["No.", "Email", "Name", "Quota (MB)", "Active", "Maildir"]
|
213
223
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
224
|
+
puts_title("Addresses")
|
225
|
+
if mailboxes.empty?
|
226
|
+
puts "No addresses"
|
227
|
+
return
|
228
|
+
end
|
229
|
+
|
230
|
+
mailboxes.each_with_index do |m, i|
|
231
|
+
no = i + 1
|
232
|
+
rows << [no.to_s, m.username, m.name, m.quota_mb_str,
|
233
|
+
m.active_str, m.maildir]
|
218
234
|
end
|
235
|
+
|
236
|
+
puts_table(headings: headings, rows: rows)
|
219
237
|
end
|
220
238
|
|
221
239
|
def show_alias(domain_name)
|
@@ -228,21 +246,24 @@ module PostfixAdmin
|
|
228
246
|
end
|
229
247
|
|
230
248
|
show_alias_base("Forwards", forwards)
|
249
|
+
puts
|
231
250
|
show_alias_base("Aliases", aliases)
|
232
251
|
end
|
233
252
|
|
234
253
|
def show_admin_domain(user_name)
|
235
254
|
admin = Admin.find(user_name)
|
255
|
+
puts_title("Admin Domains (#{user_name})")
|
236
256
|
if admin.rel_domains.empty?
|
237
|
-
puts "\nNo
|
257
|
+
puts "\nNo domains for #{user_name}"
|
238
258
|
return
|
239
259
|
end
|
240
260
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
261
|
+
rows = []
|
262
|
+
admin.rel_domains.each_with_index do |d, i|
|
263
|
+
no = i + 1
|
264
|
+
rows << [no.to_s, d.domain]
|
245
265
|
end
|
266
|
+
puts_table(rows: rows, headings: %w[No. Domain])
|
246
267
|
end
|
247
268
|
|
248
269
|
def add_admin(user_name, password, super_admin = false, scheme = nil)
|
@@ -270,9 +291,8 @@ module PostfixAdmin
|
|
270
291
|
def add_account(address, password, scheme = nil, name = nil)
|
271
292
|
validate_password(password)
|
272
293
|
|
273
|
-
@base.add_account(address, hashed_password(password, scheme), name)
|
294
|
+
@base.add_account(address, hashed_password(password, scheme), name: name)
|
274
295
|
puts_registered(address, "an account")
|
275
|
-
show_account_details(address)
|
276
296
|
end
|
277
297
|
|
278
298
|
def add_alias(address, goto)
|
@@ -324,11 +344,25 @@ module PostfixAdmin
|
|
324
344
|
puts_deleted(address)
|
325
345
|
end
|
326
346
|
|
327
|
-
def log
|
328
|
-
|
329
|
-
|
330
|
-
|
347
|
+
def log(domain: nil, last: nil)
|
348
|
+
headings = %w[Timestamp Admin Domain Action Data]
|
349
|
+
rows = []
|
350
|
+
|
351
|
+
logs = if domain
|
352
|
+
Log.where(domain: domain)
|
353
|
+
else
|
354
|
+
Log.all
|
355
|
+
end
|
356
|
+
|
357
|
+
logs = logs.last(last) if last
|
358
|
+
|
359
|
+
logs.each do |l|
|
360
|
+
# TODO: Consider if zone should be included ('%Z').
|
361
|
+
time = l.timestamp.strftime("%Y-%m-%d %X")
|
362
|
+
rows << [time, l.username, l.domain, l.action, l.data]
|
331
363
|
end
|
364
|
+
|
365
|
+
puts_table(headings: headings, rows: rows)
|
332
366
|
end
|
333
367
|
|
334
368
|
def dump
|
@@ -365,17 +399,58 @@ module PostfixAdmin
|
|
365
399
|
|
366
400
|
private
|
367
401
|
|
402
|
+
def show_general_summary
|
403
|
+
rows = []
|
404
|
+
title = "Summary"
|
405
|
+
rows << ["Domains", Domain.without_all.count]
|
406
|
+
rows << ["Admins", Admin.count]
|
407
|
+
rows << ["Mailboxes", Mailbox.count]
|
408
|
+
rows << ["Aliases", Alias.pure.count]
|
409
|
+
|
410
|
+
puts_title(title)
|
411
|
+
puts_table(rows: rows)
|
412
|
+
end
|
413
|
+
|
414
|
+
def show_domain_summary(domain_name)
|
415
|
+
domain_name = domain_name.downcase
|
416
|
+
domain_check(domain_name)
|
417
|
+
|
418
|
+
rows = []
|
419
|
+
domain = Domain.find(domain_name)
|
420
|
+
rows << ["Mailboxes", "%4d / %4s" % [domain.rel_mailboxes.count, domain.mailboxes_str]]
|
421
|
+
rows << ["Aliases", "%4d / %4s" % [domain.pure_aliases.count, domain.aliases_str]]
|
422
|
+
rows << ["Max Quota (MB)", domain.maxquota_str]
|
423
|
+
rows << ["Active", domain.active_str]
|
424
|
+
rows << ["Description", domain.description]
|
425
|
+
|
426
|
+
puts_title(domain_name)
|
427
|
+
puts_table(rows: rows)
|
428
|
+
end
|
429
|
+
|
430
|
+
def show_domain_details(domain_name)
|
431
|
+
show_admin(domain_name)
|
432
|
+
puts
|
433
|
+
show_address(domain_name)
|
434
|
+
puts
|
435
|
+
show_alias(domain_name)
|
436
|
+
end
|
437
|
+
|
368
438
|
def show_alias_base(title, addresses)
|
369
|
-
|
370
|
-
|
371
|
-
puts " No #{title.downcase}"
|
372
|
-
next
|
373
|
-
end
|
439
|
+
rows = []
|
440
|
+
puts_title(title)
|
374
441
|
|
375
|
-
|
376
|
-
|
377
|
-
|
442
|
+
if addresses.empty?
|
443
|
+
puts "No #{title.downcase}"
|
444
|
+
return
|
378
445
|
end
|
446
|
+
|
447
|
+
headings = ["No.", "Address", "Active", "Go to"]
|
448
|
+
addresses.each_with_index do |a, i|
|
449
|
+
no = i + 1
|
450
|
+
rows << [no.to_s, a.address, a.active_str, a.goto]
|
451
|
+
end
|
452
|
+
|
453
|
+
puts_table(headings: headings, rows: rows)
|
379
454
|
end
|
380
455
|
|
381
456
|
def puts_registered(name, as_str)
|
@@ -387,7 +462,7 @@ module PostfixAdmin
|
|
387
462
|
end
|
388
463
|
|
389
464
|
def config_file
|
390
|
-
|
465
|
+
File.expand_path(CLI.config_file)
|
391
466
|
end
|
392
467
|
|
393
468
|
def load_config
|
@@ -408,17 +483,12 @@ module PostfixAdmin
|
|
408
483
|
File.chmod(0600, file)
|
409
484
|
end
|
410
485
|
|
411
|
-
def
|
412
|
-
puts
|
486
|
+
def puts_table(args)
|
487
|
+
puts Terminal::Table.new(args)
|
413
488
|
end
|
414
489
|
|
415
|
-
def
|
416
|
-
puts "
|
417
|
-
print_line if index
|
418
|
-
puts index if index
|
419
|
-
print_line
|
420
|
-
yield
|
421
|
-
print_line
|
490
|
+
def puts_title(title)
|
491
|
+
puts "| #{title} |"
|
422
492
|
end
|
423
493
|
|
424
494
|
def account_check(user_name)
|
@@ -468,23 +538,10 @@ module PostfixAdmin
|
|
468
538
|
end
|
469
539
|
end
|
470
540
|
|
471
|
-
def max_str(value)
|
472
|
-
case value
|
473
|
-
when 0
|
474
|
-
'--'
|
475
|
-
when -1
|
476
|
-
'0'
|
477
|
-
else
|
478
|
-
value.to_s
|
479
|
-
end
|
480
|
-
end
|
481
|
-
|
482
|
-
private
|
483
|
-
|
484
541
|
def hashed_password(password, in_scheme = nil)
|
542
|
+
prefix = @base.config[:passwordhash_prefix]
|
485
543
|
scheme = in_scheme || @base.config[:scheme]
|
486
|
-
|
487
|
-
PostfixAdmin::Doveadm.password(password, scheme)
|
544
|
+
PostfixAdmin::Doveadm.password(password, scheme, prefix)
|
488
545
|
end
|
489
546
|
end
|
490
547
|
end
|
data/lib/postfix_admin/domain.rb
CHANGED
@@ -8,91 +8,82 @@ module PostfixAdmin
|
|
8
8
|
message: "must be a valid domain name" }
|
9
9
|
validates :transport, presence: true
|
10
10
|
|
11
|
+
# max aliases (Disabled: -1, Unlimited: 0)
|
11
12
|
validates :aliases, presence: true,
|
12
13
|
numericality: { only_integer: true,
|
13
|
-
greater_than_or_equal_to:
|
14
|
+
greater_than_or_equal_to: -1 }
|
15
|
+
# max mailboxes (Disabled: -1, Unlimited: 0)
|
14
16
|
validates :mailboxes, presence: true,
|
15
17
|
numericality: { only_integer: true,
|
16
|
-
greater_than_or_equal_to:
|
18
|
+
greater_than_or_equal_to: -1 }
|
19
|
+
|
20
|
+
# max quota (MB) for each mailbox (Unlimited: 0)
|
21
|
+
# It's not sure what 'disabled' means for max quota.
|
22
|
+
# So it's better not to allow users to set `maxquota` to -1.
|
17
23
|
validates :maxquota, presence: true,
|
18
24
|
numericality: { only_integer: true,
|
19
25
|
greater_than_or_equal_to: 0 }
|
20
26
|
|
27
|
+
# mailboxes that belong to this domain
|
21
28
|
has_many :rel_mailboxes, class_name: "Mailbox", foreign_key: :domain,
|
22
29
|
dependent: :destroy
|
30
|
+
# aliases that belong to this domain
|
23
31
|
has_many :rel_aliases, class_name: "Alias", foreign_key: :domain,
|
24
32
|
dependent: :destroy
|
25
33
|
|
34
|
+
# It causes errors to set `dependent: :destroy` as other columns
|
35
|
+
# because the domain_admins table doesn't have a single primary key.
|
36
|
+
#
|
37
|
+
# PostfixAdmin::DomainAdmin Load (0.5ms) SELECT `domain_admins`.* FROM `domain_admins` WHERE `domain_admins`.`domain` = 'example.com'
|
38
|
+
# PostfixAdmin::DomainAdmin Destroy (1.1ms) DELETE FROM `domain_admins` WHERE `domain_admins`.`` IS NULL
|
39
|
+
#
|
40
|
+
# ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'domain_admins.' in 'where clause'
|
41
|
+
# from /usr/local/bundle/gems/mysql2-0.5.4/lib/mysql2/client.rb:148:in `_query'
|
42
|
+
# Caused by Mysql2::Error: Unknown column 'domain_admins.' in 'where clause'
|
43
|
+
# from /usr/local/bundle/gems/mysql2-0.5.4/lib/mysql2/client.rb:148:in `_query'
|
44
|
+
#
|
45
|
+
# It works well with `dependent: :delete_all` instead.
|
46
|
+
#
|
47
|
+
# PostfixAdmin::DomainAdmin Destroy (0.4ms) DELETE FROM `domain_admins` WHERE `domain_admins`.`domain` = 'example.com'
|
26
48
|
has_many :domain_admins, foreign_key: :domain, dependent: :delete_all
|
49
|
+
|
27
50
|
has_many :admins, through: :domain_admins
|
28
51
|
|
29
52
|
before_validation do |domain|
|
30
|
-
domain.domain = domain.domain
|
53
|
+
domain.domain = domain.domain&.downcase
|
31
54
|
domain.transport = "virtual"
|
32
55
|
end
|
33
56
|
|
34
57
|
scope :without_all, -> { where.not(domain: "ALL") }
|
35
58
|
|
59
|
+
# aliases that don't belong to a mailbox
|
36
60
|
def pure_aliases
|
37
61
|
rel_aliases.pure
|
38
62
|
end
|
39
63
|
|
40
|
-
def aliases_unlimited?
|
41
|
-
aliases.zero?
|
42
|
-
end
|
43
|
-
|
44
|
-
def mailboxes_unlimited?
|
45
|
-
mailboxes.zero?
|
46
|
-
end
|
47
|
-
|
48
64
|
def aliases_str
|
49
|
-
|
65
|
+
max_num_str(aliases)
|
50
66
|
end
|
51
67
|
|
52
68
|
def mailboxes_str
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
def aliases_short_str
|
57
|
-
num_short_str(aliases)
|
58
|
-
end
|
59
|
-
|
60
|
-
def mailboxes_short_str
|
61
|
-
num_short_str(mailboxes)
|
69
|
+
max_num_str(mailboxes)
|
62
70
|
end
|
63
71
|
|
64
72
|
def maxquota_str
|
65
|
-
|
66
|
-
"Unlimited"
|
67
|
-
else
|
68
|
-
"#{maxquota} MB"
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def maxquota_short_str
|
73
|
-
if maxquota.zero?
|
74
|
-
"--"
|
75
|
-
else
|
76
|
-
"#{maxquota} MB"
|
77
|
-
end
|
73
|
+
max_num_str(maxquota)
|
78
74
|
end
|
79
75
|
|
80
76
|
private
|
81
77
|
|
82
|
-
def
|
83
|
-
|
78
|
+
def max_num_str(num)
|
79
|
+
case num
|
80
|
+
when -1
|
81
|
+
"Disabled"
|
82
|
+
when 0
|
84
83
|
"Unlimited"
|
85
84
|
else
|
86
85
|
num.to_s
|
87
86
|
end
|
88
87
|
end
|
89
|
-
|
90
|
-
def num_short_str(num)
|
91
|
-
if num.zero?
|
92
|
-
"--"
|
93
|
-
else
|
94
|
-
num.to_s
|
95
|
-
end
|
96
|
-
end
|
97
88
|
end
|
98
89
|
end
|
@@ -9,24 +9,25 @@ module PostfixAdmin
|
|
9
9
|
result.split
|
10
10
|
end
|
11
11
|
|
12
|
-
def self.password(in_password, in_scheme)
|
12
|
+
def self.password(in_password, in_scheme, prefix)
|
13
13
|
password = Shellwords.escape(in_password)
|
14
|
-
scheme
|
15
|
-
|
14
|
+
scheme = Shellwords.escape(in_scheme)
|
15
|
+
_stdin, stdout, stderr = Open3.popen3("#{self.command_name} -s #{scheme} -p #{password}")
|
16
|
+
|
16
17
|
if stderr.readlines.to_s =~ /Fatal:/
|
17
18
|
raise Error, stderr.readlines
|
18
19
|
else
|
19
|
-
stdout.readlines.first.chomp
|
20
|
+
res = stdout.readlines.first.chomp
|
21
|
+
if prefix
|
22
|
+
res
|
23
|
+
else
|
24
|
+
res.gsub("{#{scheme}}", "")
|
25
|
+
end
|
20
26
|
end
|
21
27
|
end
|
22
28
|
|
23
29
|
def self.command_name
|
24
|
-
|
25
|
-
Open3.capture3("doveadm pw -l")[2].exited?
|
26
|
-
"doveadm pw"
|
27
|
-
rescue Errno::ENOENT
|
28
|
-
"dovecotpw"
|
29
|
-
end
|
30
|
+
"doveadm pw"
|
30
31
|
end
|
31
32
|
end
|
32
33
|
end
|
@@ -12,9 +12,13 @@ module PostfixAdmin
|
|
12
12
|
message: "must be a valid email address" }
|
13
13
|
validates :maildir, presence: true, uniqueness: { case_sensitive: false }
|
14
14
|
validates :local_part, presence: true
|
15
|
+
|
16
|
+
# quota (KB)
|
15
17
|
validates :quota, presence: true,
|
16
18
|
numericality: { only_integer: true,
|
17
19
|
greater_than_or_equal_to: 0 }
|
20
|
+
|
21
|
+
# quota (MB), which actually doesn't exist in DB
|
18
22
|
validates :quota_mb, presence: true,
|
19
23
|
numericality: { only_integer: true,
|
20
24
|
greater_than_or_equal_to: 0 }
|
@@ -63,7 +67,7 @@ module PostfixAdmin
|
|
63
67
|
mailbox.quota = 0
|
64
68
|
end
|
65
69
|
mailbox.username = "#{mailbox.local_part}@#{mailbox.domain}"
|
66
|
-
mailbox.maildir
|
70
|
+
mailbox.maildir ||= "#{mailbox.domain}/#{mailbox.username}/"
|
67
71
|
mailbox.build_alias(local_part: mailbox.local_part, goto: mailbox.username,
|
68
72
|
domain: mailbox.domain)
|
69
73
|
end
|
@@ -77,12 +81,16 @@ module PostfixAdmin
|
|
77
81
|
end
|
78
82
|
end
|
79
83
|
|
80
|
-
def
|
81
|
-
|
82
|
-
|
84
|
+
def quota_mb_str
|
85
|
+
case quota
|
86
|
+
when -1
|
87
|
+
# It's not sure what 'disabled' means for quota.
|
88
|
+
"Disabled"
|
89
|
+
when 0
|
90
|
+
"Unlimited"
|
83
91
|
else
|
84
|
-
|
85
|
-
|
92
|
+
mb_size = quota / KB_TO_MB
|
93
|
+
mb_size.to_s
|
86
94
|
end
|
87
95
|
end
|
88
96
|
end
|