Files
2024-12-17 17:34:10 +01:00

560 lines
17 KiB
PHP

<?php
/**
* @package JEM
* @copyright (C) 2013-2024 joomlaeventmanager.net
* @copyright (C) 2005-2009 Christoph Lukes
* @license https://www.gnu.org/licenses/gpl-3.0 GNU/GPL
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\User\User;
/**
* JEM user class with additional functions.
* Because User::getInstance has different paramters on different versions
* we must split out class.
*
* @package JEM
*/
abstract class JemUserAbstract extends User
{
/**
* @var array JemUser instances container.
*/
protected static $instances_jemuser = array();
static protected function _getInstance($id = 0)
{
$id = (int)$id;
// Check if the user ID is already cached.
if (empty(self::$instances_jemuser[$id]) || !(self::$instances_jemuser[$id] instanceof JemUser))
{
$user = new JemUser($id);
self::$instances_jemuser[$id] = $user;
}
return self::$instances_jemuser[$id];
}
/**
* Checks access permissions of the user regarding on the groupid
*
* @param int $recurse
* @param int $level
* @return boolean True on success
*/
public function validate_user($recurse, $level)
{
// Only check when user is logged in
if ($this->id) {
//open for superuser or registered and thats all what is needed
//level = -1 all registered users
//level = -2 disabled
if ((($level == -1) && $this->id) || (($level == -2) && ($this->authorise('core.manage')))) {
return true;
}
}
// User has no permissions
return false;
}
/**
* Checks if the user is allowed to edit an item
*
*
* @param int $allowowner
* @param int $ownerid
* @param int $recurse
* @param int $level
* @return boolean True on success
*/
public function editaccess($allowowner, $ownerid, $recurse, $level)
{
$generalaccess = $this->validate_user($recurse, $level);
if ((($allowowner == 1) || $this->authorise('core.edit.own','com_jem')) && ($this->id == $ownerid) && ($ownerid != 0)) {
return true;
} elseif (($generalaccess == 1) || $this->authorise('core.edit','com_jem')) {
return true;
}
return false;
}
/**
* Checks if the user is a superuser
* A superuser will allways have access if the feature is activated
*
* @return boolean True on success
*
* @deprecated since version 2.1.5
*/
static function superuser()
{
$user = Factory::getApplication()->getIdentity();
if ($user->authorise('core.manage', 'com_jem')) {
return true;
} else {
return false;
}
}
/**
* Checks if the user has the privileges to use the wysiwyg editor
*
* We could use the validate_user method instead of this to allow to set a groupid
* Not sure if this is a good idea
*
* @return boolean True on success
*
* @deprecated since version 2.1.5
*/
static function editoruser()
{
return false;
}
/**
* Checks if the user is a maintainer of a category
*
* @return NULL int of maintained categories or null
*
* @deprecated Use JemUser::can($action, 'event', $eventid) instead.
*/
public function ismaintainer($action, $eventid = false)
{
// lets look if the user is a maintainer
$db = Factory::getContainer()->get('DatabaseDriver');
$query = 'SELECT gr.id' . ' FROM #__jem_groups AS gr'
. ' LEFT JOIN #__jem_groupmembers AS g ON g.group_id = gr.id'
. ' WHERE g.member = ' . (int)$this->id
. ' AND ' . $db->quoteName('gr.' . $action . 'event') . ' = 1 '
. ' AND g.member NOT LIKE 0';
$db->setQuery($query);
$groupnumber = $db->loadColumn();
// no results, the user is not within a group with the required right
if (!$groupnumber) {
return false;
}
// the user is in a group with the required right but is there a
// published category where he is allowed to post in?
$categories = implode(' OR groupid = ', $groupnumber);
if ($action == 'edit') {
$query = 'SELECT a.catid' . ' FROM #__jem_cats_event_relations AS a'
. ' LEFT JOIN #__jem_categories AS c ON c.id = a.catid'
. ' WHERE c.published = 1'
. ' AND (c.groupid = ' . $categories . ')'
. ' AND a.itemid = ' . $eventid;
$db->setQuery($query);
}
else {
$query = 'SELECT id' . ' FROM #__jem_categories'
. ' WHERE published = 1'
. ' AND (groupid = ' . $categories . ')';
$db->setQuery($query);
}
$maintainer = $db->loadResult();
if (!$maintainer) {
return false;
}
else {
return true;
}
}
/**
* Checks if an user is a groupmember and if so
* if the group is allowed for $action on venues
*
*/
public function venuegroups($action)
{
/*
* just a basic check to see if the current user is in an usergroup with
* access for submitting venues. if a result then return true, otherwise false
*
* Actions: addvenue, publishvenue, editvenue
*
* views: venues, venue, editvenue
*/
$db = Factory::getContainer()->get('DatabaseDriver');
$query = 'SELECT gr.id'
. ' FROM #__jem_groups AS gr'
. ' LEFT JOIN #__jem_groupmembers AS g ON g.group_id = gr.id'
. ' AND '.$db->quoteName('gr.'.$action.'venue').' = 1 '
. ' WHERE g.member = ' . (int)$this->id
. ' AND g.member NOT LIKE 0';
;
$db->setQuery($query);
$groupnumber = $db->loadResult();
return !empty($groupnumber);
}
/**
* Returns all JEM groups user is member of.
* The array returned is keyed by group id where the value is
* an assoziative array of ['field_name' => 'row_value'] pairs.
*
* @param $asset mixed false, string or array of strings to restrict to groups
* with at least one of this asset(s) set;
* must be valid field names of #__jem_groups table. (optional)
* @return mixed List of JEM groups or null
*/
public function getJemGroups($asset = false)
{
$userId = (int)$this->id;
// no registered user -> no groups
if (empty($userId)) {
return false;
}
$db = Factory::getContainer()->get('DatabaseDriver');
if (is_array($asset) && !empty($asset)) {
array_walk($asset, function(&$v, $k, $db) { $v = $db->quoteName($v); }, $db);
$field = ' AND (' . implode(' > 0 OR ', $asset) . ' > 0)';
} else {
$field = empty($asset) ? '' : ' AND ' . $db->quoteName($asset) . ' > 0';
}
$query = 'SELECT gr.*'
. ' FROM #__jem_groups AS gr'
. ' LEFT JOIN #__jem_groupmembers AS gm ON gm.group_id = gr.id'
. ' WHERE gm.member = '. $userId . $field
. ' GROUP BY gr.id';
$db->setQuery($query);
$groups = $db->loadAssocList('id');
return $groups;
}
/**
* Method to return a list of all JEM categories that a user has permission for a given action
*
* @param mixed $action One or array of 'add', 'edit', 'publish'
* @param string $type One of 'event', 'venue'
* @param array $options additional options as 'option' => value, supported are:
* 'ignore_access' (bool) true if access level should be ignored
* 'use_disable' (bool) true to include non-allowed categories with attribute 'disable' set to true
* 'owner' (bbol) true if 'edit.own' can be used
*
* @return array List of categories that this user can do this action (empty array if none).
* Other categories will be returned too (with disable = true) if option 'disable' is set.
*/
public function getJemCategories($action, $type, $options = array())
{
$action = (array)$action;
$ignore_access = array_key_exists('ignore_access', $options) ? (bool)$options['ignore_access'] : false;
$use_disable = array_key_exists('use_disable', $options) ? (bool)$options['use_disable'] : false;
$owner = array_key_exists('owner', $options) ? (bool)$options['owner'] : false;
$jemsettings = JemHelper::config();
$asset = 'com_jem';
$all = (bool)$this->authorise('core.manage', $asset);
if (!$all) {
foreach ($action as $act) {
switch ($act) {
case 'add':
$all = (bool)$this->authorise('core.create', $asset);
break;
case 'edit':
$all = (bool)$this->authorise('core.edit', $asset) || (bool)$this->authorise('core.edit.own', $asset);
break;
case 'publish':
$all = (bool)$this->authorise('core.edit.state', $asset);
break;
default:
break;
}
}
}
$jemgroups = array();
if (!$all && (($type == 'event') || ($type == 'venue'))) {
$fields = array();
foreach ($action as $act) {
switch ($act) {
case 'add':
$fields[] = $act . $type;
break;
case 'edit':
$fields[] = $act . $type;
break;
case 'publish':
$fields[] = $act . $type;
break;
default:
break;
}
}
switch ($type) {
case 'event':
$create = ($jemsettings->delivereventsyes == -1);
$edit = ($jemsettings->eventedit == -1);
$edit_own = ($jemsettings->eventowner == 1) && $owner;
break;
case 'venue':
$create = ($jemsettings->deliverlocsyes == -1);
$edit = ($jemsettings->venueedit == -1);
$edit_own = ($jemsettings->venueowner == 1) && $owner;
break;
default:
$create = $edit = $edit_own = false;
break;
}
// Get all JEM groups with requested permissions and user is member of.
$jemgroups = empty($fields) ? array() : $this->getJemGroups($fields);
// If registered users are generally allowed (by JEM Settings) to edit events/venues
// add JEM group 0 and make category check
if (($create && in_array('add', $action)) || (($edit || $edit_own) && in_array('edit', $action))) {
$jemgroups[0] = true;
}
}
$disable = '';
$where = $ignore_access ? '' : ' AND c.access IN (' . implode(',', $this->getAuthorisedViewLevels()) . ')';
if (!empty($jemgroups)) {
if ($use_disable) {
$disable = ', IF (c.groupid IN (' . implode(',', array_keys($jemgroups)) . '), 0, 1) AS disable';
} else {
$where .= ' AND c.groupid IN (' . implode(',', array_keys($jemgroups)) . ')';
}
}
// We have to check ALL categories, also those not seen by user.
$db = Factory::getContainer()->get('DatabaseDriver');
$query = 'SELECT DISTINCT c.*' . $disable
. ' FROM #__jem_categories AS c'
. ' WHERE c.published = 1'
. $where
. ' ORDER BY c.lft';
$db->setQuery( $query );
$cats = $db->loadObjectList('id');
return $cats;
}
/**
* Checks if user is allowed to do actions on objects.
* Respects Joomla and JEM group permissions.
*
* @param $action mixed One or array of 'add', 'edit', 'publish', 'delete'
* @param $type string One of 'event', 'venue'
* @param $id mixed The event or venue id or false (default)
* @param $created_by mixed User id of creator or false (default)
* @param $categoryIds mixed List of category IDs to limit for or false (default)
* @return true if allowed, false otherwise
* @note If nno categoryIds are given this functions checks if there is any potential way
* to allow requested action. To prevent this check set categoryIds to 1 (root category)
*/
public function can($action, $type, $id = false, $created_by = false, $categoryIds = false)
{
$userId = (int)$this->id;
// guests are not allowed to do anything except looking
if (empty($userId) || $this->get('guest', 0)) {
return false;
}
$action = (array)$action;
if (!empty($categoryIds)) {
$categoryIds = (array)$categoryIds;
$catIds = array();
foreach ($categoryIds as $catId) {
if ((int)$catId > 0) { // allow 'root' category with which caller can skip "potentially allowed" check
$catIds[] = (int)$catId;
}
}
$categoryIds = $catIds; // non-zero integers
} else {
$categoryIds = array();
}
$created_by = (int)$created_by;
$id = ($id === false) ? $id : (int)$id;
$asset = 'com_jem';
$jemsettings = JemHelper::config();
switch ($type) {
case 'event':
$create = ($jemsettings->delivereventsyes == -1);
$edit = ($jemsettings->eventedit == -1);
$edit_own = ($jemsettings->eventowner == 1);
$autopubl = ($jemsettings->autopubl == -1); // auto-publish new events
// not supported yet
//if (!empty($id)) {
// $asset .= '.event.' . $id;
//}
break;
case 'venue':
$create = ($jemsettings->deliverlocsyes == -1);
$edit = ($jemsettings->venueedit == -1);
$edit_own = ($jemsettings->venueowner == 1);
$autopubl = ($jemsettings->autopublocate == -1); // auto-publish new venues
// not supported yet
//if (!empty($id)) {
// $asset .= '.venue.' . $id;
//}
break;
default:
$create = $edit = $edit_own = $autopubl = false;
break;
}
$assets[] = $asset;
// not supported yet
//foreach($categoryIds as $catId) {
// $assets[] = 'com_jem.category.'.$catId;
//}
// Joomla ACL system, JEM global settings
$authorised = false;
foreach ($assets as $asset) {
if ($authorised) { break; }
$authorised |= (boolean)$this->authorise('core.manage', $asset);
foreach ($action as $act) {
if ($authorised) { break; }
switch ($act) {
case 'add':
$authorised |= $create || $this->authorise('core.create', $asset);
break;
case 'edit':
$authorised |= $this->authorise('core.edit', $asset); // $edit is limited to events not attached to jem groups
// user is owner and edit-own is enabled
$authorised |= ($edit_own || $this->authorise('core.edit.own', $asset)) &&
!empty($created_by) && ($userId == $created_by);
break;
case 'publish':
$authorised |= $this->authorise('core.edit.state', $asset);
// user is creator of new item and auto-publish is enabled
$authorised |= $autopubl && ($id === 0) &&
(empty($created_by) || ($userId == $created_by));
// user is creator, can edit this item and auto-publish is enabled
// (that's because we allowed user to not publish new item with auto-puplish enabled)
$authorised |= $autopubl && ($edit || $edit_own) && ($id !== 0) &&
!empty($created_by) && ($userId == $created_by);
break;
case 'delete':
$authorised |= $this->authorise('core.delete', $asset);
break;
}
}
}
// JEM User groups
if (!$authorised) {
if (($type == 'event') || ($type == 'venue')) {
$fields = array();
foreach ($action as $act) {
switch ($act) {
case 'add':
case 'edit':
case 'publish':
$fields[] = $act.$type;
break;
default:
break;
}
}
// Get all JEM groups with requested permissions and user is member of.
$jemgroups = empty($fields) ? array() : $this->getJemGroups($fields);
// If registered users are generally allowed (by JEM Settings) to edit events/venues
// add JEM group 0 and make category check
if ($edit && (in_array('edit', $action))) {
$jemgroups[0] = true;
}
if (!empty($jemgroups)) {
if (empty($categoryIds) && (($type != 'event') || (empty($id) && (!in_array('publish', $action))))) {
$authorised = true; // new events and venues have no limiting categories, so generally authorised
} else { // we have a valid event object so check event's categories against jem groups
$whereCats = empty($categoryIds) ? '' : ' AND c.id IN ('.implode(',', $categoryIds).')';
$levels = $this->getAuthorisedViewLevels();
// We have to check ALL categories, also those not seen by user.
$db = Factory::getContainer()->get('DatabaseDriver');
$query = 'SELECT DISTINCT c.id, c.groupid, c.access'
. ' FROM #__jem_categories AS c';
if (!empty($id)) {
$query .= ' LEFT JOIN #__jem_cats_event_relations AS rel ON rel.catid = c.id'
. ' WHERE rel.itemid = ' . $id
. ' AND c.published = 1';
} else {
$query .= ' WHERE c.published = 1';
}
$query .= $whereCats;
$db->setQuery( $query );
$cats = $db->loadObjectList();
}
if (!empty($cats)) {
$unspecific = in_array('publish', $action) ? -1 : 0; // publish requires jemgroup
foreach($cats as $cat) {
if (empty($cat->groupid)) {
if ($unspecific === 0) {
$unspecific = 1;
}
} else {
$unspecific = -1; // at least one group assigned so group permissions take precedence
if (in_array($cat->access, $levels) && array_key_exists($cat->groupid, $jemgroups)) {
// user can "see" this category and is member of connected jem group granting permission
$authorised = true;
break; // foreach cats
}
}
}
if ($unspecific === 1) {
// only categories without connected JEM group found, so user is authorised
$authorised = true;
}
}
}
}
}
return (bool)$authorised;
}
}
/**
* JEM user class with additional functions.
* Compatible with Joomla since 3.4.0.
*
* @package JEM
*
* @see JemUserAbstract
*/
class JemUser extends JemUserAbstract
{
static function getInstance($id = 0, JUserWrapperHelper $userHelper = null)
{
// we don't need this helper
return parent::_getInstance($id);
}
}