You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

652 lines
18 KiB

<?php
// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
class Tracker_Item
{
const PERM_NAME_MAX_ALLOWED_SIZE = 50;
/**
* includes itemId, trackerId and fields using the fieldId as key
* @var array - plain from database.
*/
private $info;
/**
* object with tracker definition. includes itemId, items (nr of items for that tracker).
* other important attributes: trackerInfo array, factory null, fields array, perms Perms_Accessor
* @var object Tracker_Definition -
*/
private $definition;
private $owners;
private $ownerGroup;
private $writerGroup;
private $perms;
private $isNew = false;
/**
* @param $itemId int
* @return Tracker_Item Tracker_Item
* @throws Exception
*/
public static function fromId($itemId)
{
$info = TikiLib::lib('trk')->get_tracker_item($itemId);
if ($info) {
return self::fromInfo($info);
}
}
public static function fromInfo($info)
{
$obj = new self();
if (empty($info['trackerId']) && ! empty($info['itemId'])) {
$info['trackerId'] = TikiLib::lib('trk')->get_tracker_for_item($info['itemId']);
}
$obj->info = $info;
$obj->definition = Tracker_Definition::get($info['trackerId']);
$obj->initialize();
return $obj;
}
public static function newItem($trackerId)
{
$obj = new self();
$obj->info = [];
$obj->definition = Tracker_Definition::get($trackerId);
$obj->asNew();
$obj->initialize();
return $obj;
}
private function __construct()
{
}
public function asNew()
{
$this->isNew = true;
$this->info['itemId'] = null;
}
public function canView()
{
if ($this->isNew()) {
return true;
}
if ($this->canFromSpecialPermissions('Modify') || $this->canFromSpecialPermissions('View')) {
return true;
}
if ($this->canSeeOwn()) {
return true;
}
$permName = $this->getViewPermission();
return $this->perms->$permName;
}
public function canViewHistory()
{
$permName = 'tracker_view_history';;
return $this->perms->$permName;
}
public function canModify()
{
if ($this->isNew()) {
return $this->perms->create_tracker_items;
}
if ($this->canFromSpecialPermissions('Modify')) {
return true;
}
$status = $this->info['status'];
if ($status == 'c') {
return $this->perms->modify_tracker_items_closed;
} elseif ($status == 'p') {
return $this->perms->modify_tracker_items_pending;
} else {
return $this->perms->modify_tracker_items;
}
}
public function canRemove()
{
if ($this->isNew()) {
return false;
}
if ($this->canFromSpecialPermissions('Remove')) {
return true;
}
$status = $this->info['status'];
if ($status == 'c') {
return $this->perms->remove_tracker_items_closed;
} elseif ($status == 'p') {
return $this->perms->remove_tracker_items_pending;
} else {
return $this->perms->remove_tracker_items;
}
}
public function canViewComments()
{
if ($this->perms->tracker_view_comments || $this->perms->comment_tracker_items) {
return true;
}
if ($this->canSeeOwn()) {
return true;
}
return false;
}
public function canPostComments()
{
if ($this->perms->comment_tracker_items) {
return true;
}
if ($this->canSeeOwn()) {
return true;
}
if ($this->canFromSpecialPermissions('Modify')) {
return true;
}
return false;
}
public function getSpecialPermissionUsers($itemId, $operation)
{
$users = [];
if ($operation == 'View' && $this->definition->getConfiguration('userCanSeeOwn') == 'y') {
$users = array_unique(array_merge($users, $this->owners));
}
if ($operation == 'View' && $this->definition->getConfiguration('groupCanSeeOwn') == 'y' && $this->ownerGroup && in_array($this->ownerGroup, $this->perms->getGroups())) {
$users = array_unique(array_merge($users, TikiLib::lib('user')->get_group_users($this->ownerGroup)));
}
if ($this->definition->getConfiguration('writerCan' . $operation, 'n') == 'y') {
$users = array_unique(array_merge($users, $this->owners));
}
if ($this->definition->getConfiguration('writerGroupCan' . $operation, 'n') == 'y' && $this->writerGroup && in_array($this->writerGroup, $this->perms->getGroups())) {
$users = array_unique(array_merge($users, TikiLib::lib('user')->get_group_users($this->writerGroup)));
}
return $users;
}
public function getOwners()
{
return $this->owners;
}
private function canFromSpecialPermissions($operation)
{
global $user;
if (! $this->definition) {
return false;
}
if ($operation == 'View' && $this->canSeeOwn()) {
return true;
}
if ($this->definition->getConfiguration('writerCan' . $operation, 'n') == 'y' && $user && $this->owners && in_array($user, $this->owners)) {
return true;
}
if ($this->definition->getConfiguration('writerGroupCan' . $operation, 'n') == 'y' && $this->ownerGroup && in_array($this->ownerGroup, $this->perms->getGroups())) {
return true;
}
return false;
}
private function canSeeOwn()
{
global $user;
if (! $this->definition) {
return false;
}
if ($this->definition->getConfiguration('userCanSeeOwn') == 'y' && ! empty($user) && $this->owners && in_array($user, $this->owners)) {
return true;
}
if ($this->definition->getConfiguration('groupCanSeeOwn') == 'y' && ! empty($user) && $this->ownerGroup) {
$usergroups = TikiLib::lib('tiki')->get_user_groups($user);
if (in_array($this->ownerGroup, $usergroups)) {
return true;
}
}
return false;
}
private function initialize()
{
$this->owners = $this->getItemOwners();
$this->ownerGroup = $this->getItemGroupOwner();
$this->writerGroup = $this->getItemGroupWriter();
$this->perms = $this->getItemPermissions();
}
private function getItemPermissions()
{
if ($this->isNew()) {
if ($this->definition) {
$trackerId = $this->definition->getConfiguration('trackerId');
return Perms::get('tracker', $trackerId);
} else {
$accessor = new Perms_Accessor();
$accessor->setResolver(new Perms_Resolver_Default(false));
return $accessor;
}
} else {
$itemId = $this->info['itemId'];
return Perms::get('trackeritem', $itemId, $this->info['trackerId']);
}
}
private function getItemOwners()
{
if (! is_object($this->definition)) {
return []; // TODO: This is a temporary fix, we should be able to getItemOwners always
}
if ($this->isNew()) {
global $user;
return [$user];
}
if (isset($this->info['itemUsers'])) {
// Used by TRACKERLIST - not all data is loaded, but this is loaded separately
return $this->info['itemUsers'];
}
$owners = array_map(function ($field) {
$owners = $this->getValue($field);
return TikiLib::lib('trk')->parse_user_field($owners);
}, $this->definition->getItemOwnerFields());
if ($owners) {
return call_user_func_array('array_merge', $owners);
} else {
return [];
}
}
private function getItemGroupOwner()
{
if (! is_object($this->definition)) {
return; // TODO: This is a temporary fix, we should be able to getItemOwner always
}
$groupFields = $this->definition->getItemGroupOwnerFields();
if ($groupFields) {
return $this->getValue($groupFields[0]);
}
}
private function getItemGroupWriter()
{
if (! is_object($this->definition)) {
return; // TODO: This is a temporary fix, we should be able to getItemOwner always
}
$groupField = $this->definition->getWriterGroupField();
if ($groupField) {
return $this->getValue($groupField);
}
}
public function getAllowedUserGroupsForField($field)
{
$isHidden = $field['isHidden'];
$visibleBy = $field['visibleBy'];
$allowed = [
'allowed_users' => [],
'allowed_groups' => [],
];
if ($isHidden == 'c') {
// Creator or creator group check when field can be modified by creator only
if ($this->definition->getConfiguration('writerCanModify', 'n') == 'y' && $this->owners) {
$allowed['allowed_users'] = $this->owners;
}
if ($this->definition->getConfiguration('writerGroupCanModify', 'n') == 'y' && $this->ownerGroup) {
$allowed['allowed_groups'] = [$this->ownerGroup];
}
} elseif ($isHidden == 'y') {
// Visible by administrator only
} else {
// Permission based on visibleBy apply
$allowed['allowed_groups'] = $visibleBy;
}
return $allowed;
}
public function canViewField($fieldId)
{
$fieldId = $this->prepareFieldId($fieldId);
// Nothing stops the tracker administrator from doing anything
if ($this->perms->admin_trackers) {
return true;
}
// Viewing the item is required to view the field (safety)
if (! $this->canView()) {
return false;
}
$field = $this->definition->getField($fieldId);
if (! $field) {
return false;
}
// filter fields to show only Tag field that users has permissio to access
if ($field['type'] == 'F' && empty($this->perms['view_freetags'])) {
return false;
}
$isHidden = $field['isHidden'];
$visibleBy = $field['visibleBy'];
if ($isHidden == 'c' && $this->canFromSpecialPermissions('Modify')) {
// Creator or creator group check when field can be modified by creator only
return true;
} elseif ($isHidden == 'y') {
// Visible by administrator only
return false;
} else {
// Permission based on visibleBy apply
return $this->isMemberOfGroups($visibleBy);
}
}
public function canModifyField($fieldId)
{
$fieldId = $this->prepareFieldId($fieldId);
// Nothing stops the tracker administrator from doing anything
if ($this->perms->admin_trackers) {
return true;
}
// Modify the item is required to modify the field (safety)
if (! $this->canModify()) {
return false;
}
// Cannot modify a field you are not supposed to see
// Modify without view means insert-only
if (! $this->isNew() && ! $this->canViewField($fieldId)) {
return false;
}
$field = $this->definition->getField($fieldId);
if (! $field) {
return false;
}
$isHidden = $field['isHidden'];
$editableBy = $field['editableBy'];
if ($isHidden == 'i' || $isHidden == 'a') {
// Immutable or editable by admin only after creation
return $this->isNew();
} elseif ($isHidden == 'c') {
// Creator or creator group check when field can be modified by creator only
return $this->canFromSpecialPermissions('Modify');
} elseif ($isHidden == 'p') {
// Editable by administrator only
return false;
} else {
// Permission based on editableBy apply
return $this->isMemberOfGroups($editableBy);
}
}
private function isMemberOfGroups($groups)
{
// Nothing specified means everyone
if (empty($groups)) {
return true;
}
$commonGroups = array_intersect($groups, $this->perms->getGroups());
return count($commonGroups) != 0;
}
/**
* Return raw value of a field. Raw means, value as saved in database.
* @param integer $fieldId
* @return string - note: all values are saved as a string.
*/
private function getValue($fieldId)
{
if (isset($this->info[$fieldId])) {
return $this->info[$fieldId];
}
}
public function getId()
{
return $this->info['itemId'];
}
private function isNew()
{
return $this->isNew;
}
public function prepareInput($input)
{
$input = $input->none();
$fields = $this->definition->getFields();
$output = [];
foreach ($fields as $field) {
$output[] = $this->prepareFieldInput($field, $input);
}
return array_filter($output);
}
public function prepareOutput()
{
$fields = $this->definition->getFields();
$output = [];
foreach ($fields as $field) {
$output[] = $this->prepareFieldOutput($field);
}
return array_filter($output);
}
public function prepareFieldInput($field, $input)
{
$fid = $field['fieldId'];
if ($this->canModifyField($fid)) {
$field['ins_id'] = "ins_$fid";
$factory = $this->definition->getFieldFactory();
$handler = $factory->getHandler($field, $this->info);
if (! isset($input[$field['ins_id']]) && isset($input['fields'][$field['permName']])) {
// getFieldData expects the value to be in $input['ins_xx']
$input[$field['ins_id']] = $input['fields'][$field['permName']];
}
return array_merge($field, $handler->getFieldData($input));
}
}
public function prepareFieldOutput($field)
{
$fid = $field['fieldId'];
if ($this->canViewField($fid)) {
$field['ins_id'] = "ins_$fid";
$factory = $this->definition->getFieldFactory();
$handler = $factory->getHandler($field, $this->info);
return array_merge($field, $handler->getFieldData([]));
}
}
private function prepareFieldId($fieldId)
{
if (TikiLib::startsWith($fieldId, 'ins_') == true) {
$fieldId = str_replace('ins_', '', $fieldId);
}
if (! is_numeric($fieldId)) {
if ($field = $this->definition->getFieldFromPermName($fieldId)) {
$fieldId = $field['fieldId'];
}
}
return $fieldId;
}
/**
* Getter method for the permissions of this
* item.
*
* @param string $permName
* @return bool|null
*/
public function getPerm($permName)
{
return isset($this->perms->$permName) ? $this->perms->$permName : null;
}
public function getPerms()
{
return $this->perms;
}
public function getOwnerGroup()
{
return $this->ownerGroup;
}
public function getViewPermission()
{
$status = isset($this->info['status']) ? $this->info['status'] : 'o';
if ($status == 'c') {
return 'view_trackers_closed';
} elseif ($status == 'p') {
return 'view_trackers_pending';
} else {
return 'view_trackers';
}
}
/**
* Gets a tracker item's data
*
* @param JitFilter|null $input optional input object
* @param bool|false $forExport gets the field output in list_mode=csv not necessarily the stored value
* @return array [permName => value]
*/
public function getData($input = null, $forExport = false)
{
$out = [];
if ($input) {
$fields = $this->prepareInput($input);
foreach ($fields as $field) {
$permName = $field['permName'];
$out[$permName] = $field['value'];
if (isset($input->fields) && isset($input->fields[$permName])) {
$out[$permName] = $input->fields->$permName->none();
}
}
} else {
$factory = $this->definition->getFieldFactory();
$info = $this->info;
foreach ($this->definition->getFields() as $field) {
$handler = $factory->getHandler($field, $info);
$data = $handler->getFieldData();
$permName = $field['permName'];
$out[$permName] = isset($data['value']) ? $data['value'] : null;
}
}
$newStatus = 'o';
if ($this->isNew() && isset($this->definition)) {
// set status based on tracker setting if status not explicitly requested
$newStatus = $this->definition->getConfiguration('newItemStatus', 'o');
}
return [
'itemId' => $this->isNew() ? null : $this->info['itemId'],
'status' => $this->isNew() ? $newStatus : $this->info['status'],
'creation_date' => $this->info['created'],
'trackerId' => $this->isNew() ? null : $this->info['trackerId'],
'fields' => $out,
];
}
public function getDefinition()
{
return $this->definition;
}
public function getDisplayedStatus()
{
if (
($this->definition->getConfiguration('showStatus', 'n') == 'y' && $this->definition->getConfiguration('showStatusAdminOnly', 'n') == 'n')
|| ($this->definition->getConfiguration('showStatusAdminOnly', 'n') == 'y' && $this->perms->admin_trackers)
) {
$status = $this->isNew()
? $this->definition->getConfiguration('newItemStatus', 'o')
: $this->info['status'];
switch ($status) {
case 'o':
return 'open';
case 'p':
return 'pending';
case 'c':
return 'closed';
}
}
}
}