diff --git a/include/dba.php b/include/dba.php index 5066dcd56d..76791911a3 100644 --- a/include/dba.php +++ b/include/dba.php @@ -10,6 +10,7 @@ require_once('include/datetime.php'); * When logging, all binary info is converted to text and html entities are escaped so that * the debugging stream is safe to view within both terminals and web pages. * + * This class is for the low level database stuff that does driver specific things. */ class dba { @@ -21,6 +22,7 @@ class dba { public $connected = false; public $error = false; private $_server_info = ''; + private static $dbo; function __construct($server, $user, $pass, $db, $install = false) { $a = get_app(); @@ -93,6 +95,8 @@ class dba { } } $a->save_timestamp($stamp1, "network"); + + self::$dbo = $this; } /** @@ -131,30 +135,6 @@ class dba { return $r[0]['db']; } - /** - * @brief Returns the number of rows - * - * @return integer - */ - public function num_rows() { - if (!$this->result) { - return 0; - } - - switch ($this->driver) { - case 'pdo': - $rows = $this->result->rowCount(); - break; - case 'mysqli': - $rows = $this->result->num_rows; - break; - case 'mysql': - $rows = mysql_num_rows($this->result); - break; - } - return $rows; - } - /** * @brief Analyze a database query and log this if some conditions are met. * @@ -249,7 +229,7 @@ class dba { break; } $stamp2 = microtime(true); - $duration = (float)($stamp2-$stamp1); + $duration = (float)($stamp2 - $stamp1); $a->save_timestamp($stamp1, "database"); @@ -379,41 +359,6 @@ class dba { return($r); } - public function qfetch() { - $x = false; - - if ($this->result) { - switch ($this->driver) { - case 'pdo': - $x = $this->result->fetch(PDO::FETCH_ASSOC); - break; - case 'mysqli': - $x = $this->result->fetch_array(MYSQLI_ASSOC); - break; - case 'mysql': - $x = mysql_fetch_array($this->result, MYSQL_ASSOC); - break; - } - } - return($x); - } - - public function qclose() { - if ($this->result) { - switch ($this->driver) { - case 'pdo': - $this->result->closeCursor(); - break; - case 'mysqli': - $this->result->free_result(); - break; - case 'mysql': - mysql_free_result($this->result); - break; - } - } - } - public function dbg($dbg) { $this->debug = $dbg; } @@ -497,6 +442,285 @@ class dba { } return $sql; } + + /** + * @brief Replaces the ? placeholders with the parameters in the $args array + * + * @param string $sql SQL query + * @param array $args The parameters that are to replace the ? placeholders + * @return string The replaced SQL query + */ + static private function replace_parameters($sql, $args) { + $offset = 0; + foreach ($args AS $param => $value) { + if (is_int($args[$param]) OR is_float($args[$param])) { + $replace = intval($args[$param]); + } else { + $replace = "'".dbesc($args[$param])."'"; + } + + $pos = strpos($sql, '?', $offset); + if ($pos !== false) { + $sql = substr_replace($sql, $replace, $pos, 1); + } + $offset = $pos + strlen($replace); + } + return $sql; + } + + /** + * @brief Executes a prepared statement that returns data + * @usage Example: $r = p("SELECT * FROM `item` WHERE `guid` = ?", $guid); + * @param string $sql SQL statement + * @return object statement object + */ + static public function p($sql) { + $a = get_app(); + + $stamp1 = microtime(true); + + $args = func_get_args(); + unset($args[0]); + + if (!self::$dbo OR !self::$dbo->connected) { + return false; + } + + $sql = self::$dbo->any_value_fallback($sql); + + if (x($a->config,'system') && x($a->config['system'], 'db_callstack')) { + $sql = "/*".$a->callstack()." */ ".$sql; + } + + switch (self::$dbo->driver) { + case 'pdo': + if (!$stmt = self::$dbo->db->prepare($sql)) { + $errorInfo = self::$dbo->db->errorInfo(); + self::$dbo->error = $errorInfo[2]; + self::$dbo->errorno = $errorInfo[1]; + $retval = false; + break; + } + + foreach ($args AS $param => $value) { + $stmt->bindParam($param, $args[$param]); + } + + if (!$stmt->execute()) { + $errorInfo = self::$dbo->db->errorInfo(); + self::$dbo->error = $errorInfo[2]; + self::$dbo->errorno = $errorInfo[1]; + $retval = false; + } else { + $retval = $stmt; + } + break; + case 'mysqli': + $stmt = self::$dbo->db->stmt_init(); + + if (!$stmt->prepare($sql)) { + self::$dbo->error = self::$dbo->db->error; + self::$dbo->errorno = self::$dbo->db->errno; + $retval = false; + break; + } + + $params = ''; + $values = array(); + foreach ($args AS $param => $value) { + if (is_int($args[$param])) { + $params .= 'i'; + } elseif (is_float($args[$param])) { + $params .= 'd'; + } elseif (is_string($args[$param])) { + $params .= 's'; + } else { + $params .= 'b'; + } + $values[] = &$args[$param]; + } + + array_unshift($values, $params); + + call_user_func_array(array($stmt, 'bind_param'), $values); + + if (!$stmt->execute()) { + self::$dbo->error = self::$dbo->db->error; + self::$dbo->errorno = self::$dbo->db->errno; + $retval = false; + } else { + $stmt->store_result(); + $retval = $stmt; + } + break; + case 'mysql': + // For the old "mysql" functions we cannot use prepared statements + $retval = mysql_query(self::replace_parameters($sql, $args), self::$dbo->db); + if (mysql_errno(self::$dbo->db)) { + self::$dbo->error = mysql_error(self::$dbo->db); + self::$dbo->errorno = mysql_errno(self::$dbo->db); + } + break; + } + + $a->save_timestamp($stamp1, 'database'); + + if (x($a->config,'system') && x($a->config['system'], 'db_log')) { + + $stamp2 = microtime(true); + $duration = (float)($stamp2 - $stamp1); + + if (($duration > $a->config["system"]["db_loglimit"])) { + $duration = round($duration, 3); + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + + @file_put_contents($a->config["system"]["db_log"], datetime_convert()."\t".$duration."\t". + basename($backtrace[1]["file"])."\t". + $backtrace[1]["line"]."\t".$backtrace[2]["function"]."\t". + substr(self::replace_parameters($sql, $args), 0, 2000)."\n", FILE_APPEND); + } + } + return $retval; + } + + /** + * @brief Executes a prepared statement like UPDATE or INSERT that doesn't return data + * + * @param string $sql SQL statement + * @return boolean Was the query successfull? False is returned only if an error occurred + */ + static public function e($sql) { + $a = get_app(); + + $stamp = microtime(true); + + $args = func_get_args(); + + $stmt = call_user_func_array('self::p', $args); + + if (is_bool($stmt)) { + $retval = $stmt; + } elseif (is_object($stmt)) { + $retval = true; + } else { + $retval = false; + } + + self::close($stmt); + + $a->save_timestamp($stamp, "database_write"); + + return $retval; + } + + /** + * @brief Check if data exists + * + * @param string $sql SQL statement + * @return boolean Are there rows for that query? + */ + static public function exists($sql) { + $args = func_get_args(); + + $stmt = call_user_func_array('self::p', $args); + + if (is_bool($stmt)) { + $retval = $stmt; + } else { + $retval = (self::rows($stmt) > 0); + } + + self::close($stmt); + + return $retval; + } + + /** + * @brief Returns the number of rows of a statement + * + * @param object Statement object + * @return int Number of rows + */ + static public function num_rows($stmt) { + switch (self::$dbo->driver) { + case 'pdo': + return $stmt->rowCount(); + case 'mysqli': + return $stmt->num_rows; + case 'mysql': + return mysql_num_rows($stmt); + } + return 0; + } + + /** + * @brief Fetch a single row + * + * @param object $stmt statement object + * @return array current row + */ + static public function fetch($stmt) { + if (!is_object($stmt)) { + return false; + } + + switch (self::$dbo->driver) { + case 'pdo': + return $stmt->fetch(PDO::FETCH_ASSOC); + case 'mysqli': + // This code works, but is slow + + // Bind the result to a result array + $cols = array(); + + $cols_num = array(); + for ($x = 0; $x < $stmt->field_count; $x++) { + $cols[] = &$cols_num[$x]; + } + + call_user_func_array(array($stmt, 'bind_result'), $cols); + + if (!$stmt->fetch()) { + return false; + } + + // The slow part: + // We need to get the field names for the array keys + // It seems that there is no better way to do this. + $result = $stmt->result_metadata(); + $fields = $result->fetch_fields(); + + $columns = array(); + foreach ($cols_num AS $param => $col) { + $columns[$fields[$param]->name] = $col; + } + return $columns; + case 'mysql': + return mysql_fetch_array(self::$dbo->result, MYSQL_ASSOC); + } + } + + /** + * @brief Closes the current statement + * + * @param object $stmt statement object + * @return boolean was the close successfull? + */ + static public function close($stmt) { + if (!is_object($stmt)) { + return false; + } + + switch (self::$dbo->driver) { + case 'pdo': + return $stmt->closeCursor(); + case 'mysqli': + return $stmt->free_result(); + return $stmt->close(); + case 'mysql': + return mysql_free_result($stmt); + } + } } function printable($s) { diff --git a/include/dbclean.php b/include/dbclean.php index bff4ff2a24..64ceb51d37 100644 --- a/include/dbclean.php +++ b/include/dbclean.php @@ -43,96 +43,103 @@ function remove_orphans($stage = 0) { if (($stage == 1) OR ($stage == 0)) { logger("Deleting old global item entries from item table without user copy"); - if ($db->q("SELECT `id` FROM `item` WHERE `uid` = 0 + $r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) - AND `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + AND `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found global item orphans: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `item` WHERE `id` = %d", intval($orphan["id"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting old global item entries from item table without user copy"); } if (($stage == 2) OR ($stage == 0)) { logger("Deleting items without parents"); - if ($db->q("SELECT `id` FROM `item` WHERE NOT EXISTS (SELECT `id` FROM `item` AS `i` WHERE `item`.`parent` = `i`.`id`) LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + $r = dba::p("SELECT `id` FROM `item` WHERE NOT EXISTS (SELECT `id` FROM `item` AS `i` WHERE `item`.`parent` = `i`.`id`) LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found item orphans without parents: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `item` WHERE `id` = %d", intval($orphan["id"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting items without parents"); } if (($stage == 3) OR ($stage == 0)) { logger("Deleting orphaned data from thread table"); - if ($db->q("SELECT `iid` FROM `thread` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`) LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + $r = dba::p("SELECT `iid` FROM `thread` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`) LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found thread orphans: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `thread` WHERE `iid` = %d", intval($orphan["iid"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting orphaned data from thread table"); } if (($stage == 4) OR ($stage == 0)) { logger("Deleting orphaned data from notify table"); - if ($db->q("SELECT `iid` FROM `notify` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`) LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + $r = dba::p("SELECT `iid` FROM `notify` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`) LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found notify orphans: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `notify` WHERE `iid` = %d", intval($orphan["iid"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting orphaned data from notify table"); } if (($stage == 5) OR ($stage == 0)) { logger("Deleting orphaned data from notify-threads table"); - if ($db->q("SELECT `id` FROM `notify-threads` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `notify-threads`.`master-parent-item`) LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + $r = dba::p("SELECT `id` FROM `notify-threads` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `notify-threads`.`master-parent-item`) LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found notify-threads orphans: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `notify-threads` WHERE `id` = %d", intval($orphan["id"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting orphaned data from notify-threads table"); } if (($stage == 6) OR ($stage == 0)) { logger("Deleting orphaned data from sign table"); - if ($db->q("SELECT `iid` FROM `sign` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`) LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + $r = dba::p("SELECT `iid` FROM `sign` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`) LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found sign orphans: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `sign` WHERE `iid` = %d", intval($orphan["iid"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting orphaned data from sign table"); } if (($stage == 7) OR ($stage == 0)) { logger("Deleting orphaned data from term table"); - if ($db->q("SELECT `oid` FROM `term` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`) LIMIT ".intval($limit), true)) { - $count = $db->num_rows(); + $r = dba::p("SELECT `oid` FROM `term` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`) LIMIT ".intval($limit)); + $count = dba::num_rows($r); + if ($count > 0) { logger("found term orphans: ".$count); - while ($orphan = $db->qfetch()) { + while ($orphan = dba::fetch($r)) { q("DELETE FROM `term` WHERE `oid` = %d", intval($orphan["oid"])); } } - $db->qclose(); + dba::close($r); logger("Done deleting orphaned data from term table"); } diff --git a/include/dbm.php b/include/dbm.php index d28d49d63b..3430577da6 100644 --- a/include/dbm.php +++ b/include/dbm.php @@ -2,6 +2,7 @@ /** * @brief This class contain functions for the database management * + * This class contains functions that doesn't need to know if pdo, mysqli or whatever is used. */ class dbm { /** @@ -47,6 +48,11 @@ class dbm { if (is_bool($array)) { return $array; } + + if (is_object($array)) { + return true; + } + return (is_array($array) && count($array) > 0); } diff --git a/include/tags.php b/include/tags.php index 0a09438478..d809da2bf5 100644 --- a/include/tags.php +++ b/include/tags.php @@ -111,12 +111,11 @@ function create_tags_from_itemuri($itemuri, $uid) { } function update_items() { - global $db; - $messages = $db->q("SELECT `oid`,`item`.`guid`, `item`.`created`, `item`.`received` FROM `term` INNER JOIN `item` ON `item`.`id`=`term`.`oid` WHERE `term`.`otype` = 1 AND `term`.`guid` = ''", true); + $messages = dba::p("SELECT `oid`,`item`.`guid`, `item`.`created`, `item`.`received` FROM `term` INNER JOIN `item` ON `item`.`id`=`term`.`oid` WHERE `term`.`otype` = 1 AND `term`.`guid` = ''"); - logger("fetched messages: ".count($messages)); - while ($message = $db->qfetch()) { + logger("fetched messages: ".dba::num_rows($messages)); + while ($message = dba::fetch($messages)) { if ($message["uid"] == 0) { $global = true; @@ -135,15 +134,15 @@ function update_items() { intval($global), intval(TERM_OBJ_POST), intval($message["oid"])); } - $db->qclose(); + dba::close($messages); - $messages = $db->q("SELECT `guid` FROM `item` WHERE `uid` = 0", true); + $messages = dba::p("SELECT `guid` FROM `item` WHERE `uid` = 0"); - logger("fetched messages: ".count($messages)); - while ($message = $db->qfetch()) { + logger("fetched messages: ".dba::num_rows($messages)); + while ($message = dba::fetch(messages)) { q("UPDATE `item` SET `global` = 1 WHERE `guid` = '%s'", dbesc($message["guid"])); } - $db->qclose(); + dba::close($messages); } ?> diff --git a/include/threads.php b/include/threads.php index c214cf2644..3d0aa05c3c 100644 --- a/include/threads.php +++ b/include/threads.php @@ -251,19 +251,17 @@ function delete_thread($itemid, $itemuri = "") { } function update_threads() { - global $db; - logger("update_threads: start"); - $messages = $db->q("SELECT `id` FROM `item` WHERE `id` = `parent`", true); + $messages = dba::p("SELECT `id` FROM `item` WHERE `id` = `parent`"); - logger("update_threads: fetched messages: ".count($messages)); + logger("update_threads: fetched messages: ".dba::num_rows($messages)); - while ($message = $db->qfetch()) { + while ($message = dba::fetch($messages)) { add_thread($message["id"]); add_shadow_thread($message["id"]); } - $db->qclose(); + dba::close($messages); } function update_threads_mention() { @@ -283,18 +281,16 @@ function update_threads_mention() { function update_shadow_copy() { - global $db; - logger("start"); - $messages = $db->q(sprintf("SELECT `iid` FROM `thread` WHERE `uid` != 0 AND `network` IN ('', '%s', '%s', '%s') - AND `visible` AND NOT `deleted` AND NOT `moderated` AND NOT `private` ORDER BY `created`", - NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS), true); + $messages = dba::p("SELECT `iid` FROM `thread` WHERE `uid` != 0 AND `network` IN ('', ?, ?, ?) + AND `visible` AND NOT `deleted` AND NOT `moderated` AND NOT `private` ORDER BY `created`", + NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS); - logger("fetched messages: ".count($messages)); - while ($message = $db->qfetch()) + logger("fetched messages: ".dba::num_rows($messages)); + while ($message = dba::fetch($messages)) add_shadow_thread($message["iid"]); - $db->qclose(); + dba::close($messages); } ?> diff --git a/index.php b/index.php index ebc65cdb01..efaf07c1a0 100644 --- a/index.php +++ b/index.php @@ -174,6 +174,10 @@ if (! x($_SESSION,'sysmsg_info')) { $_SESSION['sysmsg_info'] = array(); } +// Array for informations about last received items +if (! x($_SESSION,'last_updated')) { + $_SESSION['last_updated'] = array(); +} /* * check_config() is responsible for running update scripts. These automatically * update the DB schema whenever we push a new one out. It also checks to see if diff --git a/mod/group.php b/mod/group.php index 2042c765f8..81477c3298 100644 --- a/mod/group.php +++ b/mod/group.php @@ -1,38 +1,38 @@ page['aside'] = group_side('contacts','group','extended',(($a->argc > 1) ? intval($a->argv[1]) : 0)); + if (local_user()) { + require_once 'include/group.php'; + $a->page['aside'] = group_side('contacts', 'group', 'extended', (($a->argc > 1) ? intval($a->argv[1]) : 0)); } } - - function group_post(App $a) { if (! local_user()) { - notice( t('Permission denied.') . EOL); + notice(t('Permission denied.') . EOL); return; } - if(($a->argc == 2) && ($a->argv[1] === 'new')) { + if (($a->argc == 2) && ($a->argv[1] === 'new')) { check_form_security_token_redirectOnErr('/group/new', 'group_edit'); $name = notags(trim($_POST['groupname'])); - $r = group_add(local_user(),$name); + $r = group_add(local_user(), $name); if ($r) { - info( t('Group created.') . EOL ); - $r = group_byname(local_user(),$name); + info(t('Group created.') . EOL); + $r = group_byname(local_user(), $name); if ($r) { goaway(App::get_baseurl() . '/group/' . $r); } } else { - notice( t('Could not create group.') . EOL ); + notice(t('Could not create group.') . EOL); } goaway(App::get_baseurl() . '/group'); return; // NOTREACHED @@ -46,7 +46,7 @@ function group_post(App $a) { intval(local_user()) ); if (! dbm::is_result($r)) { - notice( t('Group not found.') . EOL ); + notice(t('Group not found.') . EOL); goaway(App::get_baseurl() . '/contacts'); return; // NOTREACHED } @@ -60,7 +60,7 @@ function group_post(App $a) { ); if ($r) { - info( t('Group name changed.') . EOL ); + info(t('Group name changed.') . EOL); } } @@ -73,17 +73,19 @@ function group_content(App $a) { $change = false; if (! local_user()) { - notice( t('Permission denied') . EOL); + notice(t('Permission denied') . EOL); return; } // Switch to text mode interface if we have more than 'n' contacts or group members - $switchtotext = get_pconfig(local_user(),'system','groupedit_image_limit'); - if($switchtotext === false) - $switchtotext = get_config('system','groupedit_image_limit'); - if($switchtotext === false) + $switchtotext = get_pconfig(local_user(), 'system', 'groupedit_image_limit'); + if ($switchtotext === false) { + $switchtotext = get_config('system', 'groupedit_image_limit'); + } + if ($switchtotext === false) { $switchtotext = 400; + } $tpl = get_markup_template('group_edit.tpl'); @@ -92,7 +94,6 @@ function group_content(App $a) { ); if (($a->argc == 2) && ($a->argv[1] === 'new')) { - return replace_macros($tpl, $context + array( '$title' => t('Create a group of contacts/friends.'), '$gname' => array('groupname', t('Group Name: '), '', ''), @@ -115,13 +116,13 @@ function group_content(App $a) { $result = null; if (dbm::is_result($r)) { - $result = group_rmv(local_user(),$r[0]['name']); + $result = group_rmv(local_user(), $r[0]['name']); } if ($result) { - info( t('Group removed.') . EOL); + info(t('Group removed.') . EOL); } else { - notice( t('Unable to remove group.') . EOL); + notice(t('Unable to remove group.') . EOL); } } goaway(App::get_baseurl() . '/group'); @@ -135,66 +136,75 @@ function group_content(App $a) { intval($a->argv[2]), intval(local_user()) ); - if (dbm::is_result($r)) + if (dbm::is_result($r)) { $change = intval($a->argv[2]); + } } if (($a->argc > 1) && (intval($a->argv[1]))) { + require_once 'include/acl_selectors.php'; + require_once 'mod/contacts.php'; - require_once('include/acl_selectors.php'); $r = q("SELECT * FROM `group` WHERE `id` = %d AND `uid` = %d AND `deleted` = 0 LIMIT 1", intval($a->argv[1]), intval(local_user()) ); + if (! dbm::is_result($r)) { - notice( t('Group not found.') . EOL ); + notice(t('Group not found.') . EOL); goaway(App::get_baseurl() . '/contacts'); } + $group = $r[0]; $members = group_get_members($group['id']); $preselected = array(); - if(count($members)) { - foreach($members as $member) + $entry = array(); + $id = 0; + + if (count($members)) { + foreach ($members as $member) { $preselected[] = $member['id']; + } } - if($change) { - if(in_array($change,$preselected)) { - group_rmv_member(local_user(),$group['name'],$change); - } - else { - group_add_member(local_user(),$group['name'],$change); + if ($change) { + if (in_array($change, $preselected)) { + group_rmv_member(local_user(), $group['name'], $change); + } else { + group_add_member(local_user(), $group['name'], $change); } $members = group_get_members($group['id']); $preselected = array(); - if(count($members)) { - foreach($members as $member) + if (count($members)) { + foreach ($members as $member) { $preselected[] = $member['id']; + } } } - $drop_tpl = get_markup_template('group_drop.tpl'); $drop_txt = replace_macros($drop_tpl, array( '$id' => $group['id'], - '$delete' => t('Delete'), + '$delete' => t('Delete Group'), '$form_security_token' => get_form_security_token("group_drop"), )); $context = $context + array( '$title' => t('Group Editor'), - '$gname' => array('groupname', t('Group Name: '),$group['name'], ''), + '$gname' => array('groupname', t('Group Name: '), $group['name'], ''), '$gid' => $group['id'], '$drop' => $drop_txt, '$form_security_token' => get_form_security_token('group_edit'), + '$edit_name' => t('Edit Group Name') ); } - if(! isset($group)) + if (! isset($group)) { return; + } $groupeditor = array( 'label_members' => t('Members'), @@ -205,14 +215,24 @@ function group_content(App $a) { ); $sec_token = addslashes(get_form_security_token('group_member_change')); - $textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : false); - foreach($members as $member) { - if($member['url']) { - $member['click'] = 'groupChangeMember(' . $group['id'] . ',' . $member['id'] . ',\'' . $sec_token . '\'); return true;'; - $groupeditor['members'][] = micropro($member,true,'mpgroup', $textmode); + + // Format the data of the group members + foreach ($members as $member) { + if ($member['url']) { + $entry = _contact_detail_for_template($member); + $entry['label'] = 'members'; + $entry['photo_menu'] = ''; + $entry['change_member'] = array( + 'title' => t("Remove Contact"), + 'gid' => $group['id'], + 'cid' => $member['id'], + 'sec_token' => $sec_token + ); + + $groupeditor['members'][] = $entry; + } else { + group_rmv_member(local_user(), $group['name'], $member['id']); } - else - group_rmv_member(local_user(),$group['name'],$member['id']); } $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND NOT `blocked` AND NOT `pending` AND NOT `self` ORDER BY `name` ASC", @@ -220,11 +240,20 @@ function group_content(App $a) { ); if (dbm::is_result($r)) { - $textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : false); - foreach($r as $member) { - if(! in_array($member['id'],$preselected)) { - $member['click'] = 'groupChangeMember(' . $group['id'] . ',' . $member['id'] . ',\'' . $sec_token . '\'); return true;'; - $groupeditor['contacts'][] = micropro($member,true,'mpall', $textmode); + // Format the data of the contacts who aren't in the contact group + foreach ($r as $member) { + if (! in_array($member['id'], $preselected)) { + $entry = _contact_detail_for_template($member); + $entry['label'] = 'contacts'; + $entry['photo_menu'] = ''; + $entry['change_member'] = array( + 'title' => t("Add Contact"), + 'gid' => $group['id'], + 'cid' => $member['id'], + 'sec_token' => $sec_token + ); + + $groupeditor['contacts'][] = $entry; } } } @@ -232,7 +261,11 @@ function group_content(App $a) { $context['$groupeditor'] = $groupeditor; $context['$desc'] = t('Click on a contact to add or remove.'); - if($change) { + // If there are to many contacts we could provide an alternative view mode + $total = count($groupeditor['members']) + count($groupeditor['contacts']); + $context['$shortmode'] = (($switchtotext && ($total > $switchtotext)) ? true : false); + + if ($change) { $tpl = get_markup_template('groupeditor.tpl'); echo replace_macros($tpl, $context); killme(); diff --git a/mod/profile.php b/mod/profile.php index a83cb076f2..838a550944 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -149,6 +149,7 @@ function profile_content(App $a, $update = 0) { } $is_owner = ((local_user()) && (local_user() == $a->profile['profile_uid']) ? true : false); + $last_updated_key = "profile:" . $a->profile['profile_uid'] . ":" . local_user() . ":" . remote_user(); if ($a->profile['hidewall'] && (! $is_owner) && (! $remote_contact)) { notice( t('Access to this profile has been restricted.') . EOL); @@ -195,9 +196,9 @@ function profile_content(App $a, $update = 0) { 'visitor' => (($is_owner || $commvisitor) ? 'block' : 'none'), 'profile_uid' => $a->profile['profile_uid'], 'acl_data' => ( $is_owner ? construct_acl_data($a, $a->user) : '' ), // For non-Javascript ACL selector - ); + ); - $o .= status_editor($a,$x); + $o .= status_editor($a,$x); } } @@ -209,6 +210,16 @@ function profile_content(App $a, $update = 0) { if ($update) { + $last_updated = (x($_SESSION['last_updated'], $last_updated_key) ? $_SESSION['last_updated'][$last_updated_key] : 0); + + // If the page user is the owner of the page we should query for unseen + // items. Otherwise use a timestamp of the last succesful update request. + if ($is_owner || !$last_updated) { + $sql_extra4 = " AND `item`.`unseen`"; + } else { + $gmupdate = gmdate("Y-m-d H:i:s", $last_updated); + $sql_extra4 = " AND `item`.`received` > '" . $gmupdate . "'"; + } $r = q("SELECT distinct(parent) AS `item_id`, `item`.`network` AS `item_network`, `item`.`created` FROM `item` INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` @@ -217,13 +228,18 @@ function profile_content(App $a, $update = 0) { (`item`.`deleted` = 0 OR item.verb = '" . ACTIVITY_LIKE ."' OR item.verb = '" . ACTIVITY_DISLIKE . "' OR item.verb = '" . ACTIVITY_ATTEND . "' OR item.verb = '" . ACTIVITY_ATTENDNO . "' OR item.verb = '" . ACTIVITY_ATTENDMAYBE . "') - AND `item`.`moderated` = 0 and `item`.`unseen` = 1 + AND `item`.`moderated` = 0 AND `item`.`wall` = 1 + $sql_extra4 $sql_extra ORDER BY `item`.`created` DESC", intval($a->profile['profile_uid']) ); + if (!dbm::is_result($r)) { + return ''; + } + } else { $sql_post_table = ""; @@ -283,11 +299,16 @@ function profile_content(App $a, $update = 0) { ORDER BY `thread`.`created` DESC $pager_sql", intval($a->profile['profile_uid']) ); + } $parents_arr = array(); $parents_str = ''; + // Set a time stamp for this page. We will make use of it when we + // search for new items (update routine) + $_SESSION['last_updated'][$last_updated_key] = time(); + if (dbm::is_result($r)) { foreach($r as $rr) $parents_arr[] = $rr['item_id']; diff --git a/view/templates/group_drop.tpl b/view/templates/group_drop.tpl index 9b8ff98708..0e3c320a94 100644 --- a/view/templates/group_drop.tpl +++ b/view/templates/group_drop.tpl @@ -5,6 +5,8 @@ id="group-delete-icon-{{$id}}" class="icon drophide group-delete-icon" onmouseover="imgbright(this);" - onmouseout="imgdull(this);" > + onmouseout="imgdull(this);" + title="{{$delete}}"> +
diff --git a/view/templates/groupeditor.tpl b/view/templates/groupeditor.tpl index 86458ded2e..28abc486ed 100644 --- a/view/templates/groupeditor.tpl +++ b/view/templates/groupeditor.tpl @@ -1,21 +1,62 @@ +{{* Template for the contact group list *}} + +{{* The contacts who are already members of the contact group *}}