qa-db-points.php 8.74 KB
Newer Older
Gideon Greenspan committed
1 2 3 4 5 6 7
<?php

/*
	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-db-points.php
	Version: See define()s at top of qa-include/qa-base.php
	Description: Database-level access to user points and statistics


	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 31 32 33 34 35 36 37
	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;
	}


	function qa_db_points_option_names()
/*
	Returns an array of option names required to perform calculations in userpoints table
*/
	{
Gideon Greenspan committed
38
		if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
Scott Vivian committed
39

Gideon Greenspan committed
40 41 42 43
		return array(
			'points_post_q', 'points_select_a', 'points_per_q_voted_up', 'points_per_q_voted_down', 'points_q_voted_max_gain', 'points_q_voted_max_loss',
			'points_post_a', 'points_a_selected', 'points_per_a_voted_up', 'points_per_a_voted_down', 'points_a_voted_max_gain', 'points_a_voted_max_loss',
			'points_vote_up_q', 'points_vote_down_q', 'points_vote_up_a', 'points_vote_down_a',
Scott Vivian committed
44

Gideon Greenspan committed
45 46 47 48
			'points_multiple', 'points_base',
		);
	}

Scott Vivian committed
49

Gideon Greenspan committed
50 51 52 53 54 55 56 57 58
	function qa_db_points_calculations()
/*
	Returns an array containing all the calculation formulae for the userpoints table. Each element of this
	array is for one column - the key contains the column name, and the value is a further array of two elements.
	The element 'formula' contains the SQL fragment that calculates the columns value for one or more users,
	where the ~ symbol within the fragment is substituted for a constraint on which users we are interested in.
	The element 'multiple' specifies what to multiply each column by to create the final sum in the points column.
*/
	{
Gideon Greenspan committed
59
		if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
Scott Vivian committed
60

Gideon Greenspan committed
61
		require_once QA_INCLUDE_DIR.'qa-app-options.php';
Scott Vivian committed
62

Gideon Greenspan committed
63
		$options=qa_get_options(qa_db_points_option_names());
Scott Vivian committed
64

Gideon Greenspan committed
65 66 67 68 69
		return array(
			'qposts' => array(
				'multiple' => $options['points_multiple']*$options['points_post_q'],
				'formula' => "COUNT(*) AS qposts FROM ^posts AS userid_src WHERE userid~ AND type='Q'",
			),
Scott Vivian committed
70

Gideon Greenspan committed
71 72 73 74
			'aposts' => array(
				'multiple' => $options['points_multiple']*$options['points_post_a'],
				'formula' => "COUNT(*) AS aposts FROM ^posts AS userid_src WHERE userid~ AND type='A'",
			),
Scott Vivian committed
75

Gideon Greenspan committed
76 77 78 79
			'cposts' => array(
				'multiple' => 0,
				'formula' => "COUNT(*) AS cposts FROM ^posts AS userid_src WHERE userid~ AND type='C'",
			),
Scott Vivian committed
80

Gideon Greenspan committed
81 82 83 84
			'aselects' => array(
				'multiple' => $options['points_multiple']*$options['points_select_a'],
				'formula' => "COUNT(*) AS aselects FROM ^posts AS userid_src WHERE userid~ AND type='Q' AND selchildid IS NOT NULL",
			),
Scott Vivian committed
85

Gideon Greenspan committed
86 87 88 89
			'aselecteds' => array(
				'multiple' => $options['points_multiple']*$options['points_a_selected'],
				'formula' => "COUNT(*) AS aselecteds FROM ^posts AS userid_src JOIN ^posts AS questions ON questions.selchildid=userid_src.postid WHERE userid_src.userid~ AND userid_src.type='A' AND NOT (questions.userid<=>userid_src.userid)",
			),
Scott Vivian committed
90

Gideon Greenspan committed
91 92 93 94
			'qupvotes' => array(
				'multiple' => $options['points_multiple']*$options['points_vote_up_q'],
				'formula' => "COUNT(*) AS qupvotes FROM ^uservotes AS userid_src JOIN ^posts ON userid_src.postid=^posts.postid WHERE userid_src.userid~ AND LEFT(^posts.type, 1)='Q' AND userid_src.vote>0",
			),
Scott Vivian committed
95

Gideon Greenspan committed
96 97 98 99
			'qdownvotes' => array(
				'multiple' => $options['points_multiple']*$options['points_vote_down_q'],
				'formula' => "COUNT(*) AS qdownvotes FROM ^uservotes AS userid_src JOIN ^posts ON userid_src.postid=^posts.postid WHERE userid_src.userid~ AND LEFT(^posts.type, 1)='Q' AND userid_src.vote<0",
			),
Scott Vivian committed
100

Gideon Greenspan committed
101 102 103 104
			'aupvotes' => array(
				'multiple' => $options['points_multiple']*$options['points_vote_up_a'],
				'formula' => "COUNT(*) AS aupvotes FROM ^uservotes AS userid_src JOIN ^posts ON userid_src.postid=^posts.postid WHERE userid_src.userid~ AND LEFT(^posts.type, 1)='A' AND userid_src.vote>0",
			),
Scott Vivian committed
105

Gideon Greenspan committed
106 107 108 109
			'adownvotes' => array(
				'multiple' => $options['points_multiple']*$options['points_vote_down_a'],
				'formula' => "COUNT(*) AS adownvotes FROM ^uservotes AS userid_src JOIN ^posts ON userid_src.postid=^posts.postid WHERE userid_src.userid~ AND LEFT(^posts.type, 1)='A' AND userid_src.vote<0",
			),
Scott Vivian committed
110

Gideon Greenspan committed
111 112 113 114 115 116 117 118
			'qvoteds' => array(
				'multiple' => $options['points_multiple'],
				'formula' => "COALESCE(SUM(".
					"LEAST(".((int)$options['points_per_q_voted_up'])."*upvotes,".((int)$options['points_q_voted_max_gain']).")".
					"-".
					"LEAST(".((int)$options['points_per_q_voted_down'])."*downvotes,".((int)$options['points_q_voted_max_loss']).")".
					"), 0) AS qvoteds FROM ^posts AS userid_src WHERE LEFT(type, 1)='Q' AND userid~",
			),
Scott Vivian committed
119

Gideon Greenspan committed
120 121 122 123 124 125 126 127
			'avoteds' => array(
				'multiple' => $options['points_multiple'],
				'formula' => "COALESCE(SUM(".
					"LEAST(".((int)$options['points_per_a_voted_up'])."*upvotes,".((int)$options['points_a_voted_max_gain']).")".
					"-".
					"LEAST(".((int)$options['points_per_a_voted_down'])."*downvotes,".((int)$options['points_a_voted_max_loss']).")".
					"), 0) AS avoteds FROM ^posts AS userid_src WHERE LEFT(type, 1)='A' AND userid~",
			),
Scott Vivian committed
128

Gideon Greenspan committed
129 130 131 132 133 134 135 136 137 138 139 140
			'upvoteds' => array(
				'multiple' => 0,
				'formula' => "COALESCE(SUM(upvotes), 0) AS upvoteds FROM ^posts AS userid_src WHERE userid~",
			),

			'downvoteds' => array(
				'multiple' => 0,
				'formula' => "COALESCE(SUM(downvotes), 0) AS downvoteds FROM ^posts AS userid_src WHERE userid~",
			),
		);
	}

Scott Vivian committed
141

Gideon Greenspan committed
142 143 144 145 146 147 148
	function qa_db_points_update_ifuser($userid, $columns)
/*
	Update the userpoints table in the database for $userid and $columns, plus the summary points column.
	Set $columns to true for all, empty for none, an array for several, or a single value for one.
	This dynamically builds some fairly crazy looking SQL, but it works, and saves repeat calculations.
*/
	{
Gideon Greenspan committed
149
		if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
Scott Vivian committed
150

Gideon Greenspan committed
151 152 153 154
		if (qa_should_update_counts() && isset($userid)) {
			require_once QA_INCLUDE_DIR.'qa-app-options.php';

			$calculations=qa_db_points_calculations();
Scott Vivian committed
155

Gideon Greenspan committed
156 157 158 159 160 161 162 163
			if ($columns===true)
				$keycolumns=$calculations;
			elseif (empty($columns))
				$keycolumns=array();
			elseif (is_array($columns))
				$keycolumns=array_flip($columns);
			else
				$keycolumns=array($columns => true);
Scott Vivian committed
164

Gideon Greenspan committed
165 166 167 168 169 170
			$insertfields='userid, ';
			$insertvalues='$, ';
			$insertpoints=(int)qa_opt('points_base');

			$updates='';
			$updatepoints=$insertpoints;
Scott Vivian committed
171

Gideon Greenspan committed
172 173
			foreach ($calculations as $field => $calculation) {
				$multiple=(int)$calculation['multiple'];
Scott Vivian committed
174

Gideon Greenspan committed
175 176 177 178 179 180
				if (isset($keycolumns[$field])) {
					$insertfields.=$field.', ';
					$insertvalues.='@_'.$field.':=(SELECT '.$calculation['formula'].'), ';
					$updates.=$field.'=@_'.$field.', ';
					$insertpoints.='+('.(int)$multiple.'*@_'.$field.')';
				}
Scott Vivian committed
181

Gideon Greenspan committed
182 183
				$updatepoints.='+('.$multiple.'*'.(isset($keycolumns[$field]) ? '@_' : '').$field.')';
			}
Scott Vivian committed
184

Gideon Greenspan committed
185 186
			$query='INSERT INTO ^userpoints ('.$insertfields.'points) VALUES ('.$insertvalues.$insertpoints.') '.
				'ON DUPLICATE KEY UPDATE '.$updates.'points='.$updatepoints.'+bonus';
Scott Vivian committed
187

Gideon Greenspan committed
188 189
			qa_db_query_raw(str_replace('~', "='".qa_db_escape_string($userid)."'", qa_db_apply_sub($query, array($userid))));
				// build like this so that a #, $ or ^ character in the $userid (if external integration) isn't substituted
Scott Vivian committed
190

191 192 193 194 195
			qa_report_event('u_points', qa_get_logged_in_userid(), qa_get_logged_in_handle(), qa_cookie_get(), array(
				'userid' => $userid,
				'columns' => array_keys($keycolumns),
			));

Gideon Greenspan committed
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
			if (qa_db_insert_on_duplicate_inserted())
				qa_db_userpointscount_update();
		}
	}


	function qa_db_points_set_bonus($userid, $bonus)
/*
	Set the number of explicit bonus points for $userid to $bonus
*/
	{
		qa_db_query_sub(
			"INSERT INTO ^userpoints (userid, bonus) VALUES ($, #) ON DUPLICATE KEY UPDATE bonus=#",
			$userid, $bonus, $bonus
		);
	}
Scott Vivian committed
212 213


Gideon Greenspan committed
214 215 216 217 218 219 220 221 222 223 224 225 226
	function qa_db_userpointscount_update()
/*
	Update the cached count in the database of the number of rows in the userpoints table
*/
	{
		if (qa_should_update_counts())
			qa_db_query_sub("REPLACE ^options (title, content) SELECT 'cache_userpointscount', COUNT(*) FROM ^userpoints");
	}


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