Skip to content

Commit

Permalink
Improve handling of Matchgrid deletion (CO-1705)
Browse files Browse the repository at this point in the history
  • Loading branch information
Benn Oshrin committed Dec 29, 2022
1 parent 370678f commit dbc0024
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 13 deletions.
15 changes: 15 additions & 0 deletions app/resources/locales/en_US/default.po
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,9 @@ msgstr "When this value is selected, {0} cannot be empty"
msgid "match.er.input.invalid"
msgstr "Invalid character found"

msgid "match.er.mg.active"
msgstr "This matchgrid is in Active status and cannot be deleted"

msgid "match.er.mg.inuse"
msgstr "A Matchgrid with table name {0} already exists"

Expand Down Expand Up @@ -571,6 +574,9 @@ msgid "match.home.welcome"
msgstr "Welcome to {0}."

### Informational Messages
msgid "match.in.delete.matchgrid.info"
msgstr "The database table for this Matchgrid currently exists. You may delete it, or leave it in place. If you delete it, the table CAN NOT BE RESTORED except via database backups. Do you want to delete the physical Matchgrid table ({0})?"

msgid "match.in.matchgrid.display"
msgstr "Display all records associated with this Matchgrid."

Expand Down Expand Up @@ -638,6 +644,15 @@ msgstr "Delete"
msgid "match.op.delete.confirm"
msgstr "Are you sure you wish to delete this record ({0})?"

msgid "match.op.delete.matchgrid"
msgstr "Delete Matchgrid \"{0}\""

msgid "match.op.delete.matchgrid.leave"
msgstr "Leave the table {0} in the database"

msgid "match.op.delete.matchgrid.remove"
msgstr "Remove the table {0} from the database"

msgid "match.op.display"
msgstr "Display"

Expand Down
61 changes: 60 additions & 1 deletion app/src/Controller/MatchgridsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

use \Cake\Log\Log;
use \Cake\Event\EventInterface;

use \App\Lib\Enum\PermissionEnum;
use \App\Lib\Enum\MatchgridActionEnum;

Expand Down Expand Up @@ -77,6 +78,64 @@ public function build(string $id) {
return $this->redirect(['action' => 'manage', $id]);
}

/**
* Handle a delete action for a Matchgrid object.
*
* @since COmanage Match v1.1.0
* @param Integer $id Object ID
*/

public function delete($id) {
// Deleting a Matchgrid is a bit more complicated than other objects.

try {
// First, we'll pull the requested object.
$obj = $this->Matchgrids->findById($id)->firstOrFail();

// We manually apply the status check rule here, since otherwise
// it won't get applied until we actually try to remove the Matchgrid,
// which could be _after_ we remove the table, below, which is confusing.
$err = $this->Matchgrids->ruleIsActive($obj, []);

if(is_string($err)) {
throw new \Exception($err);
}

// See if the Matchgrid table exists.
if(!$this->Matchgrids->tableExists($obj)) {
// Just execute the delete
parent::delete($id);
}

// Determine what the admin wants to do with the matchgrid table.
// The first time through this will be empty, so we provide the form.
$action = $this->request->getData('remove');

if($action === 'leave') {
// Leave the Matchgrid table in place
parent::delete($id);
} elseif($action === 'remove') {
// Remove the Matchgrid table, then execute the standard delete
$this->Matchgrids->removeTable($obj);
parent::delete($id);
} else {
// The table exists, require the admin to indicate whether or
// not the table should also be deleted. Set some view variables.

$this->set('vv_title', __('match.op.delete.matchgrid', [$obj->table_name]));
$this->set('vv_matchgrid', $obj->prefixed_table_name);
}
}
catch(\Exception $e) {
// findById throws Cake\Datasource\Exception\RecordNotFoundException

$this->Flash->error($e->getMessage());
return $this->generateRedirect();
}

// If we get here, we need to render the form for table deletion
}

/**
* Authorization for this Controller, called by Auth component
* - postcondition: $vv_permissions set with calculated permissions for this Controller
Expand Down Expand Up @@ -286,7 +345,7 @@ public function reconcile(string $id) {
$this->request->getSession()->read('Auth.User.username'));
}
}

$MatchService->disconnectDatabase();

// Redirect back to list of pending requests
Expand Down
21 changes: 9 additions & 12 deletions app/src/Controller/StandardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,19 +98,16 @@ public function delete($id) {
try {
$obj = $this->$modelsName->findById($id)->firstOrFail();

if($this->$modelsName->delete($obj)) {
// Use the display field to generate the flash message

$field = $this->$modelsName->getDisplayField();

if(!empty($obj->$field)) {
$this->Flash->success(__('match.rs.deleted.a', [$obj->$field]));
} else {
$this->Flash->success(__('match.rs.deleted'));
}
$this->$modelsName->deleteOrFail($obj);

// Use the display field to generate the flash message

$field = $this->$modelsName->getDisplayField();

if(!empty($obj->$field)) {
$this->Flash->success(__('match.rs.deleted.a', [$obj->$field]));
} else {
// It's hard to get a specific failure reason to render...
$this->Flash->error(__('match.er.delete'));
$this->Flash->success(__('match.rs.deleted'));
}
}
catch(\Exception $e) {
Expand Down
45 changes: 45 additions & 0 deletions app/src/Lib/Match/MatchgridBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,49 @@ protected function configToSchema(
$stmt = $dbc->executeQuery($sql);
}
}

/**
* Remove the Matchgrid table.
*
* @since COmanage Match v1.1.0
* @param EntityInterface $Matchgrid Matchgrid Object
* @return bool True on success
*/

public function removeTable(EntityInterface $Matchgrid) {
// Connect to the database
$dbc = $this->connectDatabase();

// We just construct the drop statement here since it's simple and the
// table_name is constrained from having any special characters
$sql = "DROP TABLE " . $Matchgrid->prefixed_table_name;

// $stmt just returns the query string so we don't bother examining it
$stmt = $dbc->executeQuery($sql);

$this->disconnectDatabase();

return true;
}

/**
* Determine if the Matchgrid table exists.
*
* @since COmanage Match v1.1.0
* @param EntityInterface $Matchgrid Matchgrid Object
* @return bool True if the Matchgrid table exists, false otherwise
*/

public function tableExists(EntityInterface $Matchgrid) {
// Connect to the database
$dbc = $this->connectDatabase();

$sm = $dbc->getSchemaManager();

$ret = $sm->tablesExist($Matchgrid->prefixed_table_name);

$this->disconnectDatabase();

return $ret;
}
}
56 changes: 56 additions & 0 deletions app/src/Model/Table/MatchgridsTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

namespace App\Model\Table;

use \Cake\Datasource\EntityInterface;
use \Cake\Event\EventInterface;
use \Cake\ORM\Query;
use \Cake\ORM\RulesChecker;
Expand Down Expand Up @@ -151,6 +152,14 @@ public function buildRules(RulesChecker $rules): RulesChecker {
'isUnique',
['errorField' => 'table_name']);

// A Matchgrid cannot be deleted if it is in Active status.
// Similar to COs in Registry PE, this requires two steps to delete a CO
// reducing the likelihood of accidentally deleting a CO.
// Note this rule is also called manually in MatchgridsController::delete.
$rules->addDelete([$this, 'ruleIsActive'],
'isActive',
['errorField' => 'status']);

return $rules;
}

Expand Down Expand Up @@ -203,6 +212,39 @@ public function getMatchgridConfig($id) {
]]);
}

/**
* Remove the Matchgrid table.
*
* @since COmanage Match v1.1.0
* @param EntityInterface $Matchgrid Matchgrid entity
* @return bool True on success
*/

public function removeTable(EntityInterface $Matchgrid) {
$Builder = new MatchgridBuilder();

return $Builder->removeTable($Matchgrid);
}

/**
* Application Rule to determine if the current entity is not Active.
*
* @param Entity $entity Entity to be validated
* @param array $options Application rule options
*
* @return bool|string true if the Rule check passes, false otherwise
* @since COmanage Match v1.1.0
*/

public function ruleIsActive($entity, array $options): bool|string {
// We want negative logic since we want to fail if the record is Active
if($entity->status === StatusEnum::Active) {
return __('match.er.mg.active');
}

return true;
}

/**
* Application Rule to determine if the current entity is uniquely named
* (case insensitive).
Expand Down Expand Up @@ -234,6 +276,20 @@ public function ruleIsUnique($entity, array $options): bool|string {
return true;
}

/**
* Determine if the Matchgrid table exists.
*
* @since COmanage Match v1.1.0
* @param EntityInterface $Matchgrid Matchgrid entity
* @return bool True if the Matchgrid table exists, false otherwise
*/

public function tableExists(EntityInterface $Matchgrid) {
$Builder = new MatchgridBuilder();

return $Builder->tableExists($Matchgrid);
}

/**
* Set validation rules.
*
Expand Down
47 changes: 47 additions & 0 deletions app/templates/Matchgrids/delete.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php
/**
* COmanage Matchgrid Delete Page
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* UCAID licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @link https://www.internet2.edu/comanage COmanage Project
* @package match
* @since COmanage Match v1.1.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/

declare(strict_types = 1);

?>
<div class="titleNavContainer">
<div class="pageTitle">
<h1><?= $vv_title; ?></h1>
</div>
</div>

<p><?= __('match.in.delete.matchgrid.info', [$vv_matchgrid]); ?></p>

<?php
print $this->Form->create(); //$vv_delete_matchgrid_form);
print $this->Form->radio('remove',
[
['value' => 'leave', 'text' => __('match.op.delete.matchgrid.leave', [$vv_matchgrid])],
['value' => 'remove', 'text' => __('match.op.delete.matchgrid.remove', [$vv_matchgrid])]
]);
print $this->Form->submit(__('match.op.confirm'));
print $this->Form->end();

0 comments on commit dbc0024

Please sign in to comment.