Passed
Push — master ( 2e7fdd...aa5487 )
by Daimona
01:38
created

PageRiconferma::edit()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php declare( strict_types=1 );
2
3
namespace BotRiconferme;
4
5
use BotRiconferme\Request\RequestBase;
6
7
/**
8
 * Represents a single riconferma page
9
 */
10
class PageRiconferma {
11
	/** @var string */
12
	private $title;
13
	/** @var WikiController */
14
	private $controller;
15
	/** @var string */
16
	private $content;
17
18
	// Sections of the page value is section number
19
	const SECTION_SUPPORT = 3;
20
	const SECTION_OPPOSE = 4;
21
22
	// Possible outcomes of a vote
23
	const OUTCOME_OK = 0;
24
	const OUTCOME_FAIL_VOTES = 1;
25
	const OUTCOME_NO_QUOR = 2;
26
	const OUTCOME_FAIL = self::OUTCOME_FAIL_VOTES | self::OUTCOME_NO_QUOR;
27
28
	/**
29
	 * @param string $title
30
	 * @param WikiController $controller
31
	 */
32
	public function __construct( string $title, WikiController $controller ) {
33
		$this->title = $title;
34
		$this->controller = $controller;
35
	}
36
37
	/**
38
	 * @return string
39
	 */
40
	public function getTitle() : string {
41
		return $this->title;
42
	}
43
44
	/**
45
	 * Get the name of the user from the title
46
	 *
47
	 * @return string
48
	 */
49
	public function getUser() : string {
50
		return explode( '/', $this->title )[2];
51
	}
52
53
	/**
54
	 * Returns the progressive number in the title
55
	 *
56
	 * @return int
57
	 */
58
	public function getNum() : int {
59
		$bits = explode( '/', $this->getTitle() );
60
		return intval( end( $bits ) );
61
	}
62
63
	/**
64
	 * Get the last part of the title as Username/Num
65
	 *
66
	 * @return string
67
	 */
68
	public function getUserNum() : string {
69
		return explode( '/', $this->getTitle(), 3 )[2];
70
	}
71
72
	/**
73
	 * Strip the part with the progressive number
74
	 *
75
	 * @return string
76
	 */
77
	public function getBaseTitle() : string {
78
		// @phan-suppress-next-line PhanTypeMismatchArgumentInternal Phan bug
79
		return substr( $this->getTitle(), 0, strrpos( $this->getTitle(), '/' ) );
80
	}
81
82
	/**
83
	 * Get the content of this page
84
	 *
85
	 * @return string
86
	 */
87
	public function getContent() : string {
88
		if ( $this->content === null ) {
89
			$this->content = $this->controller->getPageContent( $this->title );
90
		}
91
		return $this->content;
92
	}
93
94
	/**
95
	 * Get the amount of opposing votes
96
	 *
97
	 * @return int
98
	 */
99
	public function getOpposingCount() : int {
100
		return $this->getCountForSection( self::SECTION_OPPOSE );
101
	}
102
103
	/**
104
	 * Get the amount support votes
105
	 *
106
	 * @return int
107
	 */
108
	public function getSupportCount() : int {
109
		return $this->getCountForSection( self::SECTION_SUPPORT );
110
	}
111
112
	/**
113
	 * Count the votes in the given section
114
	 *
115
	 * @param int $secNum
116
	 * @return int
117
	 */
118
	protected function getCountForSection( int $secNum ) : int {
119
		$params = [
120
			'action' => 'query',
121
			'prop' => 'revisions',
122
			'titles' => $this->title,
123
			'rvprop' => 'content',
124
			'rvslots' => 'main',
125
			'rvsection' => $secNum
126
		];
127
128
		$res = RequestBase::newFromParams( $params )->execute();
129
		$page = reset( $res->query->pages );
130
		$content = $page->revisions[0]->slots->main->{ '*' };
131
		// Let's hope that this is good enough...
132
		return substr_count( $content, "\n\# *(?![#*])" );
133
	}
134
135
	/**
136
	 * Gets the quorum used for the current page
137
	 *
138
	 * @return int
139
	 */
140
	protected function getQuorum() : int {
141
		$reg = "!soddisfare il \[\[[^|\]]+\|quorum]] di '''(\d+) voti'''!";
142
		$matches = [];
143
		preg_match( $reg, $this->getContent(), $matches );
144
		return intval( $matches[1] );
145
	}
146
147
	/**
148
	 * Whether this page has enough opposing votes
149
	 *
150
	 * @return bool
151
	 */
152
	public function hasOpposition() : bool {
153
		return $this->getOpposingCount() >= 15;
154
	}
155
156
	/**
157
	 * Gets the outcome for the vote
158
	 *
159
	 * @return int One of the OUTCOME_* constants
160
	 * @throws \BadMethodCallException
161
	 */
162
	public function getOutcome() : int {
163
		if ( !$this->isVote() ) {
164
			throw new \BadMethodCallException( 'Cannot get outcome for a non-vote page.' );
165
		}
166
		$totalVotes = $this->getOpposingCount() + $this->getSupportCount();
167
		if ( $this->getSupportCount() < $this->getQuorum() ) {
168
			return self::OUTCOME_NO_QUOR;
169
		} elseif ( $this->getSupportCount() < 2 * $totalVotes / 3 ) {
170
			return self::OUTCOME_FAIL_VOTES;
171
		}
172
		return self::OUTCOME_OK;
173
	}
174
175
	/**
176
	 * Get the result text for the page itself
177
	 *
178
	 * @return string
179
	 * @throws \BadMethodCallException
180
	 */
181
	public function getOutcomeText() : string {
182
		if ( !$this->isVote() ) {
183
			throw new \BadMethodCallException( 'No need for an outcome text.' );
184
		}
185
186
		$text = sprintf(
187
			' Con %d voti a favore e %d contrari',
188
			$this->getSupportCount(),
189
			$this->getOpposingCount()
190
		);
191
		$user = $this->getUser();
192
193
		switch ( $this->getOutcome() ) {
194
			case self::OUTCOME_OK:
195
				$text .= " $user viene riconfermato amministratore.";
196
				break;
197
			/** @noinspection PhpMissingBreakStatementInspection */
198
			case self::OUTCOME_NO_QUOR:
199
				$text .= ', non raggiungendo il quorum,';
200
				// Fall through intended
201
			case self::OUTCOME_FAIL:
202
				$text .= " $user non viene riconfermato amministratore";
203
				break;
204
		}
205
		return $text;
206
	}
207
208
	/**
209
	 * Whether this page is a vote
210
	 *
211
	 * @return bool
212
	 */
213
	public function isVote() : bool {
214
		$sectionReg = '/<!-- SEZIONE DA UTILIZZARE PER/';
215
		return preg_match( $sectionReg, $this->getContent() ) === false;
216
	}
217
218
	/**
219
	 * Get the end time
220
	 *
221
	 * @return int
222
	 */
223
	public function getEndTimestamp() : int {
224
		if ( $this->isVote() ) {
225
			$matches = [];
226
			$reg = "!La votazione ha inizio il.+ e ha termine.+ '''([^']+)''' alle ore '''([^']+)'''!";
227
			preg_match( $reg, $this->getContent(), $matches );
228
			list( , $day, $hours ) = $matches;
229
			$day = preg_replace( '![^\d \w]!', '', $day );
230
			return WikiController::getTimestampFromLocalTime( $day . " alle " . $hours );
231
		} else {
232
			$created = $this->controller->getPageCreationTS( $this->title );
233
			return $created + 60 * 60 * 24 * 7;
234
		}
235
	}
236
237
	/**
238
	 * Edit this page and update content
239
	 *
240
	 * @param array $params
241
	 */
242
	public function edit( array $params ) {
243
		$params = [
244
			'title' => $this->getTitle()
245
		] + $params;
246
247
		$this->controller->editPage( $params );
248
		if ( isset( $params['text'] ) ) {
249
			$this->content = $params['text'];
250
		} elseif ( isset( $params['appendtext'] ) ) {
251
			$this->content .= $params['appendtext'];
252
		}
253
	}
254
	public function __toString() {
255
		return $this->getTitle();
256
	}
257
}
258