Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
67 / 67
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
mention_helper
100.00% covered (success)
100.00%
67 / 67
100.00% covered (success)
100.00%
5 / 5
15
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 inject_metadata
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
3
 get_mentionable_groups
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
4
 get_user_ids_for_group
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
4
 get_mentioned_user_ids
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2/**
3 *
4 * This file is part of the phpBB Forum Software package.
5 *
6 * @copyright (c) phpBB Limited <https://www.phpbb.com>
7 * @license       GNU General Public License, version 2 (GPL-2.0)
8 *
9 * For full copyright and license information, please see
10 * the docs/CREDITS.txt file.
11 *
12 */
13
14namespace phpbb\textformatter\s9e;
15
16use s9e\TextFormatter\Utils as TextFormatterUtils;
17
18class mention_helper
19{
20    /**
21     * @var \phpbb\db\driver\driver_interface
22     */
23    protected $db;
24
25    /**
26     * @var \phpbb\auth\auth
27     */
28    protected $auth;
29
30    /**
31     * @var \phpbb\user
32     */
33    protected $user;
34
35    /**
36     * @var string Base URL for a user profile link, uses {USER_ID} as placeholder
37     */
38    protected $user_profile_url;
39
40    /**
41     * @var string Base URL for a group profile link, uses {GROUP_ID} as placeholder
42     */
43    protected $group_profile_url;
44
45    /**
46     * @var array Array of group IDs allowed to be mentioned by current user
47     */
48    protected $mentionable_groups = null;
49
50    /**
51     * Constructor
52     *
53     * @param \phpbb\db\driver\driver_interface $db
54     * @param \phpbb\auth\auth                  $auth
55     * @param \phpbb\user                       $user
56     * @param string                            $root_path
57     * @param string                            $php_ext
58     */
59    public function __construct($db, $auth, $user, $root_path, $php_ext)
60    {
61        $this->db = $db;
62        $this->auth = $auth;
63        $this->user = $user;
64        $this->user_profile_url = append_sid($root_path . 'memberlist.' . $php_ext, 'mode=viewprofile&u={USER_ID}', false);
65        $this->group_profile_url = append_sid($root_path . 'memberlist.' . $php_ext, 'mode=group&g={GROUP_ID}', false);
66    }
67
68    /**
69     * Inject dynamic metadata into MENTION tags in given XML
70     *
71     * @param  string $xml Original XML
72     * @return string      Modified XML
73     */
74    public function inject_metadata($xml)
75    {
76        $profile_urls = [
77            'u' => $this->user_profile_url,
78            'g' => $this->group_profile_url,
79        ];
80
81        return TextFormatterUtils::replaceAttributes(
82            $xml,
83            'MENTION',
84            function ($attributes) use ($profile_urls)
85            {
86                if (isset($attributes['user_id']))
87                {
88                    $attributes['profile_url'] = str_replace('{USER_ID}', $attributes['user_id'], $profile_urls['u']);
89                }
90                else if (isset($attributes['group_id']))
91                {
92                    $attributes['profile_url'] = str_replace('{GROUP_ID}', $attributes['group_id'], $profile_urls['g']);
93                }
94
95                return $attributes;
96            }
97        );
98    }
99
100    /**
101     * Get group IDs allowed to be mentioned by current user
102     *
103     * @return array
104     */
105    protected function get_mentionable_groups()
106    {
107        if (is_array($this->mentionable_groups))
108        {
109            return $this->mentionable_groups;
110        }
111
112        $hidden_restriction = (!$this->auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) ? ' AND (g.group_type <> ' . GROUP_HIDDEN . ' OR (ug.user_pending = 0 AND ug.user_id = ' . (int) $this->user->data['user_id'] . '))' : '';
113
114        $query = $this->db->sql_build_query('SELECT', [
115            'SELECT'    => 'g.group_id',
116            'FROM'      => [
117                GROUPS_TABLE => 'g',
118            ],
119            'LEFT_JOIN' => [[
120                'FROM' => [
121                    USER_GROUP_TABLE => 'ug',
122                ],
123                'ON'   => 'g.group_id = ug.group_id',
124            ]],
125            'WHERE'     => '(g.group_type <> ' . GROUP_SPECIAL . ' OR ' . $this->db->sql_in_set('g.group_name', ['ADMINISTRATORS', 'GLOBAL_MODERATORS']) . ')' . $hidden_restriction,
126        ]);
127        $result = $this->db->sql_query($query);
128
129        $this->mentionable_groups = [];
130
131        while ($row = $this->db->sql_fetchrow($result))
132        {
133            $this->mentionable_groups[] = $row['group_id'];
134        }
135
136        $this->db->sql_freeresult($result);
137
138        return $this->mentionable_groups;
139    }
140
141    /**
142     * Selects IDs of user members of a certain group
143     *
144     * @param array $user_ids Array of already selected user IDs
145     * @param int   $group_id ID of the group to search members in
146     */
147    protected function get_user_ids_for_group(&$user_ids, $group_id)
148    {
149        if (!in_array($group_id, $this->get_mentionable_groups()))
150        {
151            return;
152        }
153
154        $query = $this->db->sql_build_query('SELECT', [
155            'SELECT' => 'ug.user_id, ug.group_id',
156            'FROM'   => [
157                USER_GROUP_TABLE => 'ug',
158                GROUPS_TABLE     => 'g',
159            ],
160            'WHERE'  => 'g.group_id = ug.group_id',
161        ]);
162        // Cache results for 5 minutes
163        $result = $this->db->sql_query($query, 300);
164
165        while ($row = $this->db->sql_fetchrow($result))
166        {
167            if ($row['group_id'] == $group_id)
168            {
169                $user_ids[] = (int) $row['user_id'];
170            }
171        }
172
173        $this->db->sql_freeresult($result);
174    }
175
176    /**
177     * Get a list of mentioned user IDs
178     *
179     * @param string $xml  Parsed text
180     * @return int[]       List of user IDs
181     */
182    public function get_mentioned_user_ids($xml)
183    {
184        $ids = array();
185        if (strpos($xml, '<MENTION ') === false)
186        {
187            return $ids;
188        }
189
190        // Add IDs of users mentioned directly
191        $user_ids = TextFormatterUtils::getAttributeValues($xml, 'MENTION', 'user_id');
192        $ids = array_merge($ids, array_map('intval', $user_ids));
193
194        // Add IDs of users mentioned as group members
195        $group_ids = TextFormatterUtils::getAttributeValues($xml, 'MENTION', 'group_id');
196        foreach ($group_ids as $group_id)
197        {
198            $this->get_user_ids_for_group($ids, (int) $group_id);
199        }
200
201        return $ids;
202    }
203}