lib/Users/Group.php
<?php
/**
* UserGroup class
* @since Version 3.5
* @package Railpage
* @author Michael Greenhill
*/
namespace Railpage\Users;
use Exception;
use DateTime;
use Railpage\Organisations\Factory as OrganisationsFactory;
use Railpage\Organisations\Organisation;
use Railpage\Url;
use Railpage\Module;
use Railpage\Users\User;
use Railpage\Debug;
/**
* UserGroup class
*/
class Group extends Groups {
/**
* Group type: open/public
* @since Version 3.9.1
* @const int TYPE_OPEN
*/
const TYPE_OPEN = 0;
/**
* Group type: closed
* @since Version 3.9.1
* @const int TYPE_CLOSED
*/
const TYPE_CLOSED = 1;
/**
* Group type: hidden
* @since Version 3.9.1
* @const int TYPE_HIDDEN
*/
const TYPE_HIDDEN = 2;
/**
* Group ID
* @var int $id
*/
public $id;
/**
* Group name
* @var string $name
*/
public $name;
/**
* Group type
* @var int $type
*/
public $type;
/**
* Group description
* @var string $desc
*/
public $desc;
/**
* Group owner user ID
* @var int $owner_user_id
*/
public $owner_user_id;
/**
* Group owner username
* @var string $owner_username
*/
public $owner_username;
/**
* Organisation name
* @since Version 3.6
* @var string $organisation
*/
public $organisation;
/**
* Organisation ID
* @since Version 3.6
* @var int $organisation_id
*/
public $organisation_id;
/**
* Attributes
* @since Version 3.8
* @var array $attributes
*/
public $attributes;
/**
* Constructor
* @since Version 3.5
* @param int $groupId
*/
public function __construct($groupId = null) {
parent::__construct();
if (!filter_var($groupId, FILTER_VALIDATE_INT)) {
return;
}
$this->id = $groupId;
$this->fetch();
}
/**
* Populate this object
* @since Version 3.5
* @return boolean
*/
public function fetch() {
$mckey = sprintf("railpage:group=%d", intval($this->id));
if (!$row = $this->Redis->fetch($mckey)) {
$query = "SELECT g.group_attrs, g.organisation_id, g.group_id AS id, g.group_name AS name, g.group_type AS type,
g.group_description AS description, g.group_moderator AS owner_user_id, u.username AS owner_username
FROM nuke_bbgroups AS g
INNER JOIN nuke_users AS u ON g.group_moderator = u.user_id
WHERE g.group_id = ?";
$row = $this->db->fetchRow($query, $this->id);
$this->Redis->save($mckey, $row, 0);
}
if (!is_array($row)) {
throw new Exception("Could not fetch group data for group ID " . $this->id);
}
$this->name = $row['name'];
$this->type = $row['type'];
$this->desc = $row['description'];
$this->owner_user_id = $row['owner_user_id'];
$this->owner_username = $row['owner_username'];
$this->attributes = json_decode($row['group_attrs'], true);
if (filter_var($row['organisation_id'], FILTER_VALIDATE_INT) && $row['organisation_id'] !== 0) {
$Organisation = OrganisationsFactory::CreateOrganisation(false, $this->organisation_id);
if ($Organisation instanceof Organisation) {
$this->organisation_id = $row['organisation_id'];
$this->organisation = $Organisation->name;
}
}
$this->makeURLs();
}
/**
* Set the owner of this group
* @since Version 3.9.1
* @return \Railpage\Users\Group
* @param \Railpage\Users\User $userObject
*/
public function setOwner(User $userObject) {
$this->owner_user_id = $userObject->id;
$this->owner_username = $userObject->username;
return $this;
}
/**
* Set the organisation associated to this group
* @since Version 3.9.1
* @return \Railpage\Users\Group
* @param \Railpage\Organisations\Organisation $orgObject
*/
public function setOrganisation(Organisation $orgObject) {
$this->organisation_id = $orgObject->id;
$this->organisation = $orgObject->name;
return $this;
}
/**
* Make URLs
* @since Version 3.9.1
* @return void
*/
private function makeURLs() {
$this->url = new Url(sprintf("%s/%d", "/usergroups", $this->id));
$this->url->edit = sprintf("%s/edit", $this->url->url);
$this->url->addMember = sprintf("%s/addmember", $this->url->url);
}
/**
* Get member list
* @since Version 3.5
* @param int $itemsPerPage
* @param int $page
* @return array
*/
public function members($itemsPerPage = 25, $page = 1) {
if (!filter_var($this->id, FILTER_VALIDATE_INT)) {
throw new Exception("Cannot fetch group - group ID cannot be empty");
}
$thispage = ($page - 1) * $itemsPerPage;
$params = [ $this->id, $thispage, $itemsPerPage ];
$query = "SELECT SQL_CALC_FOUND_ROWS u.user_id, u.username, u.user_from AS user_location, u.name AS user_realname
FROM nuke_bbuser_group AS gm
INNER JOIN nuke_users AS u ON gm.user_id = u.user_id
WHERE gm.group_id = ? ORDER BY u.username LIMIT ?, ?";
$result = $this->db->fetchAll($query, $params);
$return = array();
$total = $this->db->fetchOne("SELECT FOUND_ROWS() AS total");
$return = array();
$return['total'] = $total['total'];
$return['page'] = $page;
$return['perpage'] = $itemsPerPage;
foreach ($result as $row) {
$return['members'][$row['user_id']] = $row;
}
return $return;
}
/**
* Alias of members()
* @since Version 3.6
* @param int $itemsPerPage
* @param int $page
*/
public function getMembers($itemsPerPage = 25, $page = 1) {
return $this->members($itemsPerPage, $page);
}
/**
* Add a user to this group
* @since Version 3.5
* @param string $username
* @param int $userId
* @param string $orgRole
* @param string $orgContact
* @param int $orgPerms
* @return boolean
*/
public function addMember($username = null, $userId = null, $orgRole = null, $orgContact = null, $orgPerms = null) {
$mckey = sprintf("railpage:group=%d", intval($this->id));
$this->Redis->delete($mckey);
if ($username != null && !filter_var($userId, FILTER_VALIDATE_INT)) {
$query = "SELECT user_id FROM nuke_users WHERE username = ? AND user_active = 1";
$params = [ $username ];
$userId = $this->db->fetchOne($query, $params);
if (!filter_var($userId, FILTER_VALIDATE_INT)) {
return false;
}
$data = [
"group_id" => $this->id,
"user_id" => $userId
];
if ($orgRole != null && $orgContact != null && $orgPerms != null) {
$data = [
"group_id" => $this->id,
"user_id" => $userId,
"organisation_role" => $orgRole,
"organisation_contact" => $orgContact,
"organisation_privileges" => $orgPerms
];
}
$this->db->insert("nuke_bbuser_group", $data);
$this->updateUserGroupMembership($userId);
return true;
}
$data = [
"group_id" => $this->id,
"user_id" => $userId
];
$this->db->insert("nuke_bbuser_group", $data);
$this->updateUserGroupMembership($userId);
return true;
}
/**
* Force refresh the user group membership
* @since Version 3.9.1
* @param \Railpage\Users\User|int $userObject
* @return void
*/
private function updateUserGroupMembership($userObject) {
if (filter_var($userObject, FILTER_VALIDATE_INT)) {
$userObject = new User($userObject);
}
if (!$userObject instanceof User) {
throw new Exception("No instance of \\Railpage\\Users\\User provided");
}
$mckey = sprintf("railpage:group=%d.user_id=%d", $this->id, $userObject->id);
$this->Redis->delete($mckey);
$rdkey = sprintf("railpage:usergroups.user_id=%d", $userObject->id);
$this->Redis->delete($rdkey);
$userObject->getGroups(true);
return;
}
/**
* Validate changes to this group
* @since Version 3.5
* @return boolean
*/
public function validate() {
if (empty($this->name)) {
throw new Exception("Cannot validate group - group name cannot be empty");
}
if (empty($this->desc)) {
throw new Exception("Cannot validate group - group description cannot be empty");
}
if (!filter_var($this->type, FILTER_VALIDATE_INT)) {
$this->type = self::TYPE_OPEN;
}
if (empty($this->owner_user_id)) {
Debug::logEvent(__METHOD__ . " : updating owner_user_id for group ID " . $this->id);
$query = "SELECT user_id FROM nuke_users WHERE username = ?";
$this->owner_user_id = $this->db->fetchOne($query, $this->owner_username);
}
if (empty($this->owner_user_id)) {
throw new Exception("Cannot validate group - group owner user ID cannot be empty");
}
return true;
}
/**
* Commit changes to this group
* @since Version 3.5
* @return boolean
*/
public function commit() {
$this->validate();
$data = [
"group_name" => $this->name,
"group_description" => $this->desc,
"group_moderator" => $this->owner_user_id,
"group_type" => $this->type,
"group_attrs" => json_encode($this->attributes)
];
if (filter_var($this->organisation_id, FILTER_VALIDATE_INT)) {
$data['organisation_id'] = $this->organisation_id;
}
// Update
if (filter_var($this->id, FILTER_VALIDATE_INT)) {
$where = [ "group_id = ?" => $this->id ];
$this->db->update("nuke_bbgroups", $data, $where);
$mckey = sprintf("railpage:group=%d", intval($this->id));
$this->Redis->delete($mckey);
$this->makeURLs();
return true;
}
// Insert
$data['group_single_user'] = 0;
$this->db->insert("nuke_bbgroups", $data);
$this->id = $this->db->lastInsertId();
$this->makeURLs();
return true;
}
/**
* Check if a user is a member of this group
* @since Version 3.7.5
* @paran int $userId
* @return boolean
*/
public function userInGroup($userId = null) {
if ($userId instanceof User) {
$userId = $userId->id;
}
if (!filter_var($userId, FILTER_VALIDATE_INT)) {
return false;
}
$mckey = sprintf("railpage:group=%d.user_id=%d", $this->id, $userId);
$timer = Debug::getTimer();
$result = false;
if (!$result = $this->Redis->fetch($mckey)) {
$query = "SELECT user_id FROM nuke_bbuser_group WHERE group_id = ? AND user_id = ? AND user_pending = 0";
$params = [ $this->id, $userId ];
$id = $this->db->fetchOne($query, $params);
if (filter_var($id, FILTER_VALIDATE_INT)) {
$this->Redis->save($mckey, "yes", strtotime("+1 day"));
Debug::logEvent(__METHOD__ . " found user ID " . $userId . " in group ID " . $this->id, $timer);
return true;
}
}
Debug::logEvent(__METHOD__ . " did not find ID " . $userId . " in group ID " . $this->id, $timer);
return (bool) $result;
}
/**
* Remove a member from this group
* @since Version 3.7.5
* @param int $userId
* @return boolean
*/
public function removeUser($userId = null) {
if ($userId instanceof User) {
$userId = $userId->id;
}
if (!filter_var($userId, FILTER_VALIDATE_INT)) {
return false;
}
$where = [
"group_id = ?" => $this->id,
"user_id = ?" => $userId
];
$this->db->delete("nuke_bbuser_group", $where);
$mckey = sprintf("railpage:group=%d", intval($this->id));
$this->Redis->delete($mckey);
$this->updateUserGroupMembership($userId);
return true;
}
/**
* Approve user membership
* @since Version 3.9.1
* @param \Railpage\Users\User|int $userObject
* @return \Railpage\Users\Group
*/
public function approveUser($userObject) {
if (!$userObject instanceof User) {
$userObject = Factory::CreateUser($userObject);
}
$data = [ "user_pending" => 0 ];
$where = [
"user_id = ?" => $userObject->id,
"group_id = ?" => $this->id
];
$mckey = sprintf("railpage:group=%d", intval($this->id));
$this->Redis->delete($mckey);
$this->db->update("nuke_bbuser_group", $data, $where);
return $this;
}
}