1<?php
2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
3//
4// All Rights Reserved. See copyright.txt for details and a complete list of authors.
5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
6// $Id$
7
8/**
9 * Handler class for GroupSelector
10 *
11 * Letter key: ~g~
12 *
13 */
14class Tracker_Field_GroupSelector extends Tracker_Field_Abstract implements Tracker_Field_Filterable
15{
16	public static function getTypes()
17	{
18		return [
19			'g' => [
20				'name' => tr('Group Selector'),
21				'description' => tr('Allow a selection from a specified list of user groups.'),
22				'help' => 'Group selector',
23				'prefs' => ['trackerfield_groupselector'],
24				'tags' => ['advanced'],
25				'default' => 'n',
26				'params' => [
27					'autoassign' => [
28						'name' => tr('Auto-Assign'),
29						'description' => tr('Determines if any group should be automatically assigned to the field.'),
30						'filter' => 'int',
31						'options' => [
32							0 => tr('None'),
33							1 => tr('Creator'),
34							2 => tr('Modifier'),
35						],
36						'legacy_index' => 0,
37					],
38					'owner' => [
39						'name' => tr('Item Owner'),
40						'description' => tr('Field that determines permissions of the item when "Group can see their own items" is enabled for the tracker'),
41						'filter' => 'int',
42						'options' => [
43							0 => tr('No'),
44							1 => tr('Yes'),
45						],
46						'default' => 0,
47					],
48					'groupId' => [
49						'name' => tr('Group Filter'),
50						'description' => tr('Limit listed groups to those including the specified group.'),
51						'filter' => 'text',
52						'legacy_index' => 1,
53					],
54					'userGroups' => [
55						'name' => tr('User Groups'),
56						'description' => tr('Show groups user belongs to instead of the ones user has permission to see.'),
57						'filter' => 'int',
58						'options' => [
59							0 => tr('No'),
60							1 => tr('Yes'),
61						],
62						'default' => 0,
63						'legacy_index' => 4,
64					],
65					'assign' => [
66						'name' => tr('Assign to the group'),
67						'description' => tr('For no auto-assigned field, the user (user selector if it exists, or user) will be assigned to the group and it will be his or her default group. The group must have the user choice setting activated.'),
68						'filter' => 'int',
69						'options' => [
70							0 => tr('None'),
71							1 => tr('Assign'),
72						],
73						'default' => 0,
74						'legacy_index' => 2,
75					],
76					'unassign' => [
77						'name' => tr('Unassign from previous selection'),
78						'description' => tr('When assign to the group is set, the user (user selector if it exists, or user) will be unassigned from the previously selected group (if any). That group must have the user choice setting activated.'),
79						'filter' => 'int',
80						'options' => [
81							0 => tr('None'),
82							1 => tr('Unassign'),
83						],
84						'default' => 0,
85					],
86					'notify' => [
87						'name' => tr('Email Notification'),
88						'description' => tr('Add selected group to group monitor the item. Group watches feature must be enabled.'),
89						'filter' => 'int',
90						'options' => [
91							0 => tr('No'),
92							1 => tr('Yes'),
93						],
94						'legacy_index' => 3,
95					]
96				],
97			],
98		];
99	}
100
101	function getFieldData(array $requestData = [])
102	{
103		// $group is set to the default group in lib/setup/user_prefs.php
104		global $group, $user;
105		$usersLib = TikiLib::lib('user');
106
107		$ins_id = $this->getInsertId();
108
109		$data = [];
110		$defGroup = $group;
111		$userGroups = $usersLib->get_user_groups_inclusion($user);
112		$perms = Perms::get('tracker', $this->getConfiguration('trackerId'));
113
114		$groupId = $this->getOption('groupId');
115		if (empty($groupId)) {
116			if ($this->getOption('userGroups')) {
117				$data['list'] = array_keys($userGroups);
118				sort($data['list']);
119			} else {
120				$data['list'] = $usersLib->list_all_groups_with_permission();
121			}
122		} else {
123			if (ctype_digit($groupId)) {
124				$group_info = $usersLib->get_groupId_info($groupId);
125				$data['list'] =	$usersLib->get_including_groups($group_info['groupName']);
126			} elseif ($usersLib->group_exists($groupId)) {
127				$data['list'] = $usersLib->get_including_groups($groupId);
128			}
129		}
130
131		// check the default group is one of the groups we are looking for
132		if (! in_array($defGroup, $data['list'])) {
133			// find the one in the list this user is in
134			$includedGroups = array_intersect(array_keys($userGroups), $data['list']);
135			if (empty($includedGroups) && ! $perms->admin_trackers) {
136				// user not in any of the required groups, use the global default $group and warn
137				$defGroup = $group;
138				Feedback::warning(tr('User not in any of the required groups for GroupSelector field'));
139			} else if (count($includedGroups) === 1) {
140				// just the one, easy
141				$defGroup = array_shift($includedGroups);
142			} else {
143				// more than one?
144				if (in_array($group, $includedGroups)) {
145					// use the user's default group if there
146					$defGroup = $group;
147				} else {
148					$found = false;
149					foreach ($userGroups as $userGroup => $membership) {
150						if (in_array($userGroup, $includedGroups) && $membership === 'real') {
151							// use the first group this user is a real member of, not just included
152							$defGroup = $userGroup;
153							$found = true;
154							break;
155						}
156					}
157					if (! $found) {
158						// use the first one as a fall back
159						$defGroup = array_shift($includedGroups);
160					}
161				}
162			}
163		}
164
165		if (isset($requestData[$ins_id])) {
166			if ($this->getOption('autoassign') < 1 || $perms->admin_trackers) {
167				$data['value'] = in_array($requestData[$ins_id], $data['list']) ? $requestData[$ins_id] : '';
168			} else {
169				if ($this->getOption('autoassign') == 2) {
170					$data['defvalue'] = $defGroup;
171					$data['value'] = $defGroup;
172				} elseif ($this->getOption('autoassign') == 1) {
173					$data['value'] = $defGroup;
174				} else {
175					$data['value'] = '';
176				}
177			}
178		} else {
179			$data['defvalue'] = $defGroup;
180			$data['value'] = $this->getValue();
181		}
182
183		return $data;
184	}
185
186	function renderInput($context = [])
187	{
188		return $this->renderTemplate('trackerinput/groupselector.tpl', $context);
189	}
190
191	function handleSave($value, $oldValue)
192	{
193		global $prefs, $user;
194
195		if ($this->getOption('autoassign') && is_null($oldValue)) {
196			$definition = $this->getTrackerDefinition();
197			if ($prefs['groupTracker'] == 'y' && $definition->isEnabled('autoCreateGroup')) {
198				$value = TikiLib::lib('trk')->groupName($definition->getInformation(), $this->getItemId());
199			}
200		}
201		if ($this->getOption('assign')) {
202			$creators = TikiLib::lib('trk')->get_item_creators($this->getConfiguration('trackerId'), $this->getItemId());
203			if (empty($creators)) {
204				$creators = [$user];
205			}
206			$ginfo = TikiLib::lib('user')->get_group_info($value);
207			if ($this->getOption('unassign') && $oldValue) {
208				$oldginfo = TikiLib::lib('user')->get_group_info($oldValue);
209			}
210			foreach ($creators as $creator) {
211				if ($ginfo['userChoice'] == 'y') {
212					TikiLib::lib('user')->assign_user_to_group($creator, $value);
213					TikiLib::lib('user')->set_default_group($creator, $value);
214				}
215				if ($this->getOption('unassign') && $oldValue && $oldginfo['userChoice'] == 'y') {
216					TikiLib::lib('user')->remove_user_from_group($creator, $oldValue);
217				}
218			}
219		}
220
221		if ($this->getOption('notify') && $prefs['feature_group_watches'] == 'y') {
222			$objectId = $this->getItemId();
223			$watchEvent = 'tracker_item_modified';
224			$objectType = 'tracker ' . $this->getConfiguration('trackerId');
225
226			$tikilib = TikiLib::lib('tiki');
227			$old_watches = $tikilib->get_groups_watching($objectId, $watchEvent, $objectType);
228
229			foreach ($old_watches as $key => $group) {
230				if ($group != $value) {
231					$tikilib->remove_group_watch($group, $watchEvent, $objectId, $objectType);
232				}
233			}
234
235			if (! empty($value) && ! in_array($value, $old_watches)) {
236				$trackerInfo = $this->getTrackerDefinition()->getInformation();
237				$objectName = $trackerInfo['name'];
238				$objectHref = 'tiki-view_tracker_item.php?trackerId=' . $this->getConfiguration('trackerId') . '&itemId=' . $this->getItemId();
239				$tikilib->add_group_watch($value, $watchEvent, $objectId, $objectType, $objectName, $objectHref);
240			}
241		}
242
243		return [
244			'value' => $value,
245		];
246	}
247
248	function getDocumentPart(Search_Type_Factory_Interface $typeFactory)
249	{
250		$baseKey = $this->getBaseKey();
251
252		$value = $this->getValue();
253
254		return [
255			$baseKey => $typeFactory->identifier($value),
256			"{$baseKey}_text" => $typeFactory->sortable($value),
257		];
258	}
259
260	function getProvidedFields() {
261		$baseKey = $this->getBaseKey();
262		return [$baseKey, "{$baseKey}_text"];
263	}
264
265	function getFilterCollection()
266	{
267		$userlib = TikiLib::lib('user');
268		$groups = $userlib->list_all_groups_with_permission();
269		$groups = $userlib->get_group_info($groups);
270
271		$possibilities = [];
272		foreach ($groups as $group) {
273			$possibilities[$group['groupName']] = $group['groupName'];
274		}
275		$possibilities['-Blank (no data)-'] = tr('-Blank (no data)-');
276
277		$filters = new Tracker\Filter\Collection($this->getTrackerDefinition());
278		$permName = $this->getConfiguration('permName');
279		$name = $this->getConfiguration('name');
280		$baseKey = $this->getBaseKey();
281
282		$filters->addNew($permName, 'dropdown')
283			->setLabel($name)
284			->setControl(new Tracker\Filter\Control\DropDown("tf_{$permName}_dd", $possibilities))
285			->setApplyCondition(function ($control, Search_Query $query) use ($baseKey) {
286				$value = $control->getValue();
287
288				if ($value === '-Blank (no data)-') {
289					$query->filterIdentifier('', $baseKey . '_text');
290				} elseif ($value) {
291					$query->filterIdentifier($value, $baseKey);
292				}
293			});
294
295		$filters->addNew($permName, 'multiselect')
296			->setLabel($name)
297			->setControl(new Tracker\Filter\Control\MultiSelect("tf_{$permName}_ms", $possibilities))
298			->setApplyCondition(function ($control, Search_Query $query) use ($permName, $baseKey) {
299				$values = $control->getValues();
300
301				if (! empty($values)) {
302					$sub = $query->getSubQuery("ms_$permName");
303
304					foreach ($values as $v) {
305						if ($v === '-Blank (no data)-') {
306							$sub->filterIdentifier('', $baseKey . '_text');
307						} elseif ($v) {
308							$sub->filterIdentifier((string) $v, $baseKey);
309						}
310					}
311				}
312			});
313
314		return $filters;
315	}
316}
317