xaizek / rocketgit (License: AGPLv3+) (since 2018-12-09)
Light and fast Git hosting solution suitable to serve both as a hub or as a personal code storage with its tickets, pull requests, API and much more.
<root> / inc / watch.inc.php (1ade19d5d75a8a062a10fbaf4f6cead860d34ba0) (8,055B) (mode 100644) [raw]
<?php
require_once($INC . "/util.inc.php");
require_once($INC . "/log.inc.php");
require_once($INC . "/sql.inc.php");
require_once($INC . "/user.inc.php");
require_once($INC . "/prof.inc.php");

$rg_watch_error = "";

function rg_watch_set_error($str)
{
	global $rg_watch_error;
	$rg_watch_error = $str;
	rg_log('Set error to ' . $str);
}

function rg_watch_error()
{
	global $rg_watch_error;
	return $rg_watch_error;
}


/*
 * Returns a watched entry
 */
function rg_watch_load($db, $type, $uid, $obj_id1, $obj_id2)
{
	rg_prof_start("watch_load");
	rg_log_enter("watch_load: type=$type uid=$uid obj_id=$obj_id1/$obj_id2");

	$ret = FALSE;
	while (1) {
		$key = 'watch' . '::' . $type . '::' . $uid
			. '::' . $obj_id1 . '::' . $obj_id2;
		$c = rg_cache_get($key);
		if ($c !== FALSE) {
			$ret = $c;
			break;
		}

		$params = array(
			'uid' => $uid,
			'obj_id1' => $obj_id1,
			'obj_id2' => $obj_id2);
		if (strcmp($type, "bug") == 0) {
			$sql = "SELECT 1 FROM watch_bug"
				. " WHERE uid = @@uid@@"
				. " AND repo_id = @@obj_id1@@"
				. " AND bug_id = @@obj_id2@@";
		} else if (strcmp($type, "repo") == 0) {
			$sql = "SELECT 1 FROM watch_repo"
				. " WHERE uid = @@uid@@"
				. " AND repo_id = @@obj_id1@@";
		} else if (strcmp($type, "user") == 0) {
			$sql = "SELECT 1 FROM watch_user"
				. " WHERE uid = @@uid@@"
				. " AND watch_uid = @@obj_id1@@";
		} else {
			rg_internal_error("Invalid watch type!");
			break;
		}
		$res = rg_sql_query_params($db, $sql, $params);
		if ($res === FALSE) {
			rg_watch_set_error('cannot get data from db');
			break;
		}

		$rows = rg_sql_num_rows($res);
		rg_sql_free_result($res);

		$ret = $rows > 0 ? 1 : 0;

		rg_cache_set($key, $ret, RG_SOCKET_NO_WAIT);
		break;
	}

	rg_log_exit();
	rg_prof_end("watch_load");
	return $ret;
}

/*
 * Add somebody to the watch list
 */
function rg_watch_add($db, $type, $login_uid, $obj_id1, $obj_id2)
{
	global $rg_watch_add_state;

	rg_prof_start("watch_add");
	rg_log_enter("watch_add type=$type, login_uid=$login_uid"
		. " obj_id=$obj_id1/$obj_id2");

	$ret = FALSE;
	while (1) {
		$r = rg_watch_load($db, $type, $login_uid, $obj_id1, $obj_id2);
		if ($r === FALSE)
			break;
		if ($r === 1) { // already in watch list
			$ret = TRUE;
			break;
		}

		$params = array("uid" => $login_uid,
			"obj_id1" => $obj_id1,
			"obj_id2" => $obj_id2);

		if (strcmp($type, "bug") == 0) {
			$sql = "INSERT INTO watch_bug (uid, repo_id, bug_id)"
				. " VALUES (@@uid@@, @@obj_id1@@, @@obj_id2@@)";
		} else if (strcmp($type, "repo") == 0) {
			$sql = "INSERT INTO watch_repo (uid, repo_id)"
				. " VALUES (@@uid@@, @@obj_id1@@)";
		} else if (strcmp($type, "user") == 0) {
			$sql = "INSERT INTO watch_user (uid, watch_uid)"
				. " VALUES (@@uid@@, @@obj_id1@@)";
		} else {
			rg_internal_error("Invalid watch type!");
			break;
		}
		$res = rg_sql_query_params($db, $sql, $params);
		if ($res === FALSE) {
			rg_watch_set_error('cannot insert data in db');
			break;
		}
		rg_sql_free_result($res);

		$key = 'watch' . '::' . $type . '::' . $login_uid
			. '::' . $obj_id1 . '::' . $obj_id2;
		rg_cache_set($key, 1, RG_SOCKET_NO_WAIT);

		$ret = TRUE;
		break;
	}

	rg_log_exit();
	rg_prof_end("watch_add");
	return $ret;
}

/*
 * Delete somebody from the watch list
 */
function rg_watch_del($db, $type, $login_uid, $obj_id1, $obj_id2)
{
	rg_prof_start("watch_del");
	rg_log_enter("watch_del type=$type, login_uid=$login_uid"
		. " obj_id=$obj_id1/$obj_id2");

	$ret = FALSE;
	while (1) {
		$r = rg_watch_load($db, $type, $login_uid, $obj_id1, $obj_id2);
		if ($r === FALSE)
			break;
		if ($r === 0) { // already deleted
			rg_log('DEBUG: watch not active, nothing to do');
			$ret = TRUE;
			break;
		}

		$params = array("login_uid" => $login_uid,
			"obj_id1" => $obj_id1,
			"obj_id2" => $obj_id2);

		if (strcmp($type, "bug") == 0) {
			$sql = "DELETE FROM watch_bug"
				. " WHERE uid = @@login_uid@@"
				. " AND repo_id = @@obj_id1@@"
				. " AND bug_id = @@obj_id2@@";
		} else if (strcmp($type, "repo") == 0) {
			$sql = "DELETE FROM watch_repo"
				. " WHERE uid = @@login_uid@@"
				. " AND repo_id = @@obj_id1@@";
		} else if (strcmp($type, "user") == 0) {
			$sql = "DELETE FROM watch_user"
				. " WHERE uid = @@login_uid@@"
				. " AND watch_uid = @@obj_id1@@";
		} else {
			rg_internal_error("Invalid watch type!");
			break;
		}
		$res = rg_sql_query_params($db, $sql, $params);
		if ($res === FALSE) {
			rg_watch_set_error('cannot delete data from db');
			break;
		}
		rg_sql_free_result($res);

		$key = 'watch' . '::' . $type . '::' . $login_uid
			. '::' . $obj_id1 . '::' . $obj_id2;
		rg_cache_unset($key, RG_SOCKET_NO_WAIT);

		$ret = TRUE;
		break;
	}

	rg_log_exit();
	rg_prof_end("watch_del");
	return $ret;
}

/*
 * Returns a list of uids by type and obj_id
 */
function rg_watch_load_by_obj_id($db, $type, $obj_id1, $obj_id2)
{
	rg_prof_start("watch_load_by_obj_id");
	rg_log_enter("watch_load_by_obj_id: type=$type obj_id=$obj_id1/$obj_id2");

	$ret = FALSE;
	while (1) {
		$params = array("obj_id1" => $obj_id1,
			"obj_id2" => $obj_id2);

		if (strcmp($type, "bug") == 0) {
			$sql = "SELECT uid FROM watch_bug"
				. " WHERE repo_id = @@obj_id1@@"
				. " AND bug_id = @@obj_id2@@";
		} else if (strcmp($type, "repo") == 0) {
			$sql = "SELECT uid FROM watch_repo"
				. " WHERE repo_id = @@obj_id1@@";
		} else if (strcmp($type, "user") == 0) {
			$sql = "SELECT uid FROM watch_user"
				. " WHERE watch_uid = @@obj_id1@@";
		} else {
			rg_internal_error("Invalid watch type!");
			break;
		}
		$res = rg_sql_query_params($db, $sql, $params);
		if ($res === FALSE) {
			rg_watch_set_error('cannot get data from db');
			break;
		}

		$ret = array();
		while (($row = rg_sql_fetch_array($res)))
			$ret[] = $row['uid'];
		rg_sql_free_result($res);

		break;
	}

	rg_log_exit();
	rg_prof_end("watch_load_by_obj_id");
	return $ret;
}

/*
 * Helper to easy dealing witch watch buttons.
 * It show and process the presses.
 */
function rg_watch_hl_process($db, &$rg, $type, $obj_id1, $obj_id2, $url)
{
	rg_prof_start('watch_hl_process');
	rg_log_enter('watch_hl_process type=' . $type);

	$ret = FALSE;
	$rg['HTML:watch_form'] = '';
	$rg['HTML:watch_error'] = '';
	while (1) {
		// If user is not logged in, we cannot add a watch
		if ($rg['login_ui']['uid'] == 0) {
			$ret = TRUE;
			break;
		}

		// The owner is already watching his repos
		if ($rg['login_ui']['uid'] == $rg['page_ui']['uid']) {
			$ret = TRUE;
			break;
		}

		$watch = rg_watch_load($db, $type, $rg['login_ui']['uid'],
			$obj_id1, $obj_id2);
		if ($watch === FALSE)
			break;

		// It is our watch? Please note that we may have multiple
		// watches on the same page: think bugs.
		$passed_type = rg_var_str('watch_type');
		$ours = strcmp($passed_type, $type) == 0;

		if ((rg_var_uint('watch_doit') == 1) && $ours) {
			if (!rg_valid_referer()) {
				rg_watch_set_error('invalid referer; try again');
				break;
			}

			if (!rg_token_valid($db, $rg, 'watch_' . $type, FALSE)) {
				rg_watch_set_error('invalid token; try again');
				break;
			}

			if (rg_var_uint('watch') == $watch)
				$next_value = 1 - $watch;
			else
				$next_value = $watch;
		} else {
			$next_value = 1 - $watch;
		}

		rg_log('DEBUG: watch=' . $watch . ' next_value=' . $next_value);
		$rg['watch'] = array(
			'type' => $type,
			'url' => $url,
			'next_value' => $next_value);
		$rg['rg_form_token_tag'] = 'watch_' . $type;
		$rg['rg_form_token'] = rg_token_get($db, $rg, 'watch_' . $type);
		$rg['HTML:watch_form'] = rg_template('watch.html',
			$rg, TRUE /*xss*/);

		if ((rg_var_uint('watch_doit') != 1) || !$ours) {
			$ret = TRUE;
			break;
		}

		if ($watch == 0)
			$r = rg_watch_add($db, $type, $rg['login_ui']['uid'],
				$obj_id1, $obj_id2);
		else
			$r = rg_watch_del($db, $type, $rg['login_ui']['uid'],
				$obj_id1, $obj_id2);
		if ($r === FALSE)
			break;

		$ret = TRUE;
		break;
	}

	if ($ret === FALSE)
		$rg['HTML:watch_error'] = rg_warning('Watch error: ' . rg_watch_error());

	rg_log_exit();
	rg_prof_end('watch_hl_process');
	return $ret;
}

?>
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/rocketgit

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/rocketgit

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master