wikidotrb 3.0.7.pre.6
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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +77 -0
- data/CHANGELOG.md +52 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/Rakefile +12 -0
- data/_config.yml +4 -0
- data/lib/wikidotrb/common/decorators.rb +81 -0
- data/lib/wikidotrb/common/exceptions.rb +88 -0
- data/lib/wikidotrb/common/logger.rb +25 -0
- data/lib/wikidotrb/connector/ajax.rb +192 -0
- data/lib/wikidotrb/connector/api.rb +20 -0
- data/lib/wikidotrb/module/auth.rb +76 -0
- data/lib/wikidotrb/module/client.rb +146 -0
- data/lib/wikidotrb/module/forum.rb +92 -0
- data/lib/wikidotrb/module/forum_category.rb +197 -0
- data/lib/wikidotrb/module/forum_group.rb +109 -0
- data/lib/wikidotrb/module/forum_post.rb +223 -0
- data/lib/wikidotrb/module/forum_thread.rb +346 -0
- data/lib/wikidotrb/module/page.rb +598 -0
- data/lib/wikidotrb/module/page_revision.rb +142 -0
- data/lib/wikidotrb/module/page_source.rb +17 -0
- data/lib/wikidotrb/module/page_votes.rb +31 -0
- data/lib/wikidotrb/module/private_message.rb +142 -0
- data/lib/wikidotrb/module/site.rb +207 -0
- data/lib/wikidotrb/module/site_application.rb +97 -0
- data/lib/wikidotrb/module/user.rb +119 -0
- data/lib/wikidotrb/util/parser/odate.rb +47 -0
- data/lib/wikidotrb/util/parser/user.rb +105 -0
- data/lib/wikidotrb/util/quick_module.rb +61 -0
- data/lib/wikidotrb/util/requestutil.rb +51 -0
- data/lib/wikidotrb/util/stringutil.rb +39 -0
- data/lib/wikidotrb/util/table/char_table.rb +477 -0
- data/lib/wikidotrb/version.rb +5 -0
- data/lib/wikidotrb.rb +41 -0
- data/sig/wikidotrb.rbs +4 -0
- metadata +197 -0
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nokogiri"
|
4
|
+
require "date"
|
5
|
+
require_relative "page_source"
|
6
|
+
|
7
|
+
module Wikidotrb
|
8
|
+
module Module
|
9
|
+
class PageRevisionCollection < Array
|
10
|
+
attr_accessor :page
|
11
|
+
|
12
|
+
# 初期化メソッド
|
13
|
+
# @param page [Page] ページオブジェクト
|
14
|
+
# @param revisions [Array<PageRevision>] リビジョンのリスト
|
15
|
+
def initialize(page: nil, revisions: [])
|
16
|
+
super(revisions)
|
17
|
+
@page = page || revisions.first.page
|
18
|
+
end
|
19
|
+
|
20
|
+
# ソースを取得して設定する
|
21
|
+
# @param page [Page] ページオブジェクト
|
22
|
+
# @param revisions [Array<PageRevision>] リビジョンのリスト
|
23
|
+
# @return [Array<PageRevision>] 更新されたリビジョンのリスト
|
24
|
+
def self.acquire_sources(page:, revisions:)
|
25
|
+
target_revisions = revisions.reject(&:source_acquired?)
|
26
|
+
|
27
|
+
return revisions if target_revisions.empty?
|
28
|
+
|
29
|
+
responses = page.site.amc_request(
|
30
|
+
bodies: target_revisions.map do |revision|
|
31
|
+
{ "moduleName" => "history/PageSourceModule", "revision_id" => revision.id }
|
32
|
+
end
|
33
|
+
)
|
34
|
+
|
35
|
+
responses.each_with_index do |response, index|
|
36
|
+
body = response["body"]
|
37
|
+
body_html = Nokogiri::HTML(body)
|
38
|
+
target_revisions[index].source = PageSource.new(
|
39
|
+
page: page,
|
40
|
+
wiki_text: body_html.at_css("div.page-source").text.strip
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
revisions
|
45
|
+
end
|
46
|
+
|
47
|
+
# HTMLを取得して設定する
|
48
|
+
# @param page [Page] ページオブジェクト
|
49
|
+
# @param revisions [Array<PageRevision>] リビジョンのリスト
|
50
|
+
# @return [Array<PageRevision>] 更新されたリビジョンのリスト
|
51
|
+
def self.acquire_htmls(page:, revisions:)
|
52
|
+
target_revisions = revisions.reject(&:html_acquired?)
|
53
|
+
|
54
|
+
return revisions if target_revisions.empty?
|
55
|
+
|
56
|
+
responses = page.site.amc_request(
|
57
|
+
bodies: target_revisions.map do |revision|
|
58
|
+
{ "moduleName" => "history/PageVersionModule", "revision_id" => revision.id }
|
59
|
+
end
|
60
|
+
)
|
61
|
+
|
62
|
+
responses.each_with_index do |response, index|
|
63
|
+
body = response["body"]
|
64
|
+
# HTMLソースの抽出
|
65
|
+
source = body.split(
|
66
|
+
"onclick=\"document.getElementById('page-version-info').style.display='none'\">",
|
67
|
+
2
|
68
|
+
)[1].split("</a>\n\t</div>\n\n\n\n", 2)[1]
|
69
|
+
target_revisions[index].html = source
|
70
|
+
end
|
71
|
+
|
72
|
+
revisions
|
73
|
+
end
|
74
|
+
|
75
|
+
# ソースをリビジョンに取得する
|
76
|
+
def get_sources
|
77
|
+
PageRevisionCollection.acquire_sources(page: @page, revisions: self)
|
78
|
+
end
|
79
|
+
|
80
|
+
# HTMLをリビジョンに取得する
|
81
|
+
def get_htmls
|
82
|
+
PageRevisionCollection.acquire_htmls(page: @page, revisions: self)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class PageRevision
|
87
|
+
attr_accessor :page, :id, :rev_no, :created_by, :created_at, :comment, :source, :html
|
88
|
+
|
89
|
+
# 初期化メソッド
|
90
|
+
# @param page [Page] ページオブジェクト
|
91
|
+
# @param id [Integer] リビジョンID
|
92
|
+
# @param rev_no [Integer] リビジョン番号
|
93
|
+
# @param created_by [AbstractUser] 作成者
|
94
|
+
# @param created_at [DateTime] 作成日時
|
95
|
+
# @param comment [String] コメント
|
96
|
+
# @param source [PageSource, nil] ページソース
|
97
|
+
# @param html [String, nil] HTMLソース
|
98
|
+
def initialize(page:, id:, rev_no:, created_by:, created_at:, comment:, source: nil, html: nil)
|
99
|
+
@page = page
|
100
|
+
@id = id
|
101
|
+
@rev_no = rev_no
|
102
|
+
@created_by = created_by
|
103
|
+
@created_at = created_at
|
104
|
+
@comment = comment
|
105
|
+
@source = source
|
106
|
+
@html = html
|
107
|
+
end
|
108
|
+
|
109
|
+
# ソースの取得状況を確認する
|
110
|
+
# @return [Boolean] ソースが取得済みかどうか
|
111
|
+
def source_acquired?
|
112
|
+
!@source.nil?
|
113
|
+
end
|
114
|
+
|
115
|
+
# HTMLの取得状況を確認する
|
116
|
+
# @return [Boolean] HTMLが取得済みかどうか
|
117
|
+
def html_acquired?
|
118
|
+
!@html.nil?
|
119
|
+
end
|
120
|
+
|
121
|
+
# ソースのゲッターメソッド
|
122
|
+
# ソースが取得されていなければ取得する
|
123
|
+
# @return [PageSource] ソースオブジェクト
|
124
|
+
def source
|
125
|
+
PageRevisionCollection.new(page: @page, revisions: [self]).get_sources unless source_acquired?
|
126
|
+
@source
|
127
|
+
end
|
128
|
+
|
129
|
+
# ソースのセッターメソッド
|
130
|
+
|
131
|
+
# HTMLのゲッターメソッド
|
132
|
+
# HTMLが取得されていなければ取得する
|
133
|
+
# @return [String] HTMLソース
|
134
|
+
def html
|
135
|
+
PageRevisionCollection.new(page: @page, revisions: [self]).get_htmls unless html_acquired?
|
136
|
+
@html
|
137
|
+
end
|
138
|
+
|
139
|
+
# HTMLのセッターメソッド
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wikidotrb
|
4
|
+
module Module
|
5
|
+
class PageSource
|
6
|
+
attr_accessor :page, :wiki_text
|
7
|
+
|
8
|
+
# 初期化メソッド
|
9
|
+
# @param page [Page] ページオブジェクト
|
10
|
+
# @param wiki_text [String] ページのWikiテキスト
|
11
|
+
def initialize(page:, wiki_text:)
|
12
|
+
@page = page
|
13
|
+
@wiki_text = wiki_text
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wikidotrb
|
4
|
+
module Module
|
5
|
+
class PageVoteCollection < Array
|
6
|
+
attr_accessor :page
|
7
|
+
|
8
|
+
# 初期化メソッド
|
9
|
+
# @param page [Page] ページオブジェクト
|
10
|
+
# @param votes [Array<PageVote>] 投票オブジェクトのリスト
|
11
|
+
def initialize(page:, votes: [])
|
12
|
+
super(votes)
|
13
|
+
@page = page
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class PageVote
|
18
|
+
attr_accessor :page, :user, :value
|
19
|
+
|
20
|
+
# 初期化メソッド
|
21
|
+
# @param page [Page] ページオブジェクト
|
22
|
+
# @param user [AbstractUser] ユーザーオブジェクト
|
23
|
+
# @param value [Integer] 投票の値
|
24
|
+
def initialize(page:, user:, value:)
|
25
|
+
@page = page
|
26
|
+
@user = user
|
27
|
+
@value = value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "httpx"
|
4
|
+
require "nokogiri"
|
5
|
+
require "date"
|
6
|
+
require_relative "client"
|
7
|
+
require_relative "user"
|
8
|
+
require_relative "../common/exceptions"
|
9
|
+
require_relative "../common/decorators"
|
10
|
+
require_relative "../util/parser/odate"
|
11
|
+
require_relative "../util/parser/user"
|
12
|
+
|
13
|
+
module Wikidotrb
|
14
|
+
module Module
|
15
|
+
class PrivateMessageCollection < Array
|
16
|
+
extend Wikidotrb::Common::Decorators
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
"#{self.class.name}(#{size} messages)"
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.from_ids(client:, message_ids:)
|
23
|
+
bodies = message_ids.map do |message_id|
|
24
|
+
{ item: message_id, moduleName: "dashboard/messages/DMViewMessageModule" }
|
25
|
+
end
|
26
|
+
|
27
|
+
responses = client.amc_client.request(bodies: bodies, return_exceptions: true)
|
28
|
+
|
29
|
+
messages = []
|
30
|
+
|
31
|
+
responses.each_with_index do |response, index|
|
32
|
+
if response.is_a?(Wikidotrb::Common::Exceptions::WikidotStatusCodeException) && response.status_code == ("no_message")
|
33
|
+
raise Wikidotrb::Common::Exceptions::ForbiddenException.new(
|
34
|
+
"Failed to get message: #{message_ids[index]}"
|
35
|
+
), response
|
36
|
+
end
|
37
|
+
|
38
|
+
raise response if response.is_a?(Exception)
|
39
|
+
|
40
|
+
html = Nokogiri::HTML(response["body"])
|
41
|
+
sender, recipient = html.css("div.pmessage div.header span.printuser")
|
42
|
+
messages << PrivateMessage.new(
|
43
|
+
client: client,
|
44
|
+
id: message_ids[index],
|
45
|
+
sender: Wikidotrb::Util::Parser::UserParser.parse(client, sender),
|
46
|
+
recipient: Wikidotrb::Util::Parser::UserParser.parse(client, recipient),
|
47
|
+
subject: html.css("div.pmessage div.header span.subject").text.strip,
|
48
|
+
body: html.css("div.pmessage div.body").text.strip,
|
49
|
+
created_at: Wikidotrb::Util::Parser::ODateParser.parse(html.css("div.header span.odate"))
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
new(messages)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self._acquire(client:, module_name:)
|
57
|
+
response = client.amc_client.request(bodies: [{ moduleName: module_name }])[0]
|
58
|
+
|
59
|
+
html = Nokogiri::HTML(response["body"])
|
60
|
+
pager = html.css("div.pager span.target")
|
61
|
+
max_page = pager.length > 2 ? pager[-2].text.to_i : 1
|
62
|
+
|
63
|
+
responses = if max_page > 1
|
64
|
+
bodies = (1..max_page).map { |page| { page: page, moduleName: module_name } }
|
65
|
+
client.amc_client.request(bodies: bodies, return_exceptions: false)
|
66
|
+
else
|
67
|
+
[response]
|
68
|
+
end
|
69
|
+
|
70
|
+
message_ids = []
|
71
|
+
responses.each do |res|
|
72
|
+
html = Nokogiri::HTML(res["body"])
|
73
|
+
message_ids += html.css("tr.message").map { |tr| tr["data-href"].split("/").last.to_i }
|
74
|
+
end
|
75
|
+
|
76
|
+
from_ids(client: client, message_ids: message_ids)
|
77
|
+
end
|
78
|
+
|
79
|
+
# メソッドが定義された後にデコレータを適用
|
80
|
+
login_required :from_ids, :_acquire
|
81
|
+
end
|
82
|
+
|
83
|
+
class PrivateMessageInbox < PrivateMessageCollection
|
84
|
+
def self.from_ids(client:, message_ids:)
|
85
|
+
new(super)
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.acquire(client:)
|
89
|
+
new(_acquire(client: client, module_name: "dashboard/messages/DMInboxModule"))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class PrivateMessageSentBox < PrivateMessageCollection
|
94
|
+
def self.from_ids(client:, message_ids:)
|
95
|
+
new(super)
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.acquire(client:)
|
99
|
+
new(_acquire(client: client, module_name: "dashboard/messages/DMSentModule"))
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class PrivateMessage
|
104
|
+
attr_reader :client, :id, :sender, :recipient, :subject, :body, :created_at
|
105
|
+
|
106
|
+
def initialize(client:, id:, sender:, recipient:, subject:, body:, created_at:)
|
107
|
+
@client = client
|
108
|
+
@id = id
|
109
|
+
@sender = sender
|
110
|
+
@recipient = recipient
|
111
|
+
@subject = subject
|
112
|
+
@body = body
|
113
|
+
@created_at = created_at
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_s
|
117
|
+
"PrivateMessage(id=#{id}, sender=#{sender}, recipient=#{recipient}, subject=#{subject})"
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.from_id(client:, message_id:)
|
121
|
+
PrivateMessageCollection.from_ids(client: client, message_ids: [message_id]).first
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.send_message(client:, recipient:, subject:, body:)
|
125
|
+
client.amc_client.request(
|
126
|
+
bodies: [{
|
127
|
+
source: body,
|
128
|
+
subject: subject,
|
129
|
+
to_user_id: recipient.id,
|
130
|
+
action: "DashboardMessageAction",
|
131
|
+
event: "send",
|
132
|
+
moduleName: "Empty"
|
133
|
+
}]
|
134
|
+
)
|
135
|
+
end
|
136
|
+
|
137
|
+
# メソッド定義後にデコレータを適用
|
138
|
+
extend Wikidotrb::Common::Decorators
|
139
|
+
login_required :send_message
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "httpx"
|
4
|
+
require_relative "forum"
|
5
|
+
require_relative "page"
|
6
|
+
require_relative "site_application"
|
7
|
+
require_relative "../common/exceptions"
|
8
|
+
require_relative "../common/decorators"
|
9
|
+
|
10
|
+
module Wikidotrb
|
11
|
+
module Module
|
12
|
+
class SitePagesMethods
|
13
|
+
def initialize(site)
|
14
|
+
@site = site
|
15
|
+
end
|
16
|
+
|
17
|
+
# ページを検索する
|
18
|
+
# @param kwargs [Hash] 検索クエリのパラメータ
|
19
|
+
# @return [PageCollection] ページのコレクション
|
20
|
+
def search(**kwargs)
|
21
|
+
query = SearchPagesQuery.new(**kwargs)
|
22
|
+
PageCollection.search_pages(@site, query)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class SitePageMethods
|
27
|
+
def initialize(site)
|
28
|
+
@site = site
|
29
|
+
end
|
30
|
+
|
31
|
+
# フルネームからページを取得する
|
32
|
+
# @param fullname [String] ページのフルネーム
|
33
|
+
# @param raise_when_not_found [Boolean] ページが見つからない場合に例外を発生させるかどうか
|
34
|
+
# @return [Page, nil] ページオブジェクト、もしくはnil
|
35
|
+
def get(fullname, raise_when_not_found: true)
|
36
|
+
res = PageCollection.search_pages(@site, Wikidotrb::Module::SearchPagesQuery.new(fullname: fullname))
|
37
|
+
|
38
|
+
if res.empty?
|
39
|
+
raise Wikidotrb::Common::Exceptions::NotFoundException, "Page is not found: #{fullname}" if raise_when_not_found
|
40
|
+
|
41
|
+
return nil
|
42
|
+
end
|
43
|
+
|
44
|
+
res.first
|
45
|
+
end
|
46
|
+
|
47
|
+
# ページを作成する
|
48
|
+
# @param fullname [String] ページのフルネーム
|
49
|
+
# @param title [String] ページのタイトル
|
50
|
+
# @param source [String] ページのソース
|
51
|
+
# @param comment [String] コメント
|
52
|
+
# @param force_edit [Boolean] ページが存在する場合に上書きするかどうか
|
53
|
+
# @return [Page] 作成されたページオブジェクト
|
54
|
+
def create(fullname:, title: "", source: "", comment: "", force_edit: false)
|
55
|
+
Page.create_or_edit(
|
56
|
+
site: @site,
|
57
|
+
fullname: fullname,
|
58
|
+
title: title,
|
59
|
+
source: source,
|
60
|
+
comment: comment,
|
61
|
+
force_edit: force_edit,
|
62
|
+
raise_on_exists: true
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class Site
|
68
|
+
attr_reader :client, :id, :title, :unix_name, :domain, :ssl_supported, :pages, :page
|
69
|
+
|
70
|
+
extend Wikidotrb::Common::Decorators
|
71
|
+
|
72
|
+
def initialize(client:, id:, title:, unix_name:, domain:, ssl_supported:)
|
73
|
+
@client = client
|
74
|
+
@id = id
|
75
|
+
@title = title
|
76
|
+
@unix_name = unix_name
|
77
|
+
@domain = domain
|
78
|
+
@ssl_supported = ssl_supported
|
79
|
+
|
80
|
+
@pages = SitePagesMethods.new(self)
|
81
|
+
@page = SitePageMethods.new(self)
|
82
|
+
@forum = Forum.new(site: self)
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_s
|
86
|
+
"Site(id=#{id}, title=#{title}, unix_name=#{unix_name})"
|
87
|
+
end
|
88
|
+
|
89
|
+
# UNIX名からサイトオブジェクトを取得する
|
90
|
+
# @param client [Client] クライアント
|
91
|
+
# @param unix_name [String] サイトのUNIX名
|
92
|
+
# @return [Site] サイトオブジェクト
|
93
|
+
def self.from_unix_name(client:, unix_name:)
|
94
|
+
url = "http://#{unix_name}.wikidot.com"
|
95
|
+
timeout = { connect: client.amc_client.config.request_timeout }
|
96
|
+
response = HTTPX.with(timeout: timeout).get(url)
|
97
|
+
|
98
|
+
# リダイレクトの対応
|
99
|
+
while response.status >= 300 && response.status < 400
|
100
|
+
url = response.headers["location"]
|
101
|
+
response = HTTPX.with(timeout: timeout).get(url)
|
102
|
+
end
|
103
|
+
|
104
|
+
# サイトが存在しない場合
|
105
|
+
raise Wikidotrb::Common::Exceptions::NotFoundException, "Site is not found: #{unix_name}.wikidot.com" if response.status == 404
|
106
|
+
|
107
|
+
# サイトが存在する場合
|
108
|
+
source = response.body.to_s
|
109
|
+
|
110
|
+
# id : WIKIREQUEST.info.siteId = xxxx;
|
111
|
+
id_match = source.match(/WIKIREQUEST\.info\.siteId = (\d+);/)
|
112
|
+
raise Wikidotrb::Common::Exceptions::UnexpectedException, "Cannot find site id: #{unix_name}.wikidot.com" if id_match.nil?
|
113
|
+
|
114
|
+
site_id = id_match[1].to_i
|
115
|
+
|
116
|
+
# title : titleタグ
|
117
|
+
title_match = source.match(%r{<title>(.*?)</title>})
|
118
|
+
raise Wikidotrb::Common::Exceptions::UnexpectedException, "Cannot find site title: #{unix_name}.wikidot.com" if title_match.nil?
|
119
|
+
|
120
|
+
title = title_match[1]
|
121
|
+
|
122
|
+
# unix_name : WIKIREQUEST.info.siteUnixName = "xxxx";
|
123
|
+
unix_name_match = source.match(/WIKIREQUEST\.info\.siteUnixName = "(.*?)";/)
|
124
|
+
if unix_name_match.nil?
|
125
|
+
raise Wikidotrb::Common::Exceptions::UnexpectedException,
|
126
|
+
"Cannot find site unix_name: #{unix_name}.wikidot.com"
|
127
|
+
end
|
128
|
+
|
129
|
+
unix_name = unix_name_match[1]
|
130
|
+
|
131
|
+
# domain : WIKIREQUEST.info.domain = "xxxx";
|
132
|
+
domain_match = source.match(/WIKIREQUEST\.info\.domain = "(.*?)";/)
|
133
|
+
raise Wikidotrb::Common::Exceptions::UnexpectedException, "Cannot find site domain: #{unix_name}.wikidot.com" if domain_match.nil?
|
134
|
+
|
135
|
+
domain = domain_match[1]
|
136
|
+
|
137
|
+
# SSL対応チェック
|
138
|
+
ssl_supported = response.uri.to_s.start_with?("https")
|
139
|
+
|
140
|
+
new(
|
141
|
+
client: client,
|
142
|
+
id: site_id,
|
143
|
+
title: title,
|
144
|
+
unix_name: unix_name,
|
145
|
+
domain: domain,
|
146
|
+
ssl_supported: ssl_supported
|
147
|
+
)
|
148
|
+
end
|
149
|
+
|
150
|
+
# このサイトに対してAMCリクエストを実行する
|
151
|
+
# @param bodies [Array<Hash>] リクエストボディのリスト
|
152
|
+
# @param return_exceptions [Boolean] 例外を返すかどうか
|
153
|
+
def amc_request(bodies:, return_exceptions: false)
|
154
|
+
client.amc_client.request(
|
155
|
+
bodies: bodies,
|
156
|
+
return_exceptions: return_exceptions,
|
157
|
+
site_name: unix_name,
|
158
|
+
site_ssl_supported: ssl_supported
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
# サイトへの未処理の参加申請を取得する
|
163
|
+
# @return [Array<SiteApplication>] 未処理の申請リスト
|
164
|
+
def get_applications
|
165
|
+
SiteApplication.acquire_all(site: self)
|
166
|
+
end
|
167
|
+
|
168
|
+
# ユーザーをサイトに招待する
|
169
|
+
# @param user [User] 招待するユーザー
|
170
|
+
# @param text [String] 招待文
|
171
|
+
def invite_user(user:, text:)
|
172
|
+
amc_request(
|
173
|
+
bodies: [{
|
174
|
+
action: "ManageSiteMembershipAction",
|
175
|
+
event: "inviteMember",
|
176
|
+
user_id: user.id,
|
177
|
+
text: text,
|
178
|
+
moduleName: "Empty"
|
179
|
+
}]
|
180
|
+
)
|
181
|
+
rescue Wikidotrb::Common::Exceptions::WikidotStatusCodeException => e
|
182
|
+
case e.status_code
|
183
|
+
when "already_invited"
|
184
|
+
raise Wikidotrb::Common::Exceptions::TargetErrorException.new(
|
185
|
+
"User is already invited to #{unix_name}: #{user.name}"
|
186
|
+
), e
|
187
|
+
when "already_member"
|
188
|
+
raise Wikidotrb::Common::Exceptions::TargetErrorException.new(
|
189
|
+
"User is already a member of #{unix_name}: #{user.name}"
|
190
|
+
), e
|
191
|
+
else
|
192
|
+
raise e
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# サイトのURLを取得する
|
197
|
+
# @return [String] サイトのURL
|
198
|
+
def get_url
|
199
|
+
"http#{ssl_supported ? "s" : ""}://#{domain}"
|
200
|
+
end
|
201
|
+
|
202
|
+
# `invite_user`にデコレータを適用
|
203
|
+
login_required :invite_user
|
204
|
+
login_required :get_applications
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nokogiri"
|
4
|
+
require_relative "site"
|
5
|
+
require_relative "user"
|
6
|
+
require_relative "../common/exceptions"
|
7
|
+
require_relative "../util/parser/odate"
|
8
|
+
require_relative "../util/parser/user"
|
9
|
+
|
10
|
+
module Wikidotrb
|
11
|
+
module Module
|
12
|
+
class SiteApplication
|
13
|
+
attr_reader :site, :user, :text
|
14
|
+
|
15
|
+
def initialize(site:, user:, text:)
|
16
|
+
@site = site
|
17
|
+
@user = user
|
18
|
+
@text = text
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
"SiteApplication(user=#{user}, site=#{site}, text=#{text})"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.acquire_all(site:)
|
26
|
+
# サイトへの未処理の申請を取得する
|
27
|
+
# @param site [Site] サイト
|
28
|
+
# @return [Array<SiteApplication>] 申請のリスト
|
29
|
+
response = site.amc_request(
|
30
|
+
bodies: [{ moduleName: "managesite/ManageSiteMembersApplicationsModule" }]
|
31
|
+
).first
|
32
|
+
|
33
|
+
body = response["body"]
|
34
|
+
|
35
|
+
raise Wikidotrb::Common::Exceptions::ForbiddenException, "You are not allowed to access this page" if body.include?("WIKIDOT.page.listeners.loginClick(event)")
|
36
|
+
|
37
|
+
html = Nokogiri::HTML(response["body"])
|
38
|
+
|
39
|
+
applications = []
|
40
|
+
|
41
|
+
user_elements = html.css("h3 span.printuser")
|
42
|
+
text_wrapper_elements = html.css("table")
|
43
|
+
|
44
|
+
if user_elements.length != text_wrapper_elements.length
|
45
|
+
raise Wikidotrb::Common::Exceptions::UnexpectedException,
|
46
|
+
"Length of user_elements and text_wrapper_elements are different"
|
47
|
+
end
|
48
|
+
|
49
|
+
user_elements.each_with_index do |user_element, i|
|
50
|
+
text_wrapper_element = text_wrapper_elements[i]
|
51
|
+
|
52
|
+
user = Wikidotrb::Util::Parser::UserParser.user(site.client, user_element)
|
53
|
+
text = text_wrapper_element.css("td")[1].text.strip
|
54
|
+
|
55
|
+
applications << SiteApplication.new(site: site, user: user, text: text)
|
56
|
+
end
|
57
|
+
|
58
|
+
applications
|
59
|
+
end
|
60
|
+
|
61
|
+
def _process(action)
|
62
|
+
# 申請を処理する
|
63
|
+
# @param action [String] 処理の種類 ('accept' または 'decline')
|
64
|
+
raise ArgumentError, "Invalid action: #{action}" unless %w[accept decline].include?(action)
|
65
|
+
|
66
|
+
begin
|
67
|
+
site.amc_request(
|
68
|
+
bodies: [{
|
69
|
+
action: "ManageSiteMembershipAction",
|
70
|
+
event: "acceptApplication",
|
71
|
+
user_id: user.id,
|
72
|
+
text: "your application has been #{action}ed",
|
73
|
+
type: action,
|
74
|
+
moduleName: "Empty"
|
75
|
+
}]
|
76
|
+
)
|
77
|
+
rescue Wikidotrb::Common::Exceptions::WikidotStatusCodeException => e
|
78
|
+
raise e unless e.status_code == "no_application"
|
79
|
+
|
80
|
+
raise Wikidotrb::Common::Exceptions::NotFoundException.new(
|
81
|
+
"Application not found: #{user}"
|
82
|
+
), e
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# 申請を承認する
|
87
|
+
def accept
|
88
|
+
_process("accept")
|
89
|
+
end
|
90
|
+
|
91
|
+
# 申請を拒否する
|
92
|
+
def decline
|
93
|
+
_process("decline")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|