Completed
Push — master ( ef38b3...a48b5a )
by Bryan
03:47
created

topicsolved::image()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 3
eloc 10
c 2
b 0
f 1
nc 4
nop 3
dl 0
loc 20
ccs 14
cts 14
cp 1
crap 3
rs 9.4285
1
<?php
2
/**
3
 * This file is part of the phpBB Topic Solved extension package.
4
 *
5
 * @copyright (c) Bryan Petty
6
 * @license GNU General Public License, version 2 (GPL-2.0)
7
 *
8
 * @package tierra/topicsolved
9
 */
10
11
namespace tierra\topicsolved;
12
13
/**
14
 * Core topic solved functionality used throughout the extension.
15
 *
16
 * @package tierra/topicsolved
17
 */
18
class topicsolved
19
{
20
	/** No-one can mark topics as solved. */
21
	const TOPIC_SOLVED_NO = 0;
22
23
	/** Topic starter and moderators can mark topics as solved. */
24
	const TOPIC_SOLVED_YES = 1;
25
26
	/** Only moderators can mark topics as solved. */
27
	const TOPIC_SOLVED_MOD = 2;
28
29
	/** @var \phpbb\db\driver\driver_interface */
30
	protected $db;
31
32
	/** @var \phpbb\user */
33
	protected $user;
34
35
	/** @var \phpbb\auth\auth */
36
	protected $auth;
37
38
	/** @var \phpbb\event\dispatcher_interface */
39
	protected $dispatcher;
40
41
	/** @var string core.root_path */
42
	protected $root_path;
43
44
	/** @var string core.php_ext */
45
	protected $php_ext;
46
47
	/**
48
	 * Constructor
49
	 *
50
	 * @param \phpbb\db\driver\driver_interface $db Database object
51
	 * @param \phpbb\user $user
52
	 * @param \phpbb\auth\auth $auth
53
	 * @param \phpbb\event\dispatcher_interface $dispatcher
54
	 * @param string $root_path core.root_path
55
	 * @param string $php_ext core.php_ext
56
	 */
57 12
	public function __construct(
58
		\phpbb\db\driver\driver_interface $db,
59
		\phpbb\user $user,
60
		\phpbb\auth\auth $auth,
61
		\phpbb\event\dispatcher_interface $dispatcher,
62
		$root_path, $php_ext)
63
	{
64 12
		$this->db = $db;
65 12
		$this->user = $user;
66 12
		$this->auth = $auth;
67 12
		$this->dispatcher = $dispatcher;
68 12
		$this->root_path = $root_path;
69 12
		$this->php_ext = $php_ext;
70
71 12
		$this->user->add_lang_ext('tierra/topicsolved', 'common');
72 12
	}
73
74
	/**
75
	 * Determine if user is allowed to mark a post as solved or unsolved.
76
	 *
77
	 * @param string $solved Either "solved" or "unsolved".
78
	 * @param array $topic_data Topic to be solved or unsolved.
79
	 *
80
	 * @throws \phpbb\exception\runtime_exception
81
	 *         if an invalid solved parameter is specified.
82
	 *
83
	 * @return bool User is authorized to (un)solve topic.
84
	 */
85 1
	public function user_can_solve_post($solved, $topic_data)
86
	{
87
		// Disallow (un)solving topic if post is global.
88 1
		if ($topic_data['topic_type'] == POST_GLOBAL)
89 1
		{
90
			return false;
91
		}
92
93
		$forum_permission = array(
94 1
			'solved' => 'forum_allow_solve',
95 1
			'unsolved' => 'forum_allow_unsolve',
96 1
		);
97
98 1
		if (!array_key_exists($solved, $forum_permission))
99 1
		{
100
			throw new \phpbb\exception\runtime_exception(
101
				'BAD_METHOD_CALL', array('user_can_solve_post'));
102
		}
103
104 1
		if (($topic_data[$forum_permission[$solved]] == topicsolved::TOPIC_SOLVED_MOD ||
105 1
			$topic_data[$forum_permission[$solved]] == topicsolved::TOPIC_SOLVED_YES) &&
106 1
			$this->auth->acl_get('m_', $topic_data['forum_id']))
107 1
		{
108
			return true;
109
		}
110 1
		else if ($topic_data[$forum_permission[$solved]] == topicsolved::TOPIC_SOLVED_YES &&
111 1
			$topic_data['topic_poster'] == $this->user->data['user_id'] &&
112 1
			$topic_data['topic_status'] == ITEM_UNLOCKED)
113 1
		{
114 1
			return true;
115
		}
116
117
		return false;
118
	}
119
120
	/**
121
	 * Fetches all topic solved data related to the given post.
122
	 *
123
	 * @param int $post_id ID of post to fetch topic/forum data for.
124
	 *
125
	 * @return mixed topic data, or false if not found
126
	 */
127 1
	public function get_topic_data($post_id)
128
	{
129
		$select_sql_array = array(
130
			'SELECT' =>
131
				't.topic_id, t.topic_poster, t.topic_status, t.topic_type, t.topic_solved, ' .
132 1
				'f.forum_id, f.forum_allow_solve, f.forum_allow_unsolve, f.forum_lock_solved, ' .
133 1
				'p.post_id',
134
			'FROM' => array(
135 1
				FORUMS_TABLE => 'f',
136 1
				POSTS_TABLE => 'p',
137 1
				TOPICS_TABLE => 't',
138 1
			),
139
			'WHERE' =>
140 1
				'p.post_id = ' . (int) $post_id .
141 1
				' AND t.topic_id = p.topic_id AND f.forum_id = t.forum_id',
142 1
		);
143 1
		$select_sql = $this->db->sql_build_query('SELECT', $select_sql_array);
144 1
		$result = $this->db->sql_query($select_sql);
145 1
		$topic_data = $this->db->sql_fetchrow($result);
146 1
		$this->db->sql_freeresult($result);
147
148 1
		return $topic_data;
149
	}
150
151
	/**
152
	 * Update topic with the given data.
153
	 *
154
	 * @param int $topic_id Topic to update.
155
	 * @param array $data Topic data to update.
156
	 *
157
	 * @return mixed true if successful
158
	 */
159 3
	public function update_topic($topic_id, $data)
160
	{
161 3
		$update_sql = $this->db->sql_build_array('UPDATE', $data);
162 3
		$result = $this->db->sql_query('
163 3
			UPDATE ' . TOPICS_TABLE . '
164 3
			SET ' . $update_sql . '
165 3
			WHERE topic_id = ' . (int) $topic_id
166 3
		);
167
168 3
		return $result;
169
	}
170
171
	/**
172
	 * Marks a topic as solved.
173
	 *
174
	 * @param array $topic_data Topic to be marked as solved.
175
	 * @param int $post_id Post to mark as the solution.
176
	 */
177 2 View Code Duplication
	public function mark_solved($topic_data, $post_id)
178
	{
179
		// Database column values to set.
180 2
		$column_data = array('topic_solved' => $post_id);
181
182 2
		if ($topic_data['forum_lock_solved'] &&
183 1
			$this->user_can_lock_post($topic_data['forum_id']))
184 2
		{
185 1
			$column_data['topic_status'] = ITEM_LOCKED;
186 1
		}
187
188 2
		$this->update_topic($topic_data['topic_id'], $column_data);
189
190
		/**
191
		 * This event allows you to perform additional actions after a topic has been marked as solved.
192
		 *
193
		 * @event tierra.topicsolved.mark_solved_after
194
		 * @var	array	topic_data	Array with general topic data
195
		 * @var	array	column_data	Array with topic data that the database has been updated with
196
		 * @since 2.2.0
197
		 */
198
		$vars = array(
199 2
			'topic_data',
200 2
			'column_data',
201 2
		);
202 2
		extract($this->dispatcher->trigger_event('tierra.topicsolved.mark_solved_after', compact($vars)));
203 2
	}
204
205
	/**
206
	 * Marks a topic as unsolved.
207
	 *
208
	 * @param array $topic_data Topic to be marked as unsolved.
209
	 */
210 1 View Code Duplication
	public function mark_unsolved($topic_data)
211
	{
212
		// Database column values to set.
213 1
		$column_data = array('topic_solved' => 0);
214
215 1
		if ($topic_data['forum_lock_solved'] &&
216 1
			$this->auth->acl_get('m_lock', $topic_data['forum_id']))
217 1
		{
218 1
			$column_data['topic_status'] = ITEM_UNLOCKED;
219 1
		}
220
221 1
		$this->update_topic($topic_data['topic_id'], $column_data);
222
223
		/**
224
		 * This event allows you to perform additional actions after a topic has been marked as unsolved.
225
		 *
226
		 * @event tierra.topicsolved.mark_unsolved_after
227
		 * @var	array	topic_data	Array with general topic data
228
		 * @var	array	column_data	Array with topic data that the database has been updated with
229
		 * @since 2.2.0
230
		 */
231
		$vars = array(
232 1
			'topic_data',
233 1
			'column_data',
234 1
		);
235 1
		extract($this->dispatcher->trigger_event('tierra.topicsolved.mark_unsolved_after', compact($vars)));
236 1
	}
237
238
	/**
239
	 * Checks if the currently logged in user has permission to lock a post.
240
	 *
241
	 * Regular users won't have permission to solve any topics other than their
242
	 * own, and moderator permissions are forum based, so we only need to know
243
	 * the forum, not the post.
244
	 *
245
	 * @param int $forum_id Forum to check permissions on.
246
	 *
247
	 * @return bool true if user has permission to lock a post.
248
	 */
249 4
	public function user_can_lock_post($forum_id)
250
	{
251
		// Check if user is moderator with appropriate lock permission
252 4
		if ($this->auth->acl_get('m_lock', $forum_id))
253 4
		{
254 2
			return true;
255
		}
256
257
		// Check if user has "lock own posts" permission
258 2
		if ($this->auth->acl_get('f_user_lock', $forum_id))
259 2
		{
260 1
			return true;
261
		}
262
263 1
		return false;
264
	}
265
266
	/**
267
	 * Generate markup for the given solved indicator image.
268
	 *
269
	 * @param string $type One of "head", "list", or "post".
270
	 * @param string $alt Language code for title and alternative text.
271
	 * @param string $url Optional link to solved post.
272
	 *
273
	 * @return string HTML markup for image.
274
	 */
275 6
	public function image($type, $alt = '', $url = '')
276
	{
277 6
		$title = '';
278
279 6
		$markup = $this->user->img('icon_solved_' . $type, $alt);
280
281 6
		if (!empty($alt))
282 6
		{
283 4
			$alt = $this->user->lang($alt);
284 4
			$title = ' title="' . htmlspecialchars($alt, ENT_QUOTES, 'UTF-8') . '"';
285 4
		}
286
287 6
		if (!empty($url))
288 6
		{
289 6
			$markup = sprintf('<a href="%s"%s>%s</a>',
290 6
				htmlspecialchars($url, ENT_QUOTES, 'UTF-8'), $title, $markup);
291 6
		}
292
293 6
		return $markup;
294
	}
295
296
	/**
297
	 * Generate link to specific post (usually solution post).
298
	 *
299
	 * @param int $forum_id
300
	 * @param int $topic_id
301
	 * @param int $post_id
302
	 *
303
	 * @return string Relative URL to post
304
	 */
305 1
	public function get_link_to_post($forum_id, $topic_id, $post_id)
306
	{
307 1
		return append_sid("{$this->root_path}viewtopic.{$this->php_ext}",
308 1
			"f=$forum_id&t=$topic_id&p=$post_id") . '#p' . $post_id;
309
	}
310
}
311