Merge remote-tracking branch 'upstream/develop' into 1704-conversation
This commit is contained in:
commit
2e4db2e64e
16 changed files with 898 additions and 217 deletions
342
include/dba.php
342
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
|
* 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.
|
* 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 {
|
class dba {
|
||||||
|
@ -21,6 +22,7 @@ class dba {
|
||||||
public $connected = false;
|
public $connected = false;
|
||||||
public $error = false;
|
public $error = false;
|
||||||
private $_server_info = '';
|
private $_server_info = '';
|
||||||
|
private static $dbo;
|
||||||
|
|
||||||
function __construct($server, $user, $pass, $db, $install = false) {
|
function __construct($server, $user, $pass, $db, $install = false) {
|
||||||
$a = get_app();
|
$a = get_app();
|
||||||
|
@ -93,6 +95,8 @@ class dba {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$a->save_timestamp($stamp1, "network");
|
$a->save_timestamp($stamp1, "network");
|
||||||
|
|
||||||
|
self::$dbo = $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -131,30 +135,6 @@ class dba {
|
||||||
return $r[0]['db'];
|
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.
|
* @brief Analyze a database query and log this if some conditions are met.
|
||||||
*
|
*
|
||||||
|
@ -379,41 +359,6 @@ class dba {
|
||||||
return($r);
|
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) {
|
public function dbg($dbg) {
|
||||||
$this->debug = $dbg;
|
$this->debug = $dbg;
|
||||||
}
|
}
|
||||||
|
@ -497,6 +442,285 @@ class dba {
|
||||||
}
|
}
|
||||||
return $sql;
|
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) {
|
function printable($s) {
|
||||||
|
|
|
@ -43,96 +43,103 @@ function remove_orphans($stage = 0) {
|
||||||
|
|
||||||
if (($stage == 1) OR ($stage == 0)) {
|
if (($stage == 1) OR ($stage == 0)) {
|
||||||
logger("Deleting old global item entries from item table without user copy");
|
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 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)) {
|
AND `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY LIMIT ".intval($limit));
|
||||||
$count = $db->num_rows();
|
$count = dba::num_rows($r);
|
||||||
|
if ($count > 0) {
|
||||||
logger("found global item orphans: ".$count);
|
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"]));
|
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");
|
logger("Done deleting old global item entries from item table without user copy");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($stage == 2) OR ($stage == 0)) {
|
if (($stage == 2) OR ($stage == 0)) {
|
||||||
logger("Deleting items without parents");
|
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)) {
|
$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 = $db->num_rows();
|
$count = dba::num_rows($r);
|
||||||
|
if ($count > 0) {
|
||||||
logger("found item orphans without parents: ".$count);
|
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"]));
|
q("DELETE FROM `item` WHERE `id` = %d", intval($orphan["id"]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$db->qclose();
|
dba::close($r);
|
||||||
logger("Done deleting items without parents");
|
logger("Done deleting items without parents");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($stage == 3) OR ($stage == 0)) {
|
if (($stage == 3) OR ($stage == 0)) {
|
||||||
logger("Deleting orphaned data from thread table");
|
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)) {
|
$r = dba::p("SELECT `iid` FROM `thread` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`) LIMIT ".intval($limit));
|
||||||
$count = $db->num_rows();
|
$count = dba::num_rows($r);
|
||||||
|
if ($count > 0) {
|
||||||
logger("found thread orphans: ".$count);
|
logger("found thread orphans: ".$count);
|
||||||
while ($orphan = $db->qfetch()) {
|
while ($orphan = dba::fetch($r)) {
|
||||||
q("DELETE FROM `thread` WHERE `iid` = %d", intval($orphan["iid"]));
|
q("DELETE FROM `thread` WHERE `iid` = %d", intval($orphan["iid"]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$db->qclose();
|
dba::close($r);
|
||||||
logger("Done deleting orphaned data from thread table");
|
logger("Done deleting orphaned data from thread table");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($stage == 4) OR ($stage == 0)) {
|
if (($stage == 4) OR ($stage == 0)) {
|
||||||
logger("Deleting orphaned data from notify table");
|
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)) {
|
$r = dba::p("SELECT `iid` FROM `notify` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`) LIMIT ".intval($limit));
|
||||||
$count = $db->num_rows();
|
$count = dba::num_rows($r);
|
||||||
|
if ($count > 0) {
|
||||||
logger("found notify orphans: ".$count);
|
logger("found notify orphans: ".$count);
|
||||||
while ($orphan = $db->qfetch()) {
|
while ($orphan = dba::fetch($r)) {
|
||||||
q("DELETE FROM `notify` WHERE `iid` = %d", intval($orphan["iid"]));
|
q("DELETE FROM `notify` WHERE `iid` = %d", intval($orphan["iid"]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$db->qclose();
|
dba::close($r);
|
||||||
logger("Done deleting orphaned data from notify table");
|
logger("Done deleting orphaned data from notify table");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($stage == 5) OR ($stage == 0)) {
|
if (($stage == 5) OR ($stage == 0)) {
|
||||||
logger("Deleting orphaned data from notify-threads table");
|
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)) {
|
$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 = $db->num_rows();
|
$count = dba::num_rows($r);
|
||||||
|
if ($count > 0) {
|
||||||
logger("found notify-threads orphans: ".$count);
|
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"]));
|
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");
|
logger("Done deleting orphaned data from notify-threads table");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (($stage == 6) OR ($stage == 0)) {
|
if (($stage == 6) OR ($stage == 0)) {
|
||||||
logger("Deleting orphaned data from sign table");
|
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)) {
|
$r = dba::p("SELECT `iid` FROM `sign` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`) LIMIT ".intval($limit));
|
||||||
$count = $db->num_rows();
|
$count = dba::num_rows($r);
|
||||||
|
if ($count > 0) {
|
||||||
logger("found sign orphans: ".$count);
|
logger("found sign orphans: ".$count);
|
||||||
while ($orphan = $db->qfetch()) {
|
while ($orphan = dba::fetch($r)) {
|
||||||
q("DELETE FROM `sign` WHERE `iid` = %d", intval($orphan["iid"]));
|
q("DELETE FROM `sign` WHERE `iid` = %d", intval($orphan["iid"]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$db->qclose();
|
dba::close($r);
|
||||||
logger("Done deleting orphaned data from sign table");
|
logger("Done deleting orphaned data from sign table");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (($stage == 7) OR ($stage == 0)) {
|
if (($stage == 7) OR ($stage == 0)) {
|
||||||
logger("Deleting orphaned data from term table");
|
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)) {
|
$r = dba::p("SELECT `oid` FROM `term` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`) LIMIT ".intval($limit));
|
||||||
$count = $db->num_rows();
|
$count = dba::num_rows($r);
|
||||||
|
if ($count > 0) {
|
||||||
logger("found term orphans: ".$count);
|
logger("found term orphans: ".$count);
|
||||||
while ($orphan = $db->qfetch()) {
|
while ($orphan = dba::fetch($r)) {
|
||||||
q("DELETE FROM `term` WHERE `oid` = %d", intval($orphan["oid"]));
|
q("DELETE FROM `term` WHERE `oid` = %d", intval($orphan["oid"]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$db->qclose();
|
dba::close($r);
|
||||||
logger("Done deleting orphaned data from term table");
|
logger("Done deleting orphaned data from term table");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
/**
|
/**
|
||||||
* @brief This class contain functions for the database management
|
* @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 {
|
class dbm {
|
||||||
/**
|
/**
|
||||||
|
@ -47,6 +48,11 @@ class dbm {
|
||||||
if (is_bool($array)) {
|
if (is_bool($array)) {
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_object($array)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return (is_array($array) && count($array) > 0);
|
return (is_array($array) && count($array) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,12 +111,11 @@ function create_tags_from_itemuri($itemuri, $uid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_items() {
|
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));
|
logger("fetched messages: ".dba::num_rows($messages));
|
||||||
while ($message = $db->qfetch()) {
|
while ($message = dba::fetch($messages)) {
|
||||||
|
|
||||||
if ($message["uid"] == 0) {
|
if ($message["uid"] == 0) {
|
||||||
$global = true;
|
$global = true;
|
||||||
|
@ -135,15 +134,15 @@ function update_items() {
|
||||||
intval($global), intval(TERM_OBJ_POST), intval($message["oid"]));
|
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));
|
logger("fetched messages: ".dba::num_rows($messages));
|
||||||
while ($message = $db->qfetch()) {
|
while ($message = dba::fetch(messages)) {
|
||||||
q("UPDATE `item` SET `global` = 1 WHERE `guid` = '%s'", dbesc($message["guid"]));
|
q("UPDATE `item` SET `global` = 1 WHERE `guid` = '%s'", dbesc($message["guid"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
$db->qclose();
|
dba::close($messages);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -251,19 +251,17 @@ function delete_thread($itemid, $itemuri = "") {
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_threads() {
|
function update_threads() {
|
||||||
global $db;
|
|
||||||
|
|
||||||
logger("update_threads: start");
|
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_thread($message["id"]);
|
||||||
add_shadow_thread($message["id"]);
|
add_shadow_thread($message["id"]);
|
||||||
}
|
}
|
||||||
$db->qclose();
|
dba::close($messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_threads_mention() {
|
function update_threads_mention() {
|
||||||
|
@ -283,18 +281,16 @@ function update_threads_mention() {
|
||||||
|
|
||||||
|
|
||||||
function update_shadow_copy() {
|
function update_shadow_copy() {
|
||||||
global $db;
|
|
||||||
|
|
||||||
logger("start");
|
logger("start");
|
||||||
|
|
||||||
$messages = $db->q(sprintf("SELECT `iid` FROM `thread` WHERE `uid` != 0 AND `network` IN ('', '%s', '%s', '%s')
|
$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`",
|
AND `visible` AND NOT `deleted` AND NOT `moderated` AND NOT `private` ORDER BY `created`",
|
||||||
NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS), true);
|
NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS);
|
||||||
|
|
||||||
logger("fetched messages: ".count($messages));
|
logger("fetched messages: ".dba::num_rows($messages));
|
||||||
while ($message = $db->qfetch())
|
while ($message = dba::fetch($messages))
|
||||||
add_shadow_thread($message["iid"]);
|
add_shadow_thread($message["iid"]);
|
||||||
|
|
||||||
$db->qclose();
|
dba::close($messages);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -174,6 +174,10 @@ if (! x($_SESSION,'sysmsg_info')) {
|
||||||
$_SESSION['sysmsg_info'] = array();
|
$_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
|
* 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
|
* update the DB schema whenever we push a new one out. It also checks to see if
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* @file mod/group.php
|
||||||
|
* @brief The group module (create and rename contact groups, add and
|
||||||
|
* remove contacts to the contact groups
|
||||||
|
*/
|
||||||
|
|
||||||
function validate_members(&$item) {
|
|
||||||
$item = intval($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
function group_init(App $a) {
|
function group_init(App $a) {
|
||||||
if (local_user()) {
|
if (local_user()) {
|
||||||
require_once('include/group.php');
|
require_once 'include/group.php';
|
||||||
$a->page['aside'] = group_side('contacts', 'group', 'extended', (($a->argc > 1) ? intval($a->argv[1]) : 0));
|
$a->page['aside'] = group_side('contacts', 'group', 'extended', (($a->argc > 1) ? intval($a->argv[1]) : 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function group_post(App $a) {
|
function group_post(App $a) {
|
||||||
|
|
||||||
if (! local_user()) {
|
if (! local_user()) {
|
||||||
|
@ -80,10 +80,12 @@ function group_content(App $a) {
|
||||||
// Switch to text mode interface if we have more than 'n' contacts or group members
|
// Switch to text mode interface if we have more than 'n' contacts or group members
|
||||||
|
|
||||||
$switchtotext = get_pconfig(local_user(), 'system', 'groupedit_image_limit');
|
$switchtotext = get_pconfig(local_user(), 'system', 'groupedit_image_limit');
|
||||||
if($switchtotext === false)
|
if ($switchtotext === false) {
|
||||||
$switchtotext = get_config('system', 'groupedit_image_limit');
|
$switchtotext = get_config('system', 'groupedit_image_limit');
|
||||||
if($switchtotext === false)
|
}
|
||||||
|
if ($switchtotext === false) {
|
||||||
$switchtotext = 400;
|
$switchtotext = 400;
|
||||||
|
}
|
||||||
|
|
||||||
$tpl = get_markup_template('group_edit.tpl');
|
$tpl = get_markup_template('group_edit.tpl');
|
||||||
|
|
||||||
|
@ -92,7 +94,6 @@ function group_content(App $a) {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (($a->argc == 2) && ($a->argv[1] === 'new')) {
|
if (($a->argc == 2) && ($a->argv[1] === 'new')) {
|
||||||
|
|
||||||
return replace_macros($tpl, $context + array(
|
return replace_macros($tpl, $context + array(
|
||||||
'$title' => t('Create a group of contacts/friends.'),
|
'$title' => t('Create a group of contacts/friends.'),
|
||||||
'$gname' => array('groupname', t('Group Name: '), '', ''),
|
'$gname' => array('groupname', t('Group Name: '), '', ''),
|
||||||
|
@ -135,50 +136,57 @@ function group_content(App $a) {
|
||||||
intval($a->argv[2]),
|
intval($a->argv[2]),
|
||||||
intval(local_user())
|
intval(local_user())
|
||||||
);
|
);
|
||||||
if (dbm::is_result($r))
|
if (dbm::is_result($r)) {
|
||||||
$change = intval($a->argv[2]);
|
$change = intval($a->argv[2]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (($a->argc > 1) && (intval($a->argv[1]))) {
|
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",
|
$r = q("SELECT * FROM `group` WHERE `id` = %d AND `uid` = %d AND `deleted` = 0 LIMIT 1",
|
||||||
intval($a->argv[1]),
|
intval($a->argv[1]),
|
||||||
intval(local_user())
|
intval(local_user())
|
||||||
);
|
);
|
||||||
|
|
||||||
if (! dbm::is_result($r)) {
|
if (! dbm::is_result($r)) {
|
||||||
notice(t('Group not found.') . EOL);
|
notice(t('Group not found.') . EOL);
|
||||||
goaway(App::get_baseurl() . '/contacts');
|
goaway(App::get_baseurl() . '/contacts');
|
||||||
}
|
}
|
||||||
|
|
||||||
$group = $r[0];
|
$group = $r[0];
|
||||||
$members = group_get_members($group['id']);
|
$members = group_get_members($group['id']);
|
||||||
$preselected = array();
|
$preselected = array();
|
||||||
|
$entry = array();
|
||||||
|
$id = 0;
|
||||||
|
|
||||||
if (count($members)) {
|
if (count($members)) {
|
||||||
foreach($members as $member)
|
foreach ($members as $member) {
|
||||||
$preselected[] = $member['id'];
|
$preselected[] = $member['id'];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($change) {
|
if ($change) {
|
||||||
if (in_array($change, $preselected)) {
|
if (in_array($change, $preselected)) {
|
||||||
group_rmv_member(local_user(), $group['name'], $change);
|
group_rmv_member(local_user(), $group['name'], $change);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
group_add_member(local_user(), $group['name'], $change);
|
group_add_member(local_user(), $group['name'], $change);
|
||||||
}
|
}
|
||||||
|
|
||||||
$members = group_get_members($group['id']);
|
$members = group_get_members($group['id']);
|
||||||
$preselected = array();
|
$preselected = array();
|
||||||
if (count($members)) {
|
if (count($members)) {
|
||||||
foreach($members as $member)
|
foreach ($members as $member) {
|
||||||
$preselected[] = $member['id'];
|
$preselected[] = $member['id'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$drop_tpl = get_markup_template('group_drop.tpl');
|
$drop_tpl = get_markup_template('group_drop.tpl');
|
||||||
$drop_txt = replace_macros($drop_tpl, array(
|
$drop_txt = replace_macros($drop_tpl, array(
|
||||||
'$id' => $group['id'],
|
'$id' => $group['id'],
|
||||||
'$delete' => t('Delete'),
|
'$delete' => t('Delete Group'),
|
||||||
'$form_security_token' => get_form_security_token("group_drop"),
|
'$form_security_token' => get_form_security_token("group_drop"),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -189,12 +197,14 @@ function group_content(App $a) {
|
||||||
'$gid' => $group['id'],
|
'$gid' => $group['id'],
|
||||||
'$drop' => $drop_txt,
|
'$drop' => $drop_txt,
|
||||||
'$form_security_token' => get_form_security_token('group_edit'),
|
'$form_security_token' => get_form_security_token('group_edit'),
|
||||||
|
'$edit_name' => t('Edit Group Name')
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(! isset($group))
|
if (! isset($group)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$groupeditor = array(
|
$groupeditor = array(
|
||||||
'label_members' => t('Members'),
|
'label_members' => t('Members'),
|
||||||
|
@ -205,26 +215,45 @@ function group_content(App $a) {
|
||||||
);
|
);
|
||||||
|
|
||||||
$sec_token = addslashes(get_form_security_token('group_member_change'));
|
$sec_token = addslashes(get_form_security_token('group_member_change'));
|
||||||
$textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : false);
|
|
||||||
|
// Format the data of the group members
|
||||||
foreach ($members as $member) {
|
foreach ($members as $member) {
|
||||||
if ($member['url']) {
|
if ($member['url']) {
|
||||||
$member['click'] = 'groupChangeMember(' . $group['id'] . ',' . $member['id'] . ',\'' . $sec_token . '\'); return true;';
|
$entry = _contact_detail_for_template($member);
|
||||||
$groupeditor['members'][] = micropro($member,true,'mpgroup', $textmode);
|
$entry['label'] = 'members';
|
||||||
}
|
$entry['photo_menu'] = '';
|
||||||
else
|
$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']);
|
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",
|
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND NOT `blocked` AND NOT `pending` AND NOT `self` ORDER BY `name` ASC",
|
||||||
intval(local_user())
|
intval(local_user())
|
||||||
);
|
);
|
||||||
|
|
||||||
if (dbm::is_result($r)) {
|
if (dbm::is_result($r)) {
|
||||||
$textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : false);
|
// Format the data of the contacts who aren't in the contact group
|
||||||
foreach ($r as $member) {
|
foreach ($r as $member) {
|
||||||
if (! in_array($member['id'], $preselected)) {
|
if (! in_array($member['id'], $preselected)) {
|
||||||
$member['click'] = 'groupChangeMember(' . $group['id'] . ',' . $member['id'] . ',\'' . $sec_token . '\'); return true;';
|
$entry = _contact_detail_for_template($member);
|
||||||
$groupeditor['contacts'][] = micropro($member,true,'mpall', $textmode);
|
$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,6 +261,10 @@ function group_content(App $a) {
|
||||||
$context['$groupeditor'] = $groupeditor;
|
$context['$groupeditor'] = $groupeditor;
|
||||||
$context['$desc'] = t('Click on a contact to add or remove.');
|
$context['$desc'] = t('Click on a contact to add or remove.');
|
||||||
|
|
||||||
|
// 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) {
|
if ($change) {
|
||||||
$tpl = get_markup_template('groupeditor.tpl');
|
$tpl = get_markup_template('groupeditor.tpl');
|
||||||
echo replace_macros($tpl, $context);
|
echo replace_macros($tpl, $context);
|
||||||
|
|
|
@ -149,6 +149,7 @@ function profile_content(App $a, $update = 0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$is_owner = ((local_user()) && (local_user() == $a->profile['profile_uid']) ? true : false);
|
$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)) {
|
if ($a->profile['hidewall'] && (! $is_owner) && (! $remote_contact)) {
|
||||||
notice( t('Access to this profile has been restricted.') . EOL);
|
notice( t('Access to this profile has been restricted.') . EOL);
|
||||||
|
@ -209,6 +210,16 @@ function profile_content(App $a, $update = 0) {
|
||||||
|
|
||||||
|
|
||||||
if ($update) {
|
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`
|
$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`
|
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 ."'
|
(`item`.`deleted` = 0 OR item.verb = '" . ACTIVITY_LIKE ."'
|
||||||
OR item.verb = '" . ACTIVITY_DISLIKE . "' OR item.verb = '" . ACTIVITY_ATTEND . "'
|
OR item.verb = '" . ACTIVITY_DISLIKE . "' OR item.verb = '" . ACTIVITY_ATTEND . "'
|
||||||
OR item.verb = '" . ACTIVITY_ATTENDNO . "' OR item.verb = '" . ACTIVITY_ATTENDMAYBE . "')
|
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
|
AND `item`.`wall` = 1
|
||||||
|
$sql_extra4
|
||||||
$sql_extra
|
$sql_extra
|
||||||
ORDER BY `item`.`created` DESC",
|
ORDER BY `item`.`created` DESC",
|
||||||
intval($a->profile['profile_uid'])
|
intval($a->profile['profile_uid'])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!dbm::is_result($r)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$sql_post_table = "";
|
$sql_post_table = "";
|
||||||
|
|
||||||
|
@ -283,11 +299,16 @@ function profile_content(App $a, $update = 0) {
|
||||||
ORDER BY `thread`.`created` DESC $pager_sql",
|
ORDER BY `thread`.`created` DESC $pager_sql",
|
||||||
intval($a->profile['profile_uid'])
|
intval($a->profile['profile_uid'])
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$parents_arr = array();
|
$parents_arr = array();
|
||||||
$parents_str = '';
|
$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)) {
|
if (dbm::is_result($r)) {
|
||||||
foreach($r as $rr)
|
foreach($r as $rr)
|
||||||
$parents_arr[] = $rr['item_id'];
|
$parents_arr[] = $rr['item_id'];
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
id="group-delete-icon-{{$id}}"
|
id="group-delete-icon-{{$id}}"
|
||||||
class="icon drophide group-delete-icon"
|
class="icon drophide group-delete-icon"
|
||||||
onmouseover="imgbright(this);"
|
onmouseover="imgbright(this);"
|
||||||
onmouseout="imgdull(this);" ></a>
|
onmouseout="imgdull(this);"
|
||||||
|
title="{{$delete}}">
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="group-delete-end"></div>
|
<div class="group-delete-end"></div>
|
||||||
|
|
|
@ -1,21 +1,62 @@
|
||||||
|
|
||||||
|
{{* Template for the contact group list *}}
|
||||||
|
|
||||||
|
{{* The contacts who are already members of the contact group *}}
|
||||||
<div id="group">
|
<div id="group">
|
||||||
<h3>{{$groupeditor.label_members}}</h3>
|
<h3>{{$groupeditor.label_members}}</h3>
|
||||||
<div id="group-members" class="contact_list">
|
<div id="group-members" class="contact_list">
|
||||||
|
|
||||||
{{if $groupeditor.members }}
|
{{if $groupeditor.members }}
|
||||||
{{foreach $groupeditor.members as $c}} {{$c}} {{/foreach}}
|
|
||||||
|
{{foreach $groupeditor.members as $c}}
|
||||||
|
{{* If there are too many contacts we use another view mode *}}
|
||||||
|
{{if $shortmode}}
|
||||||
|
<div class="contact-block-textdiv mpgroup">
|
||||||
|
<a class="contact-block-link mpgroup fakelink" target="redir" onclick="groupChangeMember({{$c.change_member.gid}},{{$c.change_member.cid}},'{{$c.change_member.sec_token}}'); return true;" title="{{$c.name}} [{{$c.itemurl}}]" alt="{{$c.name}}">
|
||||||
|
{{$c.name}}"
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{* The normal view mode *}}
|
||||||
|
<div class="contact-block-div mpgroup">
|
||||||
|
<a class="contact-block-link mpgroup fakelink" target="redir" onclick="groupChangeMember({{$c.change_member.gid}},{{$c.change_member.cid}},'{{$c.change_member.sec_token}}'); return true;">
|
||||||
|
<img class="contact-block-img mpgroup " src="{{$c.thumb}}" title="{{$c.name}} [{{$c.itemurl}}]" alt="{{$c.name}}">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{/foreach}}
|
||||||
|
|
||||||
{{else}}
|
{{else}}
|
||||||
{{$groupeditor.group_is_empty}}
|
{{$groupeditor.group_is_empty}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="group-members-end"></div>
|
<div id="group-members-end"></div>
|
||||||
<hr id="group-separator" />
|
<hr id="group-separator" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{* The contacts who are not members of the contact group *}}
|
||||||
<div id="contacts">
|
<div id="contacts">
|
||||||
<h3>{{$groupeditor.label_contacts}}</h3>
|
<h3>{{$groupeditor.label_contacts}}</h3>
|
||||||
<div id="group-all-contacts" class="contact_list">
|
<div id="group-all-contacts" class="contact_list">
|
||||||
{{foreach $groupeditor.contacts as $m}} {{$m}} {{/foreach}}
|
{{foreach $groupeditor.contacts as $m}}
|
||||||
|
{{* If there are too many contacts we use another view mode *}}
|
||||||
|
{{if $shortmode}}
|
||||||
|
<div class="contact-block-textdiv mpall">
|
||||||
|
<a class="contact-block-link mpall fakelink" target="redir" onclick="groupChangeMember({{$m.change_member.gid}},{{$m.change_member.cid}},'{{$m.change_member.sec_token}}'); return true;" title="{{$m.name}} [{{$m.itemurl}}]" alt="{{$m.name}}">
|
||||||
|
{{$m.name}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{* The normal view mode *}}
|
||||||
|
<div class="contact-block-div mpall">
|
||||||
|
<a class="contact-block-link mpall fakelink" target="redir" onclick="groupChangeMember({{$m.change_member.gid}},{{$m.change_member.cid}},'{{$m.change_member.sec_token}}'); return true;">
|
||||||
|
<img class="contact-block-img mpall " src="{{$m.thumb}}" title="{{$m.name}} [{{$m.itemurl}}]" alt="{{$m.name}}">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{/foreach}}
|
||||||
</div>
|
</div>
|
||||||
<div id="group-all-contacts-end"></div>
|
<div id="group-all-contacts-end"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -164,6 +164,9 @@ code {
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
a.btn:hover {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-default {
|
.btn-default {
|
||||||
background: #ededed;
|
background: #ededed;
|
||||||
|
@ -211,6 +214,12 @@ code {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
|
.btn-clear,
|
||||||
|
.btn-clear:active {
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
.btn-eventnav, btn-eventnav:hover {
|
.btn-eventnav, btn-eventnav:hover {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
background: none;
|
background: none;
|
||||||
|
@ -1394,6 +1403,12 @@ section #jotOpen {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
.panel.panel-inline {
|
||||||
|
margin-left: -15px;
|
||||||
|
margin-right: -15px;
|
||||||
|
margin-top: 15px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
.panel .panel-body {
|
.panel .panel-body {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
@ -1927,7 +1942,8 @@ ul.dropdown-menu li:hover {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
.media-list > li:hover,
|
.media-list > li:hover,
|
||||||
.media-list > li.selected {
|
.media-list > li.selected,
|
||||||
|
.media-list > li.active {
|
||||||
border-left: 3px solid $link_color;
|
border-left: 3px solid $link_color;
|
||||||
background-color: rgba(247, 247, 247, $contentbg_transp);
|
background-color: rgba(247, 247, 247, $contentbg_transp);
|
||||||
}
|
}
|
||||||
|
@ -2015,9 +2031,9 @@ ul.dropdown-menu li:hover {
|
||||||
.allfriends-content-wrapper, .match-content-wrapper, .dirfind-content-wrapper,
|
.allfriends-content-wrapper, .match-content-wrapper, .dirfind-content-wrapper,
|
||||||
.directory-content-wrapper, .manage-content-wrapper, .notes-content-wrapper,
|
.directory-content-wrapper, .manage-content-wrapper, .notes-content-wrapper,
|
||||||
.message-content-wrapper, .apps-content-wrapper, .photos-content-wrapper,
|
.message-content-wrapper, .apps-content-wrapper, .photos-content-wrapper,
|
||||||
.admin-content-wrapper, .group-content-wrapper, .viewcontacts-content-wrapper,
|
.admin-content-wrapper, .viewcontacts-content-wrapper, .dfrn_request-content-wrapper,
|
||||||
.dfrn_request-content-wrapper, .friendica-content-wrapper, .credits-content-wrapper,
|
.friendica-content-wrapper, .credits-content-wrapper, .nogroup-content-wrapper,
|
||||||
.nogroup-content-wrapper, .profperm-content-wrapper {
|
.profperm-content-wrapper {
|
||||||
min-height: calc(100vh - 150px);
|
min-height: calc(100vh - 150px);
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
|
@ -2064,6 +2080,9 @@ ul.viewcontact_wrapper > li {
|
||||||
position: relative;*/
|
position: relative;*/
|
||||||
/*border-left: 3px solid white;*/
|
/*border-left: 3px solid white;*/
|
||||||
}
|
}
|
||||||
|
.contact-wrapper .contact-photo-wrapper button {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
.contact-wrapper.media {
|
.contact-wrapper.media {
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
|
@ -2094,6 +2113,9 @@ ul.viewcontact_wrapper > li {
|
||||||
.contact-wrapper .contact-photo-overlay-content.xl {
|
.contact-wrapper .contact-photo-overlay-content.xl {
|
||||||
font-size: 48px;
|
font-size: 48px;
|
||||||
}
|
}
|
||||||
|
.contact-wrapper .contact-photo-menu {
|
||||||
|
top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.contact-entry-desc {
|
.contact-entry-desc {
|
||||||
color: #555;
|
color: #555;
|
||||||
|
@ -2167,6 +2189,61 @@ ul li:hover .contact-wrapper .contact-action-link:hover {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* group edit page */
|
||||||
|
.group-actions {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
.group-actions button,
|
||||||
|
.group-actions a {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
#group-edit-wrapper {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#group-update-wrapper .contact-photo-overlay {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#group-update-wrapper .viewcontact_wrapper .contact-group-actions {
|
||||||
|
height: 100%;
|
||||||
|
margin-top: -10px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
#group-update-wrapper .viewcontact_wrapper .contact-action-link {
|
||||||
|
opacity: 0.8;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 50px;
|
||||||
|
}
|
||||||
|
#group-update-wrapper .viewcontact_wrapper .contact-action-link:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
#group-update-wrapper .shortmode {
|
||||||
|
height: 53px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#group-update-wrapper .shortmode .contact-photo {
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
#group-update-wrapper .shortmode .media {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#group-update-wrapper .shortmode .contact-entry-desc {
|
||||||
|
font-size: 12px !important;
|
||||||
|
}
|
||||||
|
#group-update-wrapper .shortmode .contact-entry-desc h4.media-heading {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#group-update-wrapper .shortmode .contact-entry-desc h4.media-heading a {
|
||||||
|
font-size: 13px !important;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#group-update-wrapper .shortmode .contact-entry-desc .contact-entry-rel,
|
||||||
|
#group-update-wrapper .shortmode .contact-entry-desc .contact-entry-network {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* private mail */
|
/* private mail */
|
||||||
.message-content-wrapper > li {
|
.message-content-wrapper > li {
|
||||||
/* we need this overwriting because we have no template file
|
/* we need this overwriting because we have no template file
|
||||||
|
|
88
view/theme/frio/js/mod_group.js
Normal file
88
view/theme/frio/js/mod_group.js
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file view/theme/frio/js/mod_group.js
|
||||||
|
* @brief The javascript for the group module
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
// Add an event listeners on buttons for switching the contact list view
|
||||||
|
$("body").on("click", ".group-list-switcher", function(){
|
||||||
|
switchGroupViewMode(this);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Change the group membership of the contacts and fetch the new grup list
|
||||||
|
* as html
|
||||||
|
*
|
||||||
|
* @param {int} gid The group ID
|
||||||
|
* @param {int} cid The contact ID
|
||||||
|
* @param {string} sec_token The security token
|
||||||
|
*
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
function groupChangeMember(gid, cid, sec_token) {
|
||||||
|
$("#contact-entry-wrapper-" + cid).fadeTo("fast", 0.33);
|
||||||
|
$(".tooltip").tooltip("hide");
|
||||||
|
$("body").css("cursor", "wait");
|
||||||
|
|
||||||
|
$.get('group/' + gid + '/' + cid + "?t=" + sec_token, function(data) {
|
||||||
|
// Insert the new group member list
|
||||||
|
$("#group-update-wrapper").html(data);
|
||||||
|
|
||||||
|
// Apply the actual gropu list view mode to the new
|
||||||
|
// group list html
|
||||||
|
var activeMode = $(".group-list-switcher.active");
|
||||||
|
switchGroupViewMode(activeMode[0]);
|
||||||
|
|
||||||
|
$("body").css("cursor", "auto");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Change the group list view mode
|
||||||
|
*
|
||||||
|
* @param {object} elm The button element of the view mode switcher
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
function switchGroupViewMode(elm) {
|
||||||
|
// Remove the active class from group list switcher buttons
|
||||||
|
$(".group-list-switcher").removeClass("active");
|
||||||
|
// And add it to the active button element
|
||||||
|
$(elm).addClass("active");
|
||||||
|
|
||||||
|
// Add or remove the css classes for the group list with regard to the active view mode
|
||||||
|
if (elm.id === "group-list-small") {
|
||||||
|
$("#contact-group-list > li").addClass("shortmode col-lg-6 col-md-6 col-sm-6 col-xs-12");
|
||||||
|
} else {
|
||||||
|
$("#contact-group-list > li").removeClass("shortmode col-lg-6 col-md-6 col-sm-6 col-xs-12");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Filter the group member list for contacts
|
||||||
|
*
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
function filterList() {
|
||||||
|
// Declare variables
|
||||||
|
var input, filter, ul, li, a, i;
|
||||||
|
input = document.getElementById("contacts-search");
|
||||||
|
filter = input.value.toUpperCase();
|
||||||
|
li = document.querySelectorAll("#contact-group-list>li");
|
||||||
|
|
||||||
|
// Loop through all list items, and hide those who don't match the search query
|
||||||
|
for (i = 0; i < li.length; i++) {
|
||||||
|
// Get the heading element
|
||||||
|
var mh = li[i].getElementsByClassName("media-heading")[0];
|
||||||
|
// The first child of the heading element should contain
|
||||||
|
// the text which we want to filter
|
||||||
|
a = mh.firstChild;
|
||||||
|
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
|
||||||
|
li[i].style.display = "";
|
||||||
|
} else {
|
||||||
|
li[i].style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="contact-wrapper media" id="contact-entry-wrapper-{{$contact.id}}">
|
<div class="contact-wrapper media" id="contact-entry-wrapper-{{$contact.id}}">
|
||||||
|
|
||||||
{{* This is a wrapper for the contact picture and the dropdown menu with contact relating actions *}}
|
{{* This is a wrapper for the contact picture and the dropdown menu with contact relating actions *}}
|
||||||
<div class="contact-photo-wrapper dropdown pull-left" >
|
<div class="contact-photo-wrapper dropdown media-left">
|
||||||
<div class="contact-entry-photo mframe" id="contact-entry-photo-{{$contact.id}}">
|
<div class="contact-entry-photo mframe" id="contact-entry-photo-{{$contact.id}}">
|
||||||
|
|
||||||
<button type="button" class="btn btn-link dropdown-toggle" id="contact-photo-menu-{{$contact.id}}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button type="button" class="btn btn-link dropdown-toggle" id="contact-photo-menu-{{$contact.id}}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
@ -45,16 +45,59 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
|
{{if $contact.photo_menu}}
|
||||||
{{* The contact actions like private mail, delete contact, edit contact and so on *}}
|
{{* The contact actions like private mail, delete contact, edit contact and so on *}}
|
||||||
<div class="contact-actions pull-right nav-pills preferences hidden-xs">
|
<div class="contact-actions pull-right nav-pills preferences hidden-xs">
|
||||||
{{if $contact.photo_menu.pm }}<button type="button" class="contact-action-link btn-link" onclick="addToModal('{{$contact.photo_menu.pm.1}}')" data-toggle="tooltip" title="{{$contact.photo_menu.pm.0}}"><i class="fa fa-envelope" aria-hidden="true"></i></button>{{/if}}
|
{{if $contact.photo_menu.pm}}
|
||||||
{{if $contact.photo_menu.poke }}<button type="button" class="contact-action-link btn-link" onclick="addToModal('{{$contact.photo_menu.poke.1}}')" data-toggle="tooltip" title="{{$contact.photo_menu.poke.0}}"><i class="fa fa-heartbeat" aria-hidden="true"></i></button>{{/if}}
|
<button type="button" class="contact-action-link btn-link" onclick="addToModal('{{$contact.photo_menu.pm.1}}'); retrurn false;" data-toggle="tooltip" title="{{$contact.photo_menu.pm.0}}">
|
||||||
{{if $contact.photo_menu.network}}<a class="contact-action-link btn-link" href="{{$contact.photo_menu.network.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.network.0}}"><i class="fa fa-cloud" aria-hidden="true"></i></a>{{/if}}
|
<i class="fa fa-envelope" aria-hidden="true"></i>
|
||||||
{{if $contact.photo_menu.edit }}<a class="contact-action-link btn-link" href="{{$contact.photo_menu.edit.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.edit.0}}"><i class="fa fa-user" aria-hidden="true"></i></a>{{/if}}
|
</button>
|
||||||
{{if $contact.photo_menu.drop }}<button type="button" class="contact-action-link btn-link" onclick="addToModal('{{$contact.photo_menu.drop.1}}')" data-toggle="tooltip" title="{{$contact.photo_menu.drop.0}}"><i class="fa fa-user-times" aria-hidden="true"></i></button>{{/if}}
|
{{/if}}
|
||||||
{{if $contact.photo_menu.follow }}<a class="contact-action-link btn-link" href="{{$contact.photo_menu.follow.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.follow.0}}"><i class="fa fa-user-plus" aria-hidden="true"></i></a>{{/if}}
|
{{if $contact.photo_menu.poke}}
|
||||||
{{if $contact.photo_menu.hide }}<a class="contact-action-link btn-link" href="{{$contact.photo_menu.hide.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.hide.0}}"><i class="fa fa-times" aria-hidden="true"></i></a>{{/if}}
|
<button type="button" class="contact-action-link btn-link" onclick="addToModal('{{$contact.photo_menu.poke.1}}'); retrurn false;" data-toggle="tooltip" title="{{$contact.photo_menu.poke.0}}">
|
||||||
|
<i class="fa fa-heartbeat" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
{{if $contact.photo_menu.network}}
|
||||||
|
<a class="contact-action-link btn-link" href="{{$contact.photo_menu.network.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.network.0}}">
|
||||||
|
<i class="fa fa-cloud" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
{{/if}}
|
||||||
|
{{if $contact.photo_menu.edit}}
|
||||||
|
<a class="contact-action-link btn-link" href="{{$contact.photo_menu.edit.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.edit.0}}">
|
||||||
|
<i class="fa fa-user" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
{{/if}}
|
||||||
|
{{if $contact.photo_menu.drop}}
|
||||||
|
<button type="button" class="contact-action-link btn-link" onclick="addToModal('{{$contact.photo_menu.drop.1}}'); retrurn false;" data-toggle="tooltip" title="{{$contact.photo_menu.drop.0}}">
|
||||||
|
<i class="fa fa-user-times" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
{{if $contact.photo_menu.follow}}
|
||||||
|
<a class="contact-action-link btn-link" href="{{$contact.photo_menu.follow.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.follow.0}}">
|
||||||
|
<i class="fa fa-user-plus" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
{{/if}}
|
||||||
|
{{if $contact.photo_menu.hide}}
|
||||||
|
<a class="contact-action-link btn-link" href="{{$contact.photo_menu.hide.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.hide.0}}">
|
||||||
|
<i class="fa fa-times" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{* The button to add or remove contacts from a contact group - group edit page *}}
|
||||||
|
{{if $contact.change_member}}
|
||||||
|
<div class="contact-group-actions pull-right nav-pills preferences">
|
||||||
|
<button type="button" class="contact-action-link btn-link" onclick="groupChangeMember({{$contact.change_member.gid}},{{$contact.change_member.cid}},'{{$contact.change_member.sec_token}}'); return true;" data-toggle="tooltip" title="{{$contact.change_member.title}}">
|
||||||
|
{{if $contact.label == "members"}}
|
||||||
|
<i class="fa fa-times-circle" aria-hidden="true"></i>
|
||||||
|
{{elseif $contact.label == "contacts"}}
|
||||||
|
<i class="fa fa-plus-circle" aria-hidden="true"></i>
|
||||||
|
{{/if}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{* The contact description (e.g. Name, Network, kind of connection and so on *}}
|
{{* The contact description (e.g. Name, Network, kind of connection and so on *}}
|
||||||
<div class="contact-entry-desc">
|
<div class="contact-entry-desc">
|
||||||
|
@ -65,11 +108,11 @@
|
||||||
{{* @todo this needs some changing in core because $contact.account_type contains a translated string which may notbe the same in every language *}}
|
{{* @todo this needs some changing in core because $contact.account_type contains a translated string which may notbe the same in every language *}}
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
{{if $contact.alt_text}}<div class="contact-entry-details" id="contact-entry-rel-{{$contact.id}}" >{{$contact.alt_text}}</div>{{/if}}
|
{{if $contact.alt_text}}<div class="contact-entry-details contact-entry-rel" id="contact-entry-rel-{{$contact.id}}" >{{$contact.alt_text}}</div>{{/if}}
|
||||||
{{if $contact.itemurl}}<div class="contact-entry-details" id="contact-entry-url-{{$contact.id}}" >{{$contact.itemurl}}</div>{{/if}}
|
{{if $contact.itemurl}}<div class="contact-entry-details contact-entry-url" id="contact-entry-url-{{$contact.id}}" >{{$contact.itemurl}}</div>{{/if}}
|
||||||
{{if $contact.tags}}<div class="contact-entry-details" id="contact-entry-tags-{{$contact.id}}" >{{$contact.tags}}</div>{{/if}}
|
{{if $contact.tags}}<div class="contact-entry-details" id="contact-entry-tags-{{$contact.id}}" >{{$contact.tags}}</div>{{/if}}
|
||||||
{{if $contact.details}}<div class="contact-entry-details" id="contact-entry-details-{{$contact.id}}" >{{$contact.details}}</div>{{/if}}
|
{{if $contact.details}}<div class="contact-entry-details contact-entry-tags" id="contact-entry-details-{{$contact.id}}" >{{$contact.details}}</div>{{/if}}
|
||||||
{{if $contact.network}}<div class="contact-entry-details" id="contact-entry-network-{{$contact.id}}" >{{$contact.network}}</div>{{/if}}
|
{{if $contact.network}}<div class="contact-entry-details contact-entry-network" id="contact-entry-network-{{$contact.id}}" >{{$contact.network}}</div>{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{* The checkbox to perform batch actions to these contacts (for batch actions have a look at contacts-template.tpl) *}}
|
{{* The checkbox to perform batch actions to these contacts (for batch actions have a look at contacts-template.tpl) *}}
|
||||||
|
@ -91,7 +134,7 @@ We use this part to filter the contacts with jquery.textcomplete *}}
|
||||||
<div class="contact-wrapper media" id="contact-entry-wrapper-{$id}">
|
<div class="contact-wrapper media" id="contact-entry-wrapper-{$id}">
|
||||||
|
|
||||||
{{* This is a wrapper for the contact picture and the dropdown menu with contact relating actions *}}
|
{{* This is a wrapper for the contact picture and the dropdown menu with contact relating actions *}}
|
||||||
<div class="contact-photo-wrapper dropdown pull-left" >
|
<div class="contact-photo-wrapper dropdown media-left">
|
||||||
<div class="contact-entry-photo mframe" id="contact-entry-photo-{$id}">
|
<div class="contact-entry-photo mframe" id="contact-entry-photo-{$id}">
|
||||||
|
|
||||||
<button type="button" class="btn btn-link dropdown-toggle" id="contact-photo-menu-{$id}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button type="button" class="btn btn-link dropdown-toggle" id="contact-photo-menu-{$id}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
@ -135,15 +178,54 @@ We use this part to filter the contacts with jquery.textcomplete *}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
|
{if $photo_menu}
|
||||||
{{* The contact actions like private mail, delete contact, edit contact and so on *}}
|
{{* The contact actions like private mail, delete contact, edit contact and so on *}}
|
||||||
<div class="contact-actions pull-right nav-pills preferences hidden-xs">
|
<div class="contact-actions pull-right nav-pills preferences hidden-xs">
|
||||||
{if $photo_menu.pm}<button type="button" class="contact-action-link btn-link" onclick="addToModal('{$photo_menu.pm.1}')" data-toggle="tooltip" title="{$photo_menu.pm.0}"><i class="fa fa-envelope" aria-hidden="true"></i></button>{/if}
|
{if $photo_menu.pm}
|
||||||
{if $photo_menu.poke}<button type="button" class="contact-action-link btn-link" onclick="addToModal('{$photo_menu.poke.1}')" data-toggle="tooltip" title="{$photo_menu.poke.0}"><i class="fa fa-heartbeat" aria-hidden="true"></i></button>{/if}
|
<button type="button" class="contact-action-link btn-link" onclick="addToModal('{$photo_menu.pm.1}')" data-toggle="tooltip" title="{$photo_menu.pm.0}">
|
||||||
{if $photo_menu.network}<a class="contact-action-link btn-link" href="{$photo_menu.network.1}" data-toggle="tooltip" title="{$photo_menu.network.0}"><i class="fa fa-cloud" aria-hidden="true"></i></a>{/if}
|
<i class="fa fa-envelope" aria-hidden="true"></i>
|
||||||
{if $photo_menu.edit}<a class="contact-action-link btn-link" href="{$photo_menu.edit.1}" data-toggle="tooltip" title="{$photo_menu.edit.0}"><i class="fa fa-pencil" aria-hidden="true"></i></a>{/if}
|
</button>
|
||||||
{if $photo_menu.drop}<a class="contact-action-link btn-link" href="{$photo_menu.drop.1}" data-toggle="tooltip" title="{$photo_menu.drop.0}"><i class="fa fa-user-times" aria-hidden="true"></i></a>{/if}
|
{/if}
|
||||||
{if $photo_menu.follow}<a class="contact-action-link btn-link" href="{$photo_menu.follow.1}" data-toggle="tooltip" title="{$photo_menu.follow.0}"><i class="fa fa-user-plus" aria-hidden="true"></i></a>{/if}
|
{if $photo_menu.poke}
|
||||||
|
<button type="button" class="contact-action-link btn-link" onclick="addToModal('{$photo_menu.poke.1}')" data-toggle="tooltip" title="{$photo_menu.poke.0}">
|
||||||
|
<i class="fa fa-heartbeat" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
{if $photo_menu.network}
|
||||||
|
<a class="contact-action-link btn-link" href="{$photo_menu.network.1}" data-toggle="tooltip" title="{$photo_menu.network.0}">
|
||||||
|
<i class="fa fa-cloud" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
{if $photo_menu.edit}
|
||||||
|
<a class="contact-action-link btn-link" href="{$photo_menu.edit.1}" data-toggle="tooltip" title="{$photo_menu.edit.0}">
|
||||||
|
<i class="fa fa-pencil" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
{if $photo_menu.drop}
|
||||||
|
<a class="contact-action-link btn-link" href="{$photo_menu.drop.1}" data-toggle="tooltip" title="{$photo_menu.drop.0}">
|
||||||
|
<i class="fa fa-user-times" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
{if $photo_menu.follow}
|
||||||
|
<a class="contact-action-link btn-link" href="{$photo_menu.follow.1}" data-toggle="tooltip" title="{$photo_menu.follow.0}">
|
||||||
|
<i class="fa fa-user-plus" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{{* The button to add or remove contacts from a contact group - group edit page *}}
|
||||||
|
{if $contact.change_member}
|
||||||
|
<div class="contact-group-actions pull-right nav-pills preferences">
|
||||||
|
<button type="button" class="contact-action-link btn-link" onclick="groupChangeMember({$contact.change_member.gid},{$contact.change_member.cid},'{$contact.change_member.sec_token}'); return true;" data-toggle="tooltip" title="{$contact.change_member.title}">
|
||||||
|
{if $contact.label == "members"}
|
||||||
|
<i class="fa fa-times-circle" aria-hidden="true"></i>
|
||||||
|
{elseif $contact.label == "contacts"}
|
||||||
|
<i class="fa fa-plus-circle" aria-hidden="true"></i>
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{{* The contact description (e.g. Name, Network, kind of connection and so on *}}
|
{{* The contact description (e.g. Name, Network, kind of connection and so on *}}
|
||||||
<div class="contact-entry-desc">
|
<div class="contact-entry-desc">
|
||||||
|
|
5
view/theme/frio/templates/group_drop.tpl
Normal file
5
view/theme/frio/templates/group_drop.tpl
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
{{* Link for deleting contact groups *}}
|
||||||
|
<a href="group/drop/{{$id}}?t={{$form_security_token}}" onclick="return confirmDelete();" id="group-delete-icon-{{$id}}" class="btn btn-clear" title="{{$delete}}" data-toggle="tooltip">
|
||||||
|
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||||
|
</a>
|
77
view/theme/frio/templates/group_edit.tpl
Normal file
77
view/theme/frio/templates/group_edit.tpl
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
|
||||||
|
{{* This template is for the "group" module. It provides the user the possibility to
|
||||||
|
modify a specific contact group (remove contact group, edit contact group name,
|
||||||
|
add or remove contacts to the contact group.
|
||||||
|
*}}
|
||||||
|
|
||||||
|
<script type="text/javascript" src="view/theme/frio/js/mod_group.js"></script>
|
||||||
|
|
||||||
|
<div class="generic-page-wrapper">
|
||||||
|
|
||||||
|
{{* The buttons for editing the contact group (edit name / remove contact group) *}}
|
||||||
|
<div class="group-actions pull-right">
|
||||||
|
<button type="button" id="group-rename" class="btn btn-clear" onclick="openClose('group-edit-wrapper'); return false;" title="{{$edit_name}}" data-toggle="tooltip">
|
||||||
|
<i class="fa fa-pencil" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
{{if $drop}}{{$drop}}{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{include file="section_title.tpl"}}
|
||||||
|
|
||||||
|
{{* Edit the name of the group *}}
|
||||||
|
<div id="group-edit-wrapper" class="panel panel-inline">
|
||||||
|
<form action="group/{{$gid}}" id="group-edit-form" method="post">
|
||||||
|
<input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
|
||||||
|
|
||||||
|
{{include file="field_input.tpl" field=$gname}}
|
||||||
|
<div id="group-edit-submit-wrapper" class="form-group pull-right">
|
||||||
|
<button class="btn btn-primary btn-small" type="submit" name="submit" value="{{$submit|escape:'html'}}">
|
||||||
|
{{$submit|escape:'html'}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="group-edit-select-end" class="clear"></div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{* The search input field to search for contacts *}}
|
||||||
|
<div id="contacts-search-wrapper">
|
||||||
|
<div id="contacts-search-form" class="navbar-form" role="search">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-2"></div>
|
||||||
|
<div class="col-md-8 ">
|
||||||
|
<div class="form-group form-group-search">
|
||||||
|
<input type="text"
|
||||||
|
name="filter"
|
||||||
|
id="contacts-search"
|
||||||
|
class="search-input form-control form-search"
|
||||||
|
onkeyup="filterList(); return false;"
|
||||||
|
onfocus="this.select(); return false;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<div id="contacts-search-end"></div>
|
||||||
|
|
||||||
|
{{if $groupeditor}}
|
||||||
|
{{* The buttons to switch between the different view modes *}}
|
||||||
|
<div id="group-list-view-switcher" class="btn-group btn-group-sm pull-right">
|
||||||
|
<botton type="button" id="group-list-big" class="active group-list-switcher btn btn-default">
|
||||||
|
<i class="fa fa-align-justify" aria-hidden="true"></i>
|
||||||
|
</botton>
|
||||||
|
<button type="button" id="group-list-small" class="btn btn-default group-list-switcher">
|
||||||
|
<i class="fa fa-th-large" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
|
||||||
|
{{* The contact group list *}}
|
||||||
|
<div id="group-update-wrapper">
|
||||||
|
{{include file="groupeditor.tpl"}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
19
view/theme/frio/templates/groupeditor.tpl
Normal file
19
view/theme/frio/templates/groupeditor.tpl
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
{{* Template for the contact group list *}}
|
||||||
|
<div id="group" class="contact_list">
|
||||||
|
|
||||||
|
<ul id="contact-group-list" class="viewcontact_wrapper media-list">
|
||||||
|
|
||||||
|
{{* The contacts who are already members of the contact group *}}
|
||||||
|
{{foreach $groupeditor.members as $contact}}
|
||||||
|
<li class="members active">{{include file="contact_template.tpl"}}</li>
|
||||||
|
{{/foreach}}
|
||||||
|
|
||||||
|
{{* The contacts who are not members of the contact group *}}
|
||||||
|
{{foreach $groupeditor.contacts as $contact}}
|
||||||
|
<li class="contacts">{{include file="contact_template.tpl"}}</li>
|
||||||
|
{{/foreach}}
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</div>
|
Loading…
Reference in a new issue