Passed
Push — master ( d72fa1...8ee621 )
by Daimona
01:55
created

WikiController   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 200
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 93
dl 0
loc 200
rs 10
c 0
b 0
f 0
wmc 17

9 Methods

Rating   Name   Duplication   Size   Complexity  
A editPage() 0 12 2
A __construct() 0 2 1
A getPageContent() 0 18 2
A getTimeWithArticle() 0 9 2
A login() 0 29 5
A protectPage() 0 14 1
A getToken() 0 15 2
A hasOpposition() 0 15 1
A getPageCreationTS() 0 14 1
1
<?php declare( strict_types=1 );
2
3
namespace BotRiconferme;
4
5
use BotRiconferme\Exception\EditException;
6
use BotRiconferme\Exception\LoginException;
7
use BotRiconferme\Exception\APIRequestException;
8
use BotRiconferme\Exception\MissingPageException;
9
use BotRiconferme\Request\RequestBase;
10
11
/**
12
 * Class for wiki interaction, contains some requests shorthands
13
 */
14
class WikiController {
15
	/** @var bool */
16
	private static $loggedIn = false;
17
	/** @var Logger */
18
	private $logger;
19
	/** @var string[] */
20
	private $tokens;
21
22
	public function __construct() {
23
		$this->logger = new Logger;
24
	}
25
26
	/**
27
	 * Gets the content of a wiki page
28
	 *
29
	 * @param string $title
30
	 * @return string
31
	 * @throws MissingPageException
32
	 */
33
	public function getPageContent( string $title ) : string {
34
		$this->logger->debug( "Retrieving page $title" );
35
		$params = [
36
			'action' => 'query',
37
			'titles' => $title,
38
			'prop' => 'revisions',
39
			'rvslots' => 'main',
40
			'rvprop' => 'content'
41
		];
42
43
		$req = RequestBase::newFromParams( $params );
44
		$data = $req->execute();
45
		$page = reset( $data->query->pages );
46
		if ( isset( $page->missing ) ) {
47
			throw new MissingPageException( $title );
48
		}
49
50
		return $page->revisions[0]->slots->main->{ '*' };
51
	}
52
53
	/**
54
	 * Basically a wrapper for action=edit
55
	 *
56
	 * @param array $params
57
	 * @throws EditException
58
	 */
59
	public function editPage( array $params ) {
60
		$this->login();
61
62
		$params = [
63
			'action' => 'edit',
64
			'token' => $this->getToken( 'csrf' ),
65
			'bot' => Config::getInstance()->get( 'bot-edits' )
66
		] + $params;
67
68
		$res = RequestBase::newFromParams( $params, true )->execute();
69
		if ( $res->edit->result !== 'Success' ) {
70
			throw new EditException( $res->edit->info );
71
		}
72
	}
73
74
	/**
75
	 * Get a localized version of article + day + time
76
	 *
77
	 * @param int $timestamp
78
	 * @return string
79
	 * @fixme Not the right place for this
80
	 */
81
	public static function getTimeWithArticle( int $timestamp ) : string {
82
		$oldLoc = setlocale( LC_TIME, 'it_IT', 'Italian_Italy', 'Italian' );
83
		$endTime = strftime( '%e %B alle %R', $timestamp );
84
		// Remove the left space if day has a single digit
85
		$endTime = ltrim( $endTime );
86
		$artic = in_array( date( 'j', $timestamp ), [ 8, 11 ] ) ? "l'" : "il ";
87
		setlocale( LC_TIME, $oldLoc );
88
89
		return $artic . $endTime;
90
	}
91
92
	/**
93
	 * @param string $page
94
	 * @return bool
95
	 * @fixme Not the right place for this
96
	 */
97
	public static function hasOpposition( string $page ) : bool {
98
		$params = [
99
			'action' => 'query',
100
			'prop' => 'revisions',
101
			'titles' => $page,
102
			'rvprop' => 'content',
103
			'rvslots' => 'main',
104
			'rvsection' => 4
105
		];
106
		$res = RequestBase::newFromParams( $params )->execute();
107
		$page = reset( $res->query->pages );
108
		$content = $page->revisions[0]->slots->main->{ '*' };
109
		// Let's hope that this is good enough...
110
		$votes = substr_count( $content, "\n\# *(?![#*])" );
111
		return $votes >= 15;
112
	}
113
114
	/**
115
	 * Login wrapper. Checks if we're already logged in and clears tokens cache
116
	 * @throws LoginException
117
	 */
118
	public function login() {
119
		if ( self::$loggedIn ) {
120
			$this->logger->debug( 'Already logged in' );
121
			return;
122
		}
123
124
		$this->logger->info( 'Logging in' );
125
126
		$params = [
127
			'action' => 'login',
128
			'lgname' => Config::getInstance()->get( 'username' ),
129
			'lgpassword' => Config::getInstance()->get( 'password' ),
130
			'lgtoken' => $this->getToken( 'login' )
131
		];
132
133
		try {
134
			$res = RequestBase::newFromParams( $params, true )->execute();
135
		} catch ( APIRequestException $e ) {
136
			throw new LoginException( $e->getMessage() );
137
		}
138
139
		if ( !isset( $res->login->result ) || $res->login->result !== 'Success' ) {
140
			throw new LoginException( 'Unknown error' );
141
		}
142
143
		self::$loggedIn = true;
144
		// Clear tokens cache
145
		$this->tokens = [];
146
		$this->logger->info( 'Login succeeded' );
147
	}
148
149
	/**
150
	 * Get a token, cached.
151
	 *
152
	 * @param string $type
153
	 * @return string
154
	 */
155
	public function getToken( string $type ) : string {
156
		if ( !isset( $this->tokens[ $type ] ) ) {
157
			$params = [
158
				'action' => 'query',
159
				'meta'   => 'tokens',
160
				'type'   => $type
161
			];
162
163
			$req = RequestBase::newFromParams( $params );
164
			$res = $req->execute();
165
166
			$this->tokens[ $type ] = $res->query->tokens->{ "{$type}token" };
167
		}
168
169
		return $this->tokens[ $type ];
170
	}
171
172
	/**
173
	 * Get the timestamp of the creation of the given page
174
	 *
175
	 * @param string $title
176
	 * @return int
177
	 */
178
	public function getPageCreationTS( string $title ) : int {
179
		$params = [
180
			'action' => 'query',
181
			'prop' => 'revisions',
182
			'titles' => $title,
183
			'rvprop' => 'timestamp',
184
			'rvslots' => 'main',
185
			'rvlimit' => 1,
186
			'rvdir' => 'newer'
187
		];
188
189
		$res = ( RequestBase::newFromParams( $params ) )->execute();
190
		$data = $res->query->pages;
191
		return strtotime( reset( $data )->revisions[0]->timestamp );
192
	}
193
194
	/**
195
	 * Sysop-level inifinite protection for a given page
196
	 *
197
	 * @param string $title
198
	 * @param string $reason
199
	 */
200
	public function protectPage( string $title, string $reason ) {
201
		$this->logger->info( "Protecting page $title" );
202
		$this->login();
203
204
		$params = [
205
			'action' => 'protect',
206
			'title' => $title,
207
			'protections' => 'edit=sysop|move=sysop',
208
			'expiry' => 'infinite',
209
			'reason' => $reason,
210
			'token' => $this->getToken( 'csrf' )
211
		];
212
213
		RequestBase::newFromParams( $params, true )->execute();
214
	}
215
}
216