postfix_admin 0.2.1 → 0.3.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 +4 -4
- data/.github/workflows/ci.yml +52 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +20 -0
- data/CHANGELOG.md +26 -12
- data/Gemfile +1 -1
- data/LICENSE +1 -1
- data/README.md +26 -20
- data/Rakefile +48 -1
- data/bin/console +6 -2
- data/db/reset.rb +7 -0
- data/db/seeds.rb +26 -0
- data/docker-admin/config.local.php +6 -1
- data/docker-app/Dockerfile +2 -6
- data/docker-app/my.cnf +2 -2
- data/docker-compose.yml +20 -20
- data/lib/postfix_admin/base.rb +119 -112
- data/lib/postfix_admin/cli.rb +267 -158
- data/lib/postfix_admin/doveadm.rb +32 -20
- data/lib/postfix_admin/{admin.rb → models/admin.rb} +25 -2
- data/lib/postfix_admin/{alias.rb → models/alias.rb} +16 -26
- data/lib/postfix_admin/{application_record.rb → models/application_record.rb} +1 -1
- data/lib/postfix_admin/{concerns → models/concerns}/existing_timestamp.rb +1 -2
- data/lib/postfix_admin/models/concerns/has_password.rb +16 -0
- data/lib/postfix_admin/models/domain.rb +112 -0
- data/lib/postfix_admin/models/domain_admin.rb +19 -0
- data/lib/postfix_admin/models/log.rb +20 -0
- data/lib/postfix_admin/models/mailbox.rb +126 -0
- data/lib/postfix_admin/models/quota2.rb +18 -0
- data/lib/postfix_admin/models.rb +8 -9
- data/lib/postfix_admin/runner.rb +91 -28
- data/lib/postfix_admin/version.rb +1 -1
- data/postfix_admin.gemspec +12 -10
- metadata +61 -34
- data/.github/workflows/ruby.yml +0 -37
- data/docker-app/docker-entrypoint.sh +0 -5
- data/docker-app-2.5/Dockerfile +0 -15
- data/lib/postfix_admin/concerns/dovecot_cram_md5_password.rb +0 -30
- data/lib/postfix_admin/domain.rb +0 -98
- data/lib/postfix_admin/domain_admin.rb +0 -8
- data/lib/postfix_admin/log.rb +0 -5
- data/lib/postfix_admin/mail_domain.rb +0 -9
- data/lib/postfix_admin/mailbox.rb +0 -89
- data/lib/postfix_admin/quota.rb +0 -6
- /data/lib/postfix_admin/{concerns → models/concerns}/.keep +0 -0
@@ -1,36 +1,48 @@
|
|
1
|
-
|
2
1
|
require 'open3'
|
3
2
|
require 'shellwords'
|
4
3
|
|
5
4
|
module PostfixAdmin
|
6
5
|
class Doveadm
|
6
|
+
# doveadm-pw: https://doc.dovecot.org/3.0/man/doveadm-pw.1/
|
7
|
+
CMD_DOVEADM_PW = "doveadm pw"
|
8
|
+
|
9
|
+
# List all supported password schemes
|
7
10
|
def self.schemes
|
8
|
-
result = `#{
|
11
|
+
result = `#{CMD_DOVEADM_PW} -l`
|
9
12
|
result.split
|
10
13
|
end
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
# Generate a password hash using `doveadm pw` command
|
16
|
+
def self.password(password, scheme, rounds: nil, user_name: nil,
|
17
|
+
prefix: true)
|
18
|
+
escaped_password = Shellwords.escape(password)
|
19
|
+
escaped_scheme = Shellwords.escape(scheme)
|
20
|
+
|
21
|
+
cmd = "#{CMD_DOVEADM_PW} -s #{escaped_scheme} -p #{escaped_password}"
|
22
|
+
|
23
|
+
# DIGEST-MD5 requires -u option (user name)
|
24
|
+
if scheme == "DIGEST-MD5"
|
25
|
+
escaped_user_name = Shellwords.escape(user_name)
|
26
|
+
cmd << " -u #{escaped_user_name}"
|
27
|
+
end
|
28
|
+
|
29
|
+
if rounds
|
30
|
+
escaped_rounds = Shellwords.escape(rounds.to_s)
|
31
|
+
cmd << " -r #{rounds}"
|
32
|
+
end
|
33
|
+
|
34
|
+
output, error, status = Open3.capture3(cmd)
|
35
|
+
|
36
|
+
if status.success?
|
37
|
+
res = output.chomp
|
20
38
|
if prefix
|
21
39
|
res
|
22
40
|
else
|
23
|
-
|
41
|
+
# Remove the prefix
|
42
|
+
res.gsub("{#{escaped_scheme}}", "")
|
24
43
|
end
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
def self.command_name
|
29
|
-
begin
|
30
|
-
Open3.capture3("doveadm pw -l")[2].exited?
|
31
|
-
"doveadm pw"
|
32
|
-
rescue Errno::ENOENT
|
33
|
-
"dovecotpw"
|
44
|
+
else
|
45
|
+
raise Error, "#{CMD_DOVEADM_PW}: #{error}"
|
34
46
|
end
|
35
47
|
end
|
36
48
|
end
|
@@ -1,16 +1,34 @@
|
|
1
|
-
require 'postfix_admin/concerns/
|
1
|
+
require 'postfix_admin/models/concerns/has_password'
|
2
2
|
|
3
3
|
module PostfixAdmin
|
4
4
|
class Admin < ApplicationRecord
|
5
|
+
# version: 1841
|
6
|
+
# > describe admin;
|
7
|
+
# +----------------+--------------+------+-----+---------------------+-------+
|
8
|
+
# | Field | Type | Null | Key | Default | Extra |
|
9
|
+
# +----------------+--------------+------+-----+---------------------+-------+
|
10
|
+
# | username | varchar(255) | NO | PRI | NULL | |
|
11
|
+
# | password | varchar(255) | NO | | NULL | |
|
12
|
+
# | created | datetime | NO | | 2000-01-01 00:00:00 | |
|
13
|
+
# | modified | datetime | NO | | 2000-01-01 00:00:00 | |
|
14
|
+
# | active | tinyint(1) | NO | | 1 | |
|
15
|
+
# | superadmin | tinyint(1) | NO | | 0 | |
|
16
|
+
# | phone | varchar(30) | NO | | | |
|
17
|
+
# | email_other | varchar(255) | NO | | | |
|
18
|
+
# | token | varchar(255) | NO | | | |
|
19
|
+
# | token_validity | datetime | NO | | 2000-01-01 00:00:00 | |
|
20
|
+
# +----------------+--------------+------+-----+---------------------+-------+
|
21
|
+
|
5
22
|
self.table_name = :admin
|
6
23
|
self.primary_key = :username
|
7
24
|
|
8
|
-
include
|
25
|
+
include HasPassword
|
9
26
|
|
10
27
|
validates :username, presence: true, uniqueness: { case_sensitive: false },
|
11
28
|
format: { with: RE_EMAIL_LIKE_WITH_ANCHORS,
|
12
29
|
message: "must be a valid email address" }
|
13
30
|
|
31
|
+
# Admin <-> DomainAdmin <-> Domain
|
14
32
|
has_many :domain_admins, foreign_key: :username, dependent: :delete_all
|
15
33
|
has_many :rel_domains, through: :domain_admins
|
16
34
|
|
@@ -22,6 +40,11 @@ module PostfixAdmin
|
|
22
40
|
admin.errors.add(:username, 'cannot be changed') if admin.username_changed?
|
23
41
|
end
|
24
42
|
|
43
|
+
def reload
|
44
|
+
@super_admin = nil
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
25
48
|
def super_admin?
|
26
49
|
if @super_admin.nil?
|
27
50
|
@super_admin = if has_superadmin_column?
|
@@ -1,5 +1,18 @@
|
|
1
1
|
module PostfixAdmin
|
2
2
|
class Alias < ApplicationRecord
|
3
|
+
# version: 1841
|
4
|
+
# > describe alias;
|
5
|
+
# +----------+--------------+------+-----+---------------------+-------+
|
6
|
+
# | Field | Type | Null | Key | Default | Extra |
|
7
|
+
# +----------+--------------+------+-----+---------------------+-------+
|
8
|
+
# | address | varchar(255) | NO | PRI | NULL | |
|
9
|
+
# | goto | text | NO | | NULL | |
|
10
|
+
# | domain | varchar(255) | NO | MUL | NULL | |
|
11
|
+
# | created | datetime | NO | | 2000-01-01 00:00:00 | |
|
12
|
+
# | modified | datetime | NO | | 2000-01-01 00:00:00 | |
|
13
|
+
# | active | tinyint(1) | NO | | 1 | |
|
14
|
+
# +----------+--------------+------+-----+---------------------+-------+
|
15
|
+
|
3
16
|
self.table_name = :alias
|
4
17
|
self.primary_key = :address
|
5
18
|
|
@@ -21,34 +34,11 @@ module PostfixAdmin
|
|
21
34
|
belongs_to :rel_domain, class_name: "Domain", foreign_key: :domain
|
22
35
|
belongs_to :mailbox, foreign_key: :address, optional: true
|
23
36
|
|
37
|
+
# aliases which do not belong to any mailbox
|
24
38
|
scope :pure, -> { joins("LEFT OUTER JOIN mailbox ON alias.address = mailbox.username").where("mailbox.username" => nil) }
|
25
39
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
def forward_addresses
|
30
|
-
if @forward_addresses.nil?
|
31
|
-
if goto.nil?
|
32
|
-
[nil]
|
33
|
-
else
|
34
|
-
goto.split(",") + [nil]
|
35
|
-
end
|
36
|
-
else
|
37
|
-
@forward_addresses
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
before_validation do |a|
|
42
|
-
unless a.address
|
43
|
-
a.address = "#{a.local_part}@#{a.domain}" unless a.local_part.empty?
|
44
|
-
end
|
45
|
-
|
46
|
-
unless a.forward_addresses.empty?
|
47
|
-
forward_addresses = a.forward_addresses.dup
|
48
|
-
forward_addresses.delete_if { |f| f.blank? }
|
49
|
-
a.goto = forward_addresses.join(",")
|
50
|
-
end
|
51
|
-
end
|
40
|
+
# aliases which belong to a mailbox and have forwardings to other addresses
|
41
|
+
scope :forward, -> { joins("LEFT OUTER JOIN mailbox ON alias.address = mailbox.username").where("mailbox.username <> alias.goto") }
|
52
42
|
|
53
43
|
def mailbox?
|
54
44
|
!!mailbox
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module HasPassword
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
# example: {CRAM-MD5}, {BLF-CRYPT}, {PLAIN}
|
7
|
+
# return nil if no scheme prefix
|
8
|
+
def scheme_prefix
|
9
|
+
res = password&.match(/^\{.*?\}/)
|
10
|
+
if res
|
11
|
+
res[0]
|
12
|
+
else
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module PostfixAdmin
|
2
|
+
class Domain < ApplicationRecord
|
3
|
+
# version: 1841
|
4
|
+
# > describe domain;
|
5
|
+
# +-------------+--------------+------+-----+---------------------+-------+
|
6
|
+
# | Field | Type | Null | Key | Default | Extra |
|
7
|
+
# +-------------+--------------+------+-----+---------------------+-------+
|
8
|
+
# | domain | varchar(255) | NO | PRI | NULL | |
|
9
|
+
# | description | varchar(255) | NO | | NULL | |
|
10
|
+
# | aliases | int(10) | NO | | 0 | |
|
11
|
+
# | mailboxes | int(10) | NO | | 0 | |
|
12
|
+
# | maxquota | bigint(20) | NO | | 0 | |
|
13
|
+
# | quota | bigint(20) | NO | | 0 | |
|
14
|
+
# | transport | varchar(255) | NO | | NULL | |
|
15
|
+
# | backupmx | tinyint(1) | NO | | 0 | |
|
16
|
+
# | created | datetime | NO | | 2000-01-01 00:00:00 | |
|
17
|
+
# | modified | datetime | NO | | 2000-01-01 00:00:00 | |
|
18
|
+
# | active | tinyint(1) | NO | | 1 | |
|
19
|
+
# +-------------+--------------+------+-----+---------------------+-------+
|
20
|
+
|
21
|
+
self.table_name = :domain
|
22
|
+
self.primary_key = :domain
|
23
|
+
|
24
|
+
validates :domain, presence: true, uniqueness: { case_sensitive: false },
|
25
|
+
format: { with: RE_DOMAIN_NAME_LIKE_WITH_ANCHORS,
|
26
|
+
message: "must be a valid domain name" }
|
27
|
+
validates :transport, presence: true
|
28
|
+
|
29
|
+
# max aliases (Disabled: -1, Unlimited: 0)
|
30
|
+
validates :aliases, presence: true,
|
31
|
+
numericality: { only_integer: true,
|
32
|
+
greater_than_or_equal_to: -1 }
|
33
|
+
# max mailboxes (Disabled: -1, Unlimited: 0)
|
34
|
+
validates :mailboxes, presence: true,
|
35
|
+
numericality: { only_integer: true,
|
36
|
+
greater_than_or_equal_to: -1 }
|
37
|
+
|
38
|
+
# max quota (MB) for each mailbox (Unlimited: 0)
|
39
|
+
# It's not sure what 'disabled' means for max quota.
|
40
|
+
# So it's better not to allow users to set `maxquota` to -1.
|
41
|
+
validates :maxquota, presence: true,
|
42
|
+
numericality: { only_integer: true,
|
43
|
+
greater_than_or_equal_to: 0 }
|
44
|
+
|
45
|
+
# mailboxes that belong to this domain
|
46
|
+
has_many :rel_mailboxes, class_name: "Mailbox", foreign_key: :domain,
|
47
|
+
dependent: :destroy
|
48
|
+
# aliases that belong to this domain
|
49
|
+
has_many :rel_aliases, class_name: "Alias", foreign_key: :domain,
|
50
|
+
dependent: :destroy
|
51
|
+
|
52
|
+
# logs that belong to this domain
|
53
|
+
has_many :logs, class_name: "Log", foreign_key: :domain,
|
54
|
+
dependent: :destroy
|
55
|
+
|
56
|
+
# It causes errors to set `dependent: :destroy` as other columns
|
57
|
+
# because the domain_admins table doesn't have a single primary key.
|
58
|
+
#
|
59
|
+
# PostfixAdmin::DomainAdmin Load (0.5ms) SELECT `domain_admins`.* FROM `domain_admins` WHERE `domain_admins`.`domain` = 'example.com'
|
60
|
+
# PostfixAdmin::DomainAdmin Destroy (1.1ms) DELETE FROM `domain_admins` WHERE `domain_admins`.`` IS NULL
|
61
|
+
#
|
62
|
+
# ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'domain_admins.' in 'where clause'
|
63
|
+
# from /usr/local/bundle/gems/mysql2-0.5.4/lib/mysql2/client.rb:148:in `_query'
|
64
|
+
# Caused by Mysql2::Error: Unknown column 'domain_admins.' in 'where clause'
|
65
|
+
# from /usr/local/bundle/gems/mysql2-0.5.4/lib/mysql2/client.rb:148:in `_query'
|
66
|
+
#
|
67
|
+
# It works well with `dependent: :delete_all` instead.
|
68
|
+
#
|
69
|
+
# PostfixAdmin::DomainAdmin Destroy (0.4ms) DELETE FROM `domain_admins` WHERE `domain_admins`.`domain` = 'example.com'
|
70
|
+
# Domain <-> DomainAdmin <-> Admin
|
71
|
+
has_many :domain_admins, foreign_key: :domain, dependent: :delete_all
|
72
|
+
|
73
|
+
has_many :admins, through: :domain_admins
|
74
|
+
|
75
|
+
before_validation do |domain|
|
76
|
+
domain.domain = domain.domain&.downcase
|
77
|
+
domain.transport = "virtual"
|
78
|
+
end
|
79
|
+
|
80
|
+
scope :without_all, -> { where.not(domain: "ALL") }
|
81
|
+
|
82
|
+
# aliases that don't belong to a mailbox
|
83
|
+
def pure_aliases
|
84
|
+
rel_aliases.pure
|
85
|
+
end
|
86
|
+
|
87
|
+
def aliases_str
|
88
|
+
max_num_str(aliases)
|
89
|
+
end
|
90
|
+
|
91
|
+
def mailboxes_str
|
92
|
+
max_num_str(mailboxes)
|
93
|
+
end
|
94
|
+
|
95
|
+
def maxquota_str
|
96
|
+
max_num_str(maxquota)
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def max_num_str(num)
|
102
|
+
case num
|
103
|
+
when -1
|
104
|
+
"Disabled"
|
105
|
+
when 0
|
106
|
+
"Unlimited"
|
107
|
+
else
|
108
|
+
num.to_s
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module PostfixAdmin
|
2
|
+
class DomainAdmin < ApplicationRecord
|
3
|
+
# version: 1841
|
4
|
+
# > describe domain_admins;
|
5
|
+
# +----------+--------------+------+-----+---------------------+-------+
|
6
|
+
# | Field | Type | Null | Key | Default | Extra |
|
7
|
+
# +----------+--------------+------+-----+---------------------+-------+
|
8
|
+
# | username | varchar(255) | NO | MUL | NULL | |
|
9
|
+
# | domain | varchar(255) | NO | | NULL | |
|
10
|
+
# | created | datetime | NO | | 2000-01-01 00:00:00 | |
|
11
|
+
# | active | tinyint(1) | NO | | 1 | |
|
12
|
+
# +----------+--------------+------+-----+---------------------+-------+
|
13
|
+
|
14
|
+
self.table_name = :domain_admins
|
15
|
+
|
16
|
+
belongs_to :admin, primary_key: :username, foreign_key: :username
|
17
|
+
belongs_to :rel_domain, class_name: "Domain", foreign_key: :domain
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module PostfixAdmin
|
2
|
+
class Log < ApplicationRecord
|
3
|
+
# version: 1841
|
4
|
+
# > describe log;
|
5
|
+
# +-----------+--------------+------+-----+---------------------+----------------+
|
6
|
+
# | Field | Type | Null | Key | Default | Extra |
|
7
|
+
# +-----------+--------------+------+-----+---------------------+----------------+
|
8
|
+
# | timestamp | datetime | NO | MUL | 2000-01-01 00:00:00 | |
|
9
|
+
# | username | varchar(255) | NO | | NULL | |
|
10
|
+
# | domain | varchar(255) | NO | MUL | NULL | |
|
11
|
+
# | action | varchar(255) | NO | | NULL | |
|
12
|
+
# | data | text | NO | | NULL | |
|
13
|
+
# | id | int(11) | NO | PRI | NULL | auto_increment |
|
14
|
+
# +-----------+--------------+------+-----+---------------------+----------------+
|
15
|
+
|
16
|
+
self.table_name = :log
|
17
|
+
|
18
|
+
belongs_to :rel_domain, class_name: "Domain", foreign_key: :domain
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'postfix_admin/models/concerns/has_password'
|
2
|
+
|
3
|
+
module PostfixAdmin
|
4
|
+
class Mailbox < ApplicationRecord
|
5
|
+
# version: 1841
|
6
|
+
# > describe mailbox;
|
7
|
+
# +----------------+--------------+------+-----+---------------------+-------+
|
8
|
+
# | Field | Type | Null | Key | Default | Extra |
|
9
|
+
# +----------------+--------------+------+-----+---------------------+-------+
|
10
|
+
# | username | varchar(255) | NO | PRI | NULL | |
|
11
|
+
# | password | varchar(255) | NO | | NULL | |
|
12
|
+
# | name | varchar(255) | NO | | NULL | |
|
13
|
+
# | maildir | varchar(255) | NO | | NULL | |
|
14
|
+
# | quota | bigint(20) | NO | | 0 | |
|
15
|
+
# | local_part | varchar(255) | NO | | NULL | |
|
16
|
+
# | domain | varchar(255) | NO | MUL | NULL | |
|
17
|
+
# | created | datetime | NO | | 2000-01-01 00:00:00 | |
|
18
|
+
# | modified | datetime | NO | | 2000-01-01 00:00:00 | |
|
19
|
+
# | active | tinyint(1) | NO | | 1 | |
|
20
|
+
# | phone | varchar(30) | NO | | | |
|
21
|
+
# | email_other | varchar(255) | NO | | | |
|
22
|
+
# | token | varchar(255) | NO | | | |
|
23
|
+
# | token_validity | datetime | NO | | 2000-01-01 00:00:00 | |
|
24
|
+
# +----------------+--------------+------+-----+---------------------+-------+
|
25
|
+
|
26
|
+
self.table_name = :mailbox
|
27
|
+
self.primary_key = :username
|
28
|
+
|
29
|
+
include HasPassword
|
30
|
+
|
31
|
+
# attribute :quota_mb, :integer
|
32
|
+
|
33
|
+
validates :username, presence: true, uniqueness: { case_sensitive: false },
|
34
|
+
format: { with: RE_EMAIL_LIKE_WITH_ANCHORS,
|
35
|
+
message: "must be a valid email address" }
|
36
|
+
validates :maildir, presence: true, uniqueness: { case_sensitive: false }
|
37
|
+
validates :local_part, presence: true
|
38
|
+
|
39
|
+
# quota (KB)
|
40
|
+
validates :quota, presence: true,
|
41
|
+
numericality: { only_integer: true,
|
42
|
+
greater_than_or_equal_to: 0 }
|
43
|
+
|
44
|
+
belongs_to :rel_domain, class_name: "Domain", foreign_key: :domain
|
45
|
+
has_one :alias, foreign_key: :address, dependent: :destroy
|
46
|
+
has_one :quota_usage, class_name: "Quota2", foreign_key: :username,
|
47
|
+
dependent: :destroy
|
48
|
+
|
49
|
+
validate on: :create do |mailbox|
|
50
|
+
domain = mailbox.rel_domain
|
51
|
+
if !domain.mailboxes.zero? && domain.rel_mailboxes.count >= domain.mailboxes
|
52
|
+
message = "already has the maximum number of mailboxes " \
|
53
|
+
"(maximum is #{domain.mailboxes} mailboxes)"
|
54
|
+
mailbox.errors.add(:domain, message)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# just in case
|
59
|
+
validate on: :update do |mailbox|
|
60
|
+
mailbox.errors.add(:username, 'cannot be changed') if mailbox.username_changed?
|
61
|
+
mailbox.errors.add(:local_part, 'cannot be changed') if mailbox.local_part_changed?
|
62
|
+
end
|
63
|
+
|
64
|
+
validate do |mailbox|
|
65
|
+
next if mailbox.quota == -1
|
66
|
+
|
67
|
+
domain = mailbox.rel_domain
|
68
|
+
|
69
|
+
unless domain.maxquota.zero?
|
70
|
+
if mailbox.quota.zero?
|
71
|
+
mailbox.errors.add(:quota, "cannot be 0")
|
72
|
+
elsif mailbox.quota_mb > domain.maxquota
|
73
|
+
message = "must be less than or equal to #{domain.maxquota} (MB)"
|
74
|
+
mailbox.errors.add(:quota, message)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
before_validation do |mailbox|
|
80
|
+
mailbox.name = "" if mailbox.name.nil?
|
81
|
+
mailbox.username = "#{mailbox.local_part}@#{mailbox.domain}"
|
82
|
+
mailbox.maildir ||= "#{mailbox.domain}/#{mailbox.username}/"
|
83
|
+
mailbox.build_alias(address: mailbox.username, goto: mailbox.username,
|
84
|
+
domain: mailbox.domain)
|
85
|
+
end
|
86
|
+
|
87
|
+
def quota_mb
|
88
|
+
raise Error, "quota is out of range: #{quota}" if quota < 0
|
89
|
+
|
90
|
+
quota / KB_TO_MB
|
91
|
+
end
|
92
|
+
|
93
|
+
def quota_mb=(value)
|
94
|
+
raise Error, "quota is out of range: #{value}" if value < 0
|
95
|
+
|
96
|
+
self.quota = value * KB_TO_MB
|
97
|
+
end
|
98
|
+
|
99
|
+
def quota_usage_str(format: "%6.1f")
|
100
|
+
usage_mb = if quota_usage
|
101
|
+
usage_mb = quota_usage.bytes / KB_TO_MB.to_f
|
102
|
+
else
|
103
|
+
0.0
|
104
|
+
end
|
105
|
+
|
106
|
+
format % usage_mb
|
107
|
+
end
|
108
|
+
|
109
|
+
def quota_mb_str(format: "%6.1f")
|
110
|
+
case quota
|
111
|
+
when -1
|
112
|
+
# It's not sure what 'disabled' means for quota.
|
113
|
+
"Disabled"
|
114
|
+
when 0
|
115
|
+
"Unlimited"
|
116
|
+
else
|
117
|
+
quota_mb = quota / KB_TO_MB.to_f
|
118
|
+
format % quota_mb
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def quota_display_str(format: "%6.1f")
|
123
|
+
"%s / %s" % [quota_usage_str(format: format), quota_mb_str(format: format)]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module PostfixAdmin
|
2
|
+
class Quota2 < ApplicationRecord
|
3
|
+
# version: 1841
|
4
|
+
# > describe quota2;
|
5
|
+
# +----------+--------------+------+-----+---------+-------+
|
6
|
+
# | Field | Type | Null | Key | Default | Extra |
|
7
|
+
# +----------+--------------+------+-----+---------+-------+
|
8
|
+
# | username | varchar(100) | NO | PRI | NULL | |
|
9
|
+
# | bytes | bigint(20) | NO | | 0 | |
|
10
|
+
# | messages | int(11) | NO | | 0 | |
|
11
|
+
# +----------+--------------+------+-----+---------+-------+
|
12
|
+
|
13
|
+
self.table_name = :quota2
|
14
|
+
self.primary_key = :username
|
15
|
+
|
16
|
+
belongs_to :rel_mailbox, class_name: "Mailbox", foreign_key: :username
|
17
|
+
end
|
18
|
+
end
|
data/lib/postfix_admin/models.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
require 'active_record'
|
2
|
-
require 'postfix_admin/application_record'
|
3
|
-
require 'postfix_admin/admin'
|
4
|
-
require 'postfix_admin/domain'
|
5
|
-
require 'postfix_admin/mailbox'
|
6
|
-
require 'postfix_admin/alias'
|
7
|
-
require 'postfix_admin/domain_admin'
|
8
|
-
require 'postfix_admin/log'
|
9
|
-
require 'postfix_admin/
|
10
|
-
require 'postfix_admin/quota'
|
2
|
+
require 'postfix_admin/models/application_record'
|
3
|
+
require 'postfix_admin/models/admin'
|
4
|
+
require 'postfix_admin/models/domain'
|
5
|
+
require 'postfix_admin/models/mailbox'
|
6
|
+
require 'postfix_admin/models/alias'
|
7
|
+
require 'postfix_admin/models/domain_admin'
|
8
|
+
require 'postfix_admin/models/log'
|
9
|
+
require 'postfix_admin/models/quota2'
|