qa-app-posts.php 15.5 KB
Newer Older
Gideon Greenspan committed
1
<?php
Scott Vivian committed
2

Gideon Greenspan committed
3 4 5 6 7
/*
	Question2Answer (c) Gideon Greenspan

	http://www.question2answer.org/

Scott Vivian committed
8

Gideon Greenspan committed
9 10 11 12 13 14 15 16 17
	File: qa-include/qa-app-posts.php
	Version: See define()s at top of qa-include/qa-base.php
	Description: Higher-level functions to create and manipulate posts


	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.
Scott Vivian committed
18

Gideon Greenspan committed
19 20 21 22 23 24 25 26 27 28 29 30
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	More about this license: http://www.question2answer.org/license.php
*/

	if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
		header('Location: ../');
		exit;
	}
Scott Vivian committed
31

Gideon Greenspan committed
32 33 34 35 36
	require_once QA_INCLUDE_DIR.'qa-db.php';
	require_once QA_INCLUDE_DIR.'qa-db-selects.php';
	require_once QA_INCLUDE_DIR.'qa-app-format.php';
	require_once QA_INCLUDE_DIR.'qa-app-post-create.php';
	require_once QA_INCLUDE_DIR.'qa-app-post-update.php';
37
	require_once QA_INCLUDE_DIR.'qa-app-users.php';
Gideon Greenspan committed
38 39 40
	require_once QA_INCLUDE_DIR.'qa-util-string.php';


Gideon Greenspan committed
41
	function qa_post_create($type, $parentid, $title, $content, $format='', $categoryid=null, $tags=null, $userid=null, $notify=null, $email=null, $extravalue=null, $name=null)
Gideon Greenspan committed
42 43
/*
	Create a new post in the database, and return its postid.
Scott Vivian committed
44

Gideon Greenspan committed
45 46 47 48 49 50 51 52 53
	Set $type to 'Q' for a new question, 'A' for an answer, or 'C' for a comment. You can also use 'Q_QUEUED',
	'A_QUEUED' or 'C_QUEUED' to create a post which is queued for moderator approval. For questions, set $parentid to
	the postid of the answer to which the question is related, or null if (as in most cases) the question is not related
	to an answer. For answers, set $parentid to the postid of the question being answered. For comments, set $parentid
	to the postid of the question or answer to which the comment relates. The $content and $format parameters go
	together - if $format is '' then $content should be in plain UTF-8 text, and if $format is 'html' then $content
	should be in UTF-8 HTML. Other values of $format may be allowed if an appropriate viewer module is installed. The
	$title, $categoryid and $tags parameters are only relevant when creating a question - $tags can either be an array
	of tags, or a string of tags separated by commas. The new post will be assigned to $userid if it is not null,
Gideon Greenspan committed
54 55 56 57
	otherwise it will be by a non-user. If $notify is true then the author will be sent notifications relating to the
	post - either to $email if it is specified and valid, or to the current email address of $userid if $email is '@'.
	If you're creating a question, the $extravalue parameter will be set as the custom extra field, if not null. For all
	post types you can specify the $name of the post's author, which is relevant if the $userid is null.
Gideon Greenspan committed
58 59
*/
	{
60
		$handle=qa_userid_to_handle($userid);
Gideon Greenspan committed
61 62 63 64 65 66 67 68
		$text=qa_post_content_to_text($content, $format);

		switch ($type) {
			case 'Q':
			case 'Q_QUEUED':
				$followanswer=isset($parentid) ? qa_post_get_full($parentid, 'A') : null;
				$tagstring=qa_post_tags_to_tagstring($tags);
				$postid=qa_question_create($followanswer, $userid, $handle, null, $title, $content, $format, $text, $tagstring,
Gideon Greenspan committed
69
					$notify, $email, $categoryid, $extravalue, $type=='Q_QUEUED', $name);
Gideon Greenspan committed
70
				break;
Scott Vivian committed
71

Gideon Greenspan committed
72 73 74
			case 'A':
			case 'A_QUEUED':
				$question=qa_post_get_full($parentid, 'Q');
Gideon Greenspan committed
75
				$postid=qa_answer_create($userid, $handle, null, $content, $format, $text, $notify, $email, $question, $type=='A_QUEUED', $name);
Gideon Greenspan committed
76
				break;
Scott Vivian committed
77

Gideon Greenspan committed
78 79 80 81 82
			case 'C':
			case 'C_QUEUED':
				$parent=qa_post_get_full($parentid, 'QA');
				$commentsfollows=qa_db_single_select(qa_db_full_child_posts_selectspec(null, $parentid));
				$question=qa_post_parent_to_question($parent);
Gideon Greenspan committed
83
				$postid=qa_comment_create($userid, $handle, null, $content, $format, $text, $notify, $email, $question, $parent, $commentsfollows, $type=='C_QUEUED', $name);
Gideon Greenspan committed
84
				break;
Scott Vivian committed
85

Gideon Greenspan committed
86 87 88 89
			default:
				qa_fatal_error('Post type not recognized: '.$type);
				break;
		}
Scott Vivian committed
90

Gideon Greenspan committed
91 92
		return $postid;
	}
Scott Vivian committed
93 94


Gideon Greenspan committed
95
	function qa_post_set_content($postid, $title, $content, $format=null, $tags=null, $notify=null, $email=null, $byuserid=null, $extravalue=null, $name=null)
Gideon Greenspan committed
96
/*
Gideon Greenspan committed
97 98 99
	Change the data stored for post $postid based on any of the $title, $content, $format, $tags, $notify, $email,
	$extravalue and $name parameters passed which are not null. The meaning of these parameters is the same as for
	qa_post_create() above. Pass the identify of the user making this change in $byuserid (or null for silent).
Gideon Greenspan committed
100 101 102
*/
	{
		$oldpost=qa_post_get_full($postid, 'QAC');
Scott Vivian committed
103

Gideon Greenspan committed
104 105
		if (!isset($title))
			$title=$oldpost['title'];
Scott Vivian committed
106

Gideon Greenspan committed
107 108
		if (!isset($content))
			$content=$oldpost['content'];
Scott Vivian committed
109

Gideon Greenspan committed
110 111
		if (!isset($format))
			$format=$oldpost['format'];
Scott Vivian committed
112

Gideon Greenspan committed
113 114
		if (!isset($tags))
			$tags=qa_tagstring_to_tags($oldpost['tags']);
Scott Vivian committed
115

Gideon Greenspan committed
116 117 118 119 120
		if (isset($notify) || isset($email))
			$setnotify=qa_combine_notify_email($oldpost['userid'], isset($notify) ? $notify : isset($oldpost['notify']),
				isset($email) ? $email : $oldpost['notify']);
		else
			$setnotify=$oldpost['notify'];
Scott Vivian committed
121

122
		$byhandle=qa_userid_to_handle($byuserid);
123

Gideon Greenspan committed
124
		$text=qa_post_content_to_text($content, $format);
Scott Vivian committed
125

Gideon Greenspan committed
126 127 128
		switch ($oldpost['basetype']) {
			case 'Q':
				$tagstring=qa_post_tags_to_tagstring($tags);
Gideon Greenspan committed
129
				qa_question_set_content($oldpost, $title, $content, $format, $text, $tagstring, $setnotify, $byuserid, $byhandle, null, $extravalue, $name);
Gideon Greenspan committed
130
				break;
Scott Vivian committed
131

Gideon Greenspan committed
132 133
			case 'A':
				$question=qa_post_get_full($oldpost['parentid'], 'Q');
Gideon Greenspan committed
134
				qa_answer_set_content($oldpost, $content, $format, $text, $setnotify, $byuserid, $byhandle, null, $question, $name);
Gideon Greenspan committed
135
				break;
Scott Vivian committed
136

Gideon Greenspan committed
137 138 139
			case 'C':
				$parent=qa_post_get_full($oldpost['parentid'], 'QA');
				$question=qa_post_parent_to_question($parent);
Gideon Greenspan committed
140
				qa_comment_set_content($oldpost, $content, $format, $text, $setnotify, $byuserid, $byhandle, null, $question, $parent, $name);
Gideon Greenspan committed
141 142 143 144
				break;
		}
	}

Scott Vivian committed
145

Gideon Greenspan committed
146 147 148 149 150 151 152 153
	function qa_post_set_category($postid, $categoryid, $byuserid=null)
/*
	Change the category of $postid to $categoryid. The category of all related posts (shown together on the same
	question page) will also be changed. Pass the identify of the user making this change in $byuserid (or null for an
	anonymous change).
*/
	{
		$oldpost=qa_post_get_full($postid, 'QAC');
Scott Vivian committed
154

Gideon Greenspan committed
155
		if ($oldpost['basetype']=='Q') {
156
			$byhandle=qa_userid_to_handle($byuserid);
Gideon Greenspan committed
157 158 159 160 161 162 163 164 165
			$answers=qa_post_get_question_answers($postid);
			$commentsfollows=qa_post_get_question_commentsfollows($postid);
			$closepost=qa_post_get_question_closepost($postid);
			qa_question_set_category($oldpost, $categoryid, $byuserid, $byhandle, null, $answers, $commentsfollows, $closepost);

		} else
			qa_post_set_category($oldpost['parentid'], $categoryid, $byuserid); // keep looking until we find the parent question
	}

Scott Vivian committed
166

Gideon Greenspan committed
167 168 169 170 171 172 173
	function qa_post_set_selchildid($questionid, $answerid, $byuserid=null)
/*
	Set the selected best answer of $questionid to $answerid (or to none if $answerid is null). Pass the identify of the
	user in $byuserid (or null for an anonymous change).
*/
	{
		$oldquestion=qa_post_get_full($questionid, 'Q');
174
		$byhandle=qa_userid_to_handle($byuserid);
Gideon Greenspan committed
175
		$answers=qa_post_get_question_answers($questionid);
Scott Vivian committed
176

Gideon Greenspan committed
177 178
		if (isset($answerid) && !isset($answers[$answerid]))
			qa_fatal_error('Answer ID could not be found: '.$answerid);
Scott Vivian committed
179

Gideon Greenspan committed
180 181 182
		qa_question_set_selchildid($byuserid, $byuserid, null, $oldquestion, $answerid, $answers);
	}

Scott Vivian committed
183

Gideon Greenspan committed
184 185 186 187 188 189 190 191 192
	function qa_post_set_closed($questionid, $closed=true, $originalpostid=null, $note=null, $byuserid=null)
/*
	Closed $questionid if $closed is true, otherwise reopen it. If $closed is true, pass either the $originalpostid of
	the question that it is a duplicate of, or a $note to explain why it's closed. Pass the identify of the user in
	$byuserid (or null for an anonymous change).
*/
	{
		$oldquestion=qa_post_get_full($questionid, 'Q');
		$oldclosepost=qa_post_get_question_closepost($questionid);
193
		$byhandle=qa_userid_to_handle($byuserid);
Scott Vivian committed
194

Gideon Greenspan committed
195 196 197 198 199 200 201
		if ($closed) {
			if (isset($originalpostid))
				qa_question_close_duplicate($oldquestion, $oldclosepost, $originalpostid, $byuserid, $byhandle, null);
			elseif (isset($note))
				qa_question_close_other($oldquestion, $oldclosepost, $note, $byuserid, $byhandle, null);
			else
				qa_fatal_error('Question must be closed as a duplicate or with a note');
Scott Vivian committed
202

Gideon Greenspan committed
203 204 205
		} else
			qa_question_close_clear($oldquestion, $oldclosepost, $byuserid, $byhandle, null);
	}
Scott Vivian committed
206 207


Gideon Greenspan committed
208 209
	function qa_post_set_hidden($postid, $hidden=true, $byuserid=null)
/*
Gideon Greenspan committed
210 211 212 213 214 215
	Hide $postid if $hidden is true, otherwise show the post. Pass the identify of the user making this change in
	$byuserid (or null for a silent change). This function is included mainly for backwards compatibility.
*/
	{
		qa_post_set_status($postid, $hidden ? QA_POST_STATUS_HIDDEN : QA_POST_STATUS_NORMAL, $byuserid);
	}
Scott Vivian committed
216 217


Gideon Greenspan committed
218 219 220 221
	function qa_post_set_status($postid, $status, $byuserid=null)
/*
	Change the status of $postid to $status, which should be one of the QA_POST_STATUS_* constants defined in
	qa-app-post-update.php. Pass the identify of the user making this change in $byuserid (or null for a silent change).
Gideon Greenspan committed
222 223 224
*/
	{
		$oldpost=qa_post_get_full($postid, 'QAC');
225
		$byhandle=qa_userid_to_handle($byuserid);
Scott Vivian committed
226

Gideon Greenspan committed
227 228 229 230 231
		switch ($oldpost['basetype']) {
			case 'Q':
				$answers=qa_post_get_question_answers($postid);
				$commentsfollows=qa_post_get_question_commentsfollows($postid);
				$closepost=qa_post_get_question_closepost($postid);
Gideon Greenspan committed
232
				qa_question_set_status($oldpost, $status, $byuserid, $byhandle, null, $answers, $commentsfollows, $closepost);
Gideon Greenspan committed
233
				break;
Scott Vivian committed
234

Gideon Greenspan committed
235 236 237
			case 'A':
				$question=qa_post_get_full($oldpost['parentid'], 'Q');
				$commentsfollows=qa_post_get_answer_commentsfollows($postid);
Gideon Greenspan committed
238
				qa_answer_set_status($oldpost, $status, $byuserid, $byhandle, null, $question, $commentsfollows);
Gideon Greenspan committed
239
				break;
Scott Vivian committed
240

Gideon Greenspan committed
241 242 243
			case 'C':
				$parent=qa_post_get_full($oldpost['parentid'], 'QA');
				$question=qa_post_parent_to_question($parent);
Gideon Greenspan committed
244
				qa_comment_set_status($oldpost, $status, $byuserid, $byhandle, null, $question, $parent);
Gideon Greenspan committed
245 246 247 248
				break;
		}
	}

Scott Vivian committed
249

Gideon Greenspan committed
250 251 252 253 254 255
	function qa_post_set_created($postid, $created)
/*
	Set the created date of $postid to $created, which is a unix timestamp.
*/
	{
		$oldpost=qa_post_get_full($postid);
Scott Vivian committed
256

Gideon Greenspan committed
257
		qa_db_post_set_created($postid, $created);
Scott Vivian committed
258

Gideon Greenspan committed
259 260 261 262
		switch ($oldpost['basetype']) {
			case 'Q':
				qa_db_hotness_update($postid);
				break;
Scott Vivian committed
263

Gideon Greenspan committed
264 265 266 267 268
			case 'A':
				qa_db_hotness_update($oldpost['parentid']);
				break;
		}
	}
Scott Vivian committed
269 270


Gideon Greenspan committed
271 272 273 274 275 276
	function qa_post_delete($postid)
/*
	Delete $postid from the database, hiding it first if appropriate.
*/
	{
		$oldpost=qa_post_get_full($postid, 'QAC');
Scott Vivian committed
277

Gideon Greenspan committed
278 279 280 281
		if (!$oldpost['hidden']) {
			qa_post_set_hidden($postid, true, null);
			$oldpost=qa_post_get_full($postid, 'QAC');
		}
Scott Vivian committed
282

Gideon Greenspan committed
283 284 285 286 287
		switch ($oldpost['basetype']) {
			case 'Q':
				$answers=qa_post_get_question_answers($postid);
				$commentsfollows=qa_post_get_question_commentsfollows($postid);
				$closepost=qa_post_get_question_closepost($postid);
Scott Vivian committed
288

Gideon Greenspan committed
289 290
				if (count($answers) || count($commentsfollows))
					qa_fatal_error('Could not delete question ID due to dependents: '.$postid);
Scott Vivian committed
291

Gideon Greenspan committed
292 293
				qa_question_delete($oldpost, null, null, null, $closepost);
				break;
Scott Vivian committed
294

Gideon Greenspan committed
295 296 297 298 299 300 301 302 303
			case 'A':
				$question=qa_post_get_full($oldpost['parentid'], 'Q');
				$commentsfollows=qa_post_get_answer_commentsfollows($postid);

				if (count($commentsfollows))
					qa_fatal_error('Could not delete answer ID due to dependents: '.$postid);

				qa_answer_delete($oldpost, $question, null, null, null);
				break;
Scott Vivian committed
304

Gideon Greenspan committed
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
			case 'C':
				$parent=qa_post_get_full($oldpost['parentid'], 'QA');
				$question=qa_post_parent_to_question($parent);
				qa_comment_delete($oldpost, $question, $parent, null, null, null);
				break;
		}
	}


	function qa_post_get_full($postid, $requiredbasetypes=null)
/*
	Return the full information from the database for $postid in an array.
*/
	{
		$post=qa_db_single_select(qa_db_full_post_selectspec(null, $postid));
Scott Vivian committed
320

Gideon Greenspan committed
321 322
		if (!is_array($post))
			qa_fatal_error('Post ID could not be found: '.$postid);
Scott Vivian committed
323

Gideon Greenspan committed
324 325
		if (isset($requiredbasetypes) && !is_numeric(strpos($requiredbasetypes, $post['basetype'])))
			qa_fatal_error('Post of wrong type: '.$post['basetype']);
Scott Vivian committed
326

Gideon Greenspan committed
327 328 329
		return $post;
	}

Scott Vivian committed
330

Gideon Greenspan committed
331 332 333 334 335
	function qa_post_userid_to_handle($userid)
/*
	Return the handle corresponding to $userid, unless it is null in which case return null.
*/
	{
336
		trigger_error('Function qa_post_userid_to_handle is deprecated; use qa_userid_to_handle instead', E_USER_NOTICE);
337
		return qa_userid_to_handle($userid);
Gideon Greenspan committed
338 339 340 341 342 343 344 345 346
	}


	function qa_post_content_to_text($content, $format)
/*
	Return the textual rendition of $content in $format (used for indexing).
*/
	{
		$viewer=qa_load_viewer($content, $format);
Scott Vivian committed
347

Gideon Greenspan committed
348 349
		if (!isset($viewer))
			qa_fatal_error('Content could not be parsed in format: '.$format);
Scott Vivian committed
350

Gideon Greenspan committed
351 352 353
		return $viewer->get_text($content, $format, array());
	}

Scott Vivian committed
354

Gideon Greenspan committed
355 356 357 358 359 360 361
	function qa_post_tags_to_tagstring($tags)
/*
	Return tagstring to store in the database based on $tags as an array or a comma-separated string.
*/
	{
		if (is_array($tags))
			$tags=implode(',', $tags);
Scott Vivian committed
362

Gideon Greenspan committed
363 364 365
		return qa_tags_to_tagstring(array_unique(preg_split('/\s*,\s*/', qa_strtolower(strtr($tags, '/', ' ')), -1, PREG_SPLIT_NO_EMPTY)));
	}

Scott Vivian committed
366

Gideon Greenspan committed
367 368 369 370 371 372
	function qa_post_get_question_answers($questionid)
/*
	Return the full database records for all answers to question $questionid
*/
	{
		$answers=array();
Scott Vivian committed
373

Gideon Greenspan committed
374
		$childposts=qa_db_single_select(qa_db_full_child_posts_selectspec(null, $questionid));
Scott Vivian committed
375

Gideon Greenspan committed
376 377 378
		foreach ($childposts as $postid => $post)
			if ($post['basetype']=='A')
				$answers[$postid]=$post;
Scott Vivian committed
379

Gideon Greenspan committed
380 381 382
		return $answers;
	}

Scott Vivian committed
383

Gideon Greenspan committed
384 385 386 387 388 389
	function qa_post_get_question_commentsfollows($questionid)
/*
	Return the full database records for all comments or follow-on questions for question $questionid or its answers
*/
	{
		$commentsfollows=array();
Scott Vivian committed
390

Gideon Greenspan committed
391 392 393 394 395 396 397 398
		list($childposts, $achildposts)=qa_db_multi_select(array(
			qa_db_full_child_posts_selectspec(null, $questionid),
			qa_db_full_a_child_posts_selectspec(null, $questionid),
		));

		foreach ($childposts as $postid => $post)
			if ($post['basetype']=='C')
				$commentsfollows[$postid]=$post;
Scott Vivian committed
399

Gideon Greenspan committed
400 401 402
		foreach ($achildposts as $postid => $post)
			if ( ($post['basetype']=='Q') || ($post['basetype']=='C') )
				$commentsfollows[$postid]=$post;
Scott Vivian committed
403

Gideon Greenspan committed
404 405
		return $commentsfollows;
	}
Scott Vivian committed
406 407


Gideon Greenspan committed
408 409 410 411 412 413 414 415
	function qa_post_get_question_closepost($questionid)
/*
	Return the full database record for the post which closed $questionid, if there is any
*/
	{
		return qa_db_single_select(qa_db_post_close_post_selectspec($questionid));
	}

Scott Vivian committed
416

Gideon Greenspan committed
417 418 419 420 421 422
	function qa_post_get_answer_commentsfollows($answerid)
/*
	Return the full database records for all comments or follow-on questions for answer $answerid
*/
	{
		$commentsfollows=array();
Scott Vivian committed
423

Gideon Greenspan committed
424 425 426 427 428
		$childposts=qa_db_single_select(qa_db_full_child_posts_selectspec(null, $answerid));

		foreach ($childposts as $postid => $post)
			if ( ($post['basetype']=='Q') || ($post['basetype']=='C') )
				$commentsfollows[$postid]=$post;
Scott Vivian committed
429

Gideon Greenspan committed
430 431
		return $commentsfollows;
	}
Scott Vivian committed
432

Gideon Greenspan committed
433 434 435 436 437 438 439 440 441 442

	function qa_post_parent_to_question($parent)
/*
	Return $parent if it's the database record for a question, otherwise return the database record for its parent
*/
	{
		if ($parent['basetype']=='Q')
			$question=$parent;
		else
			$question=qa_post_get_full($parent['parentid'], 'Q');
Scott Vivian committed
443

Gideon Greenspan committed
444 445
		return $question;
	}
Scott Vivian committed
446

Gideon Greenspan committed
447 448 449 450

/*
	Omit PHP closing tag to help avoid accidental output
*/