wikidotrb 3.0.7.pre.6
Sign up to get free protection for your applications and to get access to all the features.
- 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,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wikidotrb
|
4
|
+
module Connector
|
5
|
+
# APIキーのオブジェクト
|
6
|
+
class APIKeys
|
7
|
+
# 読み取り専用の属性
|
8
|
+
attr_reader :ro_key, :rw_key
|
9
|
+
|
10
|
+
# 初期化
|
11
|
+
# @param ro_key [String] Read Only Key
|
12
|
+
# @param rw_key [String] Read-Write Key
|
13
|
+
def initialize(ro_key:, rw_key:)
|
14
|
+
@ro_key = ro_key
|
15
|
+
@rw_key = rw_key
|
16
|
+
freeze
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "httpx"
|
4
|
+
require "uri"
|
5
|
+
require "json"
|
6
|
+
require_relative "../common/exceptions"
|
7
|
+
|
8
|
+
module Wikidotrb
|
9
|
+
module Module
|
10
|
+
class HTTPAuthentication
|
11
|
+
# ユーザー名とパスワードでログインする
|
12
|
+
# @param client [Client] クライアント
|
13
|
+
# @param username [String] ユーザー名
|
14
|
+
# @param password [String] パスワード
|
15
|
+
# @raise [SessionCreateException] セッション作成に失敗した場合
|
16
|
+
def self.login(client, username, password)
|
17
|
+
url = "https://www.wikidot.com/default--flow/login__LoginPopupScreen"
|
18
|
+
|
19
|
+
# ログインリクエストのデータを作成
|
20
|
+
request_data = {
|
21
|
+
"login" => username,
|
22
|
+
"password" => password,
|
23
|
+
"action" => "Login2Action",
|
24
|
+
"event" => "login"
|
25
|
+
}
|
26
|
+
|
27
|
+
response = HTTPX.post(
|
28
|
+
url,
|
29
|
+
headers: client.amc_client.header.get_header,
|
30
|
+
form: request_data,
|
31
|
+
timeout: { operation: 20 }
|
32
|
+
)
|
33
|
+
|
34
|
+
# ステータスコードのチェック
|
35
|
+
unless response.status == 200
|
36
|
+
raise Wikidotrb::Common::Exceptions::SessionCreateException,
|
37
|
+
"Login attempt is failed due to HTTP status code: #{response.status}"
|
38
|
+
end
|
39
|
+
|
40
|
+
# レスポンスボディのチェック
|
41
|
+
if response.body.to_s.include?("The login and password do not match")
|
42
|
+
raise Wikidotrb::Common::Exceptions::SessionCreateException,
|
43
|
+
"Login attempt is failed due to invalid username or password"
|
44
|
+
end
|
45
|
+
|
46
|
+
# クッキーのチェックとパース
|
47
|
+
set_cookie_header = response.headers["set-cookie"]
|
48
|
+
|
49
|
+
# `set-cookie` が存在しない、または `nil` の場合にエラーを発生
|
50
|
+
raise Wikidotrb::Common::Exceptions::SessionCreateException, "Login attempt is failed due to invalid cookies" if set_cookie_header.nil? || set_cookie_header.empty?
|
51
|
+
|
52
|
+
# セッションクッキーを取得
|
53
|
+
session_cookie = set_cookie_header.match(/WIKIDOT_SESSION_ID=([^;]+)/)
|
54
|
+
|
55
|
+
raise Wikidotrb::Common::Exceptions::SessionCreateException, "Login attempt is failed due to invalid cookies" unless session_cookie
|
56
|
+
|
57
|
+
# セッションクッキーの設定
|
58
|
+
client.amc_client.header.set_cookie("WIKIDOT_SESSION_ID", session_cookie[1])
|
59
|
+
end
|
60
|
+
|
61
|
+
# ログアウトする
|
62
|
+
# @param client [Client] クライアント
|
63
|
+
def self.logout(client)
|
64
|
+
begin
|
65
|
+
client.amc_client.request(
|
66
|
+
[{ "action" => "Login2Action", "event" => "logout", "moduleName" => "Empty" }]
|
67
|
+
)
|
68
|
+
rescue StandardError
|
69
|
+
# 例外を無視してログアウト処理を続ける
|
70
|
+
end
|
71
|
+
|
72
|
+
client.amc_client.header.delete_cookie("WIKIDOT_SESSION_ID")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../common/logger"
|
4
|
+
require_relative "../common/exceptions"
|
5
|
+
require_relative "../connector/ajax"
|
6
|
+
require_relative "auth"
|
7
|
+
require_relative "private_message"
|
8
|
+
require_relative "site"
|
9
|
+
require_relative "user"
|
10
|
+
|
11
|
+
module Wikidotrb
|
12
|
+
module Module
|
13
|
+
class ClientUserMethods
|
14
|
+
attr_reader :client
|
15
|
+
|
16
|
+
def initialize(client)
|
17
|
+
@client = client
|
18
|
+
end
|
19
|
+
|
20
|
+
# ユーザー名からユーザーオブジェクトを取得する
|
21
|
+
# @param name [String] ユーザー名
|
22
|
+
# @param raise_when_not_found [Boolean] ユーザーが見つからない場合に例外を送出するか
|
23
|
+
# @return [User] ユーザーオブジェクト
|
24
|
+
def get(name, raise_when_not_found: false)
|
25
|
+
Wikidotrb::Module::User.from_name(@client, name, raise_when_not_found)
|
26
|
+
end
|
27
|
+
|
28
|
+
# ユーザー名からユーザーオブジェクトを取得する
|
29
|
+
# @param names [Array<String>] ユーザー名のリスト
|
30
|
+
# @param raise_when_not_found [Boolean] ユーザーが見つからない場合に例外を送出するか
|
31
|
+
# @return [Array<User>] ユーザーオブジェクトのリスト
|
32
|
+
def get_bulk(names, raise_when_not_found: false)
|
33
|
+
Wikidotrb::Module::UserCollection.from_names(@client, names, raise_when_not_found)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class ClientPrivateMessageMethods
|
38
|
+
attr_reader :client
|
39
|
+
|
40
|
+
def initialize(client)
|
41
|
+
@client = client
|
42
|
+
end
|
43
|
+
|
44
|
+
# メッセージを送信する
|
45
|
+
# @param recipient [User] 受信者
|
46
|
+
# @param subject [String] 件名
|
47
|
+
# @param body [String] 本文
|
48
|
+
def send_message(recipient, subject, body)
|
49
|
+
Wikidotrb::Module::PrivateMessage.send_message(
|
50
|
+
client: @client, recipient: recipient, subject: subject, body: body
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
# 受信箱を取得する
|
55
|
+
# @return [PrivateMessageInbox] 受信箱
|
56
|
+
def get_inbox
|
57
|
+
Wikidotrb::Module::PrivateMessageInbox.acquire(client: @client)
|
58
|
+
end
|
59
|
+
|
60
|
+
# 送信箱を取得する
|
61
|
+
# @return [PrivateMessageSentBox] 送信箱
|
62
|
+
def get_sentbox
|
63
|
+
Wikidotrb::Module::PrivateMessageSentBox.acquire(client: @client)
|
64
|
+
end
|
65
|
+
|
66
|
+
# メッセージを取得する
|
67
|
+
# @param message_ids [Array<Integer>] メッセージIDのリスト
|
68
|
+
# @return [PrivateMessageCollection] メッセージのリスト
|
69
|
+
def get_messages(message_ids)
|
70
|
+
Wikidotrb::Module::PrivateMessageCollection.from_ids(client: @client, message_ids: message_ids)
|
71
|
+
end
|
72
|
+
|
73
|
+
# メッセージを取得する
|
74
|
+
# @param message_id [Integer] メッセージID
|
75
|
+
# @return [PrivateMessage] メッセージ
|
76
|
+
def get_message(message_id)
|
77
|
+
Wikidotrb::Module::PrivateMessage.from_id(client: @client, message_id: message_id)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class ClientSiteMethods
|
82
|
+
attr_reader :client
|
83
|
+
|
84
|
+
def initialize(client)
|
85
|
+
@client = client
|
86
|
+
end
|
87
|
+
|
88
|
+
# UNIX名からサイトオブジェクトを取得する
|
89
|
+
# @param unix_name [String] サイトのUNIX名
|
90
|
+
# @return [Site] サイトオブジェクト
|
91
|
+
def get(unix_name)
|
92
|
+
Wikidotrb::Module::Site.from_unix_name(client: client, unix_name: unix_name)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class Client
|
97
|
+
attr_accessor :amc_client, :is_logged_in, :username
|
98
|
+
attr_reader :user, :private_message, :site
|
99
|
+
|
100
|
+
# 基幹クライアント
|
101
|
+
def initialize(username: nil, password: nil, amc_config: nil, logging_level: "WARN")
|
102
|
+
# 最初にロギングレベルを決定する
|
103
|
+
Wikidotrb::Common::Logger.level = logging_level
|
104
|
+
|
105
|
+
# AMCClientを初期化
|
106
|
+
@amc_client = Wikidotrb::Connector::AjaxModuleConnectorClient.new(site_name: "www", config: amc_config)
|
107
|
+
|
108
|
+
# セッション関連変数の初期化
|
109
|
+
@is_logged_in = false
|
110
|
+
@username = nil
|
111
|
+
|
112
|
+
# usernameとpasswordが指定されていればログインする
|
113
|
+
if username && password
|
114
|
+
Wikidotrb::Module::HTTPAuthentication.login(self, username, password)
|
115
|
+
@is_logged_in = true
|
116
|
+
@username = username
|
117
|
+
end
|
118
|
+
|
119
|
+
# メソッドの定義
|
120
|
+
@user = ClientUserMethods.new(self)
|
121
|
+
@private_message = ClientPrivateMessageMethods.new(self)
|
122
|
+
@site = ClientSiteMethods.new(self)
|
123
|
+
end
|
124
|
+
|
125
|
+
# デストラクタ
|
126
|
+
def finalize
|
127
|
+
return unless @is_logged_in
|
128
|
+
|
129
|
+
Wikidotrb::Module::HTTPAuthentication.logout(self)
|
130
|
+
@is_logged_in = false
|
131
|
+
@username = nil
|
132
|
+
end
|
133
|
+
|
134
|
+
def to_s
|
135
|
+
"Client(username=#{@username}, is_logged_in=#{@is_logged_in})"
|
136
|
+
end
|
137
|
+
|
138
|
+
# ログインチェック
|
139
|
+
def login_check
|
140
|
+
raise Wikidotrb::Common::Exceptions::LoginRequiredException, "Login is required to execute this function" unless @is_logged_in
|
141
|
+
|
142
|
+
nil
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "forum_category"
|
4
|
+
require_relative "forum_group"
|
5
|
+
require_relative "forum_thread"
|
6
|
+
|
7
|
+
module Wikidotrb
|
8
|
+
module Module
|
9
|
+
class ForumCategoryMethods
|
10
|
+
# 初期化メソッド
|
11
|
+
# @param forum [Forum] フォーラムオブジェクト
|
12
|
+
def initialize(forum)
|
13
|
+
@forum = forum
|
14
|
+
end
|
15
|
+
|
16
|
+
# カテゴリをIDから取得
|
17
|
+
# @param id [Integer] カテゴリID
|
18
|
+
# @return [ForumCategory] 更新されたカテゴリ
|
19
|
+
def get(id)
|
20
|
+
category = ForumCategory.new(
|
21
|
+
site: @forum.site,
|
22
|
+
id: id,
|
23
|
+
forum: @forum
|
24
|
+
)
|
25
|
+
category.update
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class ForumThreadMethods
|
30
|
+
# 初期化メソッド
|
31
|
+
# @param forum [Forum] フォーラムオブジェクト
|
32
|
+
def initialize(forum)
|
33
|
+
@forum = forum
|
34
|
+
end
|
35
|
+
|
36
|
+
# スレッドをIDから取得
|
37
|
+
# @param id [Integer] スレッドID
|
38
|
+
# @return [ForumThread] 更新されたスレッド
|
39
|
+
def get(id)
|
40
|
+
thread = ForumThread.new(
|
41
|
+
site: @forum.site,
|
42
|
+
id: id,
|
43
|
+
forum: @forum
|
44
|
+
)
|
45
|
+
thread.update
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Forum
|
50
|
+
attr_accessor :site, :_groups, :_categories
|
51
|
+
|
52
|
+
# 初期化メソッド
|
53
|
+
# @param site [Site] サイトオブジェクト
|
54
|
+
def initialize(site:)
|
55
|
+
@site = site
|
56
|
+
@name = "Forum"
|
57
|
+
@_groups = nil
|
58
|
+
@_categories = nil
|
59
|
+
@category = ForumCategoryMethods.new(self)
|
60
|
+
@thread = ForumThreadMethods.new(self)
|
61
|
+
end
|
62
|
+
|
63
|
+
# カテゴリメソッドオブジェクトを取得
|
64
|
+
# @return [ForumCategoryMethods] カテゴリメソッド
|
65
|
+
attr_reader :category
|
66
|
+
|
67
|
+
# スレッドメソッドオブジェクトを取得
|
68
|
+
# @return [ForumThreadMethods] スレッドメソッド
|
69
|
+
attr_reader :thread
|
70
|
+
|
71
|
+
# フォーラムのURLを取得
|
72
|
+
# @return [String] フォーラムのURL
|
73
|
+
def get_url
|
74
|
+
"#{@site.get_url}/forum/start"
|
75
|
+
end
|
76
|
+
|
77
|
+
# グループのプロパティ
|
78
|
+
# @return [ForumGroupCollection] グループコレクション
|
79
|
+
def groups
|
80
|
+
ForumGroupCollection.get_groups(site: @site, forum: self) if @_groups.nil?
|
81
|
+
@_groups
|
82
|
+
end
|
83
|
+
|
84
|
+
# カテゴリのプロパティ
|
85
|
+
# @return [ForumCategoryCollection] カテゴリコレクション
|
86
|
+
def categories
|
87
|
+
ForumCategoryCollection.get_categories(site: @site, forum: self) if @_categories.nil?
|
88
|
+
@_categories
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nokogiri"
|
4
|
+
require "date"
|
5
|
+
require_relative "forum_thread"
|
6
|
+
|
7
|
+
module Wikidotrb
|
8
|
+
module Module
|
9
|
+
class ForumCategoryCollection < Array
|
10
|
+
attr_accessor :forum
|
11
|
+
|
12
|
+
# 初期化メソッド
|
13
|
+
# @param forum [Forum] フォーラムオブジェクト
|
14
|
+
# @param categories [Array<ForumCategory>] カテゴリーのリスト
|
15
|
+
def initialize(forum:, categories: [])
|
16
|
+
super(categories)
|
17
|
+
@forum = forum
|
18
|
+
end
|
19
|
+
|
20
|
+
# サイトとフォーラムからカテゴリを取得
|
21
|
+
# @param site [Site] サイトオブジェクト
|
22
|
+
# @param forum [Forum] フォーラムオブジェクト
|
23
|
+
def self.get_categories(site:, forum:)
|
24
|
+
categories = []
|
25
|
+
|
26
|
+
forum.groups.each do |group|
|
27
|
+
categories.concat(group.categories)
|
28
|
+
end
|
29
|
+
|
30
|
+
forum._categories = ForumCategoryCollection.new(forum: forum, categories: categories)
|
31
|
+
end
|
32
|
+
|
33
|
+
# IDまたはタイトルからカテゴリを検索
|
34
|
+
# @param id [Integer] カテゴリID
|
35
|
+
# @param title [String] カテゴリのタイトル
|
36
|
+
# @return [ForumCategory, nil] 一致するカテゴリ
|
37
|
+
def find(id: nil, title: nil)
|
38
|
+
find do |category|
|
39
|
+
(id.nil? || category.id == id) && (title.nil? || category.title == title)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# カテゴリ情報を取得して更新する
|
44
|
+
# @param forum [Forum] フォーラムオブジェクト
|
45
|
+
# @param categories [Array<ForumCategory>] カテゴリーのリスト
|
46
|
+
# @return [Array<ForumCategory>] 更新されたカテゴリのリスト
|
47
|
+
def self.acquire_update(forum:, categories:)
|
48
|
+
return categories if categories.empty?
|
49
|
+
|
50
|
+
responses = forum.site.amc_request(
|
51
|
+
bodies: categories.map { |category| { "c" => category.id, "moduleName" => "forum/ForumViewCategoryModule" } }
|
52
|
+
)
|
53
|
+
|
54
|
+
responses.each_with_index do |response, index|
|
55
|
+
category = categories[index]
|
56
|
+
html = Nokogiri::HTML(response.body.to_s)
|
57
|
+
statistics = html.at_css("div.statistics").text
|
58
|
+
description = html.at_css("div.description-block").text.strip
|
59
|
+
info = html.at_css("div.forum-breadcrumbs").text.match(%r{([ \S]*) / ([ \S]*)})
|
60
|
+
counts = statistics.scan(/\d+/).map(&:to_i)
|
61
|
+
|
62
|
+
category.last = nil if category.posts_counts != counts[1]
|
63
|
+
category.description = description.match(/[ \S]*$/)[0]
|
64
|
+
category.threads_counts, category.posts_counts = counts
|
65
|
+
category.group = category.forum.groups.find(info[1])
|
66
|
+
category.title = info[2]
|
67
|
+
pager_no = html.at_css("span.pager-no")
|
68
|
+
category.pagerno = pager_no.nil? ? 1 : pager_no.text.match(/of (\d+)/)[1].to_i
|
69
|
+
end
|
70
|
+
|
71
|
+
categories
|
72
|
+
end
|
73
|
+
|
74
|
+
# カテゴリ情報を更新
|
75
|
+
def update
|
76
|
+
ForumCategoryCollection.acquire_update(forum: @forum, categories: self)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class ForumCategory
|
81
|
+
attr_accessor :site, :id, :forum, :title, :description, :group, :threads_counts, :posts_counts, :pagerno
|
82
|
+
attr_reader :last
|
83
|
+
|
84
|
+
def initialize(site:, id:, forum:, title: nil, description: nil, group: nil, threads_counts: nil,
|
85
|
+
posts_counts: nil, pagerno: nil, last_thread_id: nil, last_post_id: nil)
|
86
|
+
@site = site
|
87
|
+
@id = id
|
88
|
+
@forum = forum
|
89
|
+
@title = title
|
90
|
+
@description = description
|
91
|
+
@group = group
|
92
|
+
@threads_counts = threads_counts
|
93
|
+
@posts_counts = posts_counts
|
94
|
+
@pagerno = pagerno
|
95
|
+
@_last_thread_id = last_thread_id
|
96
|
+
@_last_post_id = last_post_id
|
97
|
+
@_last = nil
|
98
|
+
end
|
99
|
+
|
100
|
+
# カテゴリのURLを取得
|
101
|
+
def get_url
|
102
|
+
"#{@site.get_url}/forum/c-#{@id}"
|
103
|
+
end
|
104
|
+
|
105
|
+
# カテゴリを更新
|
106
|
+
def update
|
107
|
+
ForumCategoryCollection.new(forum: @forum, categories: [self]).update.first
|
108
|
+
end
|
109
|
+
|
110
|
+
# 最後の投稿を取得
|
111
|
+
def last
|
112
|
+
@_last = @forum.thread.get(@_last_thread_id).get(@_last_post_id) if @_last_thread_id && @_last_post_id && @_last.nil?
|
113
|
+
@_last
|
114
|
+
end
|
115
|
+
|
116
|
+
# 最後の投稿を設定
|
117
|
+
def last=(value)
|
118
|
+
@_last = value
|
119
|
+
end
|
120
|
+
|
121
|
+
# スレッドのコレクションを取得する
|
122
|
+
# @return [ForumThreadCollection] スレッドオブジェクトのコレクション
|
123
|
+
def threads
|
124
|
+
client = @site.client
|
125
|
+
update
|
126
|
+
responses = @site.amc_request(
|
127
|
+
bodies: (1..@pagerno).map { |no| { "p" => no, "c" => @id, "moduleName" => "forum/ForumViewCategoryModule" } }
|
128
|
+
)
|
129
|
+
|
130
|
+
threads = []
|
131
|
+
|
132
|
+
responses.each do |response|
|
133
|
+
html = Nokogiri::HTML(response.body.to_s)
|
134
|
+
html.css("table.table tr.head~tr").each do |info|
|
135
|
+
title = info.at_css("div.title a")
|
136
|
+
thread_id = title["href"].match(/t-(\d+)/)[1].to_i
|
137
|
+
description = info.at_css("div.description").text.strip
|
138
|
+
user = info.at_css("span.printuser")
|
139
|
+
odate = info.at_css("span.odate")
|
140
|
+
posts_count = info.at_css("td.posts").text.to_i
|
141
|
+
last_id = info.at_css("td.last>a")
|
142
|
+
post_id = last_id.nil? ? nil : last_id["href"].match(/post-(\d+)/)[1].to_i
|
143
|
+
|
144
|
+
thread = ForumThread.new(
|
145
|
+
site: @site,
|
146
|
+
id: thread_id,
|
147
|
+
forum: @forum,
|
148
|
+
title: title.text.strip,
|
149
|
+
description: description,
|
150
|
+
created_by: user_parser(client, user),
|
151
|
+
created_at: odate_parser(odate),
|
152
|
+
posts_counts: posts_count,
|
153
|
+
_last_post_id: post_id
|
154
|
+
)
|
155
|
+
|
156
|
+
threads << thread
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
ForumThreadCollection.new(forum: @forum, threads: threads)
|
161
|
+
end
|
162
|
+
|
163
|
+
# 新しいスレッドを作成
|
164
|
+
def new_thread(title:, source:, description: "")
|
165
|
+
client = @site.client
|
166
|
+
client.login_check
|
167
|
+
|
168
|
+
response = @site.amc_request(
|
169
|
+
bodies: [
|
170
|
+
{
|
171
|
+
"category_id" => @id,
|
172
|
+
"title" => title,
|
173
|
+
"description" => description,
|
174
|
+
"source" => source,
|
175
|
+
"action" => "ForumAction",
|
176
|
+
"event" => "newThread"
|
177
|
+
}
|
178
|
+
]
|
179
|
+
).first
|
180
|
+
|
181
|
+
body = JSON.parse(response.body.to_s)
|
182
|
+
|
183
|
+
ForumThread.new(
|
184
|
+
site: @site,
|
185
|
+
id: body["threadId"].to_i,
|
186
|
+
forum: @forum,
|
187
|
+
category: self,
|
188
|
+
title: title,
|
189
|
+
description: description,
|
190
|
+
created_by: client.user.get(client.username),
|
191
|
+
created_at: DateTime.parse(body["CURRENT_TIMESTAMP"]),
|
192
|
+
posts_counts: 1
|
193
|
+
)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nokogiri"
|
4
|
+
require "json"
|
5
|
+
require_relative "forum_category"
|
6
|
+
|
7
|
+
module Wikidotrb
|
8
|
+
module Module
|
9
|
+
class ForumGroupCollection < Array
|
10
|
+
attr_accessor :forum
|
11
|
+
|
12
|
+
# 初期化メソッド
|
13
|
+
# @param forum [Forum] フォーラムオブジェクト
|
14
|
+
# @param groups [Array<ForumGroup>] グループのリスト
|
15
|
+
def initialize(forum:, groups: [])
|
16
|
+
super(groups)
|
17
|
+
@forum = forum
|
18
|
+
end
|
19
|
+
|
20
|
+
# サイトとフォーラムからグループを取得
|
21
|
+
# @param site [Site] サイトオブジェクト
|
22
|
+
# @param forum [Forum] フォーラムオブジェクト
|
23
|
+
def self.get_groups(site:, forum:)
|
24
|
+
groups = []
|
25
|
+
|
26
|
+
response = site.amc_request(bodies: [{ "moduleName" => "forum/ForumStartModule", "hidden" => "true" }]).first
|
27
|
+
body = JSON.parse(response.body)["body"]
|
28
|
+
html = Nokogiri::HTML(body)
|
29
|
+
|
30
|
+
html.css("div.forum-group").each do |group_info|
|
31
|
+
group = ForumGroup.new(
|
32
|
+
site: site,
|
33
|
+
forum: forum,
|
34
|
+
title: group_info.at_css("div.title").text.strip,
|
35
|
+
description: group_info.at_css("div.description").text.strip
|
36
|
+
)
|
37
|
+
|
38
|
+
categories = []
|
39
|
+
|
40
|
+
group_info.css("table tr.head~tr").each do |info|
|
41
|
+
name = info.at_css("td.name")
|
42
|
+
thread_count = info.at_css("td.threads").text.strip.to_i
|
43
|
+
post_count = info.at_css("td.posts").text.strip.to_i
|
44
|
+
last_id = info.at_css("td.last>a")
|
45
|
+
if last_id.nil?
|
46
|
+
thread_id = nil
|
47
|
+
post_id = nil
|
48
|
+
else
|
49
|
+
thread_id, post_id = last_id["href"].match(/t-(\d+).+post-(\d+)/).captures.map(&:to_i)
|
50
|
+
end
|
51
|
+
|
52
|
+
category = ForumCategory.new(
|
53
|
+
site: site,
|
54
|
+
id: name.at_css("a")["href"].match(/c-(\d+)/)[1].to_i,
|
55
|
+
description: name.at_css("div.description").text.strip,
|
56
|
+
forum: forum,
|
57
|
+
title: name.at_css("a").text.strip,
|
58
|
+
group: group,
|
59
|
+
threads_counts: thread_count,
|
60
|
+
posts_counts: post_count,
|
61
|
+
last_thread_id: thread_id,
|
62
|
+
last_post_id: post_id
|
63
|
+
)
|
64
|
+
|
65
|
+
categories << category
|
66
|
+
end
|
67
|
+
|
68
|
+
group.categories = ForumCategoryCollection.new(forum: forum, categories: categories)
|
69
|
+
|
70
|
+
groups << group
|
71
|
+
end
|
72
|
+
|
73
|
+
forum._groups = ForumGroupCollection.new(forum: forum, groups: groups)
|
74
|
+
end
|
75
|
+
|
76
|
+
# グループをタイトルと説明から検索
|
77
|
+
# @param title [String] グループのタイトル
|
78
|
+
# @param description [String] グループの説明
|
79
|
+
# @return [ForumGroup, nil] 見つかったグループ
|
80
|
+
def find(title: nil, description: nil)
|
81
|
+
find do |group|
|
82
|
+
(title.nil? || group.title == title) && (description.nil? || group.description == description)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# 条件に一致するすべてのグループを検索
|
87
|
+
# @param title [String] グループのタイトル
|
88
|
+
# @param description [String] グループの説明
|
89
|
+
# @return [Array<ForumGroup>] 見つかったグループのリスト
|
90
|
+
def findall(title: nil, description: nil)
|
91
|
+
select do |group|
|
92
|
+
(title.nil? || group.title == title) && (description.nil? || group.description == description)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class ForumGroup
|
98
|
+
attr_accessor :site, :forum, :title, :description, :categories
|
99
|
+
|
100
|
+
def initialize(site:, forum:, title:, description:, categories: nil)
|
101
|
+
@site = site
|
102
|
+
@forum = forum
|
103
|
+
@title = title
|
104
|
+
@description = description
|
105
|
+
@categories = categories || ForumCategoryCollection.new(forum: forum)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|