postfix_admin 0.0.2 → 0.1.0
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.
- data/README.md +21 -11
- data/Thorfile +30 -0
- data/bin/postfix_admin +5 -97
- data/lib/postfix_admin/base.rb +188 -0
- data/lib/postfix_admin/cli.rb +244 -79
- data/lib/postfix_admin/error.rb +4 -0
- data/lib/postfix_admin/models.rb +127 -17
- data/lib/postfix_admin/runner.rb +105 -0
- data/lib/postfix_admin/version.rb +2 -2
- data/lib/postfix_admin.rb +1 -157
- data/postfix_admin.gemspec +2 -1
- data/spec/base_spec.rb +218 -0
- data/spec/cli_spec.rb +165 -0
- data/spec/models_spec.rb +136 -0
- data/spec/postfix_admin.conf +5 -0
- data/spec/postfix_test.sql +250 -0
- data/spec/runner_spec.rb +144 -0
- data/spec/spec_helper.rb +160 -0
- metadata +38 -5
- data/Rakefile +0 -2
data/lib/postfix_admin/models.rb
CHANGED
@@ -1,35 +1,125 @@
|
|
1
1
|
require 'data_mapper'
|
2
2
|
|
3
|
-
|
3
|
+
#
|
4
|
+
# This extension is to avoid 'ArgumentError: invalid date' when datetime value of
|
5
|
+
# MySQL is '0000-00-00 00:00:00'.
|
6
|
+
#
|
7
|
+
class DateTime
|
8
|
+
class << self
|
9
|
+
|
10
|
+
alias org_new new
|
11
|
+
def new(year = -4712, mon = 1, mday = 1, hour = 0, min = 0, sec = 0, offset = 0, start = Date::ITALY)
|
12
|
+
if year == 0
|
13
|
+
nil
|
14
|
+
else
|
15
|
+
org_new(year, mon, mday, hour, min, sec, offset, start)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module PostfixAdmin
|
4
22
|
class Admin
|
5
23
|
include ::DataMapper::Resource
|
6
24
|
property :username, String, :key => true
|
7
25
|
property :password, String
|
8
|
-
property :created, DateTime
|
9
|
-
property :modified, DateTime
|
26
|
+
property :created, DateTime, :default => DateTime.now
|
27
|
+
property :modified, DateTime, :default => DateTime.now
|
10
28
|
|
29
|
+
has n, :domain_admins, :child_key => :username
|
30
|
+
has n, :domains, :model => 'Domain', :through => :domain_admins, :via => :domain
|
11
31
|
storage_names[:default] = 'admin'
|
32
|
+
|
33
|
+
def has_domain?(domain_name)
|
34
|
+
if super_admin?
|
35
|
+
Domain.exist?(domain_name)
|
36
|
+
else
|
37
|
+
exist_domain?(domain_name)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def super_admin=(value)
|
42
|
+
if value
|
43
|
+
domains << Domain.find('ALL')
|
44
|
+
save or raise "Could not save ALL domain for Admin"
|
45
|
+
else
|
46
|
+
domain_admins(:domain_name => 'ALL').destroy or raise "Could not destroy DoaminAdmin for Admin"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def super_admin?
|
51
|
+
exist_domain?('ALL')
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.find(username)
|
55
|
+
Admin.first(:username => username)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.exist?(username)
|
59
|
+
!!Admin.find(username)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.unnecessary
|
63
|
+
all.delete_if do |admin|
|
64
|
+
admin.domains.size > 0
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def exist_domain?(domain_name)
|
71
|
+
!!domains.first(:domain_name => domain_name)
|
72
|
+
end
|
12
73
|
end
|
13
74
|
|
14
75
|
class Domain
|
15
76
|
include ::DataMapper::Resource
|
16
|
-
property :
|
17
|
-
property :
|
18
|
-
property :
|
77
|
+
property :domain_name, String, :field => 'domain', :key => true
|
78
|
+
property :maxaliases, Integer, :field => 'aliases'
|
79
|
+
property :maxmailboxes, Integer, :field => 'mailboxes'
|
19
80
|
property :maxquota, Integer
|
20
|
-
property :transport, String
|
21
|
-
property :backupmx, Integer
|
81
|
+
property :transport, String, :default => 'virtual'
|
82
|
+
property :backupmx, Integer, :default => 0
|
22
83
|
property :description, String
|
84
|
+
property :created, DateTime, :default => DateTime.now
|
85
|
+
property :modified, DateTime, :default => DateTime.now
|
23
86
|
|
87
|
+
has n, :domain_admins, :child_key => :domain_name
|
88
|
+
has n, :admins, :model => 'Admin', :through => :domain_admins
|
89
|
+
|
90
|
+
has n, :mailboxes, :model => 'Mailbox', :child_key => :domain_name
|
91
|
+
has n, :aliases, :model => 'Alias', :child_key => :domain_name
|
24
92
|
storage_names[:default] = 'domain'
|
93
|
+
|
94
|
+
def self.all_without_special_domain
|
95
|
+
Domain.all(:domain_name.not => 'ALL')
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.find(domain)
|
99
|
+
Domain.first(:domain_name => domain)
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.exist?(domain)
|
103
|
+
!!Domain.find(domain)
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.num_total_aliases
|
107
|
+
Alias.count - Mailbox.count
|
108
|
+
end
|
109
|
+
|
110
|
+
def num_total_aliases
|
111
|
+
aliases.count - mailboxes.count
|
112
|
+
end
|
25
113
|
end
|
26
114
|
|
27
115
|
class DomainAdmin
|
28
116
|
include ::DataMapper::Resource
|
117
|
+
property :created, DateTime, :default => DateTime.now
|
118
|
+
property :domain_name, String, :field => 'domain', :key => true
|
29
119
|
property :username, String, :key => true
|
30
|
-
property :domain, String, :key => true
|
31
|
-
property :created, DateTime
|
32
120
|
|
121
|
+
belongs_to :domain, :model => 'Domain', :child_key => :domain_name
|
122
|
+
belongs_to :admin, :model => 'Admin', :child_key => :username
|
33
123
|
storage_names[:default] = 'domain_admins'
|
34
124
|
end
|
35
125
|
|
@@ -37,25 +127,45 @@ class PostfixAdmin
|
|
37
127
|
include ::DataMapper::Resource
|
38
128
|
property :username, String, :key => true
|
39
129
|
property :name, String
|
130
|
+
property :domain_name, String, :field => 'domain'
|
40
131
|
property :password, String
|
41
|
-
property :domain, String
|
42
132
|
property :maildir, String
|
43
133
|
property :quota, Integer
|
44
134
|
# property :local_part, String
|
45
|
-
property :created, DateTime
|
46
|
-
property :modified, DateTime
|
135
|
+
property :created, DateTime, :default => DateTime.now
|
136
|
+
property :modified, DateTime, :default => DateTime.now
|
137
|
+
|
138
|
+
belongs_to :domain, :model => 'Domain', :child_key => :domain_name
|
47
139
|
|
48
140
|
storage_names[:default] = 'mailbox'
|
141
|
+
|
142
|
+
def self.find(username)
|
143
|
+
Mailbox.first(:username => username)
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.exist?(username)
|
147
|
+
!!Mailbox.find(username)
|
148
|
+
end
|
49
149
|
end
|
50
150
|
|
51
151
|
class Alias
|
52
152
|
include ::DataMapper::Resource
|
53
153
|
property :address, String, :key => true
|
54
|
-
property :goto, Text
|
55
|
-
property :
|
56
|
-
property :created, DateTime
|
57
|
-
property :modified, DateTime
|
154
|
+
property :goto, Text
|
155
|
+
property :domain_name, String, :field => 'domain'
|
156
|
+
property :created, DateTime, :default => DateTime.now
|
157
|
+
property :modified, DateTime, :default => DateTime.now
|
158
|
+
|
159
|
+
belongs_to :domain, :model => 'Domain', :child_key => :domain_name
|
58
160
|
|
59
161
|
storage_names[:default] = 'alias'
|
162
|
+
|
163
|
+
def self.find(address)
|
164
|
+
Alias.first(:address => address)
|
165
|
+
end
|
166
|
+
|
167
|
+
def self.exist?(address)
|
168
|
+
!!Alias.find(address)
|
169
|
+
end
|
60
170
|
end
|
61
171
|
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'postfix_admin'
|
3
|
+
require 'postfix_admin/cli'
|
4
|
+
|
5
|
+
module PostfixAdmin
|
6
|
+
class Runner < Thor
|
7
|
+
def initialize(*args)
|
8
|
+
super
|
9
|
+
@cli = CLI.new
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "summary [example.com]", "Summarize the usage of PostfixAdmin"
|
13
|
+
def summary(domain_name=nil)
|
14
|
+
runner{ @cli.show_summary(domain_name) }
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "show [example.com]", "List of domains"
|
18
|
+
def show(domain_name=nil)
|
19
|
+
runner{ @cli.show(domain_name) }
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "setup example.com password", "Setup a domain"
|
23
|
+
def setup(domain_name, password)
|
24
|
+
runner{ @cli.setup_domain(domain_name, password) }
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "super_admin admin@example.com", "Enable super admin flag of an admin"
|
28
|
+
method_option :disable, :type => :boolean, :aliases => "-d", :desc => "Disable super admin flag"
|
29
|
+
def super_admin(user_name)
|
30
|
+
runner{ @cli.super_admin(user_name, options[:disable]) }
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "admin_passwd admin@example.com new_password", "Change password of admin"
|
34
|
+
def admin_passwd(user_name, password)
|
35
|
+
runner{ @cli.change_admin_password(user_name, password) }
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "account_passwd user@example.com new_password", "Change password of account"
|
39
|
+
def account_passwd(user_name, password)
|
40
|
+
runner{ @cli.change_account_password(user_name, password) }
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "add_domain example.com", "Add a domain"
|
44
|
+
def add_domain(domain_name)
|
45
|
+
runner{ @cli.add_domain(domain_name) }
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "delete_domain example.com", "Delete a domain"
|
49
|
+
def delete_domain(domain_name)
|
50
|
+
runner{ @cli.delete_domain(domain_name) }
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "delete_admin admin@example.com", "Delete an admin"
|
54
|
+
def delete_admin(user_name)
|
55
|
+
runner{ @cli.delete_admin(user_name) }
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "delete_account user@example.com", "Delete an account"
|
59
|
+
def delete_account(address)
|
60
|
+
runner{ @cli.delete_account(address) }
|
61
|
+
end
|
62
|
+
|
63
|
+
desc "add_account user@example.com password", "Add an account"
|
64
|
+
def add_account(address, password)
|
65
|
+
runner{ @cli.add_account(address, password) }
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "add_admin admin@example.com password", "Add an admin user"
|
69
|
+
method_option :super, :type => :boolean, :aliases => "-s", :desc => "register as a super admin"
|
70
|
+
def add_admin(user_name, password)
|
71
|
+
runner{ @cli.add_admin(user_name, password, options[:super]) }
|
72
|
+
end
|
73
|
+
|
74
|
+
desc "add_admin_domain admin@example.com example.com", "Add admin_domain"
|
75
|
+
def add_admin_domain(user_name, domain_name)
|
76
|
+
runner{ @cli.add_admin_domain(user_name, domain_name) }
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "add_alias alias@example.com goto@example.net", "Add an alias"
|
80
|
+
def add_alias(address, goto)
|
81
|
+
runner{ @cli.add_alias(address, goto) }
|
82
|
+
end
|
83
|
+
|
84
|
+
desc "delete_alias alias@example.com", "Delete an alias"
|
85
|
+
def delete_alias(address)
|
86
|
+
runner{ @cli.delete_alias(address) }
|
87
|
+
end
|
88
|
+
|
89
|
+
desc "version", "Show postfix_admin version"
|
90
|
+
def version
|
91
|
+
require 'postfix_admin/version'
|
92
|
+
say "postfix_admin #{VERSION}"
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def runner
|
98
|
+
begin
|
99
|
+
yield
|
100
|
+
rescue => e
|
101
|
+
warn e.message
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.0
|
1
|
+
module PostfixAdmin
|
2
|
+
VERSION = "0.1.0"
|
3
3
|
end
|
data/lib/postfix_admin.rb
CHANGED
@@ -1,158 +1,2 @@
|
|
1
1
|
require "postfix_admin/version"
|
2
|
-
require
|
3
|
-
|
4
|
-
require 'date'
|
5
|
-
require 'data_mapper'
|
6
|
-
|
7
|
-
class PostfixAdmin
|
8
|
-
def initialize(config)
|
9
|
-
DataMapper.setup(:default, config['database'])
|
10
|
-
DataMapper.finalize
|
11
|
-
@config = {}
|
12
|
-
@config[:aliases] = config['aliases'] || 30
|
13
|
-
@config[:mailboxes] = config['mailboxes'] || 30
|
14
|
-
@config[:maxquota] = config['maxquota'] || 100
|
15
|
-
@config[:mailbox_quota] = @config[:maxquota] * 1024 * 1000
|
16
|
-
end
|
17
|
-
def add_admin_domain(username, domain)
|
18
|
-
unless admin_exist?(username)
|
19
|
-
raise "Error: #{username} is not resistered as admin."
|
20
|
-
end
|
21
|
-
unless domain_exist?(domain)
|
22
|
-
raise "Error: Invalid domain #{domain}!"
|
23
|
-
end
|
24
|
-
if admin_domain_exist?(username, domain)
|
25
|
-
raise "Error: #{username} is already resistered as admin of #{domain}."
|
26
|
-
end
|
27
|
-
|
28
|
-
domain_admin = DomainAdmin.new
|
29
|
-
domain_admin.attributes = {
|
30
|
-
:username => username,
|
31
|
-
:domain => domain,
|
32
|
-
:created => DateTime.now
|
33
|
-
}
|
34
|
-
domain_admin.save
|
35
|
-
end
|
36
|
-
def add_admin(username, password)
|
37
|
-
if admin_exist?(username)
|
38
|
-
raise "Error: #{username} is already resistered as admin."
|
39
|
-
end
|
40
|
-
admin = Admin.new
|
41
|
-
admin.attributes = {
|
42
|
-
:username => username,
|
43
|
-
:password => password,
|
44
|
-
:created => DateTime.now,
|
45
|
-
:modified => DateTime.now
|
46
|
-
}
|
47
|
-
admin.save
|
48
|
-
end
|
49
|
-
def add_account(address, password)
|
50
|
-
if address !~ /.+\@.+\..+/
|
51
|
-
raise "Error: Invalid mail address! #{address}"
|
52
|
-
end
|
53
|
-
user, domain = address.split(/@/)
|
54
|
-
path = "#{domain}/#{address}/"
|
55
|
-
|
56
|
-
unless domain_exist?(domain)
|
57
|
-
raise "Error: Invalid domain! #{address}"
|
58
|
-
end
|
59
|
-
|
60
|
-
if alias_exist?(address)
|
61
|
-
raise "Error: #{address} is already resistered."
|
62
|
-
end
|
63
|
-
mail_alias = Alias.new
|
64
|
-
mail_alias.attributes = {
|
65
|
-
:address => address,
|
66
|
-
:goto => address,
|
67
|
-
:domain => domain,
|
68
|
-
:created => DateTime.now,
|
69
|
-
:modified => DateTime.now
|
70
|
-
}
|
71
|
-
mail_alias.save
|
72
|
-
|
73
|
-
mailbox = Mailbox.new
|
74
|
-
mailbox.attributes = {
|
75
|
-
:username => address,
|
76
|
-
:password => password,
|
77
|
-
:name => '',
|
78
|
-
:maildir => path,
|
79
|
-
:quota => @config[:mailbox_quota],
|
80
|
-
:domain => domain,
|
81
|
-
# :local_part => user,
|
82
|
-
:created => DateTime.now,
|
83
|
-
:modified => DateTime.now
|
84
|
-
}
|
85
|
-
mailbox.save
|
86
|
-
end
|
87
|
-
def add_alias(address, goto)
|
88
|
-
if alias_exist?(address)
|
89
|
-
goto_text = "#{address},#{goto}"
|
90
|
-
mail_alias = Alias.first(:address => address)
|
91
|
-
mail_alias.update(:goto => goto_text, :modified => DateTime.now)
|
92
|
-
else
|
93
|
-
raise "Error: Invalid mail address! #{address}"
|
94
|
-
end
|
95
|
-
end
|
96
|
-
def add_domain(domain_name)
|
97
|
-
if domain_name !~ /.+\..+/
|
98
|
-
raise "Error: Ivalid domain! #{domain_name}"
|
99
|
-
end
|
100
|
-
if domain_exist?(domain_name)
|
101
|
-
raise "Error: #{domain_name} is already registered!"
|
102
|
-
end
|
103
|
-
domain = Domain.new
|
104
|
-
domain.attributes = {
|
105
|
-
:domain => domain_name,
|
106
|
-
:description => domain_name,
|
107
|
-
:aliases => @config[:aliases],
|
108
|
-
:mailboxes => @config[:mailboxes],
|
109
|
-
:maxquota => @config[:maxquota],
|
110
|
-
:transport => "virtual",
|
111
|
-
:backupmx => 0
|
112
|
-
}
|
113
|
-
domain.save
|
114
|
-
end
|
115
|
-
def delete_domain(domain)
|
116
|
-
unless domain_exist?(domain)
|
117
|
-
raise "Error: #{domain} is not found!"
|
118
|
-
end
|
119
|
-
username = "admin@#{domain}"
|
120
|
-
Admin.all(:username => username).destroy
|
121
|
-
DomainAdmin.all(:username => username).destroy
|
122
|
-
Mailbox.all(:domain => domain).destroy
|
123
|
-
Alias.all(:domain => domain).destroy
|
124
|
-
Domain.all(:domain => domain).destroy
|
125
|
-
end
|
126
|
-
def admin_domain_exist?(username, domain)
|
127
|
-
DomainAdmin.all(:username => username, :domain => domain).count != 0
|
128
|
-
end
|
129
|
-
def admin_exist?(admin)
|
130
|
-
Admin.all(:username => admin).count != 0
|
131
|
-
end
|
132
|
-
def alias_exist?(address)
|
133
|
-
Alias.all(:address => address).count != 0
|
134
|
-
end
|
135
|
-
def domain_exist?(domain)
|
136
|
-
Domain.all(:domain => domain).count != 0
|
137
|
-
end
|
138
|
-
def domains
|
139
|
-
Domain.all(:domain.not => 'ALL', :order => :domain)
|
140
|
-
end
|
141
|
-
def admins
|
142
|
-
Admin.all(:order => 'username')
|
143
|
-
end
|
144
|
-
def mailboxes(domain=nil)
|
145
|
-
if domain
|
146
|
-
Mailbox.all(:domain => domain, :order => :username)
|
147
|
-
else
|
148
|
-
Mailbox.all(:order => :username)
|
149
|
-
end
|
150
|
-
end
|
151
|
-
def admin_domains(username=nil)
|
152
|
-
if username
|
153
|
-
DomainAdmin.all(:username => username, :order => :domain)
|
154
|
-
else
|
155
|
-
DomainAdmin.all(:order => :domain)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
2
|
+
require "postfix_admin/base"
|