mirror of
https://github.com/Mibew/mibew.git
synced 2025-04-24 23:36:07 +03:00
681 lines
20 KiB
PHP
681 lines
20 KiB
PHP
<?php
|
|
/*
|
|
* This file is a part of Mibew Messenger.
|
|
*
|
|
* Copyright 2005-2023 the original author or authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
// Import namespaces and classes of the core
|
|
use Mibew\EventDispatcher\EventDispatcher;
|
|
use Mibew\EventDispatcher\Events;
|
|
use Mibew\Database;
|
|
use Mibew\Settings;
|
|
|
|
/**
|
|
* Get chatgroup by id
|
|
*
|
|
* @param integer $id ID for the chat group
|
|
*
|
|
* @return null|array It is chatgroup structure. contains (groupId integer,
|
|
* parent integer, vcemail string, vclocalname string, vccommonname string,
|
|
* vclocaldescription string, vccommondescription string, iweight integer,
|
|
* vctitle string, vcchattitle string, vclogo string, vchosturl string)
|
|
*/
|
|
function group_by_id($id)
|
|
{
|
|
$db = Database::getInstance();
|
|
$group = $db->query(
|
|
"SELECT * FROM {opgroup} WHERE groupid = ?",
|
|
array($id),
|
|
array('return_rows' => Database::RETURN_ONE_ROW)
|
|
);
|
|
|
|
return $group;
|
|
}
|
|
|
|
/**
|
|
* Get chatgroup by name
|
|
*
|
|
* @param string $name Name of the chat group
|
|
*
|
|
* @return null|array It is chatgroup structure. contains (groupId integer,
|
|
* parent integer, vcemail string, vclocalname string, vccommonname string,
|
|
* vclocaldescription string, vccommondescription string, iweight integer,
|
|
* vctitle string, vcchattitle string, vclogo string, vchosturl string)
|
|
*/
|
|
function group_by_name($name)
|
|
{
|
|
$db = Database::getInstance();
|
|
$group = $db->query(
|
|
"SELECT * FROM {opgroup} WHERE vclocalname = ?",
|
|
array($name),
|
|
array('return_rows' => Database::RETURN_ONE_ROW)
|
|
);
|
|
|
|
return $group;
|
|
}
|
|
|
|
/**
|
|
* Get chatgroup name
|
|
*
|
|
* @param array $group chat group object
|
|
*
|
|
* @return string return chat group name
|
|
*/
|
|
function get_group_name($group)
|
|
{
|
|
if (!is_array($group)) {
|
|
return '';
|
|
}
|
|
|
|
$use_local_name = (get_home_locale() == get_current_locale())
|
|
|| !isset($group['vccommonname'])
|
|
|| !$group['vccommonname'];
|
|
if ($use_local_name) {
|
|
return $group['vclocalname'];
|
|
} else {
|
|
return $group['vccommonname'];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Builds list of group ids for specific operator
|
|
*
|
|
* @param int $operator_id ID of the specific operator.
|
|
*
|
|
* @return string Comma separated list of operator groups ids
|
|
*/
|
|
function get_operator_groups_list($operator_id)
|
|
{
|
|
$db = Database::getInstance();
|
|
if (Settings::get('enablegroups') == '1') {
|
|
$group_ids = array(0);
|
|
$all_groups = $db->query(
|
|
"SELECT groupid FROM {operatortoopgroup} WHERE operatorid = ? ORDER BY groupid",
|
|
array($operator_id),
|
|
array('return_rows' => Database::RETURN_ALL_ROWS)
|
|
);
|
|
foreach ($all_groups as $g) {
|
|
$group_ids[] = $g['groupid'];
|
|
}
|
|
|
|
return implode(",", $group_ids);
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* List of available groups
|
|
*
|
|
* @param array $skip_group ID of groups which most be skipped.
|
|
*
|
|
* @return array list of all available groups in chatgroup structure. contains
|
|
* (groupId integer, parent integer, vcemail string, vclocalname string,
|
|
* vccommonname string, vclocaldescription string, vccommondescription string,
|
|
* iweight integer, vctitle string, vcchattitle string, vclogo string,
|
|
* vchosturl string)
|
|
*/
|
|
function get_available_parent_groups($skip_group)
|
|
{
|
|
$result = array();
|
|
|
|
$result[] = array(
|
|
'groupid' => '',
|
|
'level' => '',
|
|
'vclocalname' => getlocal("-none-"),
|
|
);
|
|
|
|
$db = Database::getInstance();
|
|
$groups_list = $db->query(
|
|
("SELECT {opgroup}.groupid AS groupid, parent, vclocalname "
|
|
. "FROM {opgroup} ORDER BY vclocalname"),
|
|
null,
|
|
array('return_rows' => Database::RETURN_ALL_ROWS)
|
|
);
|
|
|
|
if ($skip_group) {
|
|
$skip_group = (array) $skip_group;
|
|
} else {
|
|
$skip_group = array();
|
|
}
|
|
|
|
$result = array_merge($result, get_sorted_child_groups_($groups_list, $skip_group, 0));
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Check if group has any child
|
|
*
|
|
* @param int $group_id ID of the specific chat group.
|
|
*
|
|
* @return boolean True if specified group has any child
|
|
*/
|
|
function group_has_children($group_id)
|
|
{
|
|
$db = Database::getInstance();
|
|
$children = $db->query(
|
|
"SELECT COUNT(*) AS count FROM {opgroup} WHERE parent = ?",
|
|
array($group_id),
|
|
array('return_rows' => Database::RETURN_ONE_ROW)
|
|
);
|
|
|
|
return ($children['count'] > 0);
|
|
}
|
|
|
|
/**
|
|
* Get parent of chatgroup
|
|
*
|
|
* @param array $group specific chatgroup
|
|
*
|
|
* @return array parent of given group. It is chatgroup structure. contains
|
|
* (groupId integer, parent integer, vcemail string, vclocalname string,
|
|
* vccommonname string, vclocaldescription string, vccommondescription string,
|
|
* iweight integer, vctitle string, vcchattitle string, vclogo string,
|
|
* vchosturl string)
|
|
*/
|
|
function get_top_level_group($group)
|
|
{
|
|
return is_null($group['parent']) ? $group : group_by_id($group['parent']);
|
|
}
|
|
|
|
/**
|
|
* Try to load email for specified group or for its parent.
|
|
*
|
|
* @param int $group_id Group id
|
|
* @return string|boolean Email address or false if there is no email
|
|
*/
|
|
function get_group_email($group_id)
|
|
{
|
|
// Try to get group email
|
|
$group = group_by_id($group_id);
|
|
|
|
if (empty($group)) {
|
|
return false;
|
|
}
|
|
|
|
if ($group && !empty($group['vcemail'])) {
|
|
return $group['vcemail'];
|
|
}
|
|
|
|
// Try to get parent group email
|
|
if (!is_null($group['parent'])) {
|
|
$group = group_by_id($group['parent']);
|
|
if ($group && !empty($group['vcemail'])) {
|
|
return $group['vcemail'];
|
|
}
|
|
}
|
|
|
|
// There is no email
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if group online
|
|
*
|
|
* @param array $group Associative group array. Should contain 'ilastseen' key.
|
|
* @return bool
|
|
*/
|
|
function group_is_online($group)
|
|
{
|
|
return $group['ilastseen'] !== null
|
|
&& $group['ilastseen'] < Settings::get('online_timeout');
|
|
}
|
|
|
|
/**
|
|
* Check if group is away
|
|
*
|
|
* @param array $group Associative group array. Should contain 'ilastseenaway'
|
|
* key.
|
|
* @return bool
|
|
*/
|
|
function group_is_away($group)
|
|
{
|
|
return $group['ilastseenaway'] !== null
|
|
&& $group['ilastseenaway'] < Settings::get('online_timeout');
|
|
}
|
|
|
|
/**
|
|
* Return local or common group description depending on current locale.
|
|
*
|
|
* @param array $group Associative group array. Should contain following keys:
|
|
* - 'vccommondescription': string, contain common description of the group;
|
|
* - 'vclocaldescription': string, contain local description of the group.
|
|
* @return string Group description
|
|
*/
|
|
function get_group_description($group)
|
|
{
|
|
$use_local_description = (get_home_locale() == get_current_locale())
|
|
|| !isset($group['vccommondescription'])
|
|
|| !$group['vccommondescription'];
|
|
|
|
if ($use_local_description) {
|
|
return $group['vclocaldescription'];
|
|
} else {
|
|
return $group['vccommondescription'];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks that group's array has all necessary fields.
|
|
*
|
|
* @param array $group Associative group's array.
|
|
* @return bool Boolean true if all the fields are in place and false otherwise.
|
|
*/
|
|
function check_group_fields($group)
|
|
{
|
|
$obligatory_fields = array(
|
|
'groupid',
|
|
'vclocalname',
|
|
'vclocaldescription',
|
|
'vccommonname',
|
|
'vccommondescription',
|
|
'vcemail',
|
|
'iweight',
|
|
'parent',
|
|
'vctitle',
|
|
'vcchattitle',
|
|
'vchosturl',
|
|
'vclogo',
|
|
);
|
|
|
|
return (count(array_diff($obligatory_fields, array_keys($group))) == 0);
|
|
}
|
|
|
|
/**
|
|
* Creates group
|
|
*
|
|
* Triggers {@link \Mibew\EventDispatcher\Events::GROUP_CREATE} event.
|
|
*
|
|
* @param array $group Operators' group. The $group array must contains the
|
|
* following keys:
|
|
* - vclocalname,
|
|
* - vclocaldescription,
|
|
* - vccommonname,
|
|
* - vccommondescription,
|
|
* - vcemail,
|
|
* - iweight,
|
|
* - parent,
|
|
* - vctitle,
|
|
* - vcchattitle,
|
|
* - vchosturl,
|
|
* - vclogo,
|
|
* @return array Created group
|
|
* @throws \InvalidArgumentException if not all of the group fields are
|
|
* specified.
|
|
*/
|
|
function create_group($group)
|
|
{
|
|
$group += array('groupid' => false);
|
|
if (!check_group_fields($group)) {
|
|
throw new \InvalidArgumentException('Not all group fields are specified');
|
|
}
|
|
|
|
$db = Database::getInstance();
|
|
$db->query(
|
|
("INSERT INTO {opgroup} ("
|
|
. "parent, vclocalname, vclocaldescription, vccommonname, "
|
|
. "vccommondescription, vcemail, vctitle, vcchattitle, vchosturl, "
|
|
. "vclogo, iweight"
|
|
. ") values ("
|
|
. ":parent, :name, :desc, :common_name, "
|
|
. ":common_desc, :email, :title, :chat_title, :url, "
|
|
. ":logo, :weight)"),
|
|
array(
|
|
':parent' => ($group['parent'] ? (int) $group['parent'] : null),
|
|
':name' => $group['vclocalname'],
|
|
':desc' => $group['vclocaldescription'],
|
|
':common_name' => $group['vccommonname'],
|
|
':common_desc' => $group['vccommondescription'],
|
|
':email' => $group['vcemail'],
|
|
':title' => $group['vctitle'],
|
|
':chat_title' => $group['vcchattitle'],
|
|
':url' => $group['vchosturl'],
|
|
':logo' => $group['vclogo'],
|
|
':weight' => $group['iweight'],
|
|
)
|
|
);
|
|
$id = $db->insertedId();
|
|
|
|
$new_group = $db->query(
|
|
"SELECT * FROM {opgroup} WHERE groupid = ?",
|
|
array($id),
|
|
array('return_rows' => Database::RETURN_ONE_ROW)
|
|
);
|
|
|
|
$args = array('group' => $new_group);
|
|
EventDispatcher::getInstance()->triggerEvent(Events::GROUP_CREATE, $args);
|
|
|
|
return $new_group;
|
|
}
|
|
|
|
/**
|
|
* Updates group info
|
|
*
|
|
* Triggers {@link \Mibew\EventDispatcher\Events::GROUP_UPDATE} event.
|
|
*
|
|
* @param array $group Operators' group. The $group array must contains the
|
|
* following keys:
|
|
* - groupid,
|
|
* - vclocalname,
|
|
* - vclocaldescription,
|
|
* - vccommonname,
|
|
* - vccommondescription,
|
|
* - vcemail,
|
|
* - iweight,
|
|
* - parent,
|
|
* - vctitle,
|
|
* - vcchattitle,
|
|
* - vchosturl,
|
|
* - vclogo,
|
|
* @throws \InvalidArgumentException if not all of the group fields are
|
|
* specified.
|
|
*/
|
|
function update_group($group)
|
|
{
|
|
if (!check_group_fields($group)) {
|
|
throw new \InvalidArgumentException('Not all group fields are specified');
|
|
}
|
|
|
|
// Get the original state of the group to trigger the "update" event later.
|
|
$original_group = group_by_id($group['groupid']);
|
|
|
|
$db = Database::getInstance();
|
|
$db->query(
|
|
("UPDATE {opgroup} SET "
|
|
. "parent = :parent, vclocalname = :name, vclocaldescription = :desc, "
|
|
. "vccommonname = :common_name, vccommondescription = :common_desc, "
|
|
. "vcemail = :email, vctitle = :title, vcchattitle = :chat_title, "
|
|
. "vchosturl = :host_url, vclogo = :logo, iweight = :weight "
|
|
. "where groupid = :id"),
|
|
array(
|
|
':parent' => ($group['parent'] ? (int) $group['parent'] : null),
|
|
':name' => $group['vclocalname'],
|
|
':desc' => $group['vclocaldescription'],
|
|
':common_name' => $group['vccommonname'],
|
|
':common_desc' => $group['vccommondescription'],
|
|
':email' => $group['vcemail'],
|
|
':title' => $group['vctitle'],
|
|
':chat_title' => $group['vcchattitle'],
|
|
':host_url' => $group['vchosturl'],
|
|
':logo' => $group['vclogo'],
|
|
':weight' => $group['iweight'],
|
|
':id' => $group['groupid'],
|
|
)
|
|
);
|
|
|
|
if ($group['parent']) {
|
|
$db->query(
|
|
"UPDATE {opgroup} SET parent = NULL WHERE parent = ?",
|
|
array($group['groupid'])
|
|
);
|
|
}
|
|
|
|
$args = array(
|
|
'group' => $group,
|
|
'original_group' => $original_group,
|
|
);
|
|
EventDispatcher::getInstance()->triggerEvent(Events::GROUP_UPDATE, $args);
|
|
}
|
|
|
|
/**
|
|
* Builds list of chatgroup operators ids.
|
|
*
|
|
* @param int $group_id ID of the chatgroup.
|
|
*
|
|
* @return array ID of all operators in specified group.
|
|
*/
|
|
function get_group_members($group_id)
|
|
{
|
|
$rows = Database::getInstance()->query(
|
|
"SELECT operatorid FROM {operatortoopgroup} WHERE groupid = ?",
|
|
array($group_id),
|
|
array('return_rows' => Database::RETURN_ALL_ROWS)
|
|
);
|
|
|
|
$operators = array();
|
|
foreach ($rows as $row) {
|
|
$operators[] = $row['operatorid'];
|
|
}
|
|
|
|
return $operators;
|
|
}
|
|
|
|
/**
|
|
* Update operators of specific group
|
|
*
|
|
* Triggers {@link \Mibew\EventDispatcher\Events::GROUP_UPDATE_OPERATORS} event.
|
|
*
|
|
* @param int $group_id ID of the group.
|
|
* @param array $new_value list of all operators of specified group.
|
|
*/
|
|
function update_group_members($group_id, $new_value)
|
|
{
|
|
// Get the unchanged set of operators related with the group to trigger
|
|
// "update" event later
|
|
$original_operators = get_group_members($group_id);
|
|
|
|
$db = Database::getInstance();
|
|
$db->query(
|
|
"DELETE FROM {operatortoopgroup} WHERE groupid = ?",
|
|
array($group_id)
|
|
);
|
|
|
|
foreach ($new_value as $operator_id) {
|
|
$db->query(
|
|
"INSERT INTO {operatortoopgroup} (groupid, operatorid) VALUES (?, ?)",
|
|
array($group_id, $operator_id)
|
|
);
|
|
}
|
|
if ($original_operators != $new_value) {
|
|
// Trigger the "update" event only if operators set is changed.
|
|
$args = array(
|
|
'group' => group_by_id($group_id),
|
|
'original_operators' => $original_operators,
|
|
'operators' => $new_value,
|
|
);
|
|
EventDispatcher::getInstance()->triggerEvent(Events::GROUP_UPDATE_OPERATORS, $args);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deletes a group with specified ID.
|
|
*
|
|
* Triggers {@link \Mibew\EventDispatcher\Events::GROUP_DELETE} event.
|
|
*
|
|
* @param int $group_id ID of the group that should be deleted.
|
|
*/
|
|
function delete_group($group_id)
|
|
{
|
|
$db = Database::getInstance();
|
|
$db->query("DELETE FROM {opgroup} WHERE groupid = ?", array($group_id));
|
|
$db->query("DELETE FROM {operatortoopgroup} WHERE groupid = ?", array($group_id));
|
|
$db->query("UPDATE {thread} SET groupid = 0 WHERE groupid = ?", array($group_id));
|
|
|
|
$args = array('id' => $group_id);
|
|
EventDispatcher::getInstance()->triggerEvent(Events::GROUP_DELETE, $args);
|
|
}
|
|
|
|
function get_all_groups()
|
|
{
|
|
$db = Database::getInstance();
|
|
$groups = $db->query(
|
|
("SELECT {opgroup}.groupid AS groupid, parent, "
|
|
. "vclocalname, vclocaldescription "
|
|
. "FROM {opgroup} ORDER BY vclocalname"),
|
|
null,
|
|
array('return_rows' => Database::RETURN_ALL_ROWS)
|
|
);
|
|
|
|
return get_sorted_child_groups_($groups);
|
|
}
|
|
|
|
/**
|
|
* Retrieves list of groups the operator can see.
|
|
*
|
|
* This function keeps in mind groups isolation.
|
|
*
|
|
* @deprecated since 2.1.1. Use {@link get_groups_for_operator()} function
|
|
* instead.
|
|
* @param array $operator List of operator's fields. See
|
|
* {@link operator_by_id()} for details of its keys.
|
|
* @return array List of group arrays. See {@link group_by_id()} for details
|
|
* about their structure.
|
|
*/
|
|
function get_all_groups_for_operator($operator)
|
|
{
|
|
return get_groups_for_operator($operator, false);
|
|
}
|
|
|
|
function get_sorted_child_groups_(
|
|
$groups_list,
|
|
$skip_groups = array(),
|
|
$max_level = -1,
|
|
$group_id = null,
|
|
$level = 0
|
|
) {
|
|
$child_groups = array();
|
|
foreach ($groups_list as $index => $group) {
|
|
if ($group['parent'] == $group_id && !in_array($group['groupid'], $skip_groups)) {
|
|
$group['level'] = $level;
|
|
$child_groups[] = $group;
|
|
if ($max_level == -1 || $level < $max_level) {
|
|
$child_groups = array_merge(
|
|
$child_groups,
|
|
get_sorted_child_groups_(
|
|
$groups_list,
|
|
$skip_groups,
|
|
$max_level,
|
|
$group['groupid'],
|
|
$level + 1
|
|
)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $child_groups;
|
|
}
|
|
|
|
function get_groups_($check_away, $operator, $order = null)
|
|
{
|
|
$db = Database::getInstance();
|
|
if ($order) {
|
|
switch ($order['by']) {
|
|
case 'weight':
|
|
$orderby = "iweight";
|
|
break;
|
|
case 'lastseen':
|
|
$orderby = "ilastseen";
|
|
break;
|
|
default:
|
|
$orderby = "{opgroup}.vclocalname";
|
|
}
|
|
$orderby = sprintf(
|
|
" IF(ISNULL({opgroup}.parent),CONCAT('_',%s),'') %s, {opgroup}.iweight ",
|
|
$orderby,
|
|
($order['desc'] ? 'DESC' : 'ASC')
|
|
);
|
|
} else {
|
|
$orderby = "iweight, vclocalname";
|
|
}
|
|
|
|
$values = array(
|
|
':now' => time(),
|
|
);
|
|
$query = "SELECT DISTINCT {opgroup}.groupid AS groupid, "
|
|
. "{opgroup}.parent AS parent, "
|
|
. "vclocalname, vclocaldescription, iweight, "
|
|
. "(SELECT count(*) "
|
|
. "FROM {operatortoopgroup} "
|
|
. "WHERE {opgroup}.groupid = {operatortoopgroup}.groupid"
|
|
. ") AS inumofagents, "
|
|
. "(SELECT MIN(:now - dtmlastvisited) AS time "
|
|
. "FROM {operatortoopgroup}, {operator} "
|
|
. "WHERE istatus = 0 "
|
|
. "AND {opgroup}.groupid = {operatortoopgroup}.groupid "
|
|
. "AND {operatortoopgroup}.operatorid = {operator}.operatorid" .
|
|
") AS ilastseen"
|
|
. ($check_away
|
|
? ", (SELECT MIN(:now - dtmlastvisited) AS time "
|
|
. "FROM {operatortoopgroup}, {operator} "
|
|
. "WHERE istatus <> 0 "
|
|
. "AND {opgroup}.groupid = {operatortoopgroup}.groupid "
|
|
. "AND {operatortoopgroup}.operatorid = {operator}.operatorid"
|
|
. ") AS ilastseenaway"
|
|
: "")
|
|
. " FROM {opgroup} ";
|
|
|
|
if ($operator) {
|
|
$query .= ", (SELECT {opgroup}.groupid, {opgroup}.parent "
|
|
. "FROM {opgroup}, {operatortoopgroup} "
|
|
. "WHERE {opgroup}.groupid = {operatortoopgroup}.groupid "
|
|
. "AND {operatortoopgroup}.operatorid = :operatorid) i "
|
|
. "WHERE {opgroup}.groupid = i.parent "
|
|
. "OR {opgroup}.parent = i.groupid "
|
|
. "OR ({opgroup}.parent = i.parent AND {opgroup}.parent IS NOT NULL) "
|
|
. "OR {opgroup}.groupid = i.groupid ";
|
|
$values[':operatorid'] = $operator['operatorid'];
|
|
}
|
|
|
|
$query .= " ORDER BY " . $orderby;
|
|
$groups = $db->query(
|
|
$query,
|
|
$values,
|
|
array('return_rows' => Database::RETURN_ALL_ROWS)
|
|
);
|
|
|
|
return get_sorted_child_groups_($groups);
|
|
}
|
|
|
|
function get_groups($check_away)
|
|
{
|
|
return get_groups_($check_away, null);
|
|
}
|
|
|
|
function get_groups_for_operator($operator, $check_away = false)
|
|
{
|
|
return get_groups_($check_away, $operator);
|
|
}
|
|
|
|
function get_sorted_groups($order)
|
|
{
|
|
return get_groups_(true, null, $order);
|
|
}
|
|
|
|
function get_operator_group_ids($operator_id)
|
|
{
|
|
$rows = Database::getInstance()->query(
|
|
"SELECT groupid FROM {operatortoopgroup} WHERE operatorid = ?",
|
|
array($operator_id),
|
|
array('return_rows' => Database::RETURN_ALL_ROWS)
|
|
);
|
|
|
|
$groups = array();
|
|
foreach ($rows as $row) {
|
|
$groups[] = $row['groupid'];
|
|
}
|
|
|
|
return $groups;
|
|
}
|
|
|
|
function get_operators_from_adjacent_groups($operator)
|
|
{
|
|
return get_operators_list(array(
|
|
'isolated_operator_id' => $operator['operatorid'],
|
|
));
|
|
}
|