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 * This controller will handle moving an item from one album to another. 23 * @package GalleryCore 24 * @subpackage UserInterface 25 * @author Bharat Mediratta <bharat@menalto.com> 26 * @version $Revision: 17580 $ 27 */ 28class ItemMoveSingleController extends GalleryController { 29 30 /** 31 * @see GalleryController::handleRequest 32 */ 33 function handleRequest($form) { 34 global $gallery; 35 36 list ($ret, $item) = $this->getItem(); 37 if ($ret) { 38 return array($ret, null); 39 } 40 $itemId = $item->getId(); 41 42 $status = $error = array(); 43 44 if (isset($form['action']['move'])) { 45 if (empty($form['destination'])) { 46 $error[] = 'form[error][destination][empty]'; 47 } 48 49 $ret = GalleryCoreApi::assertHasItemPermission($itemId, 'core.delete'); 50 if ($ret) { 51 return array($ret, null); 52 } 53 54 if (empty($error)) { 55 $newParentId = $form['destination']; 56 57 /* 58 * Assert that our permissions are correct. The view should never try to make a 59 * move that isn't legal so we can just bail if there's an inconsistency. 60 */ 61 list ($ret, $canView) = 62 GalleryCoreApi::hasItemPermission($newParentId, 'core.view'); 63 if ($ret) { 64 return array($ret, null); 65 } 66 if (!$canView) { 67 /* Avoid information disclosure, act as if the item didn't exist. */ 68 return array(GalleryCoreApi::error(ERROR_MISSING_OBJECT), null); 69 } 70 if (GalleryUtilities::isA($item, 'GalleryDataItem')) { 71 $ret = GalleryCoreApi::assertHasItemPermission($newParentId, 72 'core.addDataItem'); 73 if ($ret) { 74 return array($ret, null); 75 } 76 } else if (GalleryUtilities::isA($item, 'GalleryAlbumItem')) { 77 $ret = GalleryCoreApi::assertHasItemPermission($newParentId, 78 'core.addAlbumItem'); 79 if ($ret) { 80 return array($ret, null); 81 } 82 } else { 83 /* The view should never let this happen */ 84 return array(GalleryCoreApi::error(ERROR_BAD_DATA_TYPE), 85 null); 86 } 87 } 88 89 /* Make sure the destination is the right type of item */ 90 if (empty($error)) { 91 list ($ret, $newParent) = 92 GalleryCoreApi::loadEntitiesById($newParentId, 'GalleryAlbumItem'); 93 if ($ret) { 94 return array($ret, null); 95 } 96 } 97 98 /* Make sure we don't have recursive moves */ 99 if (empty($error)) { 100 list ($ret, $newParentAncestorIds) = 101 GalleryCoreApi::fetchParentSequence($newParentId); 102 if ($ret) { 103 return array($ret, null); 104 } 105 106 if ($itemId == $newParentId || in_array($itemId, $newParentAncestorIds)) { 107 $error[] = 'form[error][destination][selfMove]'; 108 } 109 } 110 111 if (empty($error)) { 112 /* 113 * Read lock both parent hierarchies 114 * TODO: Optimize this 115 */ 116 list ($ret, $lockIds[]) = GalleryCoreApi::acquireReadLockParents($newParentId); 117 if ($ret) { 118 return array($ret, null); 119 } 120 121 $oldParentId = $item->getParentId(); 122 list ($ret, $lockIds[]) = GalleryCoreApi::acquireReadLockParents($oldParentId); 123 if ($ret) { 124 GalleryCoreApi::releaseLocks($lockIds); 125 return array($ret, null); 126 } 127 128 list ($ret, $lockIds[]) = 129 GalleryCoreApi::acquireReadLock(array($newParentId, $oldParentId)); 130 if ($ret) { 131 GalleryCoreApi::releaseLocks($lockIds); 132 return array($ret, null); 133 } 134 135 /* Write lock the item we're moving */ 136 list ($ret, $lockIds[]) = GalleryCoreApi::acquireWriteLock($itemId); 137 if ($ret) { 138 GalleryCoreApi::releaseLocks($lockIds); 139 return array($ret, null); 140 } 141 142 /* Refresh the item in case it changed before it was locked */ 143 list ($ret, $item) = $item->refresh(); 144 if ($ret) { 145 GalleryCoreApi::releaseLocks($lockIds); 146 return array($ret, null); 147 } 148 149 /* Do the move */ 150 $ret = $item->move($newParentId); 151 if ($ret) { 152 GalleryCoreApi::releaseLocks($lockIds); 153 return array($ret, null); 154 } 155 156 $ret = $item->save(); 157 if ($ret) { 158 GalleryCoreApi::releaseLocks($lockIds); 159 return array($ret, null); 160 } 161 162 if (GalleryUtilities::isA($item, 'GalleryDataItem')) { 163 /* Update for derivative preferences of new parent */ 164 $ret = GalleryCoreApi::addExistingItemToAlbum($item, $newParentId); 165 if ($ret) { 166 GalleryCoreApi::releaseLocks($lockIds); 167 return array($ret, null); 168 } 169 } 170 171 /* Release all locks */ 172 $ret = GalleryCoreApi::releaseLocks($lockIds); 173 if ($ret) { 174 return array($ret, null); 175 } 176 177 /* Fix thumbnail integrity */ 178 list ($ret, $success) = GalleryCoreApi::guaranteeAlbumHasThumbnail($oldParentId); 179 if ($ret) { 180 return array($ret, null); 181 } 182 183 $status['moved'] = 1; 184 185 /* Figure out where to redirect upon success */ 186 $redirect['view'] = 'core.ItemAdmin'; 187 $redirect['subView'] = 'core.ItemMoveSingle'; 188 $redirect['itemId'] = $itemId; 189 } 190 } 191 192 if (!empty($redirect)) { 193 $results['redirect'] = $redirect; 194 } else { 195 $results['delegate']['view'] = 'core.ItemAdmin'; 196 $results['delegate']['subView'] = 'core.ItemMoveSingle'; 197 } 198 $results['status'] = $status; 199 $results['error'] = $error; 200 201 return array(null, $results); 202 } 203} 204 205/** 206 * This view will prompt for the destination of moving this item 207 */ 208class ItemMoveSingleView extends GalleryView { 209 210 /** 211 * @see GalleryView::loadTemplate 212 * @todo Scalability - Don't load all album-items into memory. Need a way to load the items 213 * incrementally, e.g. with an AJAX-powered tree widget. 214 */ 215 function loadTemplate(&$template, &$form) { 216 global $gallery; 217 218 /* itemId is the album where we want to move items from */ 219 list ($ret, $item) = $this->getItem(); 220 if ($ret) { 221 return array($ret, null); 222 } 223 $itemId = $item->getId(); 224 225 if ($form['formName'] != 'ItemMoveSingle') { 226 /* First time around, load the form with item data */ 227 $form['destination'] = ''; 228 $form['formName'] = 'ItemMoveSingle'; 229 } 230 231 if (GalleryUtilities::isA($item, 'GalleryDataItem')) { 232 $permissions = 'core.addDataItem'; 233 } else if (GalleryUtilities::isA($item, 'GalleryAlbumItem')) { 234 $permissions = 'core.addAlbumItem'; 235 } else { 236 return array(GalleryCoreApi::error(ERROR_BAD_DATA_TYPE), null); 237 } 238 $permissions = array($permissions, 'core.view'); 239 240 /* Get ids of all all albums where we can add this items */ 241 list ($ret, $albumIds) = GalleryCoreApi::fetchAllItemIds('GalleryAlbumItem', $permissions); 242 if ($ret) { 243 return array($ret, null); 244 } 245 246 /* Load all the album entities */ 247 list ($ret, $albums) = GalleryCoreApi::loadEntitiesById($albumIds, 'GalleryAlbumItem'); 248 if ($ret) { 249 return array($ret, null); 250 } 251 252 $albumTree = GalleryUtilities::createAlbumTree($albums); 253 254 $ItemMoveSingle = array(); 255 $ItemMoveSingle['albumTree'] = $albumTree; 256 $ItemMoveSingle['itemTypeNames'] = $item->itemTypeName(); 257 258 $template->setVariable('ItemMoveSingle', $ItemMoveSingle); 259 $template->setVariable('controller', 'core.ItemMoveSingle'); 260 $template->javascript('lib/yui/yahoo-dom-event.js'); 261 $template->javascript('lib/yui/container-min.js'); 262 $template->javascript('lib/yui/treeview-min.js'); 263 $template->style('modules/core/data/tree.css'); 264 return array(null, array('body' => 'modules/core/templates/ItemMoveSingle.tpl')); 265 } 266 267 /** 268 * @see GalleryView::getViewDescription 269 */ 270 function getViewDescription() { 271 list ($ret, $core) = GalleryCoreApi::loadPlugin('module', 'core'); 272 if ($ret) { 273 return array($ret, null); 274 } 275 276 list ($ret, $item) = $this->getItem(); 277 if ($ret) { 278 return array($ret, null); 279 } 280 281 $itemTypeNames = $item->itemTypeName(true); 282 283 return array(null, 284 $core->translate(array('text' => 'move %s', 'arg1' => $itemTypeNames[1]))); 285 } 286} 287?> 288