events.php 6.89 KB
<?php
/*
	Question2Answer by Gideon Greenspan and contributors
	http://www.question2answer.org/

	Description: Database-level access to userevents and sharedevents tables


	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.

	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;
}


/**
 * Add an event to the event streams for entity $entitytype with $entityid. The event of type $updatetype relates to
 * $lastpostid whose antecedent question is $questionid, and was caused by $lastuserid. Pass a unix $timestamp for the
 * event time or leave as null to use now. This will add the event both to the entity's shared stream, and the
 * individual user streams for any users following the entity not via its shared stream (See long comment in
 * /qa-include/db/favorites.php). Also handles truncation.
 * @param $entitytype
 * @param $entityid
 * @param $questionid
 * @param $lastpostid
 * @param $updatetype
 * @param $lastuserid
 * @param $timestamp
 */
function qa_db_event_create_for_entity($entitytype, $entityid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp = null)
{
	require_once QA_INCLUDE_DIR . 'db/maxima.php';
	require_once QA_INCLUDE_DIR . 'app/updates.php';

	$updatedsql = isset($timestamp) ? ('FROM_UNIXTIME(' . qa_db_argument_to_mysql($timestamp, false) . ')') : 'NOW()';

	// Enter it into the appropriate shared event stream for that entity

	qa_db_query_sub(
		'INSERT INTO ^sharedevents (entitytype, entityid, questionid, lastpostid, updatetype, lastuserid, updated) ' .
		'VALUES ($, #, #, #, $, $, ' . $updatedsql . ')',
		$entitytype, $entityid, $questionid, $lastpostid, $updatetype, $lastuserid
	);

	// If this is for a question entity, check the shared event stream doesn't have too many entries for that question

	$questiontruncated = false;

	if ($entitytype == QA_ENTITY_QUESTION) {
		$truncate = qa_db_read_one_value(qa_db_query_sub(
			'SELECT updated FROM ^sharedevents WHERE entitytype=$ AND entityid=# AND questionid=# ORDER BY updated DESC LIMIT #,1',
			$entitytype, $entityid, $questionid, QA_DB_MAX_EVENTS_PER_Q
		), true);

		if (isset($truncate)) {
			qa_db_query_sub(
				'DELETE FROM ^sharedevents WHERE entitytype=$ AND entityid=# AND questionid=# AND updated<=$',
				$entitytype, $entityid, $questionid, $truncate
			);

			$questiontruncated = true;
		}
	}

	// If we didn't truncate due to a specific question, truncate the shared event stream for its overall length

	if (!$questiontruncated) {
		$truncate = qa_db_read_one_value(qa_db_query_sub(
			'SELECT updated FROM ^sharedevents WHERE entitytype=$ AND entityid=$ ORDER BY updated DESC LIMIT #,1',
			$entitytype, $entityid, (int)qa_opt('max_store_user_updates')
		), true);

		if (isset($truncate))
			qa_db_query_sub(
				'DELETE FROM ^sharedevents WHERE entitytype=$ AND entityid=$ AND updated<=$',
				$entitytype, $entityid, $truncate
			);
	}

	// See if we can identify a user who has favorited this entity, but is not using its shared event stream

	$randomuserid = qa_db_read_one_value(qa_db_query_sub(
		'SELECT userid FROM ^userfavorites WHERE entitytype=$ AND entityid=# AND nouserevents=0 ORDER BY RAND() LIMIT 1',
		$entitytype, $entityid
	), true);

	if (isset($randomuserid)) {
		// If one was found, this means we have one or more individual event streams, so update them all
		qa_db_query_sub(
			'INSERT INTO ^userevents (userid, entitytype, entityid, questionid, lastpostid, updatetype, lastuserid, updated) ' .
			'SELECT userid, $, #, #, #, $, $, ' . $updatedsql . ' FROM ^userfavorites WHERE entitytype=$ AND entityid=# AND nouserevents=0',
			$entitytype, $entityid, $questionid, $lastpostid, $updatetype, $lastuserid, $entitytype, $entityid
		);

		// Now truncate the random individual event stream that was found earlier
		// (in theory we should truncate them all, but truncation is just a 'housekeeping' activity, so it's not necessary)
		qa_db_user_events_truncate($randomuserid, $questionid);
	}
}


/**
 * Add an event to the event stream for $userid which is not related to an entity they are following (but rather a
 * notification which is relevant for them, e.g. if someone answers their question). The event of type $updatetype
 * relates to $lastpostid whose antecedent question is $questionid, and was caused by $lastuserid. Pass a unix
 * $timestamp for the event time or leave as null to use now. Also handles truncation of event streams.
 * @param $userid
 * @param $questionid
 * @param $lastpostid
 * @param $updatetype
 * @param $lastuserid
 * @param $timestamp
 */
function qa_db_event_create_not_entity($userid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp = null)
{
	require_once QA_INCLUDE_DIR . 'app/updates.php';

	$updatedsql = isset($timestamp) ? ('FROM_UNIXTIME(' . qa_db_argument_to_mysql($timestamp, false) . ')') : 'NOW()';

	qa_db_query_sub(
		"INSERT INTO ^userevents (userid, entitytype, entityid, questionid, lastpostid, updatetype, lastuserid, updated) " .
		"VALUES ($, $, 0, #, #, $, $, " . $updatedsql . ")",
		$userid, QA_ENTITY_NONE, $questionid, $lastpostid, $updatetype, $lastuserid
	);

	qa_db_user_events_truncate($userid, $questionid);
}


/**
 * Trim the number of events in the event stream for $userid. If an event was just added for a particular question,
 * pass the question's id in $questionid (to help focus the truncation).
 * @param $userid
 * @param $questionid
 */
function qa_db_user_events_truncate($userid, $questionid = null)
{
	// First try truncating based on there being too many events for this question

	$questiontruncated = false;

	if (isset($questionid)) {
		$truncate = qa_db_read_one_value(qa_db_query_sub(
			'SELECT updated FROM ^userevents WHERE userid=$ AND questionid=# ORDER BY updated DESC LIMIT #,1',
			$userid, $questionid, QA_DB_MAX_EVENTS_PER_Q
		), true);

		if (isset($truncate)) {
			qa_db_query_sub(
				'DELETE FROM ^userevents WHERE userid=$ AND questionid=# AND updated<=$',
				$userid, $questionid, $truncate
			);

			$questiontruncated = true;
		}
	}

	// If that didn't happen, try truncating the stream in general based on its total length

	if (!$questiontruncated) {
		$truncate = qa_db_read_one_value(qa_db_query_sub(
			'SELECT updated FROM ^userevents WHERE userid=$ ORDER BY updated DESC LIMIT #,1',
			$userid, (int)qa_opt('max_store_user_updates')
		), true);

		if (isset($truncate))
			qa_db_query_sub(
				'DELETE FROM ^userevents WHERE userid=$ AND updated<=$',
				$userid, $truncate
			);
	}
}