Commit 47e20abac975dfcb787251a6eb720e504989899b

Authored by Bryn Divey
1 parent 102db588

Per-User saved searches. Please test.


git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@5439 c91229c3-7414-0410-bfa2-8a42b809f60b
lib/search/savedsearch.inc.php
@@ -146,6 +146,15 @@ class KTSavedSearch extends KTEntity { @@ -146,6 +146,15 @@ class KTSavedSearch extends KTEntity {
146 )); 146 ));
147 } 147 }
148 148
  149 + function &getUserSearches($iUserId, $bNoSystem = false) {
  150 + $sQuery = sprintf('user_id = %d', $iUserId);
  151 + if(!$bNoSystem) {
  152 + $sQuery .= ' OR user_id IS NULL';
  153 + }
  154 +
  155 + return KTEntityUtil::getList2('KTSavedSearch', $sQuery, array('orderby' => 'user_id, name'));
  156 + }
  157 +
149 function &getConditions() { 158 function &getConditions() {
150 return KTEntityUtil::getByDict('KTSavedSearch', array( 159 return KTEntityUtil::getByDict('KTSavedSearch', array(
151 'is_condition' => true, 160 'is_condition' => true,
plugins/ktcore/KTPortlets.php
@@ -40,15 +40,26 @@ class KTSearchPortlet extends KTPortlet { @@ -40,15 +40,26 @@ class KTSearchPortlet extends KTPortlet {
40 $oTemplating =& KTTemplating::getSingleton(); 40 $oTemplating =& KTTemplating::getSingleton();
41 $oTemplate = $oTemplating->loadTemplate("kt3/portlets/search_portlet"); 41 $oTemplate = $oTemplating->loadTemplate("kt3/portlets/search_portlet");
42 42
43 - $aSearches = KTSavedSearch::getSearches(); 43 + $iFolderId = KTUtil::arrayGet($_REQUEST, 'fFolderId', 1);
  44 + $iDocumentId = KTUtil::arrayGet($_REQUEST, 'fDocumentId');
  45 + if (!$iFolderId && !$iDocumentId) {
  46 + return null;
  47 + }
  48 +
  49 + $iUserId = $_SESSION['userID'];
  50 + $aSearches = KTSavedSearch::getUserSearches($iUserId);
  51 +
44 // empty on error. 52 // empty on error.
45 if (PEAR::isError($aSearches)) { 53 if (PEAR::isError($aSearches)) {
46 $aSearches = array(); 54 $aSearches = array();
47 } 55 }
48 56
  57 + $iFolderId = KTUtil::arrayGet($_REQUEST, 'fFolderId', 1);
49 $aTemplateData = array( 58 $aTemplateData = array(
50 "context" => $this, 59 "context" => $this,
51 "saved_searches" => $aSearches, 60 "saved_searches" => $aSearches,
  61 + "folder_id" => $iFolderId,
  62 + "document_id" => $iDocumentId,
52 ); 63 );
53 64
54 return $oTemplate->render($aTemplateData); 65 return $oTemplate->render($aTemplateData);
plugins/ktcore/admin/savedSearch.php
@@ -149,7 +149,7 @@ class KTSavedSearchDispatcher extends KTAdminDispatcher { @@ -149,7 +149,7 @@ class KTSavedSearchDispatcher extends KTAdminDispatcher {
149 $oSearch = KTSavedSearch::get($id); 149 $oSearch = KTSavedSearch::get($id);
150 150
151 if (PEAR::isError($oSearch) || ($oSearch == false)) { 151 if (PEAR::isError($oSearch) || ($oSearch == false)) {
152 - $this->errorRedirectToMain('No Such search'); 152 + $this->errorRedirectToMain('No such search');
153 } 153 }
154 154
155 155
@@ -212,6 +212,16 @@ class KTSavedSearchDispatcher extends KTAdminDispatcher { @@ -212,6 +212,16 @@ class KTSavedSearchDispatcher extends KTAdminDispatcher {
212 )); 212 ));
213 $this->successRedirectToMain(_kt('Search saved')); 213 $this->successRedirectToMain(_kt('Search saved'));
214 } 214 }
  215 +
  216 + // helper for the template
  217 + function _getUserName($iUserId) {
  218 + $oUser = User::get($iUserId);
  219 + if(PEAR::isError($oUser)) {
  220 + return _kt('Error retrieving username');
  221 + }
  222 + return $oUser->getUserName();
  223 + }
  224 +
215 } 225 }
216 226
217 //$oDispatcher = new KTSavedSearchDispatcher(); 227 //$oDispatcher = new KTSavedSearchDispatcher();
search/booleanSearch.php
@@ -84,7 +84,7 @@ class BooleanSearchDispatcher extends KTStandardDispatcher { @@ -84,7 +84,7 @@ class BooleanSearchDispatcher extends KTStandardDispatcher {
84 } 84 }
85 85
86 if (is_null(KTUtil::arrayGet($datavars["subgroup"][0], "values"))) { 86 if (is_null(KTUtil::arrayGet($datavars["subgroup"][0], "values"))) {
87 - $this->errorRedirectToMain("No search parameters given"); 87 + $this->errorRedirectToMain(_kt("No search parameters given"));
88 } 88 }
89 89
90 if (empty($datavars)) { 90 if (empty($datavars)) {
@@ -96,6 +96,132 @@ class BooleanSearchDispatcher extends KTStandardDispatcher { @@ -96,6 +96,132 @@ class BooleanSearchDispatcher extends KTStandardDispatcher {
96 return $res; 96 return $res;
97 } 97 }
98 98
  99 + function do_saveSearch() {
  100 + $this->startTransaction();
  101 +
  102 + $iSearchId = KTUtil::arrayGet($_REQUEST, 'fSearchId', false);
  103 + $sName = KTUtil::arrayGet($_REQUEST, 'name', false);
  104 + $sSearch = KTUtil::arrayGet($_REQUEST, 'boolean_search');
  105 +
  106 + if($iSearchId === false && $sName === false) {
  107 + $this->errorRedirectTo('performSearch', _kt('Please either enter a name, or select a search to save over'), sprintf('boolean_search_id=%s', $sSearch));
  108 + exit(0);
  109 + }
  110 +
  111 + $datavars = $_SESSION['boolean_search'][$sSearch];
  112 + if (!is_array($datavars)) {
  113 + $datavars = unserialize($datavars);
  114 + }
  115 +
  116 + if (empty($datavars)) {
  117 + $this->errorRedirectToMain(_kt('You need to have at least 1 condition.'));
  118 + }
  119 +
  120 + if($iSearchId) {
  121 + $oSearch = KTSavedSearch::get($iSearchId);
  122 + if(PEAR::isError($oSearch) || $oSearch == false) {
  123 + $this->errorRedirectToMain(_kt('No such search'));
  124 + exit(0);
  125 + }
  126 + $oSearch->setSearch($datavars);
  127 + $oSearch = $oSearch->update();
  128 +
  129 + } else {
  130 + $sName = $this->oValidator->validateEntityName('KTSavedSearch',
  131 + KTUtil::arrayGet($_REQUEST, 'name'),
  132 + array('extra_condition' => 'not is_condition', 'redirect_to' => array('new')));
  133 +
  134 + $sNamespace = KTUtil::nameToLocalNamespace('Saved searches', $sName);
  135 +
  136 + $oSearch = KTSavedSearch::createFromArray(array('name' => $sName,
  137 + 'namespace' => $sNamespace,
  138 + 'iscondition' => false,
  139 + 'iscomplete' => true,
  140 + 'userid' => $this->oUser->getId(),
  141 + 'search' => $datavars,));
  142 + }
  143 +
  144 + $this->oValidator->notError($oSearch, array(
  145 + 'redirect_to' => 'main',
  146 + 'message' => _kt('Search not saved'),
  147 + ));
  148 +
  149 + $this->commitTransaction();
  150 + $this->successRedirectTo('performSearch', _kt('Search saved'), sprintf('boolean_search_id=%s', $sSearch));
  151 + }
  152 +
  153 +
  154 + function do_deleteSearch() {
  155 + $this->startTransaction();
  156 +
  157 + $iSearchId = KTUtil::arrayGet($_REQUEST, 'fSavedSearchId', false);
  158 + $oSearch = KTSavedSearch::get($iSearchId);
  159 + if(PEAR::isError($oSearch) || $oSearch == false) {
  160 + $this->errorRedirectToMain(_kt('No such search'));
  161 + exit(0);
  162 + }
  163 +
  164 + $res = $oSearch->delete();
  165 + $this->oValidator->notError($res, array(
  166 + 'redirect_to' => 'main',
  167 + 'message' => _kt('Error deleting search'),
  168 + ));
  169 +
  170 + $this->commitTransaction();
  171 +
  172 + $iFolderId = KTUtil::arrayGet($_REQUEST, 'fFolderId', false);
  173 + $iDocumentId = KTUtil::arrayGet($_REQUEST, 'fFolderId', false);
  174 +
  175 + if($iFolderId) {
  176 + controllerRedirect('browse', 'fFolderId=' . $iFolderId);
  177 + } else {
  178 + controllerRedirect('viewDocument', 'fDocumentId=' . $iDocumentId);
  179 + }
  180 + }
  181 +
  182 + function do_editSearch() {
  183 + $sSearch = KTUtil::arrayGet($_REQUEST, 'boolean_search');
  184 + $aSearch = $_SESSION['boolean_search'][$sSearch];
  185 + if (!is_array($aSearch)) {
  186 + $aSearch = unserialize($aSearch);
  187 + }
  188 +
  189 + if (empty($aSearch)) {
  190 + $this->errorRedirectToMain(_kt('You need to have at least 1 condition.'));
  191 + }
  192 +
  193 + $oTemplating =& KTTemplating::getSingleton();
  194 + $oTemplate = $oTemplating->loadTemplate("ktcore/boolean_search_change");
  195 +
  196 + $aCriteria = Criteria::getAllCriteria();
  197 +
  198 + // we need to help out here, since it gets unpleasant inside the template.
  199 +
  200 + foreach ($aSearch['subgroup'] as $isg => $as) {
  201 + $aSubgroup =& $aSearch['subgroup'][$isg];
  202 + if (is_array($aSubgroup['values'])) {
  203 + foreach ($aSubgroup['values'] as $iv => $t) {
  204 + $datavars =& $aSubgroup['values'][$iv];
  205 + $datavars['typename'] = $aCriteria[$datavars['type']]->sDisplay;
  206 + $datavars['widgetval'] = $aCriteria[$datavars['type']]->searchWidget(null, $datavars['data']);
  207 + }
  208 + }
  209 + }
  210 +
  211 + $aTemplateData = array(
  212 + "title" => _kt("Edit an existing condition"),
  213 + "aCriteria" => $aCriteria,
  214 + "searchButton" => _kt("Search"),
  215 + 'aSearch' => $aSearch,
  216 + 'context' => $this,
  217 + // 'iSearchId' => $oSearch->getId(),
  218 + // 'old_name' => $oSearch->getName(),
  219 + 'sNameTitle' => _kt('Edit Search'),
  220 + );
  221 + return $oTemplate->render($aTemplateData);
  222 + }
  223 +
  224 +
99 function handleCriteriaSet($aCriteriaSet, $iStartIndex, $sTitle=null) { 225 function handleCriteriaSet($aCriteriaSet, $iStartIndex, $sTitle=null) {
100 226
101 if ($sTitle == null) { 227 if ($sTitle == null) {
@@ -142,6 +268,22 @@ class BooleanSearchDispatcher extends KTStandardDispatcher { @@ -142,6 +268,22 @@ class BooleanSearchDispatcher extends KTStandardDispatcher {
142 $qObj = new BooleanSearchQuery($aCriteriaSet); 268 $qObj = new BooleanSearchQuery($aCriteriaSet);
143 $collection->setQueryObject($qObj); 269 $collection->setQueryObject($qObj);
144 270
  271 +
  272 + // form fields for saving the search
  273 + $save_fields = array();
  274 + $save_fields[] = new KTStringWidget(_kt('New search'), _kt('The name to save this search as'), 'name', null, $this->oPage, true);
  275 +
  276 + $aUserSearches = KTSavedSearch::getUserSearches($this->oUser->getId(), true);
  277 + if(count($aUserSearches)) {
  278 + $aVocab = array('' => ' ---- ');
  279 + foreach($aUserSearches as $oSearch) {
  280 + $aVocab[$oSearch->getId()] = $oSearch->getName();
  281 + }
  282 +
  283 + $aSelectOptions = array('vocab' => $aVocab);
  284 + $save_fields[] = new KTLookupWidget(_kt('Existing search'), _kt('To save over one of your existing searches, select it here.'), 'fSearchId', null, $this->oPage, true, null, null, $aSelectOptions);
  285 + }
  286 +
145 $collection->getResults(); 287 $collection->getResults();
146 $oTemplating =& KTTemplating::getSingleton(); 288 $oTemplating =& KTTemplating::getSingleton();
147 $oTemplate = $oTemplating->loadTemplate("kt3/browse"); 289 $oTemplate = $oTemplating->loadTemplate("kt3/browse");
@@ -149,6 +291,8 @@ class BooleanSearchDispatcher extends KTStandardDispatcher { @@ -149,6 +291,8 @@ class BooleanSearchDispatcher extends KTStandardDispatcher {
149 "context" => $this, 291 "context" => $this,
150 "collection" => $collection, 292 "collection" => $collection,
151 "custom_title" => $sTitle, 293 "custom_title" => $sTitle,
  294 + "save_fields" => $save_fields,
  295 + "boolean_search" => $sSearch,
152 ); 296 );
153 return $oTemplate->render($aTemplateData); 297 return $oTemplate->render($aTemplateData);
154 } 298 }
templates/kt3/browse.smarty
@@ -8,7 +8,8 @@ @@ -8,7 +8,8 @@
8 <h2>{$custom_title}</h2> 8 <h2>{$custom_title}</h2>
9 {/if} 9 {/if}
10 10
11 -<form action="{$smarty.server.PHP_SELF}" METHOD="POST"> 11 +
  12 +<form action="{$smarty.server.PHP_SELF}" method="post">
12 <input type="hidden" name="action" value="massaction" /> 13 <input type="hidden" name="action" value="massaction" />
13 {if ($isEditable)} 14 {if ($isEditable)}
14 <input type="hidden" name="fFolderId" value="{$context->oFolder->getId()}" /> 15 <input type="hidden" name="fFolderId" value="{$context->oFolder->getId()}" />
@@ -21,4 +22,36 @@ @@ -21,4 +22,36 @@
21 </div> 22 </div>
22 {/if} 23 {/if}
23 </form> 24 </form>
  25 +
  26 +
  27 +
  28 +{if ($save_fields)}
  29 +<form action="{$smarty.server.PHP_SELF}" method="post">
  30 +<fieldset>
  31 +<legend>Edit search</legend>
  32 +<p class="descriptiveText">{i18n}To modify this search, press the 'Edit' button.{/i18n}</p>
  33 +<input type="hidden" name="action" value="editSearch" />
  34 +<input type="hidden" name="boolean_search" value="{$boolean_search}" />
  35 +<div class="form_actions">
  36 +<input type="submit" name="submit" value="{i18n}Edit{/i18n}" />
  37 +</div>
  38 +</fieldset>
  39 +</form>
  40 +
  41 +<form action="{$smarty.server.PHP_SELF}" method="post">
  42 +<fieldset>
  43 +<legend>{i18n}Save this search{/i18n}</legend>
  44 +<p class="descriptiveText">{i18n}To save this search permanently, so that you can run it again at any time, fill in a name below and click 'Save'.{/i18n}</p>
  45 +<input type="hidden" name="action" value="saveSearch" />
  46 +<input type="hidden" name="boolean_search" value="{$boolean_search}" />
  47 +{foreach item=oWidget from=$save_fields}
  48 + {$oWidget->render()}
  49 +{/foreach}
  50 +<div class="form_actions">
  51 +<input type="submit" name="submit" value="{i18n}Save{/i18n}" />
  52 +</div>
  53 +</fieldset>
  54 +</form>
  55 +{/if}
  56 +
24 {* we break encapsulation pretty badly here. *} 57 {* we break encapsulation pretty badly here. *}
25 \ No newline at end of file 58 \ No newline at end of file
templates/kt3/portlets/search_portlet.smarty
@@ -8,7 +8,9 @@ @@ -8,7 +8,9 @@
8 <h4>{i18n}Saved Searches{/i18n}</h4> 8 <h4>{i18n}Saved Searches{/i18n}</h4>
9 <ul class="actionlist"> 9 <ul class="actionlist">
10 {foreach item=oSearch from=$saved_searches} 10 {foreach item=oSearch from=$saved_searches}
11 -<li><a href="{"booleanSearch"|generateControllerUrl}&qs[action]=performSearch&qs[fSavedSearchId]={$oSearch->getId()}">{$oSearch->getName()}</a></li> 11 +<li>
  12 +{if ($oSearch->getUserId())}<a class="ktInline ktAction ktDelete" href="{"booleanSearch"|generateControllerUrl}&qs[action]=deleteSearch&qs[fSavedSearchId]={$oSearch->getId()}&qs[fFolderId]={$folder_id}&qs[fDocumentId]={$document_id}">{i18n}Delete{/i18n}</a>{/if}<a href="{"booleanSearch"|generateControllerUrl}&qs[action]=performSearch&qs[fSavedSearchId]={$oSearch->getId()}">{$oSearch->getName()}</a>
  13 +</li>
12 {/foreach} 14 {/foreach}
13 </ul> 15 </ul>
14 <hr /> 16 <hr />
templates/ktcore/search/administration/savedsearches.smarty
@@ -22,6 +22,7 @@ newsletters, etc.) based on a category or fieldset value.{/i18n}&lt;/p&gt; @@ -22,6 +22,7 @@ newsletters, etc.) based on a category or fieldset value.{/i18n}&lt;/p&gt;
22 <thead> 22 <thead>
23 <tr> 23 <tr>
24 <th>{i18n}Search Name{/i18n}</th> 24 <th>{i18n}Search Name{/i18n}</th>
  25 + <th>{i18n}User{/i18n}</th>
25 <th>{i18n}Edit{/i18n}</th> 26 <th>{i18n}Edit{/i18n}</th>
26 <th>{i18n}Delete{/i18n}</th> 27 <th>{i18n}Delete{/i18n}</th>
27 <th>{i18n}View Results{/i18n}</th> 28 <th>{i18n}View Results{/i18n}</th>
@@ -31,6 +32,8 @@ newsletters, etc.) based on a category or fieldset value.{/i18n}&lt;/p&gt; @@ -31,6 +32,8 @@ newsletters, etc.) based on a category or fieldset value.{/i18n}&lt;/p&gt;
31 {foreach item=oSearch from=$saved_searches} 32 {foreach item=oSearch from=$saved_searches}
32 <tr> 33 <tr>
33 <td>{$oSearch->getName()}</td> 34 <td>{$oSearch->getName()}</td>
  35 + {capture assign=iUserId}{$oSearch->getUserId()}{/capture}
  36 + <td>{if ($iUserId === '')}Global{else}{$context->_getUserName($iUserId)}{/if}</td>
34 <td><a href="{addQS}action=edit&fSavedSearchId={$oSearch->getId()}{/addQS}" class="ktAction ktEdit">{i18n}Edit{/i18n}</a></td> 37 <td><a href="{addQS}action=edit&fSavedSearchId={$oSearch->getId()}{/addQS}" class="ktAction ktEdit">{i18n}Edit{/i18n}</a></td>
35 <td><a href="{addQS}action=delete&fSavedSearchId={$oSearch->getId()}{/addQS}" class="ktAction ktDelete">{i18n}Delete{/i18n}</a></td> 38 <td><a href="{addQS}action=delete&fSavedSearchId={$oSearch->getId()}{/addQS}" class="ktAction ktDelete">{i18n}Delete{/i18n}</a></td>
36 <td><a href="{"booleanSearch"|generateControllerUrl}&qs[action]=performSearch&qs[fSavedSearchId]={$oSearch->getId()}">Run Search</a></td> 39 <td><a href="{"booleanSearch"|generateControllerUrl}&qs[action]=performSearch&qs[fSavedSearchId]={$oSearch->getId()}">Run Search</a></td>