impostor 0.2.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/.gemtest +0 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +2 -0
  4. data/.rvmrc +1 -0
  5. data/Gemfile +17 -0
  6. data/Gemfile.lock +47 -0
  7. data/History.txt +8 -0
  8. data/Manifest.txt +87 -55
  9. data/README.txt +11 -11
  10. data/Rakefile +16 -20
  11. data/lib/impostor/auth.rb +103 -0
  12. data/lib/impostor/config.rb +171 -0
  13. data/lib/impostor/errors.rb +67 -0
  14. data/lib/impostor/phpbb2.rb +202 -0
  15. data/lib/impostor/phpbb3.rb +199 -0
  16. data/lib/impostor/post.rb +111 -0
  17. data/lib/impostor/topic.rb +115 -0
  18. data/lib/impostor/wwf79.rb +186 -0
  19. data/lib/impostor/wwf80.rb +190 -0
  20. data/lib/impostor.rb +108 -5
  21. data/spec/auth_spec.rb +148 -0
  22. data/spec/base_spec_helper.rb +12 -0
  23. data/{test/test_helper.rb → spec/caged_net_http.rb} +8 -17
  24. data/spec/config_spec.rb +136 -0
  25. data/spec/fixtures/junk.html +1 -0
  26. data/{test → spec}/fixtures/phpbb2-get-new_topic-form-good-response.html +0 -0
  27. data/{test → spec}/fixtures/phpbb2-get-viewtopic-for-new-topic-good-response.html +11 -11
  28. data/{test → spec}/fixtures/phpbb2-get-viewtopic-for-new-topic-malformed-response.html +0 -0
  29. data/{test → spec}/fixtures/phpbb2-index.html +0 -0
  30. data/{test → spec}/fixtures/phpbb2-logged-in.html +0 -0
  31. data/{test → spec}/fixtures/phpbb2-login.html +0 -0
  32. data/{test → spec}/fixtures/phpbb2-not-logged-in.html +0 -0
  33. data/{test → spec}/fixtures/phpbb2-post-new_topic-good-response.html +0 -0
  34. data/{test → spec}/fixtures/phpbb2-post-reply-good-response.html +0 -0
  35. data/{test → spec}/fixtures/phpbb2-post-reply-throttled-response.html +0 -0
  36. data/{test → spec}/fixtures/phpbb2-too-many-posts.html +0 -0
  37. data/{test → spec}/fixtures/phpbb3-get-new-topic-form-good-response.html +0 -0
  38. data/{test → spec}/fixtures/phpbb3-get-reply-form-good-response.html +0 -0
  39. data/{test → spec}/fixtures/phpbb3-logged-in.html +0 -0
  40. data/{test → spec}/fixtures/phpbb3-login.html +0 -0
  41. data/{test → spec}/fixtures/phpbb3-not-logged-in.html +0 -0
  42. data/{test → spec}/fixtures/phpbb3-post-new_topic-good-response.html +0 -0
  43. data/{test → spec}/fixtures/phpbb3-post-reply-good-response.html +0 -0
  44. data/spec/fixtures/vcr_cassettes/phpbb2-should-be-overlimit-creating-topic.yml +1308 -0
  45. data/spec/fixtures/vcr_cassettes/phpbb2-should-create-topic.yml +923 -0
  46. data/spec/fixtures/vcr_cassettes/phpbb2-should-login.yml +360 -0
  47. data/spec/fixtures/vcr_cassettes/phpbb2-should-not-create-new-topic.yml +497 -0
  48. data/spec/fixtures/vcr_cassettes/phpbb2-should-not-login.yml +287 -0
  49. data/spec/fixtures/vcr_cassettes/phpbb2-should-not-post.yml +497 -0
  50. data/spec/fixtures/vcr_cassettes/phpbb2-should-overlimit-error-post.yml +1140 -0
  51. data/spec/fixtures/vcr_cassettes/phpbb2-should-post.yml +751 -0
  52. data/spec/fixtures/vcr_cassettes/phpbb3-should-be-overlimit-creating-topic.yml +995 -0
  53. data/spec/fixtures/vcr_cassettes/phpbb3-should-create-topic.yml +675 -0
  54. data/spec/fixtures/vcr_cassettes/phpbb3-should-login.yml +245 -0
  55. data/spec/fixtures/vcr_cassettes/phpbb3-should-not-create-new-topic.yml +350 -0
  56. data/spec/fixtures/vcr_cassettes/phpbb3-should-not-login.yml +253 -0
  57. data/spec/fixtures/vcr_cassettes/phpbb3-should-not-post.yml +350 -0
  58. data/spec/fixtures/vcr_cassettes/phpbb3-should-overlimit-error-post.yml +1046 -0
  59. data/spec/fixtures/vcr_cassettes/phpbb3-should-post.yml +605 -0
  60. data/{test → spec}/fixtures/wwf79-forum_posts.html +0 -0
  61. data/{test → spec}/fixtures/wwf79-general-new-topic-error.html +0 -0
  62. data/{test → spec}/fixtures/wwf79-general-posting-error.html +0 -0
  63. data/{test → spec}/fixtures/wwf79-good-post-forum_posts.html +1 -1
  64. data/{test → spec}/fixtures/wwf79-index.html +0 -0
  65. data/{test → spec}/fixtures/wwf79-logged-in.html +0 -0
  66. data/{test → spec}/fixtures/wwf79-login.html +0 -0
  67. data/{test → spec}/fixtures/wwf79-new-topic-forum_posts-response.html +0 -0
  68. data/{test → spec}/fixtures/wwf79-new-topic-post_message_form.html +0 -0
  69. data/{test → spec}/fixtures/wwf79-not-logged-in.html +0 -0
  70. data/{test → spec}/fixtures/wwf79-too-many-posts.html +0 -0
  71. data/{test → spec}/fixtures/wwf79-too-many-topics.html +0 -0
  72. data/{test → spec}/fixtures/wwf80-general-posting-error.html +0 -0
  73. data/{test → spec}/fixtures/wwf80-get-new_topic-form-good-response.html +0 -0
  74. data/{test → spec}/fixtures/wwf80-get-viewtopic-for-new-topic-good-response.html +0 -0
  75. data/{test → spec}/fixtures/wwf80-index.html +0 -0
  76. data/{test → spec}/fixtures/wwf80-logged-in.html +0 -0
  77. data/{test → spec}/fixtures/wwf80-login.html +0 -0
  78. data/{test → spec}/fixtures/wwf80-new_reply_form.html +0 -0
  79. data/{test → spec}/fixtures/wwf80-not-logged-in.html +0 -0
  80. data/{test → spec}/fixtures/wwf80-post-new_topic-good-response.html +1 -1
  81. data/{test → spec}/fixtures/wwf80-post-reply-good-response.html +0 -0
  82. data/{test → spec}/fixtures/wwf80-too-many-posts.html +0 -0
  83. data/spec/impostor_spec_helper.rb +162 -0
  84. data/spec/integration/phpbb2_spec.rb +111 -0
  85. data/spec/integration/phpbb3_spec.rb +109 -0
  86. data/spec/integration_spec_helper.rb +7 -0
  87. data/spec/phpbb2_spec.rb +346 -0
  88. data/spec/phpbb3_spec.rb +332 -0
  89. data/spec/post_spec.rb +134 -0
  90. data/spec/spec_helper.rb +2 -0
  91. data/spec/test_impostor.rb +12 -0
  92. data/spec/topic_spec.rb +143 -0
  93. data/spec/wwf79_spec.rb +342 -0
  94. data/spec/wwf80_spec.rb +339 -0
  95. metadata +156 -87
  96. data/lib/www/impostor/phpbb2.rb +0 -258
  97. data/lib/www/impostor/phpbb3.rb +0 -236
  98. data/lib/www/impostor/wwf79.rb +0 -254
  99. data/lib/www/impostor/wwf80.rb +0 -264
  100. data/lib/www/impostor.rb +0 -269
  101. data/test/test_github.rb +0 -12
  102. data/test/test_www_impostor.rb +0 -165
  103. data/test/test_www_impostor_phpbb2.rb +0 -536
  104. data/test/test_www_impostor_phpbb3.rb +0 -483
  105. data/test/test_www_impostor_wwf79.rb +0 -535
  106. data/test/test_www_impostor_wwf80.rb +0 -535
  107. data/vendor/plugins/impostor/lib/autotest/discover.rb +0 -3
  108. data/vendor/plugins/impostor/lib/autotest/impostor.rb +0 -49
@@ -0,0 +1,67 @@
1
+ class Impostor
2
+
3
+ ##
4
+ # An application error
5
+
6
+ class ImpostorError < RuntimeError
7
+
8
+ ##
9
+ # The original exception
10
+
11
+ attr_accessor :original_exception
12
+
13
+ ##
14
+ # Creates a new ImpostorError with +message+ and +original_exception+
15
+
16
+ def initialize(e = nil)
17
+ exception = e.nil? || e.is_a?(String) ? StandardError.new(e) : e
18
+ @original_exception = exception
19
+ message = "Impostor error: #{exception.message} (#{exception.class})"
20
+ super message
21
+ end
22
+
23
+ end
24
+
25
+ ##
26
+ # An error for impostor login failure
27
+
28
+ class LoginError < ImpostorError; end
29
+
30
+ ##
31
+ # An error for impostor post failure
32
+
33
+ class PostError < ImpostorError; end
34
+
35
+ ##
36
+ # An error for impostor when a topic failure
37
+
38
+ class TopicError < ImpostorError; end
39
+
40
+ ##
41
+ # An error for impostor when the receiving forum rejects the post due to
42
+ # a throttling or spam error but which the user can re-attempt at a later
43
+ # time.
44
+
45
+ class ThrottledError < ImpostorError; end
46
+
47
+ ##
48
+ # An error for misconfiguration
49
+
50
+ class ConfigError < ImpostorError; end
51
+
52
+ ##
53
+ # An error for template methods that need to be implemented
54
+
55
+ class MissingTemplateMethodError < ImpostorError; end
56
+
57
+ ##
58
+ # An exception for when a new topic has been moderated
59
+
60
+ class TopicModerated < ImpostorError; end
61
+
62
+ ##
63
+ # An exception for when a new post has been moderated
64
+
65
+ class PostModerated < ImpostorError; end
66
+
67
+ end
@@ -0,0 +1,202 @@
1
+ ##
2
+ # phpBB2 version of the Impostor
3
+ #
4
+
5
+ class Impostor
6
+
7
+ module Phpbb2
8
+
9
+ ##
10
+ # Additional configuration parameters for a Phpbb2 compatible agent:
11
+ #
12
+ # :posting_page
13
+ #
14
+ # Typical configuration parameters
15
+ # { :type => :phpbb2,
16
+ # :app_root => 'http://example.com/forum/',
17
+ # :login_page => 'login.php',
18
+ # :posting_page => 'posting.php',
19
+ # :user_agent => 'Windows IE 7',
20
+ # :username => 'myuser',
21
+ # :password => 'mypasswd' }
22
+
23
+ module Auth
24
+
25
+ ##
26
+ # Checks if the agent is already logged by stored cookie
27
+
28
+ def logged_in?(page)
29
+ mm = page.search( "//a" ).detect{ | a| a.inner_html =~ /Log out \[ #{self.config.username} \]/ } ||
30
+ page.search( "//a" ).detect{ |a| a['href'] =~ /\/login\.php\?mode=logout/ }
31
+
32
+ not mm.nil?
33
+ end
34
+
35
+ ##
36
+ # returns the login form from the login page
37
+
38
+ def get_login_form(page)
39
+ form = page.forms.detect { |form| form.action =~ /login\.php/ }
40
+ raise Impostor::LoginError.new("unknown login page format") unless form
41
+ form
42
+ end
43
+
44
+ ##
45
+ # Sets the user name and pass word on the loing form.
46
+
47
+ def set_username_and_password(form)
48
+ form['username'] = self.config.username
49
+ form['password'] = self.config.password
50
+ form['autologin'] = 'on'
51
+ form['login'] = 'Log in'
52
+ form
53
+ end
54
+
55
+ end
56
+
57
+ module Post
58
+
59
+ ##
60
+ # return a uri used to fetch the reply page based on the forum, topic, and
61
+ # message
62
+
63
+ def get_reply_uri(forum, topic)
64
+ uri = URI.join(self.config.app_root, self.config.config(:posting_page))
65
+ uri.query = "mode=reply&t=#{topic}"
66
+ uri
67
+ end
68
+
69
+ ##
70
+ # return the form used for posting a message from the reply page
71
+
72
+ def get_post_form(page)
73
+ form = page.forms.detect { |form| form.action =~ /#{Regexp.escape(self.config.config(:posting_page))}/ }
74
+ raise Impostor::PostError.new("unknown reply page format#{page_message(page, ', ')}") unless form
75
+ form
76
+ end
77
+
78
+ ##
79
+ # set the message to reply with on the reply form
80
+
81
+ def set_message(form, message)
82
+ form.message = message
83
+ form["post"] = "Submit"
84
+ form
85
+ end
86
+
87
+ ##
88
+ # get post id from the result of posting the message form
89
+
90
+ def get_post_from_result(page)
91
+ message = page_message(page)
92
+ if message =~ /Your message has been entered successfully./
93
+ kv = page.links.collect{ |l| l.uri }.compact.
94
+ collect{ |l| l.query }.compact.
95
+ collect{ |q| q.split('&')}.flatten.
96
+ detect{|kv| kv =~ /^p=/ }
97
+ postid = URI.unescape(kv).split('#').first.split('=').last.to_i
98
+ raise Impostor::PostError.new("Message did not post.") if postid.zero?
99
+ return postid
100
+ end
101
+
102
+ too_many = message =~ /You cannot make another post so soon after your last/
103
+
104
+ if too_many
105
+ raise Impostor::ThrottledError.new("too many posts in too short amount of time")
106
+ else
107
+ raise Impostor::PostError.new("message did not post")
108
+ end
109
+ end
110
+
111
+ def page_message(page, prepend = '')
112
+ message = page.search("//span[@class='gen']").last || ''
113
+ message = message.text if message.respond_to?(:text)
114
+ prepend = '' if message.empty?
115
+ "#{prepend}#{message}"
116
+ end
117
+
118
+ end
119
+
120
+ module Topic
121
+
122
+ ##
123
+ # return a uri used to fetch the new topic page based on the forum, subject,
124
+ # and message
125
+
126
+ def get_new_topic_uri(forum, subject, message)
127
+ uri = URI.join(self.config.app_root, self.config.config(:posting_page))
128
+ uri.query = "mode=newtopic&f=#{forum}"
129
+ uri
130
+ end
131
+
132
+ ##
133
+ # Get the the new topic form on the page
134
+
135
+ def get_new_topic_form(page)
136
+ form = page.form('post')
137
+ raise Impostor::TopicError.new("unknown new topic page format") unless form
138
+ form
139
+ end
140
+
141
+ ##
142
+ # Set the subject and message on the new topic form
143
+
144
+ def set_subject_and_message(form, subject, message)
145
+ form.subject = subject
146
+ form.message = message
147
+ form["post"] = "Submit"
148
+ form
149
+ end
150
+
151
+ ##
152
+ # Validate the result of posting the new topic
153
+
154
+ def validate_new_topic_result(page)
155
+ message = page_message(page)
156
+ if message !~ /Your message has been entered successfully./
157
+ if message =~ /You cannot make another post so soon after your last/
158
+ raise Impostor::ThrottledError.new("too many new topics in too short amount of time")
159
+ else
160
+ raise Impostor::TopicError.new("Topic did not post.")
161
+ end
162
+ end
163
+
164
+ begin
165
+ # <td align="center"><span class="gen">Your message has been entered successfully.<br /><br />Click <a href="viewtopic.php?p=9#9">Here</a> to view your message<br /><br />Click <a href="viewforum.php?f=1">Here</a> to return to the forum</span></td>
166
+
167
+ # TODO the link has the postid specifically for the post, not all
168
+ # forums make it easy to deduce the post id
169
+ link = page.links.detect{ |l| l.href =~ /viewtopic\.php/ }
170
+ link.click
171
+ rescue StandardError => err
172
+ raise Impostor::TopicError.new(err)
173
+ end
174
+ end
175
+
176
+ ##
177
+ # Get the new topic identifier from the result page
178
+
179
+ def get_topic_from_result(page)
180
+ begin
181
+ link = page.links.detect{ |l| l.href =~ /viewtopic\.php/ }
182
+ kv = link.uri.query.split('&').detect{|kv| kv =~ /^t=/ }
183
+ topicid = URI.unescape(kv).split('#').first.split('=').last.to_i
184
+ rescue StandardError => err
185
+ raise Impostor::TopicError.new(err)
186
+ end
187
+ raise Impostor::TopicError.new("Failed to create topic.") if topicid.zero?
188
+
189
+ topicid
190
+ end
191
+
192
+ def page_message(page, prepend = '')
193
+ message = page.search("//span[@class='gen']").last || ''
194
+ message = message.text if message.respond_to?(:text)
195
+ prepend = '' if message.empty?
196
+ "#{prepend}#{message}"
197
+ end
198
+
199
+ end
200
+
201
+ end
202
+ end
@@ -0,0 +1,199 @@
1
+ ##
2
+ # phpBB3 version of the Impostor
3
+ #
4
+
5
+ class Impostor
6
+
7
+ module Phpbb3
8
+
9
+ ##
10
+ # Additional configuration parameters for a Phpbb3 compatible agent:
11
+ #
12
+ # :posting_page
13
+ #
14
+ # Typical configuration parameters
15
+ # { :type => :phpbb3,
16
+ # :app_root => 'http://example.com/forum/',
17
+ # :login_page => 'ucp.php?mode=login',
18
+ # :posting_page => 'posting.php',
19
+ # :user_agent => 'Windows IE 7',
20
+ # :username => 'myuser',
21
+ # :password => 'mypasswd' }
22
+
23
+ module Auth
24
+
25
+ ##
26
+ # Checks if the agent is already logged by stored cookie
27
+
28
+ def logged_in?(page)
29
+ mm = page.search( "//a" ).detect{ | a| a.inner_html =~ /Logout \[ #{self.config.username} \]/ } ||
30
+ page.search( "//a" ).detect{ |a| a['href'] =~ /\.\/ucp\.php\?mode=logout/ }
31
+
32
+ not mm.nil?
33
+ end
34
+
35
+ ##
36
+ # returns the login form from the login page
37
+
38
+ def get_login_form(page)
39
+ form = page.forms.detect { |form| form.action =~ /\/ucp\.php\?mode=login/ }
40
+ raise Impostor::LoginError.new("unknown login page format") unless form
41
+ form
42
+ end
43
+
44
+ ##
45
+ # Sets the user name and pass word on the loing form.
46
+
47
+ def set_username_and_password(form)
48
+ form['username'] = self.config.username
49
+ form['password'] = self.config.password
50
+ form['login'] = 'Login'
51
+ form['autologin'] = 'on'
52
+ form
53
+ end
54
+
55
+ end
56
+
57
+ module Post
58
+
59
+ ##
60
+ # return a uri used to fetch the reply page based on the forum, topic, and
61
+ # message
62
+
63
+ def get_reply_uri(forum, topic)
64
+ uri = URI.join(self.config.app_root, self.config.config(:posting_page))
65
+ uri.query = "mode=reply&f=#{forum}&t=#{topic}"
66
+ uri
67
+ end
68
+
69
+ ##
70
+ # return the form used for posting a message from the reply page
71
+
72
+ def get_post_form(page)
73
+ form = page.forms.detect { |form| form.action =~ /#{Regexp.escape(self.config.config(:posting_page))}/ }
74
+ raise Impostor::PostError.new("unknown reply page format") unless form
75
+ form
76
+ end
77
+
78
+ ##
79
+ # set the message to reply with on the reply form
80
+
81
+ def set_message(form, message)
82
+ form.message = message
83
+ form["post"] = "Submit"
84
+ form
85
+ end
86
+
87
+ ##
88
+ # get post id from the result of posting the message form
89
+
90
+ def get_post_from_result(page)
91
+ error_message = page_error_message(page)
92
+ if error_message =~ /You cannot make another post so soon after your last/
93
+ raise Impostor::ThrottledError.new("too many posts in too short amount of time, #{error_message}")
94
+ elsif !error_message.empty?
95
+ raise Impostor::PostError.new(error_message)
96
+ end
97
+
98
+ begin
99
+ kv = page.links.collect{ |l| l.uri }.compact.
100
+ collect{ |l| l.query }.compact.
101
+ collect{ |q| q.split('&')}.flatten.
102
+ detect { |p| p =~ /^p=/ }
103
+ raise StandardError.new("Message did not post.") if kv.nil?
104
+ postid = URI.unescape(kv).split('#').first.split('=').last.to_i
105
+ raise StandardError.new("Message did not post.") if postid.zero?
106
+ postid
107
+ rescue StandardError => err
108
+ raise Impostor::PostError.new(err)
109
+ end
110
+ end
111
+
112
+ ##
113
+ # Extract the error from a page
114
+
115
+ def page_error_message(page, prepend='')
116
+ message = page.search(".//p[@class='error']").last || ''
117
+ message = message.text if message.respond_to?(:text)
118
+ prepend = '' if message.empty?
119
+ "#{prepend}#{message}"
120
+ end
121
+
122
+ end
123
+
124
+ module Topic
125
+
126
+ ##
127
+ # return a uri used to fetch the new topic page based on the forum, subject,
128
+ # and message
129
+
130
+ def get_new_topic_uri(forum, subject, message)
131
+ uri = URI.join(self.config.app_root, self.config.config(:posting_page))
132
+ uri.query = "mode=post&f=#{forum}"
133
+ uri
134
+ end
135
+
136
+ ##
137
+ # Get the the new topic form on the page
138
+
139
+ def get_new_topic_form(page)
140
+ form = page.forms.detect { |form| form.action =~ /#{Regexp.escape(self.config.config(:posting_page))}/ }
141
+ raise Impostor::TopicError.new("unknown new topic page format") unless form
142
+ form
143
+ end
144
+
145
+ ##
146
+ # Set the subject and message on the new topic form
147
+
148
+ def set_subject_and_message(form, subject, message)
149
+ form.subject = subject
150
+ form.message = message
151
+ form["post"] = "Submit"
152
+ form
153
+ end
154
+
155
+ ##
156
+ # Validate the result of posting the new topic
157
+
158
+ def validate_new_topic_result(page)
159
+ error_message = page_error_message(page)
160
+ if error_message =~ /You cannot make another post so soon after your last/
161
+ raise Impostor::ThrottledError.new("too many posts in too short amount of time, #{error_message}")
162
+ elsif !error_message.empty?
163
+ raise Impostor::PostError.new(error_message)
164
+ end
165
+
166
+ page
167
+ end
168
+
169
+ ##
170
+ # Get the new topic identifier from the result page
171
+
172
+ def get_topic_from_result(page)
173
+ moderated = page.body =~ /it will need to be approved by a moderator/i
174
+ raise Impostor::TopicModerated.new("new topic has been moderated") if moderated
175
+
176
+ link = page.links.detect{ |l| l.text =~ /View your submitted message/i }
177
+ link ||= page.links.detect{ |l| l.href =~ /viewtopic\.php/ }
178
+ raise Impostor::TopicError.new("new topic did not post") unless link
179
+ topic = link.uri.query.split('&').detect{|a| a =~ /^t=/}
180
+ raise Impostor::TopicError.new("new topic did not post") unless topic
181
+ topic = topic.split('=').last.to_i
182
+ raise Impostor::TopicError.new("new topic did not post") if topic.zero?
183
+ topic
184
+ end
185
+
186
+ ##
187
+ # Extract the error from a page
188
+
189
+ def page_error_message(page, prepend='')
190
+ message = page.search(".//p[@class='error']").last || ''
191
+ message = message.text if message.respond_to?(:text)
192
+ prepend = '' if message.empty?
193
+ "#{prepend}#{message}"
194
+ end
195
+
196
+ end
197
+
198
+ end
199
+ end
@@ -0,0 +1,111 @@
1
+ class Impostor::Post
2
+
3
+ attr_reader :config
4
+ attr_reader :auth
5
+
6
+ ##
7
+ # Post is initialized with the auth of the impostor
8
+
9
+ def initialize(config, auth)
10
+ @config = config
11
+ @auth = auth
12
+ self.extend eval("Impostor::#{config.type.to_s.capitalize}::Post")
13
+ end
14
+
15
+ ##
16
+ # post a message to the forum and topic thread
17
+ # post is comprised of the following template methods to allow
18
+ # implementation for specific forum applications
19
+ #
20
+ # * validate_post_input(forum, topic, message)
21
+ # * get_reply_uri(forum, topic)
22
+ # * get_reply_page(uri)
23
+ # * get_post_form(page)
24
+ # * set_message(form, message)
25
+ # * post_message(form)
26
+ # * get_post_from_result(page)
27
+ #
28
+ # A hash of results is returned, having keys to the :forum, :topic, new :post
29
+ # id, :message, and :result
30
+
31
+ def post(forum, topic, message)
32
+ self.validate_post_input(forum, topic, message)
33
+ self.auth.login_with_raises
34
+ uri = self.get_reply_uri(forum, topic)
35
+ page = get_reply_page(uri)
36
+ form = get_post_form(page)
37
+ set_message(form, message)
38
+ page = post_message(form)
39
+ post = get_post_from_result(page)
40
+
41
+ { :forum => forum,
42
+ :topic => topic,
43
+ :post => post,
44
+ :message => message,
45
+ :result => true }
46
+ end
47
+
48
+ ##
49
+ # validate the inputs forum, topic, and message
50
+
51
+ def validate_post_input(forum, topic, message)
52
+ raise Impostor::PostError.new("forum not set") unless forum
53
+ raise Impostor::PostError.new("topic not set") unless topic
54
+ raise Impostor::PostError.new("message not set") unless message
55
+ true
56
+ end
57
+
58
+ ##
59
+ # return a uri used to fetch the reply page based on the forum, topic, and
60
+ # message
61
+
62
+ def get_reply_uri(forum, topic)
63
+ raise Impostor::MissingTemplateMethodError.new("get_reply_uri must be implemented")
64
+ end
65
+
66
+ ##
67
+ # return the reply page that is fetched with the reply uri
68
+
69
+ def get_reply_page(uri)
70
+ begin
71
+ page = self.config.agent.get(uri)
72
+ rescue StandardError => err
73
+ raise Impostor::PostError.new(err)
74
+ end
75
+ end
76
+
77
+ ##
78
+ # return the form used for posting a message from the reply page
79
+
80
+ def get_post_form(page)
81
+ raise Impostor::MissingTemplateMethodError.new("get_post_form must be implemented")
82
+ end
83
+
84
+ ##
85
+ # set the message to reply with on the reply form
86
+
87
+ def set_message(form, message)
88
+ form.message = message
89
+ form
90
+ end
91
+
92
+ ##
93
+ # post the message form
94
+
95
+ def post_message(form)
96
+ begin
97
+ config.sleep_before_post
98
+ form.submit
99
+ rescue StandardError => err
100
+ raise Impostor::PostError.new(err)
101
+ end
102
+ end
103
+
104
+ ##
105
+ # get post id from the result of posting the message form
106
+
107
+ def get_post_from_result(page)
108
+ raise Impostor::MissingTemplateMethodError.new("get_post_from_result must be implemented")
109
+ end
110
+
111
+ end
@@ -0,0 +1,115 @@
1
+ class Impostor::Topic
2
+
3
+ attr_reader :config
4
+ attr_reader :auth
5
+
6
+ ##
7
+ # Topic is initialized with the auth of the impostor
8
+
9
+ def initialize(config, auth)
10
+ @config = config
11
+ @auth = auth
12
+ self.extend eval("Impostor::#{config.type.to_s.capitalize}::Topic")
13
+ end
14
+
15
+ ##
16
+ # create a new topic in the forum with the subject title and initial message
17
+ #
18
+ # * validate_new_topic_input(forum, subject, message)
19
+ # * get_new_topic_uri(forum, subject, message)
20
+ # * get_new_topic_page(uri)
21
+ # * get_new_topic_form(page)
22
+ # * set_subject_and_message(form, subject, message)
23
+ # * post_new_topic(form)
24
+ # * validate_new_topic_result(page)
25
+ # * get_topic_from_result(page)
26
+
27
+ def new_topic(forum, subject, message)
28
+ self.validate_topic_input(forum, subject, message)
29
+ self.auth.login_with_raises
30
+ uri = self.get_new_topic_uri(forum, subject, message)
31
+ page = self.get_new_topic_page(uri)
32
+ form = self.get_new_topic_form(page)
33
+ self.set_subject_and_message(form, subject, message)
34
+ page = self.post_new_topic(form)
35
+ page = self.validate_new_topic_result(page)
36
+ topic = self.get_topic_from_result(page)
37
+
38
+ self.config.add_subject(forum, topic, subject)
39
+
40
+ { :forum => forum,
41
+ :topic => topic,
42
+ :subject => subject,
43
+ :message => message,
44
+ :result => true }
45
+ end
46
+
47
+ ##
48
+ # validate the inputs forum, topic, and message
49
+
50
+ def validate_topic_input(forum, subject, message)
51
+ raise Impostor::TopicError.new("forum not set") unless forum
52
+ raise Impostor::TopicError.new("subject not set") unless subject
53
+ raise Impostor::TopicError.new("message not set") unless message
54
+ true
55
+ end
56
+
57
+ ##
58
+ # return a uri used to fetch the new topic page based on the forum, subject,
59
+ # and message
60
+
61
+ def get_new_topic_uri(forum, subject, message)
62
+ raise Impostor::MissingTemplateMethodError.new("get_new_topic_uri must be implemented")
63
+ end
64
+
65
+ ##
66
+ # Get the page that has the form for new topics referenced by the uri
67
+
68
+ def get_new_topic_page(uri)
69
+ begin
70
+ self.config.agent.get(uri)
71
+ rescue StandardError => err
72
+ raise Impostor::TopicError.new(err)
73
+ end
74
+ end
75
+
76
+ ##
77
+ # Get the the new topic form on the page
78
+
79
+ def get_new_topic_form(page)
80
+ raise Impostor::MissingTemplateMethodError.new("get_new_topic_form must be implemented")
81
+ end
82
+
83
+ ##
84
+ # Set the subject and message on the new topic form
85
+
86
+ def set_subject_and_message(form, subject, message)
87
+ raise Impostor::MissingTemplateMethodError.new("set_subject_and_message must be implemented")
88
+ end
89
+
90
+ ##
91
+ # Post the new topic that is contained on the form
92
+
93
+ def post_new_topic(form)
94
+ begin
95
+ config.sleep_before_post
96
+ form.submit
97
+ rescue StandardError => err
98
+ raise Impostor::TopicError.new(err)
99
+ end
100
+ end
101
+
102
+ ##
103
+ # Validate the result of posting the new topic
104
+
105
+ def validate_new_topic_result(page)
106
+ raise Impostor::MissingTemplateMethodError.new("validate_new_topic_result must be implemented")
107
+ end
108
+
109
+ ##
110
+ # Get the new topic identifier from the result page
111
+
112
+ def get_topic_from_result(page)
113
+ raise Impostor::MissingTemplateMethodError.new("get_topic_from_result must be implemented")
114
+ end
115
+ end