Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Improve handling of Matchgrid deletion (CO-1705)
Benn Oshrin committed Dec 29, 2022
1 parent 370678f commit dbc0024
Showing 6 changed files with 232 additions and 13 deletions.
15 changes: 15 additions & 0 deletions app/resources/locales/en_US/default.po
@@ -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"

@@ -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."

@@ -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"

61 changes: 60 additions & 1 deletion app/src/Controller/MatchgridsController.php
@@ -31,6 +31,7 @@

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

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

@@ -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
@@ -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
21 changes: 9 additions & 12 deletions app/src/Controller/StandardController.php
@@ -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) {
45 changes: 45 additions & 0 deletions app/src/Lib/Match/MatchgridBuilder.php
@@ -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
@@ -29,6 +29,7 @@

namespace App\Model\Table;

use \Cake\Datasource\EntityInterface;
use \Cake\Event\EventInterface;
use \Cake\ORM\Query;
use \Cake\ORM\RulesChecker;
@@ -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;
}

@@ -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).
@@ -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.
*
47 changes: 47 additions & 0 deletions app/templates/Matchgrids/delete.php
@@ -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.