sakura-cli 0.1.0 → 0.2.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.
- checksums.yaml +5 -5
- data/.gitignore +2 -0
- data/LICENSE.txt +1 -1
- data/README.md +22 -8
- data/lib/sakura.rb +1 -1
- data/lib/sakura/cli/mail.rb +91 -24
- data/lib/sakura/cli/root.rb +7 -0
- data/lib/sakura/cli/version.rb +1 -1
- data/lib/sakura/client.rb +50 -18
- data/lib/sakura/mail_address.rb +186 -65
- data/sakura-cli.gemspec +4 -3
- metadata +29 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 63e925b0d5771393ece520ba74ef24695fadf188e82980ae0cc59864a6b3abee
|
4
|
+
data.tar.gz: 2c65e42f350a073663eeb9f912b72b07eb9eb2236e839d29a0d910cd481fb483
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3b7c3668f914eefd3735d32370b2cd4031f45aef33a9e009a490a2b2a6569e59580ab66234426cd8e633163d31aec53945dd16d87068ce50b71b7ad6516d1f4
|
7
|
+
data.tar.gz: 259300757340ef237b273025a8438d841f16b65365004fbb60aaa07f6783de2a52daa0af884cf95cfcc33d6983f8695f01007c4877032603a2428e0d9411c35f
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -12,13 +12,13 @@ Sakura CLI をインストールします.
|
|
12
12
|
gem install sakura-cli
|
13
13
|
```
|
14
14
|
|
15
|
-
Sakura CLI は[
|
15
|
+
Sakura CLI は[ChromeDriver](https://chromedriver.chromium.org/downloads) に依存しています.
|
16
16
|
お使いのOS に合った方法でインストールしてください.
|
17
17
|
|
18
18
|
Mac の場合は
|
19
19
|
|
20
20
|
```zsh
|
21
|
-
brew install
|
21
|
+
brew install chromedriver
|
22
22
|
```
|
23
23
|
|
24
24
|
でもインストールできます.
|
@@ -65,6 +65,7 @@ Commands:
|
|
65
65
|
sakura mail password LOCAL_PART [PASSWORD] # Update password of a mail address
|
66
66
|
sakura mail quota LOCAL_PART [VALUE] # Update or show quota of a mail address
|
67
67
|
sakura mail scan LOCAL_PART [enable|disable] # Switch virus scan
|
68
|
+
sakura mail show LOCAL_PART # Display information about a mail address
|
68
69
|
```
|
69
70
|
|
70
71
|
### メールアドレス一覧
|
@@ -74,12 +75,25 @@ Commands:
|
|
74
75
|
```zsh
|
75
76
|
$ sakura mail list
|
76
77
|
# domain: example.com
|
77
|
-
address
|
78
|
+
address usage / quota ( %)
|
78
79
|
---------------------------------------------------------
|
79
|
-
dummy
|
80
|
-
dummy001
|
81
|
-
dummy002
|
82
|
-
postmaster
|
80
|
+
dummy 893KB / 200MB ( 0%)
|
81
|
+
dummy001 19.5MB / 200MB ( 9%)
|
82
|
+
dummy002 11.4MB / 200MB ( 5%)
|
83
|
+
postmaster 9.75MB / 200MB ( 4%)
|
84
|
+
```
|
85
|
+
|
86
|
+
### メールアドレス詳細
|
87
|
+
|
88
|
+
```sakura mail show``` コマンドで, あるメールアドレスの詳細を表示できます.
|
89
|
+
|
90
|
+
```zsh
|
91
|
+
$ sakura mail show dummy
|
92
|
+
usage / quota: 893KB / 200MB ( 0%)
|
93
|
+
forward_to: foo@example.com
|
94
|
+
keep mail: true
|
95
|
+
virus scan: false
|
96
|
+
spam filter: disable
|
83
97
|
```
|
84
98
|
|
85
99
|
### メールアドレス作成
|
@@ -167,4 +181,4 @@ dotenv -f ~/.sakura.env sakura
|
|
167
181
|
|
168
182
|
## Copyright and License
|
169
183
|
|
170
|
-
Copyright (c)
|
184
|
+
Copyright (c) 2021 Shintaro Kojima. Code released under the [MIT license](LICENSE).
|
data/lib/sakura.rb
CHANGED
data/lib/sakura/cli/mail.rb
CHANGED
@@ -7,41 +7,51 @@ module Sakura
|
|
7
7
|
module Cli
|
8
8
|
class Mail < Thor
|
9
9
|
desc 'list', 'List all mail addresses of the domain'
|
10
|
+
|
10
11
|
def list
|
12
|
+
preprocess
|
13
|
+
|
11
14
|
addrs = MailAddress.all
|
12
15
|
|
13
16
|
puts "# domain: #{Client.current_session.domain}"
|
14
17
|
puts MailAddress.header
|
15
|
-
addrs.each {|addr| puts addr.to_s }
|
18
|
+
addrs.each { |addr| puts addr.to_s }
|
16
19
|
end
|
17
20
|
|
18
21
|
desc 'create LOCAL_PART [PASSWORD]', 'Create a mail address'
|
19
|
-
|
22
|
+
|
23
|
+
def create(local_part, password = nil)
|
24
|
+
preprocess
|
25
|
+
|
20
26
|
password ||= ask_password
|
21
27
|
|
22
28
|
begin
|
23
29
|
MailAddress.create local_part, password
|
24
30
|
rescue
|
31
|
+
raise if options[:verbose]
|
25
32
|
abort $!
|
26
33
|
end
|
27
34
|
end
|
28
35
|
|
29
36
|
desc 'delete LOCAL_PART', 'Delete a mail address'
|
37
|
+
|
30
38
|
def delete(local_part)
|
31
|
-
|
32
|
-
abort %(No mail address: "#{local_part}") unless mail
|
39
|
+
preprocess
|
33
40
|
|
34
41
|
begin
|
35
|
-
|
42
|
+
find(local_part).delete
|
36
43
|
rescue
|
44
|
+
raise if options[:verbose]
|
37
45
|
abort $!
|
38
46
|
end
|
39
47
|
end
|
40
48
|
|
41
49
|
desc 'quota LOCAL_PART [VALUE]', 'Update or show quota of a mail address'
|
42
|
-
|
43
|
-
|
44
|
-
|
50
|
+
|
51
|
+
def quota(local_part, value = nil)
|
52
|
+
preprocess
|
53
|
+
|
54
|
+
mail = find(local_part)
|
45
55
|
|
46
56
|
begin
|
47
57
|
if value
|
@@ -50,29 +60,35 @@ module Sakura
|
|
50
60
|
puts mail.quota
|
51
61
|
end
|
52
62
|
rescue
|
63
|
+
raise if options[:verbose]
|
53
64
|
abort $!
|
54
65
|
end
|
55
66
|
end
|
56
67
|
|
57
68
|
desc 'password LOCAL_PART [PASSWORD]', 'Update password of a mail address'
|
58
|
-
|
69
|
+
|
70
|
+
def password(local_part, password = nil)
|
71
|
+
preprocess
|
72
|
+
|
59
73
|
password ||= ask_password
|
60
|
-
mail =
|
61
|
-
abort %(No mail address: "#{local_part}") unless mail
|
74
|
+
mail = find(local_part)
|
62
75
|
|
63
76
|
begin
|
64
77
|
mail.password = password
|
65
78
|
rescue
|
79
|
+
raise if options[:verbose]
|
66
80
|
abort $!
|
67
81
|
end
|
68
82
|
end
|
69
83
|
|
70
|
-
desc 'scan LOCAL_PART [enable|disable]', 'Switch virus scan'
|
71
|
-
|
84
|
+
desc 'scan LOCAL_PART [enable|disable]', 'Switch virus scan configuration of a mail address'
|
85
|
+
|
86
|
+
def scan(local_part, value = nil)
|
87
|
+
preprocess
|
88
|
+
|
72
89
|
self.class.handle_argument_error if value && value !~ /enable|disable/
|
73
90
|
|
74
|
-
mail =
|
75
|
-
abort %(No mail address: "#{local_part}") unless mail
|
91
|
+
mail = find(local_part)
|
76
92
|
|
77
93
|
begin
|
78
94
|
case value
|
@@ -84,18 +100,21 @@ module Sakura
|
|
84
100
|
puts mail.virus_scan
|
85
101
|
end
|
86
102
|
rescue
|
103
|
+
raise if options[:verbose]
|
87
104
|
abort $!
|
88
105
|
end
|
89
106
|
end
|
90
107
|
|
91
108
|
desc 'forward LOCAL_PART [{add|remove} EMAIL]', 'Add, remove or show mail address(es) to forward'
|
92
|
-
|
109
|
+
|
110
|
+
def forward(local_part, operation = nil, mail_to_forward = nil)
|
111
|
+
preprocess
|
112
|
+
|
93
113
|
if (operation && operation !~ /add|remove/) || (!mail_to_forward && operation)
|
94
114
|
self.class.handle_argument_error
|
95
115
|
end
|
96
116
|
|
97
|
-
mail =
|
98
|
-
abort %(No mail address: "#{local_part}") unless mail
|
117
|
+
mail = find(local_part)
|
99
118
|
|
100
119
|
begin
|
101
120
|
case operation
|
@@ -104,19 +123,22 @@ module Sakura
|
|
104
123
|
when 'remove'
|
105
124
|
mail.delete_forward_to mail_to_forward
|
106
125
|
when nil
|
107
|
-
mail.forward_list.each {|m| puts m }
|
126
|
+
mail.forward_list.each { |m| puts m }
|
108
127
|
end
|
109
128
|
rescue
|
129
|
+
raise if options[:verbose]
|
110
130
|
abort $!
|
111
131
|
end
|
112
132
|
end
|
113
133
|
|
114
|
-
desc 'keep LOCAL_PART [enable|disable]', 'Switch keep or flush
|
115
|
-
|
134
|
+
desc 'keep LOCAL_PART [enable|disable]', 'Switch keep or flush configuration of a mail address'
|
135
|
+
|
136
|
+
def keep(local_part, value = nil)
|
137
|
+
preprocess
|
138
|
+
|
116
139
|
self.class.handle_argument_error if value && value !~ /enable|disable/
|
117
140
|
|
118
|
-
mail =
|
119
|
-
abort %(No mail address: "#{local_part}") unless mail
|
141
|
+
mail = find(local_part)
|
120
142
|
|
121
143
|
begin
|
122
144
|
case value
|
@@ -128,17 +150,62 @@ module Sakura
|
|
128
150
|
puts mail.keep
|
129
151
|
end
|
130
152
|
rescue
|
153
|
+
raise if options[:verbose]
|
131
154
|
abort $!
|
132
155
|
end
|
133
156
|
end
|
134
157
|
|
158
|
+
desc 'filter LOCAL_PART [mark|disable|discard|quarantine]', 'Configure spam filter of a mail address'
|
159
|
+
|
160
|
+
def filter(local_part, value = nil)
|
161
|
+
preprocess
|
162
|
+
|
163
|
+
self.class.handle_argument_error if value && value !~ /mark|disable|discard|quarantine/
|
164
|
+
|
165
|
+
mail = find(local_part)
|
166
|
+
|
167
|
+
begin
|
168
|
+
case value
|
169
|
+
when nil
|
170
|
+
puts mail.spam_filter
|
171
|
+
else
|
172
|
+
mail.spam_filter = value.to_sym
|
173
|
+
end
|
174
|
+
rescue
|
175
|
+
raise if options[:verbose]
|
176
|
+
abort $!
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
desc 'show LOCAL_PART', 'Display information about a mail address'
|
181
|
+
|
182
|
+
def show(local_part)
|
183
|
+
preprocess
|
184
|
+
|
185
|
+
puts find(local_part).detail
|
186
|
+
end
|
135
187
|
|
136
188
|
private
|
137
189
|
|
190
|
+
def preprocess
|
191
|
+
Client.verbose = true if options[:verbose]
|
192
|
+
end
|
193
|
+
|
194
|
+
def find(local_part)
|
195
|
+
begin
|
196
|
+
mail = MailAddress.find(local_part)
|
197
|
+
rescue Capybara::ElementNotFound
|
198
|
+
raise if options[:verbose]
|
199
|
+
abort %(No mail address: "#{local_part}")
|
200
|
+
end
|
201
|
+
|
202
|
+
mail
|
203
|
+
end
|
204
|
+
|
138
205
|
def ask_password
|
139
206
|
password = ask('password?', echo: false)
|
140
207
|
puts
|
141
|
-
confirm
|
208
|
+
confirm = ask('password(confirm)?', echo: false)
|
142
209
|
puts
|
143
210
|
abort "password doesn't match" unless password == confirm
|
144
211
|
|
data/lib/sakura/cli/root.rb
CHANGED
@@ -4,6 +4,13 @@ require 'sakura/cli/mail'
|
|
4
4
|
module Sakura
|
5
5
|
module Cli
|
6
6
|
class Root < Thor
|
7
|
+
class_option :verbose, type: :boolean
|
8
|
+
|
9
|
+
# Allow failed exit codes (see https://github.com/erikhuda/thor/issues/244)
|
10
|
+
def self.exit_on_failure?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
7
14
|
desc 'mail', 'Manage mail addresses'
|
8
15
|
subcommand 'mail', Mail
|
9
16
|
end
|
data/lib/sakura/cli/version.rb
CHANGED
data/lib/sakura/client.rb
CHANGED
@@ -1,57 +1,77 @@
|
|
1
|
-
require 'capybara/
|
1
|
+
require 'capybara/dsl'
|
2
|
+
require 'selenium-webdriver'
|
3
|
+
|
2
4
|
require 'sakura'
|
3
5
|
require 'sakura/cli/version'
|
4
6
|
|
5
|
-
Capybara.default_driver = :
|
6
|
-
Capybara.current_session.driver.headers = {'User-Agent' => "sakura-cli/#{Sakura::Cli::VERSION}"}
|
7
|
+
Capybara.default_driver = :selenium_chrome_headless
|
7
8
|
|
8
9
|
module Sakura
|
9
10
|
class Client
|
10
11
|
include Capybara::DSL
|
11
12
|
|
12
13
|
attr_reader :domain
|
14
|
+
@@verbose = false
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
class << self
|
17
|
+
def current_session
|
18
|
+
@current_session ||= new
|
19
|
+
end
|
17
20
|
|
21
|
+
def verbose=(bool)
|
22
|
+
@@verbose = !!bool
|
23
|
+
end
|
24
|
+
end
|
18
25
|
|
19
26
|
def initialize
|
20
27
|
@domain, @passwd = credentials
|
21
28
|
end
|
22
29
|
|
23
30
|
def login?
|
24
|
-
|
31
|
+
@logged_in
|
25
32
|
end
|
26
33
|
|
27
34
|
def login
|
35
|
+
$stderr.puts 'login' if @@verbose
|
36
|
+
|
28
37
|
visit BASE_URL
|
29
|
-
fill_in '
|
30
|
-
fill_in 'password', with: @passwd
|
31
|
-
find('form
|
38
|
+
fill_in 'login-username', with: @domain
|
39
|
+
fill_in 'login-password', with: @passwd
|
40
|
+
find('form button[type=submit]').click
|
41
|
+
|
42
|
+
wait_for_loading
|
32
43
|
|
33
|
-
|
44
|
+
if page.text =~ /サーバコントロールパネル ホーム/
|
45
|
+
@logged_in = true
|
46
|
+
end
|
34
47
|
|
35
48
|
raise_when_error
|
36
49
|
login?
|
37
50
|
end
|
38
51
|
|
39
|
-
def get(url)
|
52
|
+
def get(url, expected)
|
40
53
|
login unless login?
|
54
|
+
|
55
|
+
$stderr.puts "visit #{url}" if @@verbose
|
41
56
|
visit url
|
57
|
+
wait_for_loading
|
58
|
+
unless page.text =~ expected
|
59
|
+
raise Timeout::Error.new('Timed out')
|
60
|
+
end
|
61
|
+
|
42
62
|
page
|
43
63
|
end
|
44
64
|
|
45
|
-
def process(url, &block)
|
65
|
+
def process(url, expected, &block)
|
46
66
|
login unless login?
|
47
|
-
|
48
|
-
|
67
|
+
|
68
|
+
get url, expected
|
69
|
+
yield page
|
49
70
|
|
50
71
|
raise_when_error
|
51
72
|
page
|
52
73
|
end
|
53
74
|
|
54
|
-
|
55
75
|
private
|
56
76
|
|
57
77
|
def credentials
|
@@ -66,8 +86,20 @@ module Sakura
|
|
66
86
|
end
|
67
87
|
|
68
88
|
def raise_when_error
|
69
|
-
error
|
70
|
-
|
89
|
+
%w[.error .input-error].each do |cls|
|
90
|
+
error = page.all(cls)
|
91
|
+
raise error.first.text unless error.empty?
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def wait_for_loading
|
96
|
+
5.times do
|
97
|
+
if find_all('読み込み中').empty?
|
98
|
+
break
|
99
|
+
else
|
100
|
+
$stderr.puts 'still loading ...' if @@verbose
|
101
|
+
end
|
102
|
+
end
|
71
103
|
end
|
72
104
|
end
|
73
105
|
end
|
data/lib/sakura/mail_address.rb
CHANGED
@@ -2,92 +2,133 @@ require 'sakura/client'
|
|
2
2
|
|
3
3
|
module Sakura
|
4
4
|
class MailAddress
|
5
|
-
MAIL_URL = BASE_URL + '
|
5
|
+
MAIL_URL = BASE_URL + 'users/list/'
|
6
6
|
|
7
|
-
attr_reader :address, :
|
7
|
+
attr_reader :address, :usage, :quota, :link
|
8
8
|
|
9
9
|
class << self
|
10
10
|
def create(local_part, password)
|
11
|
-
Client.current_session.process(MAIL_URL) do
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
Client.current_session.process(MAIL_URL, /メールアドレス一覧/) do |page|
|
12
|
+
page.first(:xpath, '//a[text() = "新規追加"]').click
|
13
|
+
|
14
|
+
page.find(:xpath, '//label[contains(text(), "ユーザ名")]/..//input')
|
15
|
+
.fill_in with: local_part
|
16
|
+
page.find_all(:xpath, '//label[contains(text(), "パスワード")]/..//input').each do |e|
|
17
|
+
e.fill_in with: password
|
18
|
+
end
|
19
|
+
page.find(:xpath, '//button[text() = "作成する"]').click
|
16
20
|
end
|
17
21
|
|
18
22
|
true
|
19
23
|
end
|
20
24
|
|
21
25
|
def all
|
22
|
-
page = Client.current_session.get(MAIL_URL)
|
26
|
+
page = Client.current_session.get(MAIL_URL, /メールアドレス一覧/)
|
27
|
+
page.first('.input-text').select '300件'
|
23
28
|
|
24
|
-
page.all(:
|
25
|
-
|
26
|
-
MailAddress.new(*arguments)
|
29
|
+
page.all(:css, '.entity-lists .entity-lists-row').map { |element|
|
30
|
+
MailAddress.new_from_element(element)
|
27
31
|
}
|
28
32
|
end
|
29
33
|
|
30
34
|
def find(local_part)
|
31
|
-
|
35
|
+
page = Client.current_session.get(MAIL_URL, /メールアドレス一覧/)
|
36
|
+
page.first('.input-text').select '300件'
|
37
|
+
|
38
|
+
element = page.find(:xpath, "//div[contains(@class, \"entity-lists-row\")]//div[@class=\"username\" and contains(text(), \"#{local_part}\")]/../../..")
|
39
|
+
MailAddress.new_from_element(element)
|
40
|
+
end
|
41
|
+
|
42
|
+
def new_from_element(element)
|
43
|
+
MailAddress.new(
|
44
|
+
element.find('.username').text.split('@').first,
|
45
|
+
element.find('.capacity').text
|
46
|
+
)
|
32
47
|
end
|
33
48
|
|
34
49
|
def header
|
35
|
-
str = tabularize('address', '
|
36
|
-
"#{str}\n#{'-' * (str.size+1)}"
|
50
|
+
str = tabularize('address', 'usage', 'quota', '%')
|
51
|
+
"#{str}\n#{'-' * (str.size + 1)}"
|
37
52
|
end
|
38
53
|
|
39
54
|
def tabularize(*args)
|
40
55
|
args[0].ljust(20) <<
|
41
|
-
args[1].to_s.rjust(
|
42
|
-
|
43
|
-
args[3].to_s.rjust(
|
56
|
+
"#{args[1]} /".to_s.rjust(15) <<
|
57
|
+
args[2].to_s.rjust(10) <<
|
58
|
+
" (#{args[3].to_s.rjust(3)})"
|
44
59
|
end
|
45
60
|
end
|
46
61
|
|
47
|
-
|
48
|
-
|
49
|
-
@
|
50
|
-
@virus_scan = virus_scan == '○'
|
51
|
-
@usage = usage
|
52
|
-
@quota = quota
|
53
|
-
@link = link
|
54
|
-
@link_to_delete = link_to_delete
|
62
|
+
def initialize(address, usage)
|
63
|
+
@address = address
|
64
|
+
@usage, @quota = usage.split(/\s*\/\s*/)
|
55
65
|
end
|
56
66
|
|
57
67
|
def delete
|
58
|
-
|
59
|
-
Client.current_session.process(MAIL_URL) do
|
60
|
-
|
68
|
+
# FIXME: The URL won't work when mail addresses are more than 300
|
69
|
+
Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
|
70
|
+
page.accept_confirm do
|
71
|
+
page.find('button.dangerous-button').click
|
72
|
+
end
|
61
73
|
end
|
62
74
|
|
63
75
|
true
|
64
76
|
end
|
65
77
|
|
66
78
|
def quota=(value)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
79
|
+
# FIXME: The URL won't work when mail addresses are more than 300
|
80
|
+
Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
|
81
|
+
case value
|
82
|
+
when /(\d+)\s*GB$/
|
83
|
+
page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//input').fill_in with: $1
|
84
|
+
page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//select').select 'GB'
|
85
|
+
when /(\d+)\s*MB$/
|
86
|
+
page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//input').fill_in with: $1
|
87
|
+
page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//select').select 'MB'
|
88
|
+
when /(\d+)\s*KB$/
|
89
|
+
page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//input').fill_in with: $1
|
90
|
+
page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//select').select 'KB'
|
91
|
+
when /(\d+)\s*B$/
|
92
|
+
page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//input').fill_in with: $1
|
93
|
+
page.find(:xpath, '//label[contains(text(), "メール容量制限")]/..//select').select 'B'
|
94
|
+
else
|
95
|
+
raise %(Unsupported quota value "#{value}")
|
96
|
+
end
|
97
|
+
|
98
|
+
page.find(:xpath, '//button[text() = "保存する"]').click
|
99
|
+
end
|
71
100
|
|
72
|
-
|
73
|
-
@quota = $1
|
101
|
+
@quota = value
|
74
102
|
end
|
75
103
|
|
76
104
|
def password=(value)
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
105
|
+
# FIXME: The URL won't work when mail addresses are more than 300
|
106
|
+
Client.current_session.process(MAIL_URL + "1/password/#{@address}", /#{@address}のパスワード設定/) do |page|
|
107
|
+
page.find_all(:xpath, '//label[contains(text(), "パスワード")]/..//input').each do |e|
|
108
|
+
e.fill_in with: value
|
109
|
+
end
|
110
|
+
page.find(:xpath, '//button[text() = "変更する"]').click
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def virus_scan(page = nil)
|
115
|
+
if @virus_scan.nil?
|
116
|
+
# FIXME: The URL won't work when mail addresses are more than 300
|
117
|
+
page ||= Client.current_session.get(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/)
|
118
|
+
@virus_scan = page.find('[name="usesVirusCheck"]:checked').value == '1'
|
81
119
|
end
|
120
|
+
|
121
|
+
@virus_scan
|
82
122
|
end
|
83
123
|
|
84
124
|
def virus_scan=(value)
|
85
|
-
|
86
|
-
Client.current_session.process(MAIL_URL + @
|
87
|
-
find("
|
125
|
+
# FIXME: The URL won't work when mail addresses are more than 300
|
126
|
+
Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
|
127
|
+
page.find("[name='usesVirusCheck'][value='#{value ? 1 : 0}']").choose
|
128
|
+
page.find(:xpath, '//button[text() = "保存する"]').click
|
88
129
|
end
|
89
130
|
|
90
|
-
@virus_scan = value
|
131
|
+
@virus_scan = value
|
91
132
|
end
|
92
133
|
|
93
134
|
def enable_virus_scan
|
@@ -98,22 +139,24 @@ module Sakura
|
|
98
139
|
virus_scan = false
|
99
140
|
end
|
100
141
|
|
101
|
-
def keep
|
142
|
+
def keep(page = nil)
|
102
143
|
if @keep.nil?
|
103
|
-
|
104
|
-
|
144
|
+
# FIXME: The URL won't work when mail addresses are more than 300
|
145
|
+
page ||= Client.current_session.get(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/)
|
146
|
+
@keep = page.find('[name="receiveType"]:checked').value == '1'
|
105
147
|
end
|
106
148
|
|
107
149
|
@keep
|
108
150
|
end
|
109
151
|
|
110
152
|
def keep=(value)
|
111
|
-
|
112
|
-
Client.current_session.process(MAIL_URL + @
|
113
|
-
find("
|
153
|
+
# FIXME: The URL won't work when mail addresses are more than 300
|
154
|
+
Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
|
155
|
+
page.find("[name='receiveType'][value='#{value ? 1 : 2}']").choose
|
156
|
+
page.find(:xpath, '//button[text() = "保存する"]').click
|
114
157
|
end
|
115
158
|
|
116
|
-
@keep = value
|
159
|
+
@keep = value
|
117
160
|
end
|
118
161
|
|
119
162
|
def enable_keep
|
@@ -124,41 +167,119 @@ module Sakura
|
|
124
167
|
keep = false
|
125
168
|
end
|
126
169
|
|
127
|
-
def
|
170
|
+
def spam_filter(page = nil)
|
171
|
+
if @spam_filter.nil?
|
172
|
+
# FIXME: The URL won't work when mail addresses are more than 300
|
173
|
+
page ||= Client.current_session.get(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/)
|
174
|
+
|
175
|
+
case page.find(:xpath, '//label[contains(text(), "迷惑メールフィルタ")]/..//select').value
|
176
|
+
when "0"
|
177
|
+
@spam_filter = :disable
|
178
|
+
when "1"
|
179
|
+
@spam_filter = :quarantine
|
180
|
+
when "2"
|
181
|
+
@spam_filter = :discard
|
182
|
+
when "3"
|
183
|
+
@spam_filter = :mark
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
@spam_filter
|
188
|
+
end
|
189
|
+
|
190
|
+
def spam_filter=(value)
|
191
|
+
# FIXME: The URL won't work when mail addresses are more than 300
|
192
|
+
Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
|
193
|
+
select = page.find(:xpath, '//label[contains(text(), "迷惑メールフィルタ")]/..//select')
|
194
|
+
|
195
|
+
value = value.to_sym
|
196
|
+
case value
|
197
|
+
when :disable
|
198
|
+
select.select '利用しない'
|
199
|
+
when :quarantine
|
200
|
+
select.select '「迷惑メール」フォルダに保存'
|
201
|
+
when :discard
|
202
|
+
select.select 'メールを破棄'
|
203
|
+
when :mark
|
204
|
+
select.select 'フィルタの利用'
|
205
|
+
end
|
206
|
+
|
207
|
+
page.find(:xpath, '//button[text() = "保存する"]').click
|
208
|
+
end
|
209
|
+
|
210
|
+
@spam_filter = value
|
211
|
+
end
|
212
|
+
|
213
|
+
def forward_list(page = nil)
|
128
214
|
if @forward_list.nil?
|
129
|
-
|
130
|
-
|
215
|
+
# FIXME: The URL won't work when mail addresses are more than 300
|
216
|
+
page ||= Client.current_session.get(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/)
|
217
|
+
@forward_list = page.find(:xpath, '//label[contains(text(), "転送先アドレス")]/..//textarea').value.split(/[\n,]+/)
|
131
218
|
end
|
132
219
|
|
133
220
|
@forward_list
|
134
221
|
end
|
135
222
|
|
136
223
|
def forward_to(mail)
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
JS
|
224
|
+
# FIXME: The URL won't work when mail addresses are more than 300
|
225
|
+
Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
|
226
|
+
@forward_list = page.find(:xpath, '//label[contains(text(), "転送先アドレス")]/..//textarea').value.split(/[\n,]+/)
|
227
|
+
page.find(:xpath, '//label[contains(text(), "転送先アドレス")]/..//textarea')
|
228
|
+
.fill_in with: (@forward_list + [mail]).uniq.join("\n")
|
229
|
+
page.find(:xpath, '//button[text() = "保存する"]').click
|
144
230
|
end
|
145
231
|
|
146
|
-
@forward_list ||= []
|
147
232
|
@forward_list << mail
|
148
233
|
end
|
149
234
|
|
150
235
|
def delete_forward_to(mail)
|
151
|
-
|
152
|
-
|
153
|
-
find('
|
236
|
+
# FIXME: The URL won't work when mail addresses are more than 300
|
237
|
+
Client.current_session.process(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/) do |page|
|
238
|
+
@forward_list = page.find(:xpath, '//label[contains(text(), "転送先アドレス")]/..//textarea').value.split(/[\n,]+/)
|
239
|
+
page.find(:xpath, '//label[contains(text(), "転送先アドレス")]/..//textarea')
|
240
|
+
.fill_in with: (@forward_list - [mail]).uniq.join("\n")
|
241
|
+
page.find(:xpath, '//button[text() = "保存する"]').click
|
154
242
|
end
|
155
243
|
|
156
|
-
@forward_list ||= []
|
157
244
|
@forward_list.delete mail
|
158
245
|
end
|
159
246
|
|
160
247
|
def to_s
|
161
|
-
self.class.tabularize(@address, @
|
248
|
+
self.class.tabularize(@address, @usage, @quota, percentage(@usage, @quota))
|
249
|
+
end
|
250
|
+
|
251
|
+
def detail
|
252
|
+
# FIXME: The URL won't work when mail addresses are more than 300
|
253
|
+
page = Client.current_session.get(MAIL_URL + "1/edit/#{@address}", /#{@address}の設定/)
|
254
|
+
|
255
|
+
<<-EOS
|
256
|
+
usage / quota: #{usage} / #{quota} (#{percentage(@usage, @quota)})
|
257
|
+
forward_to: #{forward_list(page).join(' ')}
|
258
|
+
keep mail: #{keep(page)}
|
259
|
+
virus scan: #{virus_scan(page)}
|
260
|
+
spam filter: #{spam_filter(page)}
|
261
|
+
EOS
|
262
|
+
end
|
263
|
+
|
264
|
+
private
|
265
|
+
|
266
|
+
def percentage(usage, quota)
|
267
|
+
usage, quota = [usage, quota].map { |i|
|
268
|
+
case i
|
269
|
+
when /([\d.]+)TB$/
|
270
|
+
$1.to_f * 1000000000000
|
271
|
+
when /([\d.]+)GB$/
|
272
|
+
$1.to_f * 1000000000
|
273
|
+
when /([\d.]+)MB$/
|
274
|
+
$1.to_f * 1000000
|
275
|
+
when /([\d.]+)KB$/
|
276
|
+
$1.to_f * 1000
|
277
|
+
when /([\d.]+)B$/
|
278
|
+
$1.to_i
|
279
|
+
end
|
280
|
+
}
|
281
|
+
|
282
|
+
"#{(usage * 100 / quota).to_i}%"
|
162
283
|
end
|
163
284
|
end
|
164
285
|
end
|
data/sakura-cli.gemspec
CHANGED
@@ -19,9 +19,10 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.add_runtime_dependency "
|
22
|
+
spec.add_runtime_dependency "capybara"
|
23
|
+
spec.add_runtime_dependency "selenium-webdriver"
|
23
24
|
spec.add_runtime_dependency "thor"
|
24
|
-
spec.add_development_dependency "bundler"
|
25
|
-
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "bundler"
|
26
|
+
spec.add_development_dependency "rake"
|
26
27
|
spec.required_ruby_version = '>= 2.0.0'
|
27
28
|
end
|
metadata
CHANGED
@@ -1,17 +1,31 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sakura-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shintaro Kojima
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-04-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: capybara
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: selenium-webdriver
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
16
30
|
requirements:
|
17
31
|
- - ">="
|
@@ -42,30 +56,30 @@ dependencies:
|
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
|
-
- - "
|
59
|
+
- - ">="
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
61
|
+
version: '0'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
|
-
- - "
|
66
|
+
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rake
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
|
-
- - "
|
73
|
+
- - ">="
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
75
|
+
version: '0'
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
|
-
- - "
|
80
|
+
- - ">="
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
82
|
+
version: '0'
|
69
83
|
description: Command-line tool and client library to control the dashboard of Sakura
|
70
84
|
Rental Server.
|
71
85
|
email:
|
@@ -92,7 +106,7 @@ homepage: https://github.com/codeout/sakura-cli
|
|
92
106
|
licenses:
|
93
107
|
- MIT
|
94
108
|
metadata: {}
|
95
|
-
post_install_message:
|
109
|
+
post_install_message:
|
96
110
|
rdoc_options: []
|
97
111
|
require_paths:
|
98
112
|
- lib
|
@@ -107,10 +121,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
121
|
- !ruby/object:Gem::Version
|
108
122
|
version: '0'
|
109
123
|
requirements: []
|
110
|
-
|
111
|
-
|
112
|
-
signing_key:
|
124
|
+
rubygems_version: 3.2.15
|
125
|
+
signing_key:
|
113
126
|
specification_version: 4
|
114
127
|
summary: Command-line tool for Sakura's Rental Server.
|
115
128
|
test_files: []
|
116
|
-
has_rdoc:
|