1<?php
2/*
3 * Gallery - a web based photo album viewer and editor
4 * Copyright (C) 2000-2008 Bharat Mediratta
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21/**
22 * Gallery core module.
23 * @package GalleryCore
24 * @author Bharat Mediratta <bharat@menalto.com>
25 * @version $Revision: 20996 $
26 */
27class CoreModule extends GalleryModule {
28
29    function CoreModule() {
30	global $gallery;
31
32	$this->setId('core');
33	$this->setName($gallery->i18n('Core'));
34	$this->setGalleryVersion('2.3.2');
35
36	/* Don't forget to update CoreModuleExtras::upgrade and _prepareConfigUpgrade too! */
37	$this->setVersion('1.3.0.2');
38	$this->_templateVersion = 1;
39
40	$this->setDescription($gallery->i18n('Gallery 2 Core Module'));
41	$this->setGroup('gallery', $gallery->i18n('Gallery'));
42	$this->setCallbacks(
43	    'getItemLinks|getSystemLinks|getItemAdminViews|getSiteAdminViews|getUserAdminViews');
44	$this->setRequiredCoreApi(array(7, 53));
45	$this->setRequiredModuleApi(array(3, 8));
46    }
47
48    /**
49     * @see GalleryModule::getItemLinks
50     */
51    function getItemLinks($items, $wantsDetailedLinks, $permissions, $userId) {
52	global $gallery;
53	$urlGenerator =& $gallery->getUrlGenerator();
54
55	list ($ret, $rootId) = GalleryCoreApi::getPluginParameter('module', 'core', 'id.rootAlbum');
56	if ($ret) {
57	    return array($ret, null);
58	}
59
60	/* Fetch child counts */
61	$itemIds = array();
62	foreach ($items as $item) {
63	    $itemIds[] = $item->getId();
64	}
65
66	/*
67	 * We're not doing this as the acting user id, but that's OK because we're not displaying
68	 * the result; we're only using it as a gating factor for whether or not we show a link, and
69	 * that'll also be gated by the permissions we receive which *will* be for the acting user.
70	 */
71	list ($ret, $childCounts) = GalleryCoreApi::fetchChildCounts($itemIds);
72	if ($ret) {
73	    return array($ret, null);
74	}
75
76	/* Fetch thumbnail ids */
77	list ($ret, $thumbTable) = GalleryCoreApi::fetchThumbnailsByItemIds($itemIds);
78	if ($ret) {
79	    return array($ret, null);
80	}
81
82	$links = array();
83	foreach ($items as $item) {
84	    $itemId = $item->getId();
85	    $isRoot = ($itemId == $rootId);
86	    $isAlbum = $item->getCanContainChildren();
87
88	    /* Permissions for its parent */
89	    list ($ret, $parentPermissions) =
90		GalleryCoreApi::getPermissions($item->getParentId(), $userId);
91	    if ($ret) {
92		return array($ret, null);
93	    }
94
95	    if (isset($wantsDetailedLinks[$itemId]) && $isAlbum &&
96		    isset($permissions[$itemId]['core.addDataItem'])) {
97		$links[$itemId][] =
98		    array('text' => $this->_translate('Add Items'),
99			  'params' => array('view' => 'core.ItemAdmin',
100					    'subView' => 'core.ItemAdd',
101					    'itemId' => $itemId,
102					    'return' => 1));
103	    }
104
105	    $itemTypeNames = array_merge($item->itemTypeName(), $item->itemTypeName(false));
106	    if (isset($permissions[$itemId]['core.edit'])) {
107		if (false) {
108		    /* Specific translations: */ _('Edit Album'); _('Edit Photo'); _('Edit Movie');
109		}
110		$links[$itemId][] =
111		    array('text' => $this->_translate(
112			      array('text' => 'Edit %s', 'arg1' => $itemTypeNames[0]),
113			      $itemTypeNames[2]),
114			  'params' => array('view' => 'core.ItemAdmin',
115					    'subView' => 'core.ItemEdit',
116					    'itemId' => $itemId,
117					    'return' => 1));
118	    }
119
120	    if (isset($wantsDetailedLinks[$itemId]) && $isAlbum
121		    && isset($permissions[$itemId]['core.addAlbumItem'])) {
122		$links[$itemId][] =
123		    array('text' => $this->_translate('Add Album'),
124			  'params' => array('view' => 'core.ItemAdmin',
125					    'subView' => 'core.ItemAddAlbum',
126					    'itemId' => $itemId,
127					    'return' => 1));
128	    }
129
130	    if (isset($permissions[$itemId]['core.edit'])) {
131		$links[$itemId][] =
132		    array('text' => isset($permissions[$itemId]['core.changePermissions'])
133				? $this->_translate('Edit Permissions')
134				: $this->_translate('View Permissions'),
135			  'params' => array('view' => 'core.ItemAdmin',
136					    'subView' => 'core.ItemPermissions',
137					    'itemId' => $itemId,
138					    'return' => 1));
139	    }
140
141	    if (!$isRoot && isset($permissions[$itemId]['core.delete'])) {
142		if (false) {
143		    /* Specific translations: */
144		    _('Delete Album'); _('Delete Photo'); _('Delete Movie');
145		}
146		if (!function_exists('smarty_modifier_escape')) {
147		    GalleryCoreApi::requireOnce('lib/smarty/plugins/modifier.escape.php');
148		}
149                $title = smarty_modifier_escape(GalleryUtilities::markup(
150		    $item->getTitle(), 'strip'), 'javascript', 'UTF-8');
151		list ($thisItemId, $page) = GalleryUtilities::getRequestVariables('itemId', 'page');
152		/* If no page item defined, we will navigate to the parent of the deleted item */
153		if (empty($thisItemId)) {
154		    $thisItemId = $itemId;
155		}
156		$urlParams = array('controller' => 'core.ItemDeleteSingle', 'itemId' => $itemId,
157				   'pageId' => $thisItemId);
158		if (!empty($page)) {
159		    $urlParams['page'] = $page;
160		}
161		$url = $urlGenerator->generateUrl($urlParams);
162		$moreUrl = $isAlbum ? '' : $urlGenerator->generateUrl(
163		    array('view' => 'core.ItemAdmin', 'subView' => 'core.ItemDelete',
164			  'itemId' => $item->getParentId(),
165			  'selectedId' => $itemId, 'return' => 1));
166		$links[$itemId][] =
167		    array('text' => $this->_translate(
168			  array('text' => 'Delete %s', 'arg1' => $itemTypeNames[0]),
169			  	$itemTypeNames[2]),
170			  /* Params are for g->linkId used by icons, or themes ignoring 'script' */
171			  'params' => array('view' => 'core.ItemAdmin',
172					    'subView' => 'core.ItemDelete',
173					    'itemId' => $item->getParentId(),
174					    'selectedId' => $itemId),
175			  'script' => "core_confirmDelete('$url', '$moreUrl', '$title')");
176	    }
177
178	    if (!$isRoot && isset($permissions[$itemId]['core.delete'])) {
179		if (false) {
180		    /* Specific translations: */ _('Move Album'); _('Move Photo'); _('Move Movie');
181		}
182		$links[$itemId][] =
183		    array('text' => $this->_translate(
184			      array('text' => 'Move %s', 'arg1' => $itemTypeNames[0]),
185			      $itemTypeNames[2]),
186			  'params' => array('view' => 'core.ItemAdmin',
187					    'subView' => 'core.ItemMove',
188					    'itemId' => $item->getParentId(),
189					    'selectedId' => $itemId,
190					    'return' => 1));
191	    }
192
193	    if (isset($wantsDetailedLinks[$itemId]) && $isAlbum
194		    && isset($permissions[$itemId]['core.edit']) && !empty($childCounts[$itemId])
195		    && $childCounts[$itemId] > 0) {
196		$link = array('text' => $this->_translate('Edit Captions'),
197			      'params' => array('view' => 'core.ItemAdmin',
198						'subView' => 'core.ItemEditCaptions',
199						'itemId' => $itemId,
200						'return' => 1));
201		list ($thisItemId, $thisPage) =
202		    GalleryUtilities::getRequestVariables('itemId', 'page');
203		if (!empty($thisItemId) && !empty($thisPage) && $thisItemId == $item->getId()) {
204		    $link['params']['albumPage'] = $thisPage;
205		}
206		$links[$itemId][] = $link;
207	    }
208
209	    if (!$isRoot && isset($thumbTable[$itemId]) && isset($parentPermissions['core.edit'])) {
210		$links[$itemId][] =
211		    array('text' => $this->_translate('Make Highlight'),
212			  'params' => array('view' => 'core.ItemAdmin',
213					    'subView' => 'core.ItemMakeHighlight',
214					    'itemId' => $itemId,
215					    'return' => 1));
216	    }
217
218	    if ($isAlbum && isset($permissions[$itemId]['core.edit'])
219		    && !empty($childCounts[$itemId]) && $childCounts[$itemId] > 1) {
220		$links[$itemId][] =
221		    array('text' => $this->_translate('Reorder Items'),
222			  'params' => array('view' => 'core.ItemAdmin',
223					    'subView' => 'core.ItemReorder',
224					    'itemId' => $itemId,
225					    'return' => 1));
226	    }
227
228	    if (isset($wantsDetailedLinks[$itemId]) && $isAlbum
229		    && isset($permissions[$itemId]['core.edit']) && !empty($childCounts[$itemId])
230		    && $childCounts[$itemId] > 0) {
231	    	$next = next($items);
232		$params = array('view' => 'core.ItemAdmin',
233				'subView' => 'core.ItemDelete',
234				'itemId' => $itemId,
235				'return' => 1);
236		/* First item on the page will be in the list for deletion */
237		if ($next) {
238		    $params['anchorId'] = $next->getId();
239		}
240
241		$links[$itemId][] = array('text' => $this->_translate('Delete Items'),
242					  'params' => $params);
243	    }
244	}
245
246	return array(null, $links);
247    }
248
249    /**
250     * @see GalleryModule::getSystemLinks
251     */
252    function getSystemLinks() {
253	global $gallery;
254
255	list ($ret, $param) = GalleryCoreApi::fetchAllPluginParameters('module', 'core');
256	if ($ret) {
257	    return array($ret, null);
258	}
259
260	$links = array();
261	list ($ret, $isAdmin) = GalleryCoreApi::isUserInSiteAdminGroup();
262	if ($ret) {
263	    return array($ret, null);
264	}
265
266	if ($isAdmin) {
267	    $links['SiteAdmin'] = array('text' => $this->translate('Site Admin'),
268					'params' => array('view' => 'core.SiteAdmin',
269							  'return' => 1));
270	}
271
272	if ($gallery->getConfig('login')) {
273	    list ($ret, $isAnonymous) = GalleryCoreApi::isAnonymousUser();
274	    if ($ret) {
275		return array($ret, null);
276	    }
277	    if ($isAnonymous) {
278		$links['Login'] = array('text' => $this->translate('Login'),
279					'params' => array('view' => 'core.UserAdmin',
280							  'subView' => 'core.UserLogin',
281							  'return' => 1));
282	    } else {
283		$user = $gallery->getActiveUser();
284		$links['YourAccount'] = array('text' => $this->translate('Your Account'),
285					      'params' => array('view' => 'core.UserAdmin',
286								'subView' => 'core.UserPreferences',
287								'return' => 1));
288		$links['Logout'] = array('text' => $this->translate('Logout'),
289					 'params' => array('controller' => 'core.Logout',
290							   'return' => 1));
291	    }
292	}
293
294	return array(null, $links);
295    }
296
297    /**
298     * @see GalleryModule::getSiteAdminViews
299     */
300    function getSiteAdminViews() {
301	$data = array(array('name' => $this->translate('General'),
302			    'view' => 'core.AdminCore'),
303		      array('name' => $this->translate('Plugins'),
304			    'view' => 'core.AdminPlugins'),
305		      array('name' => $this->translate('Users'),
306			    'view' => 'core.AdminUsers'),
307		      array('name' => $this->translate('Groups'),
308			    'view' => 'core.AdminGroups'),
309		      array('name' => $this->translate('Maintenance'),
310			    'view' => 'core.AdminMaintenance'),
311		      array('name' => $this->translate('Themes'),
312			    'view' => 'core.AdminThemes'),
313		      array('name' => $this->translate('Performance'),
314			    'view' => 'core.AdminPerformance'),
315		      array('name' => $this->translate('Event Logs'),
316			    'view' => 'core.AdminEventLogViewer'),
317		      array('name' => $this->translate('Language Settings'),
318			    'view' => 'core.AdminLanguageManager'),
319		      );
320
321	list ($ret, $list) = GalleryCoreApi::getRedundantToolkitPriorities();
322	if ($ret) {
323	    return array($ret, null);
324	}
325	if (!empty($list)) {
326	    $data[] = array('name' => $this->translate('Toolkit Priority'),
327			    'view' => 'core.AdminToolkitPriority',
328			    'group' => 'toolkits',
329			    'groupLabel' => $this->translate('Graphics Toolkits'));
330	}
331
332	return array(null, $data);
333    }
334
335    /**
336     * @see GalleryModule::getUserAdminViews
337     */
338    function getUserAdminViews($user) {
339	global $gallery;
340	$views = array();
341
342	if ($gallery->getConfig('login')) {
343	    list ($ret, $isAnonymous) = GalleryCoreApi::isAnonymousUser($user->getId());
344	    if ($ret) {
345		return array($ret, null);
346	    }
347
348	    if (!$isAnonymous) {
349		if (!$user->isLocked()) {
350		    $views[] = array('name' => $this->translate('Account Settings'),
351				     'view' => 'core.UserPreferences');
352		    $views[] = array('name' => $this->translate('Change Password'),
353				     'view' => 'core.UserChangePassword');
354		}
355	    } else {
356		$views[] = array('name' => $this->translate('Login'),
357				 'view' => 'core.UserLogin');
358	    }
359	}
360
361	return array(null, $views);
362    }
363
364    /**
365     * @see GalleryModule::getItemAdminViews
366     */
367    function getItemAdminViews($item) {
368	global $gallery;
369
370	$views = array();
371	list ($ret, $permissions) = GalleryCoreApi::getPermissions($item->getId());
372	if ($ret) {
373	    return array($ret, null);
374	}
375
376	$childCount = 0;
377	$isAlbum = $item->getCanContainChildren();
378	if ($isAlbum) {
379	    list ($ret, $childCounts) = GalleryCoreApi::fetchChildCounts(array($item->getId()));
380	    if ($ret) {
381		return array($ret, null);
382	    }
383	    $childCount = empty($childCounts[$item->getId()]) ? 0 : $childCounts[$item->getId()];
384	}
385
386	/* Fetch thumbnail ids */
387	list ($ret, $thumbTable) =
388	    GalleryCoreApi::fetchThumbnailsByItemIds(array($item->getId()));
389	if ($ret) {
390	    return array($ret, null);
391	}
392	$hasThumb = !empty($thumbTable[$item->getId()]);
393
394	$parentId = $item->getParentId();
395	list ($ret, $parentPermissions) = GalleryCoreApi::getPermissions($parentId);
396	if ($ret) {
397	    return array($ret, null);
398	}
399
400	list ($ret, $rootId) = GalleryCoreApi::getPluginParameter('module', 'core', 'id.rootAlbum');
401	if ($ret) {
402	    return array($ret, null);
403	}
404
405	$itemTypeNames = array_merge($item->itemTypeName(), $item->itemTypeName(false));
406	if (isset($permissions['core.edit'])) {
407	    if ($isAlbum && $childCount > 1) {
408		$views[] = array('name' => $this->_translate('Reorder Items'),
409				 'view' => 'core.ItemReorder');
410	    }
411	    if ($isAlbum && $childCount > 0) {
412		$views[] = array('name' => $this->_translate('Edit Captions'),
413				 'view' => 'core.ItemEditCaptions');
414	    }
415
416	    /* Edit view for all item types */
417	    $views[] = array('name' => $this->_translate(
418				  array('text' => 'Edit %s', 'arg1' => $itemTypeNames[0]),
419				  $itemTypeNames[2]),
420			     'view' => 'core.ItemEdit');
421	    $views[] = array('name' => isset($permissions['core.changePermissions'])
422				 ? $this->_translate('Edit Permissions')
423				 : $this->_translate('View Permissions'),
424			     'view' => 'core.ItemPermissions');
425	}
426
427	if (!empty($parentId) && $hasThumb && isset($parentPermissions['core.edit'])) {
428	    $views[] = array('name' => $this->_translate('Make Highlight'),
429			     'view' => 'core.ItemMakeHighlight');
430	}
431
432	if (isset($permissions['core.delete'])) {
433	    $itemId = $item->getId();
434	    if ($itemId != $rootId) {
435		if (!function_exists('smarty_modifier_escape')) {
436		    GalleryCoreApi::requireOnce('lib/smarty/plugins/modifier.escape.php');
437		}
438                $title = smarty_modifier_escape(GalleryUtilities::markup(
439		    $item->getTitle(), 'strip'), 'javascript', 'UTF-8');
440		/* This is ItemAdmin view, hence page item is the one we are deleting */
441		$thisItemId = $itemId;
442		$urlGenerator =& $gallery->getUrlGenerator();
443		$url = $urlGenerator->generateUrl(
444		    array('controller' => 'core.ItemDeleteSingle', 'itemId' => $itemId,
445			  'pageId' => $thisItemId));
446		$moreUrl = $isAlbum ? '' : $urlGenerator->generateUrl(
447		    array('view' => 'core.ItemAdmin', 'subView' => 'core.ItemDelete',
448			  'itemId' => $item->getParentId(),
449			  'selectedId' => $itemId));
450		$views[] = array('name' => $this->_translate(
451		    array('text' => 'Delete %s', 'arg1' => $itemTypeNames[0]), $itemTypeNames[2]),
452		    'view' => 'core.ItemDeleteSingle', /* just for g->linkId used by icons */
453		    'script' => "core_confirmDelete('$url', '$moreUrl', '$title');return false");
454
455		$views[] = array('name' => $this->_translate(
456		     array('text' => 'Move %s', 'arg1' => $itemTypeNames[0]),
457		     $itemTypeNames[2]), 'view' => 'core.ItemMoveSingle');
458	    }
459	    if ($isAlbum && $childCount > 0) {
460		$views[] = array('name' => $this->_translate('Delete Items'),
461		    		 'view' => 'core.ItemDelete');
462	    }
463	}
464
465	if (isset($permissions['core.addDataItem']) && $isAlbum) {
466	    $views[] = array('name' => $this->_translate('Add Items'),
467			     'view' => 'core.ItemAdd');
468	}
469
470	if (isset($permissions['core.addAlbumItem']) && $isAlbum) {
471	    $views[] = array('name' => $this->_translate('Add Album'),
472			     'view' => 'core.ItemAddAlbum');
473	}
474
475	return array(null, $views);
476    }
477
478    /**
479     * We pushed all this code into its own file since we need it very rarely so it doesn't make
480     * sense to load it every single time.
481     *
482     * @see GalleryModule::install
483     */
484    function upgrade($currentVersion, $statusMonitor) {
485	GalleryCoreApi::requireOnce('modules/core/CoreModuleExtras.inc');
486	$ret = CoreModuleExtras::upgrade($this, $currentVersion, $statusMonitor);
487	if ($ret) {
488	    return $ret;
489	}
490	return null;
491    }
492
493    /**
494     * Set the current version of Gallery.
495     */
496    function setGalleryVersion($version) {
497	$this->_galleryVersion = $version;
498    }
499
500    /**
501     * Get the current version of Gallery.
502     */
503    function getGalleryVersion() {
504	return $this->_galleryVersion;
505    }
506
507    /**
508     * Get the version of the core module and of Gallery itself.  We store this on disk to avoid
509     * having to load up the database (which can be problematic if we're doing an upgrade and don't
510     * want to count a specific database schema). If the versions.dat file indicates that Gallery
511     * is in maintenance mode, then set the configuration value to indicate this.
512     *
513     * @return array 'core' => core module version, 'gallery' => gallery version
514     * @static
515     */
516    function getInstalledVersions() {
517	global $gallery;
518
519	if (GalleryDataCache::containsKey('CoreModule::installedVersions')) {
520	    $versions = GalleryDataCache::get('CoreModule::installedVersions');
521	} else {
522	    $platform =& $gallery->getPlatform();
523	    $versionFile = $gallery->getConfig('data.gallery.version');
524
525	    if ($platform->file_exists($versionFile)) {
526		$versionArray = $platform->file($versionFile);
527		if (count($versionArray) >= 2) {
528		    $versions['core'] = rtrim($versionArray[0]);
529		    $versions['gallery'] = rtrim($versionArray[1]);
530		    GalleryDataCache::put('CoreModule::installedVersions', $versions, true);
531		    if (isset($versionArray[2])) {
532		    	$maintenanceMode = explode(':', rtrim($versionArray[2]), 2);
533		    	if ($maintenanceMode[0] == 'maintenance-mode') {
534			    $newMode = empty($maintenanceMode[1]) ? true : $maintenanceMode[1];
535			    $gallery->setConfig('mode.maintenance', $newMode);
536			}
537		    }
538		}
539	    } else {
540	    	/*
541	    	 * If we get here we are probably doing a fresh install so just return 0, 0 and
542	    	 * the rest of the install should work properly.
543	    	 */
544	    	$versions = array('core' => 0, 'gallery' => 0);
545	    }
546	}
547
548	return $versions;
549    }
550
551    /**
552     * @see GalleryModule::performFactoryRegistrations
553     */
554    function performFactoryRegistrations() {
555	GalleryCoreApi::requireOnce('modules/core/CoreModuleExtras.inc');
556	$ret = CoreModuleExtras::performFactoryRegistrations($this);
557	if ($ret) {
558	    return $ret;
559	}
560	return null;
561    }
562}
563?>
564