PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/beaubot/lib/MediaWiki/WWW.pm

https://bitbucket.org/plwiki/bot
Perl | 443 lines | 375 code | 57 blank | 11 comment | 27 complexity | 8f1b9e51438d63e96ca5113da1e88e0f MD5 | raw file
  1. package MediaWiki::WWW;
  2. require Exporter;
  3. use strict;
  4. use utf8;
  5. use WWW::Mechanize;
  6. use Data::Dumper;
  7. use URI::Escape;
  8. our @ISA = qw(Exporter);
  9. our @EXPORT = qw();
  10. our @EXPORT_OK = qw();
  11. our $VERSION = 20090911;
  12. sub new {
  13. my $caller = shift;
  14. my $class = ref($caller) || $caller;
  15. my $this = {
  16. 'url' => 'http://pl.wikipedia.org/w/index.php',
  17. 'login' => '',
  18. 'password' => '',
  19. 'assert' => 'user',
  20. 'nassert' => '',
  21. @_
  22. };
  23. $this->{ua} = WWW::Mechanize->new( 'agent' => "MediaWiki::WWW $VERSION" );
  24. bless $this, $class;
  25. return $this;
  26. }
  27. sub login {
  28. my ( $this, $login, $password ) = @_;
  29. $this->{login} = $login if defined $login;
  30. $this->{password} = $password if defined $password;
  31. eval {
  32. $this->_get( 'title' => 'Special:UserLogin' );
  33. $this->{ua}->submit_form(
  34. form_name => 'userlogin',
  35. fields => {
  36. 'wpName' => $this->{login},
  37. 'wpPassword' => $this->{password},
  38. },
  39. button => 'wpLoginattempt',
  40. );
  41. };
  42. if ($@) {
  43. $this->_error($@);
  44. return 0;
  45. }
  46. return 1;
  47. }
  48. sub _get {
  49. my $this = shift;
  50. my %args = (@_);
  51. if ( defined $this->{assert} and $this->{assert} ne "" ) {
  52. $args{assert} = $this->{assert};
  53. }
  54. if ( defined $this->{nassert} and $this->{nassert} ne "" ) {
  55. $args{nassert} = $this->{nassert};
  56. }
  57. my $args = "";
  58. foreach my $key ( keys %args ) {
  59. my $value = $args{$key};
  60. utf8::encode($value) if utf8::is_utf8 $value;
  61. $value = uri_escape($value);
  62. utf8::encode($key) if utf8::is_utf8 $key;
  63. $key = uri_escape($key);
  64. $args .= "&$key=$value";
  65. }
  66. $args =~ s/^&/?/;
  67. my $response = $this->{ua}->get( $this->{url} . $args );
  68. die $response->{status_line} unless $response->is_success;
  69. return $response;
  70. }
  71. sub _prepare_request {
  72. my $this = shift;
  73. my @args;
  74. while (@_) {
  75. my $data = shift;
  76. utf8::encode($data) if utf8::is_utf8 $data;
  77. push @args, $data;
  78. }
  79. my %args = @args;
  80. if ( defined $this->{assert} and $this->{assert} ne "" ) {
  81. $args{assert} = $this->{assert};
  82. }
  83. if ( defined $this->{nassert} and $this->{nassert} ne "" ) {
  84. $args{nassert} = $this->{nassert};
  85. }
  86. return %args;
  87. }
  88. sub _post {
  89. my $this = shift;
  90. my $url = shift;
  91. $url = $this->{url} unless defined $url;
  92. my %args = $this->_prepare_request(@_);
  93. my $response = $this->{ua}->post( $url, \%args );
  94. die $response->{status_line} unless $response->is_success;
  95. return $response;
  96. }
  97. sub _form {
  98. my $this = shift;
  99. my $name = shift;
  100. my $form = $this->{ua}->form_name($name);
  101. die "No form named $form\n" unless $form;
  102. return $form;
  103. }
  104. sub _error {
  105. my ( $this, $error ) = @_;
  106. $this->{error} = $error;
  107. die $error;
  108. }
  109. sub delete {
  110. my ( $this, $title, $reason ) = _encode(@_);
  111. die "delete: title is missing\n" unless defined $title;
  112. $reason = "" unless defined $reason;
  113. eval {
  114. $this->_get(
  115. action => "delete",
  116. title => $title,
  117. );
  118. $this->{ua}->submit_form(
  119. form_number => 0,
  120. fields => { wpReason => $reason },
  121. button => 'wpConfirmB',
  122. );
  123. };
  124. if ($@) {
  125. $this->_error($@);
  126. return 0;
  127. }
  128. return 1;
  129. }
  130. sub undelete {
  131. my ( $this, $title, $reason ) = _encode(@_);
  132. die "delete: title is missing\n" unless defined $title;
  133. $reason = "" unless defined $reason;
  134. eval {
  135. $this->_get(
  136. target => $title,
  137. title => 'Special:Undelete',
  138. );
  139. $this->{ua}->submit_form(
  140. form_number => 0,
  141. fields => { 'wpComment' => $reason },
  142. button => 'restore',
  143. );
  144. };
  145. if ($@) {
  146. $this->_error($@);
  147. return 0;
  148. }
  149. return 1;
  150. }
  151. my %edit_request = (
  152. 'section' => 'wpSection',
  153. 'text' => 'wpTextbox1',
  154. 'content' => 'wpTextbox1',
  155. 'summary' => 'wpSummary',
  156. 'minor' => 'wpMinoredit',
  157. 'watch' => 'wpWatchthis',
  158. 'token' => 'wpEditToken',
  159. );
  160. sub edit2 {
  161. my $this = shift;
  162. my %request = _encode(@_);
  163. %request = _rename_keys( \%request, \%edit_request );
  164. eval {
  165. # unless (exists $request{wpEditToken}){
  166. # warn "no token, fetching";
  167. # $this->_get(
  168. # action => "edit",
  169. # title => $request{title},
  170. # );
  171. #
  172. # $request{'wpEditToken'} = $this->{ua}->value('wpEditToken');
  173. # }
  174. unless ( exists $request{wpEditToken} ) {
  175. die "no token";
  176. }
  177. if ( exists $request{wpEdittime} ) {
  178. $request{wpEdittime} =~ s/\D//g;
  179. $request{wpStarttime} = $request{wpEdittime}
  180. unless exists $request{wpStarttime};
  181. }
  182. $request{action} = 'edit';
  183. $this->_post( undef, %request );
  184. };
  185. if ($@) {
  186. $this->_error($@);
  187. return 0;
  188. }
  189. return 1;
  190. }
  191. sub edit_begin {
  192. my ( $this, $title ) = _encode(@_);
  193. die "edit: title is missing\n" unless defined $title;
  194. my $text = undef;
  195. eval {
  196. $this->_get(
  197. action => "edit",
  198. title => $title,
  199. );
  200. $this->{ua}->form_name('editform');
  201. $text = $this->{ua}->value('wpTextbox1');
  202. utf8::decode($text);
  203. };
  204. if ($@) {
  205. $this->_error($@);
  206. }
  207. return $text;
  208. }
  209. sub edit_finish {
  210. my ( $this, $text, $summary ) = _encode(@_);
  211. $summary = "" unless defined $summary;
  212. $text = "" unless defined $text;
  213. eval {
  214. $this->{ua}->submit_form(
  215. form_name => 'editform',
  216. fields => {
  217. 'wpTextbox1' => $text,
  218. 'wpSummary' => $summary,
  219. },
  220. button => 'wpSave',
  221. );
  222. };
  223. if ($@) {
  224. $this->_error($@);
  225. return 0;
  226. }
  227. return 1;
  228. }
  229. sub edit {
  230. my ( $this, $title, $text, $summary ) = _encode(@_);
  231. die "edit: title is missing\n" unless defined $title;
  232. $summary = "" unless defined $summary;
  233. $text = "" unless defined $text;
  234. eval {
  235. $this->_get(
  236. action => "edit",
  237. title => $title,
  238. );
  239. $this->{ua}->submit_form(
  240. form_name => 'editform',
  241. fields => {
  242. 'wpTextbox1' => $text,
  243. 'wpSummary' => $summary,
  244. },
  245. button => 'wpSave',
  246. );
  247. };
  248. if ($@) {
  249. $this->_error($@);
  250. return 0;
  251. }
  252. return 1;
  253. }
  254. sub addsection {
  255. my ( $this, $title, $text, $summary ) = _encode(@_);
  256. die "edit: title is missing\n" unless defined $title;
  257. $summary = "" unless defined $summary;
  258. $text = "" unless defined $text;
  259. eval {
  260. $this->_get(
  261. action => "edit",
  262. title => $title,
  263. section => "new",
  264. );
  265. $this->{ua}->submit_form(
  266. form_name => 'editform',
  267. fields => {
  268. 'wpTextbox1' => $text,
  269. 'wpSummary' => $summary,
  270. },
  271. button => 'wpSave',
  272. );
  273. };
  274. if ($@) {
  275. $this->_error($@);
  276. return 0;
  277. }
  278. return 1;
  279. }
  280. sub protect {
  281. my ( $this, $title, $expiry, $reason, %levels ) = _encode(@_);
  282. die "protect: title is missing\n" unless defined $title;
  283. $reason = '' unless defined $reason;
  284. $expiry = '' unless defined $expiry;
  285. my %fields;
  286. foreach my $name ( keys %levels ) {
  287. $fields{"mwProtect-level-$name"} = $levels{$name};
  288. }
  289. eval {
  290. $this->_get(
  291. action => "protect",
  292. title => $title,
  293. );
  294. $this->{ua}->submit_form(
  295. form_number => 0,
  296. fields => {
  297. %fields,
  298. 'mwProtect-reason' => $reason,
  299. 'mwProtect-expiry' => $expiry,
  300. },
  301. button => '',
  302. );
  303. };
  304. if ($@) {
  305. $this->_error($@);
  306. return 0;
  307. }
  308. return 1;
  309. }
  310. sub move {
  311. my ( $this, $oldtitle, $newtitle, $reason ) = _encode(@_);
  312. die "move: title is missing\n" unless defined $oldtitle;
  313. die "move: title is missing\n" unless defined $newtitle;
  314. $reason = '' unless defined $reason;
  315. eval {
  316. $this->_get(
  317. action => "protect",
  318. title => "Special:MovePage/$oldtitle",
  319. );
  320. $this->{ua}->submit_form(
  321. form_number => 0,
  322. fields => {
  323. 'wpNewTitle' => $newtitle,
  324. 'wpReason' => $reason,
  325. },
  326. button => '',
  327. );
  328. };
  329. if ($@) {
  330. $this->_error($@);
  331. return 0;
  332. }
  333. return 1;
  334. }
  335. sub block {
  336. my ( $this, $address, $expiry, $reason ) = _encode(@_);
  337. die "block: address is missing\n" unless defined $address;
  338. $reason = '' unless defined $reason;
  339. $expiry = '' unless defined $expiry;
  340. eval {
  341. $this->_get(
  342. ip => $address,
  343. title => "Special:Blockip",
  344. );
  345. $this->{ua}->submit_form(
  346. form_number => 0,
  347. #form_name => 'blockip',
  348. fields => {
  349. 'wpBlockAddress' => $address,
  350. 'wpBlockReason' => $reason,
  351. 'wpBlockExpiry' => $expiry,
  352. },
  353. button => '',
  354. );
  355. };
  356. if ($@) {
  357. $this->_error($@);
  358. return 0;
  359. }
  360. return 1;
  361. }
  362. sub _rename_keys(\%\%) {
  363. my ( $data, $keys ) = @_;
  364. my %result;
  365. foreach my $key ( keys %{$data} ) {
  366. my $value = $data->{$key};
  367. if ( exists $keys->{$key} ) {
  368. $key = $keys->{$key};
  369. }
  370. $result{$key} = $value;
  371. }
  372. return %result;
  373. }
  374. sub _encode {
  375. my @result;
  376. while (@_) {
  377. my $text = shift;
  378. if ( ref($text) eq '' ) {
  379. utf8::encode($text) if utf8::is_utf8($text);
  380. }
  381. push @result, $text;
  382. }
  383. return @result;
  384. }
  385. 1;
  386. # perltidy -et=8 -l=0 -i=8