Index: trunk/core/units/general/cat_event_handler.php =================================================================== diff -u -N -r5505 -r6093 --- trunk/core/units/general/cat_event_handler.php (.../cat_event_handler.php) (revision 5505) +++ trunk/core/units/general/cat_event_handler.php (.../cat_event_handler.php) (revision 6093) @@ -13,9 +13,13 @@ { parent::mapPermissions(); $permissions = Array( - 'OnExport' => Array('self' => 'view|advanced:export'), - 'OnExportBegin' => Array('self' => 'view|advanced:export'), - 'OnSaveSettings' => Array('self' => 'add|edit|advanced:import'), + 'OnExport' => Array('self' => 'view|advanced:export'), + 'OnExportBegin' => Array('self' => 'view|advanced:export'), + 'OnSaveSettings' => Array('self' => 'add|edit|advanced:import'), + 'OnBeforeDeleteOriginal' => Array('self' => 'edit|advanced:approve'), + + 'OnCancelAction' => Array( 'self' => true), + ); $this->permMapping = array_merge($this->permMapping, $permissions); } @@ -45,100 +49,100 @@ $this->Application->StoreVar('m_cat_id', $root_category); } + if ($event->Name == 'OnEdit' || $event->Name == 'OnSave') { + // check each id from selected individually and only if all are allowed proceed next + if ($event->Name == 'OnEdit') { + $selected_ids = implode(',', $this->StoreSelectedIDs($event)); + } + else { + $selected_ids = $this->Application->RecallVar($event->getPrefixSpecial().'_selected_ids'); + } + + $id_field = $this->Application->getUnitOption($event->Prefix, 'IDField'); + $table_name = $this->Application->getUnitOption($event->Prefix, 'TableName'); + $sql = 'SELECT '.$id_field.', CreatedById, ci.CategoryId + FROM '.$table_name.' item_table + LEFT JOIN '.$this->Application->getUnitOption('ci', 'TableName').' ci ON ci.ItemResourceId = item_table.ResourceId + WHERE '.$id_field.' IN ('.$selected_ids.') AND (ci.PrimaryCat = 1)'; + $items = $this->Conn->Query($sql, $id_field); + + $perm_value = true; + $perm_helper =& $this->Application->recallObject('PermissionsHelper'); + foreach ($items as $item_id => $item_data) { + if ($perm_helper->ModifyCheckPermission($item_data['CreatedById'], $item_data['CategoryId'], $event->Prefix) == 0) { + // one of items selected has no permission + $perm_value = false; + break; + } + } + + if (!$perm_value) { + $event->status = erPERM_FAIL; + } + + return $perm_value; + } + return parent::CheckPermission($event); } + /** + * Add selected items to clipboard with mode = COPY (CLONE) + * + * @param kEvent $event + */ function OnCopy(&$event) { - $object = $event->getObject(); - $this->StoreSelectedIDs($event); - $ids = $this->getSelectedIDs($event); - $this->Application->StoreVar($event->getPrefixSpecial().'_clipboard', implode(',', $ids)); - $this->Application->StoreVar($event->getPrefixSpecial().'_clipboard_mode', 'copy'); - - $this->Application->StoreVar('ClipBoard', 'COPY-0.'.$object->TableName.'.ResourceId=0'); - $event->redirect_params = Array('opener' => 's', 'pass_events'=>true); //do not go up - STAY + $this->Application->RemoveVar('clipboard'); + $clipboard_helper =& $this->Application->recallObject('ClipboardHelper'); + $clipboard_helper->setClipboard($event, 'copy', $this->StoreSelectedIDs($event)); } + /** + * Add selected items to clipboard with mode = CUT + * + * @param kEvent $event + */ function OnCut(&$event) { - $object = $event->getObject(); - $this->StoreSelectedIDs($event); - $ids = $this->getSelectedIDs($event); - $this->Application->StoreVar($event->getPrefixSpecial().'_clipboard', implode(',', $ids)); - $this->Application->StoreVar($event->getPrefixSpecial().'_clipboard_mode', 'cut'); - - $this->Application->StoreVar('ClipBoard', 'CUT-0.'.$object->TableName.'.ResourceId=0'); - $event->redirect_params = Array('opener' => 's', 'pass_events'=>true); //do not go up - STAY + $this->Application->RemoveVar('clipboard'); + $clipboard_helper =& $this->Application->recallObject('ClipboardHelper'); + $clipboard_helper->setClipboard($event, 'cut', $this->StoreSelectedIDs($event)); } + /** + * Performs category item paste + * + * @param kEvent $event + */ function OnPaste(&$event) { - $ids = $this->Application->RecallVar($event->getPrefixSpecial().'_clipboard'); - if ($ids == '') { - $event->redirect = false; + if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) { return; } - $ids_arr = explode(',', $ids); + $clipboard_data = $event->getEventParam('clipboard_data'); - if ($this->Application->RecallVar($event->getPrefixSpecial().'_clipboard_mode') == 'copy') { - $temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler'); + if (!$clipboard_data['cut'] && !$clipboard_data['copy']) { + return false; + } - if ($ids_arr) { - $temp->CloneItems($event->Prefix, $event->Special, $ids_arr); - } + if ($clipboard_data['copy']) { + $temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler'); + $temp->CloneItems($event->Prefix, $event->Special, $clipboard_data['copy']); } - else { // mode == cut + + if ($clipboard_data['cut']) { $object =& $this->Application->recallObject($event->getPrefixSpecial().'.item', $event->Prefix, Array('skip_autoload' => true)); - foreach ($ids_arr as $id) { + foreach ($clipboard_data['cut'] as $id) { $object->Load($id); $object->MoveToCat(); } } - $event->status = erSUCCESS; } /** - * Occurs when pasting category - * - * @param kEvent $event - */ - function OnCatPaste(&$event) - { - $inp_clipboard = $this->Application->RecallVar('ClipBoard'); - $inp_clipboard = explode('-', $inp_clipboard, 2); - - if($inp_clipboard[0] == 'COPY') - { - $saved_cat_id = $this->Application->GetVar('m_cat_id'); - $cat_ids = $event->getEventParam('cat_ids'); - - $id_field = $this->Application->getUnitOption($event->Prefix, 'IDField'); - $table = $this->Application->getUnitOption($event->Prefix, 'TableName'); - $ids_sql = 'SELECT '.$id_field.' FROM '.$table.' WHERE ResourceId IN (%s)'; - $resource_ids_sql = 'SELECT ItemResourceId FROM '.TABLE_PREFIX.'CategoryItems WHERE CategoryId = %s AND PrimaryCat = 1'; - - $object =& $this->Application->recallObject($event->Prefix.'.item', $event->Prefix, Array('skip_autoload' => true)); - - foreach($cat_ids as $source_cat => $dest_cat) - { - $item_resource_ids = $this->Conn->GetCol( sprintf($resource_ids_sql, $source_cat) ); - if(!$item_resource_ids) continue; - - $this->Application->SetVar('m_cat_id', $dest_cat); - $item_ids = $this->Conn->GetCol( sprintf($ids_sql, implode(',', $item_resource_ids) ) ); - - $temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler'); - if($item_ids) $temp->CloneItems($event->Prefix, $event->Special, $item_ids); - } - - $this->Application->SetVar('m_cat_id', $saved_cat_id); - } - } - - /** * Return type clauses for list bulding on front * * @param kEvent $event @@ -314,20 +318,46 @@ } // add permission filter - $view_perm = 1; - $object->addFilter('perm_filter', 'perm.PermId = '.$view_perm); + if ($this->Application->GetVar('u_id') == -1) { + // for "root" CATEGORY.VIEW permission is checked for items lists too + $view_perm = 1; + } + else { + // for any real user itemlist view permission is checked instead of CATEGORY.VIEW + $sql = 'SELECT PermissionConfigId + FROM '.TABLE_PREFIX.'PermissionConfig + WHERE PermissionName = "'.$this->Application->getUnitOption($event->Prefix, 'PermItemPrefix').'.VIEW"'; + $view_perm = $this->Conn->GetOne($sql); - if ( !$this->Application->IsAdmin() ) - { $groups = explode( ',', $this->Application->RecallVar('UserGroups') ); foreach($groups as $group) { $view_filters[] = 'FIND_IN_SET('.$group.', perm.acl)'; } $view_filter = implode(' OR ', $view_filters); $object->addFilter('perm_filter2', $view_filter); + } + + $object->addFilter('perm_filter', 'perm.PermId = '.$view_perm); + + if ( !$this->Application->IsAdmin() ) + { $object->addFilter('status_filter', $object->TableName.'.Status = 1'); + if ($this->Application->getUnitOption($event->Prefix, 'UsePendingEditing')) { + // if category item uses pending editing abilities, then in no cases show pending copies on front + $object->addFilter('original_filter', '%1$s.OrgId = 0 OR %1$s.OrgId IS NULL'); + } } + else { + if ($this->Application->getUnitOption($event->Prefix, 'UsePendingEditing')) { + $pending_ids = $this->Conn->GetCol( + 'SELECT OrgId FROM '.$object->TableName.' + WHERE Status = -2 AND OrgId IS NOT NULL'); + if ($pending_ids) { + $object->addFilter('no_original_filter', '%1$s.'.$object->IDField.' NOT IN ('.implode(',', $pending_ids).')'); + } + } + } $types = $event->getEventParam('types'); $except_types = $event->getEventParam('except'); @@ -428,6 +458,8 @@ { $this->prepareItemStatuses($event); + $object->addCalculatedField('CachedNavbar', 'l'.$this->Application->GetVar('m_lang').'_CachedNavbar'); + if ($event->Special == 'export' || $event->Special == 'import') { $this->prepareExportColumns($event); @@ -507,14 +539,20 @@ */ function OnBeforeItemUpdate(&$event) { + $property_map = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings'); + if (!$property_map) { + return; + } + $click_field = $property_map['ClickField']; + $object =& $event->getObject(); - if( $this->Application->IsAdmin() && ($this->Application->GetVar('Hits_original') !== false) && - floor($this->Application->GetVar('Hits_original')) != $object->GetDBField('Hits') ) + if( $this->Application->IsAdmin() && ($this->Application->GetVar($click_field.'_original') !== false) && + floor($this->Application->GetVar($click_field.'_original')) != $object->GetDBField($click_field) ) { - $sql = 'SELECT MAX(Hits) FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').' - WHERE FLOOR(Hits) = '.$object->GetDBField('Hits'); - $hits = ( $res = $this->Conn->GetOne($sql) ) ? $res + 0.000001 : $object->GetDBField('Hits'); - $object->SetDBField('Hits', $hits); + $sql = 'SELECT MAX('.$click_field.') FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').' + WHERE FLOOR('.$click_field.') = '.$object->GetDBField($click_field); + $hits = ( $res = $this->Conn->GetOne($sql) ) ? $res + 0.000001 : $object->GetDBField($click_field); + $object->SetDBField($click_field, $hits); } } @@ -526,8 +564,8 @@ function OnAfterItemLoad(&$event) { $special = substr($event->Special, -6); + $object =& $event->getObject(); if ($special == 'import' || $special == 'export') { - $object =& $event->getObject(); $image_data = $object->getPrimaryImageData(); if ($image_data) { @@ -544,6 +582,16 @@ } } + //substituiting pending status value for pending editing + if ($object->HasField('OrgId') && $object->GetDBField('OrgId') > 0 && $object->GetDBField('Status') == -2) { + $options = $object->Fields['Status']['options']; + foreach ($options as $key => $val) { + if ($key == 2) $key = -2; + $new_options[$key] = $val; + } + $object->Fields['Status']['options'] = $new_options; + } + } function OnAfterItemUpdate(&$event) @@ -664,7 +712,14 @@ // processing multilingual fields if (getArrayValue($options, 'formatter') == 'kMultiLanguage') { + $field_list[$key.'_primary'] = 'l'.$this->Application->GetDefaultLanguageId().'_'.$field; $field_list[$key] = 'l'.$lang.'_'.$field; + + if(!isset($search_config[$field]['ForeignField'])) + { + $field_list[$key.'_primary'] = $local_table.'.'.$field_list[$key.'_primary']; + $search_config_map[ $field_list[$key.'_primary'] ] = $field; + } } // processing fields from other tables @@ -739,11 +794,11 @@ $revelance_parts = Array(); reset($search_config); foreach ($field_list as $field) { - $config_elem = each($search_config); - $weight = $search_config[ $search_config_map[$field] ]['Priority']; + $config_elem = $search_config[ $search_config_map[$field] ]; + $weight = $config_elem['Priority']; $revelance_parts[] = 'IF('.$field.' LIKE "%'.implode(' ', $positive_words).'%", '.$weight_sum.', 0)'; foreach ($positive_words as $keyword) { - $revelance_parts[] = 'IF('.$field.' LIKE "%'.$keyword.'%", '.$config_elem['value']['Priority'].', 0)'; + $revelance_parts[] = 'IF('.$field.' LIKE "%'.$keyword.'%", '.$weight.', 0)'; } } $rel_keywords = $this->Application->ConfigValue('SearchRel_Keyword_products') / 100; @@ -1290,7 +1345,6 @@ $event->redirect = $this->getModuleFolder($event).'/export'; $redirect_params = Array( 'm_opener' => 'd', - 'index_file' => 'index4.php', $this->Prefix.'.export_event' => 'OnNew', 'pass' => 'all,'.$this->Prefix.'.export'); @@ -1570,24 +1624,6 @@ } /** - * Shows export dialog - * - * @param kEvent $event - */ - function OnImport(&$event) - { - - $event->redirect = $this->getModuleFolder($event).'/import'; - - $redirect_params = Array( 'm_opener' => 'd', - 'index_file' => 'index4.php', - $this->Prefix.'.import_event' => 'OnNew', - 'pass' => 'all,'.$this->Prefix.'.import'); - - $event->setRedirectParams($redirect_params); - } - - /** * Prepares item for import/export operations * * @param kEvent $event @@ -1632,27 +1668,28 @@ } /** - * Saves selected category as new import category + * Process items selected in item_selector * * @param kEvent $event */ - function OnSelectItems(&$event) + function OnProcessSelected(&$event) { + $selected_ids = $this->Application->GetVar('selected_ids'); + $dst_field = $this->Application->RecallVar('dst_field'); - $items_info = $this->Application->GetVar('c'); - if ($items_info) { - $category_id = array_shift( array_keys($items_info) ); - $sql = 'SELECT CategoryId - FROM '.TABLE_PREFIX.'Category - WHERE ResourceId = '.$category_id; - $category_id = $this->Conn->GetOne($sql); + + if ($dst_field == 'ItemCategory') { + // Item Edit -> Categories Tab -> New Categories + $object =& $event->getObject(); + $category_ids = explode(',', $selected_ids['c']); + foreach ($category_ids as $category_id) { + $object->assignToCategory($category_id); + } } - else { - $category_id = 0; - } if ($dst_field == 'ImportCategory') { - $this->Application->StoreVar('ImportCategory', $category_id); + // Tools -> Import -> Item Import -> Select Import Category + $this->Application->StoreVar('ImportCategory', $selected_ids['c']); $this->Application->StoreVar($event->getPrefixSpecial().'_ForceNotValid', 1); // not to loose import/export values on form refresh $this->Application->SetVar($event->getPrefixSpecial().'_id', 0); @@ -1663,22 +1700,6 @@ $event->setEventParam('pass_events', true); } - if ($dst_field == 'ItemCategory') { - $object =& $event->getObject(); // category item object (e.g. link, product, etc.) - - $object->assignToCategory($category_id); - - /*$ci_prefix = $object->Prefix.'-ci'; - $ci_object =& $this->Application->recallObject($ci_prefix, null, Array('skip_autoload' => true)); - - $ci_object->Load($category_id); - if (!$ci_object->isLoaded()) { - $fields_hash = Array('CategoryId' => $category_id, 'ItemResourceId' => $object->GetDBField('ResourceId')); - $ci_object->SetDBFieldsFromHash($fields_hash); - $ci_object->Create(true); - }*/ - } - $this->finalizePopup($event); } @@ -1713,6 +1734,160 @@ /* === RELATED TO IMPORT/EXPORT: END === */ + /** + * Stores item's owner login into separate field together with id + * + * @param kEvent $event + * @param string $id_field + * @param string $cached_field + */ + function cacheItemOwner(&$event, $id_field, $cached_field) + { + $object =& $event->getObject(); + + $user_id = $object->GetDBField($id_field); + $options = $object->GetFieldOptions($id_field); + if (isset($options['options'][$user_id])) { + $object->SetDBField($cached_field, $options['options'][$user_id]); + } + else { + $id_field = $this->Application->getUnitOption('u', 'IDField'); + $table_name = $this->Application->getUnitOption('u', 'TableName'); + + $sql = 'SELECT Login + FROM '.$table_name.' + WHERE '.$id_field.' = '.$user_id; + $object->SetDBField($cached_field, $this->Conn->GetOne($sql)); + } + } + + /** + * Saves item beeing edited into temp table + * + * @param kEvent $event + */ + function OnPreSave(&$event) + { + parent::OnPreSave($event); + $use_pending_editing = $this->Application->getUnitOption($event->Prefix, 'UsePendingEditing'); + if ($event->status == erSUCCESS && $use_pending_editing) { + // decision: clone or not clone + + $object =& $event->getObject(); + if ($object->GetID() == 0 || $object->GetDBField('OrgId') > 0) { + // new items or cloned items shouldn't be cloned again + return true; + } + $perm_helper =& $this->Application->recallObject('PermissionsHelper'); + if ($perm_helper->ModifyCheckPermission($object->GetDBField('CreatedById'), $object->GetDBField('CategoryId'), $event->Prefix) == 2) { + + // 1. clone original item + $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler'); + $cloned_ids = $temp_handler->CloneItems($event->Prefix, $event->Special, Array($object->GetID()), null, null, null, true); + $ci_table = $this->Application->GetTempName(TABLE_PREFIX.'CategoryItems'); + + // 2. delete record from CategoryItems (about cloned item) that was automatically created during call of Create method of kCatDBItem + $sql = 'SELECT ResourceId + FROM '.$object->TableName.' + WHERE '.$object->IDField.' = '.$cloned_ids[0]; + $clone_resource_id = $this->Conn->GetOne($sql); + + $sql = 'DELETE FROM '.$ci_table.' + WHERE ItemResourceId = '.$clone_resource_id.' AND PrimaryCat = 1'; + $this->Conn->Query($sql); + + // 3. copy main item categoryitems to cloned item + $sql = ' INSERT INTO '.$ci_table.' (CategoryId, ItemResourceId, PrimaryCat, ItemPrefix, Filename) + SELECT CategoryId, '.$clone_resource_id.' AS ItemResourceId, PrimaryCat, ItemPrefix, Filename + FROM '.$ci_table.' + WHERE ItemResourceId = '.$object->GetDBField('ResourceId'); + $this->Conn->Query($sql); + + // 4. put cloned id to OrgId field of item being cloned + $sql = 'UPDATE '.$object->TableName.' + SET OrgId = '.$object->GetID().' + WHERE '.$object->IDField.' = '.$cloned_ids[0]; + $this->Conn->Query($sql); + + // 5. substitute id of item being cloned with clone id + $this->Application->SetVar($event->getPrefixSpecial().'_id', $cloned_ids[0]); + $selected_ids = explode(',', $this->Application->RecallVar($event->getPrefixSpecial().'_selected_ids')); + $selected_ids[ array_search($object->GetID(), $selected_ids) ] = $cloned_ids[0]; + $this->Application->StoreVar($event->getPrefixSpecial().'_selected_ids', implode(',', $selected_ids)); + + // 6. delete original item from temp table + $temp_handler->DeleteItems($event->Prefix, $event->Special, Array($object->GetID())); + } + } + } + + /** + * Sets default expiration based on module setting + * + * @param kEvent $event + */ + function OnPreCreate(&$event) + { + parent::OnPreCreate($event); + + if ($event->status == erSUCCESS) { + $object =& $event->getObject(); + $object->SetDBField('CreatedById', $this->Application->GetVar('u_id')); + } + } + + /** + * Occures before original item of item in pending editing got deleted (for hooking only) + * + * @param kEvent $event + */ + function OnBeforeDeleteOriginal(&$event) + { + + } + + /** + * Apply same processing to each item beeing selected in grid + * + * @param kEvent $event + * @access private + */ + function iterateItems(&$event) + { + if ($event->Name != 'OnMassApprove' && $event->Name != 'OnMassDecline') { + return parent::iterateItems($event); + } + + if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) { + return; + } + + $object =& $event->getObject( Array('skip_autoload' => true) ); + $ids = $this->StoreSelectedIDs($event); + + if ($ids) { + foreach ($ids as $id) { + $object->Load($id); + + switch ($event->Name) { + case 'OnMassApprove': + $ret = $object->ApproveChanges(); + break; + + case 'OnMassDecline': + $ret = $object->DeclineChanges(); + break; + } + + if (!$ret) { + $event->status = erFAIL; + $event->redirect = false; + break; + } + } + } + } + } ?> \ No newline at end of file