summaryrefslogtreecommitdiff
blob: a4d0cba250bb9d3c0d06f9785a0dd32fbd772e15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<?php

/**
 * Trait that adds cross-wiki functionality to an API module. For mixing into ApiBase subclasses.
 *
 * In addition to mixing in this trait, you have to do the following in your API module:
 * - In your getAllowedParams() method, merge in the return value of getCrossWikiParams()
 * - In your execute() method, call getFromForeign() somewhere and do something with the result
 * - Optionally, override getForeignQueryParams() to customize what is sent to the foreign wikis
 */
trait ApiCrossWiki {
	/**
	 * @var EchoForeignNotifications
	 */
	protected $foreignNotifications;

	/**
	 * This will take the current API call (with all of its params) and execute
	 * it on all foreign wikis, returning an array of results per wiki.
	 *
	 * @param array|null $wikis List of wikis to query. Defaults to the result of getRequestedForeignWikis().
	 * @param array $paramOverrides Request parameter overrides
	 * @return array[]
	 * @throws Exception
	 */
	protected function getFromForeign( $wikis = null, array $paramOverrides = [] ) {
		$wikis = $wikis ?? $this->getRequestedForeignWikis();
		if ( $wikis === [] ) {
			return [];
		}
		$tokenType = $this->needsToken();
		$foreignReq = new EchoForeignWikiRequest(
			$this->getUser(),
			$paramOverrides + $this->getForeignQueryParams(),
			$wikis !== null ? $wikis : $this->getRequestedForeignWikis(),
			$this->getModulePrefix() . 'wikis',
			$tokenType !== false ? $tokenType : null
		);
		return $foreignReq->execute();
	}

	/**
	 * Get the query parameters to use for the foreign API requests.
	 * Implementing classes should override this if they need to customize
	 * the parameters.
	 * @return array Query parameters
	 */
	protected function getForeignQueryParams() {
		return $this->getRequest()->getValues();
	}

	/**
	 * @return bool
	 */
	protected function allowCrossWikiNotifications() {
		global $wgEchoCrossWikiNotifications;
		return $wgEchoCrossWikiNotifications;
	}

	/**
	 * This is basically equivalent to $params['wikis'], but some added checks:
	 * - `*` will expand to "all wikis with unread notifications"
	 * - if `$wgEchoCrossWikiNotifications` is off, foreign wikis will be excluded
	 *
	 * @return string[]
	 */
	protected function getRequestedWikis() {
		$params = $this->extractRequestParams();

		// if wiki is omitted from params, that's because crosswiki is/was not
		// available, and it'll default to current wiki
		$wikis = isset( $params['wikis'] ) ? $params['wikis'] : [ wfWikiID() ];

		if ( array_search( '*', $wikis ) !== false ) {
			// expand `*` to all foreign wikis with unread notifications + local
			$wikis = array_merge(
				[ wfWikiID() ],
				$this->getForeignWikisWithUnreadNotifications()
			);
		}

		if ( !$this->allowCrossWikiNotifications() ) {
			// exclude foreign wikis if x-wiki is not enabled
			$wikis = array_intersect_key( [ wfWikiID() ], $wikis );
		}

		return $wikis;
	}

	/**
	 * @return string[] Wiki names
	 */
	protected function getRequestedForeignWikis() {
		return array_diff( $this->getRequestedWikis(), [ wfWikiID() ] );
	}

	/**
	 * @return EchoForeignNotifications
	 */
	protected function getForeignNotifications() {
		if ( $this->foreignNotifications === null ) {
			$this->foreignNotifications = new EchoForeignNotifications( $this->getUser() );
		}
		return $this->foreignNotifications;
	}

	/**
	 * @return string[] Wiki names
	 */
	protected function getForeignWikisWithUnreadNotifications() {
		return $this->getForeignNotifications()->getWikis();
	}

	/**
	 * @return array[]
	 */
	public function getCrossWikiParams() {
		global $wgConf;

		$params = [];

		if ( $this->allowCrossWikiNotifications() ) {
			$params += [
				// fetch notifications from multiple wikis
				'wikis' => [
					ApiBase::PARAM_ISMULTI => true,
					ApiBase::PARAM_DFLT => wfWikiID(),
					// `*` will let you immediately fetch from all wikis that have
					// unread notifications, without having to look them up first
					ApiBase::PARAM_TYPE => array_unique( array_merge( $wgConf->wikis, [ wfWikiID(), '*' ] ) ),
				],
			];
		}

		return $params;
	}
}