Completed
Pull Request — patch_1-1-4 (#3202)
by Spuds
15:49
created

User_Access_Mentions   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 208
Duplicated Lines 5.77 %

Coupling/Cohesion

Components 0
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 12
loc 208
ccs 0
cts 149
cp 0
rs 10
c 0
b 0
f 0
wmc 23
lcom 0
cbo 2

1 Method

Rating   Name   Duplication   Size   Complexity  
D run() 12 200 23

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/**
4
 * Re-syncs if a user can access a mention.
5
 *
6
 * @name      ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
9
 *
10
 * @version 1.1
11
 *
12
 */
13
14
namespace ElkArte\sources\subs\ScheduledTask;
15
16
/**
17
 * Re-syncs if a user can access a mention,
18
 *
19
 * - for example if they loose or gain access to a board, this will correct
20
 * the viewing of the mention table.  Since this can be a large job it is run
21
 * as a scheduled immediate task
22
 *
23
 * @package ScheduledTasks
24
 */
25
class User_Access_Mentions implements Scheduled_Task_Interface
26
{
27
	/**
28
	 * Validates / Updates user mention access
29
	 *
30
	 * @return bool
31
	 */
32
	public function run()
33
	{
34
		global $modSettings;
35
36
		$db = database();
37
38 View Code Duplication
		if (!empty($modSettings['user_access_mentions']))
39
		{
40
			$user_access_mentions = \Util::unserialize($modSettings['user_access_mentions']);
41
		}
42
		else
43
		{
44
			$user_access_mentions = array();
45
		}
46
47
		// This should be set only because of an immediate scheduled task, so higher priority
48
		if (!empty($user_access_mentions))
49
		{
50
			foreach ($user_access_mentions as $member => $begin)
51
			{
52
				// Just to stay on the safe side...
53
				if (empty($member))
54
					continue;
55
56
				// Just a touch of needy
57
				require_once(SUBSDIR . '/Boards.subs.php');
58
				require_once(SUBSDIR . '/Mentions.subs.php');
59
				require_once(SUBSDIR . '/Members.subs.php');
60
61
				$user_see_board = memberQuerySeeBoard($member);
62
				$limit = 100;
63
64
				// We need to repeat this twice: once to find the boards the user can access,
65
				// once for those he cannot access
66
				foreach (array('can', 'cannot') as $can)
67
				{
68
					// Let's always start from the begin
69
					$start = $begin;
70
71
					while (true)
72
					{
73
						// Find all the mentions that this user can or cannot see
74
						$request = $db->query('', '
75
							SELECT 
76
								mnt.id_mention, m.id_board
77
							FROM {db_prefix}log_mentions as mnt
78
								LEFT JOIN {db_prefix}messages AS m ON (m.id_msg = mnt.id_target)
79
								LEFT JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
80
							WHERE mnt.id_member = {int:current_member}
81
								AND mnt.mention_type IN ({array_string:mention_types})
82
								AND {raw:user_see_board}
83
							LIMIT {int:start}, {int:limit}',
84
							array(
85
								'current_member' => $member,
86
								'mention_types' => array('mentionmem', 'likemsg', 'rlikemsg', 'quotedmem'),
87
								'user_see_board' => ($can == 'can' ? '' : 'NOT ') . '(' . $user_see_board . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? ' AND b.id_board != ' . $modSettings['recycle_board'] : '') . ')',
88
								'start' => $start,
89
								'limit' => $limit,
90
							)
91
						);
92
93
						$mentions = array();
94
						$remove = array();
95
						while ($row = $db->fetch_assoc($request))
96
						{
97
							if (empty($row['id_board']))
98
								$remove[] = $row['id_mention'];
99
							else
100
								$mentions[] = $row['id_mention'];
101
						}
102
						$db->free_result($request);
103
104
						if (!empty($remove))
105
						{
106
							removeMentions($remove);
107
						}
108
109
						// If we found something toggle them and increment the start for the next round
110
						if (!empty($mentions))
111
							toggleMentionsAccessibility($mentions, $can == 'can');
112
						// Otherwise it means we have finished with this access level for this member
113
						else
114
							break;
115
116
						// Next batch
117
						$start += $limit;
118
					}
119
				}
120
121
				// Drop the member
122
				unset($user_access_mentions[$member]);
123
124
				// And save everything for the next run
125
				updateSettings(array('user_access_mentions' => serialize($user_access_mentions)));
126
127
				// Count helps keep things correct
128
				countUserMentions(false, '', $member);
129
130
				// Run this only once for each user, it may be quite heavy, let's split up the load
131
				break;
132
			}
133
134
			// If there are no more users, scheduleTaskImmediate can be stopped
135
			if (empty($user_access_mentions))
136
				removeScheduleTaskImmediate('user_access_mentions', false);
137
138
			return true;
139
		}
140
		else
141
		{
142
			// Checks 10 users at a time, the scheduled task is set to run once per hour, so 240 users a day
143
			// @todo <= I know you like it Spuds! :P It may be necessary to set it to something higher.
144
			$limit = 10;
145
			$current_check = !empty($modSettings['mentions_member_check']) ? $modSettings['mentions_member_check'] : 0;
146
147
			require_once(SUBSDIR . '/Members.subs.php');
148
			require_once(SUBSDIR . '/Mentions.subs.php');
149
150
			// Grab users with mentions
151
			$request = $db->query('', '
152
				SELECT COUNT(DISTINCT(id_member))
153
				FROM {db_prefix}log_mentions
154
				WHERE id_member > {int:last_id_member}
155
					AND mention_type IN ({array_string:mention_types})',
156
				array(
157
					'last_id_member' => $current_check,
158
					'mention_types' => array('mentionmem', 'likemsg', 'rlikemsg'),
159
				)
160
			);
161
			list ($remaining) = $db->fetch_row($request);
162
			$db->free_result($request);
163
164
			if ($remaining == 0)
165
				$current_check = 0;
166
167
			// Grab users with mentions
168
			$request = $db->query('', '
169
				SELECT 
170
					DISTINCT(id_member) as id_member
171
				FROM {db_prefix}log_mentions
172
				WHERE id_member > {int:last_id_member}
173
					AND mention_type IN ({array_string:mention_types})
174
				LIMIT {int:limit}',
175
				array(
176
					'last_id_member' => $current_check,
177
					'mention_types' => array('mentionmem', 'likemsg', 'rlikemsg'),
178
					'limit' => $limit,
179
				)
180
			);
181
182
			// Remember where we are
183
			updateSettings(array('mentions_member_check' => $current_check + $limit));
184
185
			while ($row = $db->fetch_assoc($request))
186
			{
187
				// Rebuild 'query_see_board', a lot of code duplication... :(
188
				$user_see_board = memberQuerySeeBoard($row['id_member']);
189
190
				// Find out if this user cannot see something that was supposed to be able to see
191
				$request2 = $db->query('', '
192
					SELECT 
193
						mnt.id_mention
194
					FROM {db_prefix}log_mentions as mnt
195
						LEFT JOIN {db_prefix}messages AS m ON (m.id_msg = mnt.id_target)
196
						LEFT JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
197
					WHERE mnt.id_member = {int:current_member}
198
						AND mnt.mention_type IN ({array_string:mention_types})
199
						AND {raw:user_see_board}
200
						AND mnt.is_accessible = 1
201
					LIMIT 1',
202
					array(
203
						'current_member' => $row['id_member'],
204
						'mention_types' => array('mentionmem', 'likemsg', 'rlikemsg', 'quotedmem'),
205
						'user_see_board' => 'NOT (' . $user_see_board . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? ' AND b.id_board != ' . $modSettings['recycle_board'] : '') . ')',
206
					)
207
				);
208
209
				// One row of results is enough: scheduleTaskImmediate!
210
				if ($db->num_rows($request2) == 1)
211
				{
212 View Code Duplication
					if (!empty($modSettings['user_access_mentions']))
213
						$modSettings['user_access_mentions'] = \Util::unserialize($modSettings['user_access_mentions']);
214
					else
215
						$modSettings['user_access_mentions'] = array();
216
217
					// But if the member is already on the list, let's skip it
218
					if (!isset($modSettings['user_access_mentions'][$row['id_member']]))
219
					{
220
						$modSettings['user_access_mentions'][$row['id_member']] = 0;
221
						updateSettings(array('user_access_mentions' => serialize(array_unique($modSettings['user_access_mentions']))));
222
						scheduleTaskImmediate('user_access_mentions');
223
					}
224
				}
225
				$db->free_result($request2);
226
			}
227
			$db->free_result($request);
228
229
			return true;
230
		}
231
	}
232
}