Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
15.19% covered (danger)
15.19%
12 / 79
50.00% covered (danger)
50.00%
6 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
UserGroupMembership
15.38% covered (danger)
15.38%
12 / 78
50.00% covered (danger)
50.00%
6 / 12
435.54
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 getUserId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getGroup
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getExpiry
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isExpired
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLink
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
20
 getLinkHTML
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
12
 getLinkWiki
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
12
 getLinkInfo
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
12
 getLinkExpiryParams
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 getGroupPage
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 equals
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 * Represents the membership of a user to a user group.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 */
22
23namespace MediaWiki\User;
24
25use InvalidArgumentException;
26use MediaWiki\Context\IContextSource;
27use MediaWiki\MediaWikiServices;
28use MediaWiki\Message\Message;
29use MediaWiki\Title\Title;
30
31/**
32 * Represents a "user group membership" -- a specific instance of a user belonging
33 * to a group. For example, the fact that user Mary belongs to the sysop group is a
34 * user group membership.
35 *
36 * The class is a pure value object. Use UserGroupManager to modify user group memberships.
37 *
38 * @since 1.29
39 */
40class UserGroupMembership {
41
42    /** @var int The ID of the user who belongs to the group */
43    private $userId;
44
45    /** @var string */
46    private $group;
47
48    /** @var string|null Timestamp of expiry in TS_MW format, or null if no expiry */
49    private $expiry;
50
51    /** @var bool Expiration flag */
52    private $expired;
53
54    /**
55     * @param int $userId The ID of the user who belongs to the group
56     * @param string|null $group The internal group name
57     * @param string|null $expiry Timestamp of expiry in TS_MW format, or null if no expiry
58     */
59    public function __construct( int $userId = 0, ?string $group = null, ?string $expiry = null ) {
60        $this->userId = $userId;
61        $this->group = $group;
62        $this->expiry = $expiry ?: null;
63        $this->expired = $expiry && wfTimestampNow() > $expiry;
64    }
65
66    /**
67     * @return int
68     */
69    public function getUserId() {
70        return $this->userId;
71    }
72
73    /**
74     * @return string
75     */
76    public function getGroup() {
77        return $this->group;
78    }
79
80    /**
81     * @return string|null Timestamp of expiry in TS_MW format, or null if no expiry
82     */
83    public function getExpiry() {
84        return $this->expiry;
85    }
86
87    /**
88     * Has the membership expired?
89     *
90     * @return bool
91     */
92    public function isExpired() {
93        return $this->expired;
94    }
95
96    /**
97     * Gets a link for a user group, possibly including the expiry date if relevant.
98     *
99     * @deprecated since 1.41 use getLinkWiki or getLinkHTML directly
100     *
101     * @param string|UserGroupMembership $ugm Either a group name as a string, or
102     *   a UserGroupMembership object
103     * @param IContextSource $context
104     * @param string $format Either 'wiki' or 'html'
105     * @param string|null $userName If you want to use the group member message
106     *   ("administrator"), pass the name of the user who belongs to the group; it
107     *   is used for GENDER of the group member message. If you instead want the
108     *   group name message ("Administrators"), omit this parameter.
109     * @return string
110     */
111    public static function getLink( $ugm, IContextSource $context, string $format, $userName = null ) {
112        switch ( $format ) {
113            case 'wiki':
114                return self::getLinkWiki( $ugm, $context, $userName );
115            case 'html':
116                return self::getLinkHTML( $ugm, $context, $userName );
117            default:
118                throw new InvalidArgumentException( 'UserGroupMembership::getLink() $format parameter should be ' .
119                    "'wiki' or 'html'" );
120        }
121    }
122
123    /**
124     * Gets a link for a user group, possibly including the expiry date if relevant.
125     * @since 1.41
126     *
127     * @param string|UserGroupMembership $ugm Either a group name as a string, or
128     *   a UserGroupMembership object
129     * @param IContextSource $context
130     * @param string|null $userName If you want to use the group member message
131     *   ("administrator"), pass the name of the user who belongs to the group; it
132     *   is used for GENDER of the group member message. If you instead want the
133     *   group name message ("Administrators"), omit this parameter.
134     * @return string
135     */
136    public static function getLinkHTML( $ugm, IContextSource $context, $userName = null ): string {
137        [
138            'expiry' => $expiry,
139            'linkTitle' => $linkTitle,
140            'groupName' => $groupName
141        ] = self::getLinkInfo( $ugm, $context, $userName );
142
143        // link to the group description page, if it exists
144        $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
145        if ( $linkTitle ) {
146            $groupLink = $linkRenderer->makeLink( $linkTitle, $groupName );
147        } else {
148            $groupLink = htmlspecialchars( $groupName );
149        }
150
151        if ( $expiry ) {
152            [
153                'expiryDT' => $expiryDT,
154                'expiryD' => $expiryD,
155                'expiryT' => $expiryT
156            ] = self::getLinkExpiryParams( $context, $expiry );
157            $groupLink = Message::rawParam( $groupLink );
158            return $context->msg( 'group-membership-link-with-expiry' )
159                ->params( $groupLink, $expiryDT, $expiryD, $expiryT )->escaped();
160        }
161        return $groupLink;
162    }
163
164    /**
165     * Gets a link for a user group, possibly including the expiry date if relevant.
166     * @since 1.41
167     *
168     * @param string|UserGroupMembership $ugm Either a group name as a string, or
169     *   a UserGroupMembership object
170     * @param IContextSource $context
171     * @param string|null $userName If you want to use the group member message
172     *   ("administrator"), pass the name of the user who belongs to the group; it
173     *   is used for GENDER of the group member message. If you instead want the
174     *   group name message ("Administrators"), omit this parameter.
175     * @return string
176     */
177    public static function getLinkWiki( $ugm, IContextSource $context, $userName = null ): string {
178        [
179            'expiry' => $expiry,
180            'linkTitle' => $linkTitle,
181            'groupName' => $groupName
182        ] = self::getLinkInfo( $ugm, $context, $userName );
183
184        // link to the group description page, if it exists
185        if ( $linkTitle ) {
186            $linkPage = $linkTitle->getFullText();
187            $groupLink = "[[$linkPage|$groupName]]";
188        } else {
189            $groupLink = $groupName;
190        }
191
192        if ( $expiry ) {
193            [
194                'expiryDT' => $expiryDT,
195                'expiryD' => $expiryD,
196                'expiryT' => $expiryT
197            ] = self::getLinkExpiryParams( $context, $expiry );
198            return $context->msg( 'group-membership-link-with-expiry' )
199                ->params( $groupLink, $expiryDT, $expiryD, $expiryT )->text();
200        }
201        return $groupLink;
202    }
203
204    /**
205     * @param self|string $ugm
206     * @param IContextSource $context
207     * @param string|null $userName
208     * @return array
209     */
210    private static function getLinkInfo( $ugm, $context, $userName = null ): array {
211        if ( $ugm instanceof UserGroupMembership ) {
212            $expiry = $ugm->getExpiry();
213            $group = $ugm->getGroup();
214        } else {
215            $expiry = null;
216            $group = $ugm;
217        }
218
219        $uiLanguage = $context->getLanguage();
220        if ( $userName !== null ) {
221            $groupName = $uiLanguage->getGroupMemberName( $group, $userName );
222        } else {
223            $groupName = $uiLanguage->getGroupName( $group );
224        }
225        $linkTitle = self::getGroupPage( $group );
226        return [ 'expiry' => $expiry, 'linkTitle' => $linkTitle, 'groupName' => $groupName ];
227    }
228
229    /**
230     * @param IContextSource $context
231     * @param string $expiry
232     * @return array
233     */
234    private static function getLinkExpiryParams( IContextSource $context, string $expiry ): array {
235        // format the expiry to a nice string
236        $uiLanguage = $context->getLanguage();
237        $uiUser = $context->getUser();
238        $expiryDT = $uiLanguage->userTimeAndDate( $expiry, $uiUser );
239        $expiryD = $uiLanguage->userDate( $expiry, $uiUser );
240        $expiryT = $uiLanguage->userTime( $expiry, $uiUser );
241        return [ 'expiryDT' => $expiryDT, 'expiryD' => $expiryD, 'expiryT' => $expiryT ];
242    }
243
244    /**
245     * Gets the title of a page describing a particular user group. When the name
246     * of the group appears in the UI, it can link to this page.
247     *
248     * @param string $group Internal group name
249     * @return Title|false Title of the page if it exists, false otherwise
250     */
251    public static function getGroupPage( $group ) {
252        $msg = wfMessage( "grouppage-$group" )->inContentLanguage();
253        if ( $msg->exists() ) {
254            $title = Title::newFromText( $msg->text() );
255            if ( is_object( $title ) ) {
256                return $title;
257            }
258        }
259        return false;
260    }
261
262    /**
263     * Compares two pure value objects
264     *
265     * @param UserGroupMembership $ugm
266     * @return bool
267     *
268     * @since 1.35
269     */
270    public function equals( UserGroupMembership $ugm ) {
271        return (
272            $ugm->getUserId() === $this->userId
273            && $ugm->getGroup() === $this->group
274        );
275    }
276
277}
278
279/** @deprecated class alias since 1.41 */
280class_alias( UserGroupMembership::class, 'UserGroupMembership' );