Problem - Add-delete-button-#457
-
Create
Delete
button function in theadmin file page
-
DatasetLog
andCurationLog
to log the events. -
Pass the
unit test
andacceptance test
.
How
- Create
Delete
button in/view/adminFile/_form.php
<td><a role="button" class="btn js-delete" name="delete_file_attr" data="<?= $fa->id ?>">Delete</a></td>
</script>
$('.js-delete').click(function (e) {
e.preventDefault();
id = $(this).attr('data');
row = $('.row-edit-' + id);
if (id) {
$.post('/adminFile/deleteFileAttribute', { 'id': id }, function(result) {
if (result) {
// console.log(result);
}
}, 'json');
}
window.location.reload();
})
</script>
- Create action
deleteFileAttribute
inAdminFileController.php
public function accessRules()
{
return array(
array('allow', // admin only
'actions'=>array('linkFolder','admin','delete','index','view','create','update','update1', 'editAttr', 'uploadAttr', 'deleteFileAttribute'),
'roles'=>array('admin'),
),
array('allow',
'actions' => array('create1'),
'users' => array('@'),
),
array('allow', // allow all users
'actions' => array('downloadCount'),
'users'=>array('*'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
/**
* Yii's method for routing urls to an action. Override to use custom actions
*/
public function actions()
{
return array(
'deleteFileAttribute'=>'application.controllers.adminFile.DeleteFileAttributeAction',
);
}
- Create
DeleteFileAttributeAction.php
in/controllers/adminFile
, becauseAdminFileController.php
is very big, so better be implemented in separate class
<?php
/**
* This action will delete file attributes in admin file update page
*/
class DeleteFileAttributeAction extends CAction
{
public function run()
{
if (!Yii::app()->request->isPostRequest)
throw new CHttpException(404, "The requested page does not exist.");
if (isset($_POST['id'])) {
$attribute = FileAttributes::model()->findByPk($_POST['id']);
if ($attribute) {
$out = $attribute->file->dataset_id;
$fileName = $attribute->file->name;
$fileModel = get_class($attribute);
$fileId = $attribute->file->id;
$modelId = $attribute->id;
$model = Dataset::model()->findByPk($out);
if ($model->upload_status === "Published") {
DatasetLog::createDatasetLogEntry($out, $fileName, $fileModel, $modelId, $fileId);
} else {
CurationLog::createCurationLogEntry($out, $fileName); //Pass in dataset_id returned from File object.
}
$attribute->delete();
Yii::app()->end();
}
}
}
}
Factory method
in/protected/models/DatasetLog.php
to logPublished
dataset
/**
* Factory method to call for common attributes
* @param int $id
* @param string $fileName
* @param string $fileModel
* @param int $modelId
* @param int $fileId
* @return DatasetLog
*/
public static function makeNewInstanceForDatasetLogBy (int $id, string $fileName, string $fileModel, int $modelId, int $fileId): DatasetLog
{
$datasetlog = new DatasetLog();
$datasetlog->created_at = date("Y-m-d H:i:s");
$datasetlog->dataset_id = $id;
$datasetlog->message = $fileName;
$datasetlog->model = $fileModel;
$datasetlog->model_id = $modelId;
$datasetlog->url = Yii::app()->createUrl('/adminFile/update', array('id'=>$fileId));
return $datasetlog;
}
/**
* Retrieves attributes and store them in dataset_log table when triggered.
* @param int $id
* @param string $fileName
* @param string $fileModel
* @param int $modelId
* @param int $fileId
* @return bool
*/
public static function createDatasetLogEntry(int $id, string $fileName, string $fileModel, int $modelId, int $fileId): bool
{
$datasetlog = self::makeNewInstanceForDatasetLogBy($id, $fileName, $fileModel, $modelId, $fileId);
$datasetlog->message = $fileName. ": file attribute deleted";
return $datasetlog->save();
}
- Pass the
unit test
fordatasetLog
<?php
class DatasetLogTest extends CDbTestCase
{
public function testDataSetLogEntryFactory()
{
// With reference to the entry in dataset_log fixture
$datasetId = 1;
$fileName = "File Tinamus_guttatus.fa.gz";
$fileModel = "File";
$modelId = 16945;
$fileId = 16945; //mockup ID
$datasetlog = DatasetLog::makeNewInstanceForDatasetLogBy($datasetId, $fileName, $fileModel, $modelId, $fileId);
$this->assertNotNull($datasetlog);
$this->assertTrue(is_a($datasetlog, DatasetLog::class));
$this->assertEquals($datasetId, $datasetlog->dataset_id);
$this->assertEquals($fileName, $datasetlog->message);
$this->assertEquals($fileModel, $datasetlog->model);
$this->assertEquals($modelId, $datasetlog->model_id);
$this->assertEquals("./bin/adminFile/update/id/$fileId", $datasetlog->url);
$this->assertTrue($datasetlog->isNewRecord);
}
// Includde Dataset fixture to avoid unique duplicate key value violation with dataset_log_pkey
protected $fixtures=array(
'datasets'=>'Dataset',
);
public function testCreateDatasetLogEntry()
{
$datasetId = 1;
$fileName = "File Tinamus_guttatus.fa.gz";
$fileModel = "File";
$modelId = 16945;
$fileId = 16945; //mockup ID
$saveNewEntry = DatasetLog::createDatasetLogEntry($datasetId, $fileName, $fileModel, $modelId, $fileId);
$this->assertTrue(is_bool($saveNewEntry) === true, "bool is returned");
$this->assertTrue(true===$saveNewEntry, "No new entry is saved to dataset log table");
// To assert the delete message will be generated as expected
$datasetlog = DatasetLog::model()->findByPk($datasetId);
$this->assertEquals("File Tinamus_guttatus.fa.gz: file attribute deleted", $datasetlog->message, "Delete message was generated in different format");
}
}
Factory method
in/protected/models/CurationLog.php
to lognon Published
dataset
/**
* Factory method to make a new instance and factor out the common code
*
* @param int $id
* @param string $creator
* @return CurationLog
*/
public static function makeNewInstanceForCurationLogBy(int $id, string $creator): CurationLog
{
$curationlog = new CurationLog();
$curationlog->creation_date = date("Y-m-d");
$curationlog->last_modified_date = null;
$curationlog->dataset_id = $id;
$curationlog->created_by = $creator;
return $curationlog;
}
public static function createlog($status,$id) {
$curationlog = self::makeNewInstanceForCurationLogBy($id, "System");
$curationlog->action = "Status changed to ".$status;
return $curationlog->save();
}
public static function createlog_assign_curator($id,$creator,$username) {
$curationlog = self::makeNewInstanceForCurationLogBy($id, $creator);
$curationlog->action = "Curator Assigned"." $username";
return $curationlog->save();
}
/**
* Retrieves attributes and store them in curation_log table when triggered
* @param $id
* @param string $fileName
* @return bool
*/
public static function createCurationLogEntry(int $id, string $fileName): bool
{
$curationlog = self::makeNewInstanceForCurationLogBy($id, "System");
$curationlog->action = $fileName.": file attribute deleted";
return $curationlog->save();
}
- Pass the
unit test
forCurationLog
<?php
class CurationLogTest extends CDbTestCase
{
public function testMakeNewInstance()
{
$datasetId = 1;
$creator = "System";
$curationLog = CurationLog::makeNewInstanceForCurationLogBy($datasetId, $creator);
$this->assertNotNull($curationLog);
$this->assertTrue(is_a($curationLog, CurationLog::class));
$this->assertEquals($datasetId, $curationLog->dataset_id);
$this->assertEquals($creator, $curationLog->created_by);
$this->assertTrue($curationLog->isNewRecord);
}
}
- Create
I should see a file attribute table
inDatasetViewContext.php
/**
* @Then I should see a file attribute table
*/
public function iShouldSeeATable(TableNode $table)
{
foreach ($table as $row) {
PHPUnit_Framework_Assert::assertTrue(
$this->minkContext->getSession()->getPage()->hasContent($row['Attribute Name'])
);
PHPUnit_Framework_Assert::assertTrue(
$this->minkContext->getSession()->getPage()->hasContent($row['Value'])
);
PHPUnit_Framework_Assert::assertTrue(
$this->minkContext->getSession()->getPage()->hasContent($row['Unit'])
);
}
}
- Pass the
acceptance test
@admin-file @issue-457
Feature: A curator can manage file attributes in admin file update page
As a curator,
I want to manage file attributes from the update form
So that I can associate various attributes to files
Background:
Given Gigadb web site is loaded with production-like data
And an admin user exists
@ok
Scenario: Guest user cannot visit admin file update page
Given I am not logged in to Gigadb web site
When I go to "/adminFile/update/"
Then I should see "Login"
@ok
Scenario: Go to a published dataset found in production-like database
Given I am not logged in to Gigadb web site
When I go to "dataset/100056"
And I should see "Termitomyces sp. J132 fungus genome assembly data."
And I follow "History"
Then I should see "History" tab with text "File Termitomyces_assembly_v1.0.fa.gz updated"
And I should see "History" tab with text "File Termitomyces_gene_v1.0.cds.fa updated"
And I should see "History" tab with text "File Termitomyces_gene_v1.0.cds.fa updated"
And I should see "History" tab with text "File Termitomyces_gene_v1.0.gff updated"
And I should see "History" tab with text "File Termitomyces_gene_v1.0.gff updated"
And I should see "History" tab with text "File Termitomyces_gene_v1.0.pep.fa updated"
And I should see "History" tab with text "File Termitomyces_gene_v1.0.pep.fa updated"
@ok @Published
Scenario: Sign in as admin and visit admin file update page and see New Attribute, Edit, Delete buttons
Given I sign in as an admin
When I am on "/adminFile/update/id/13973"
Then I should see a button "New Attribute"
And I should see a file attribute table
| Attribute Name | Value | Unit |
| last_modified | 2013-7-15 | |
And I should see a button input "Edit"
And I should see a button input "Delete"
@ok @javascript @Published
Scenario: Sign in as admin, delete an attribute of a published dataset and check history tab
Given I sign in as an admin
And I am on "/adminFile/update/id/13973"
And I should see "last_modified"
When I press "Delete"
And I go to "dataset/100056"
Then I should see "Termitomyces sp. J132 fungus genome assembly data."
And I follow "History"
And I should see "History" tab with text "Termitomyces_assembly_v1.0.fa.gz: file attribute deleted"
@ok @javascript @Published
Scenario: Sign in as admin, no delete button should be seen after delete action has been triggered
Given I sign in as an admin
And I am on "/adminFile/update/id/13973"
And I should see a file attribute table
| Attribute Name | Value | Unit |
| last_modified | 2013-7-15 | |
And I should see a button input "Delete"
When I press "Delete"
And I wait "3" seconds
Then I should not see "last_modified"
And I should not see "2013-7-15"
And I should not see a button "Delete"
@ok @javascript @NonPublished
Scenario: Go to a non published dataset found in production-like database, create then delete a keyword attribute
Given I sign in as an admin
And I am on "/adminFile/update/id/95354"
And I should see "test Bauhinia"
And I press "Delete"
And I should not see "test Bauhinia"
#Go to the last page of dataset log
When I go to "datasetLog/admin/DatasetLog_page/74"
Then I should not see "100245"
And I should not see "FCHCGJYBBXX-HKBAUpcgEAACRAAPEI-201_L2_2.fq.gz: file attribute added"
And I should not see "FCHCGJYBBXX-HKBAUpcgEAACRAAPEI-201_L2_2.fq.gz: file attribute deleted"
Learn
- Tables relationship
dataset file file_attribute id idid identifier dataset_id file_idupload_status value
2.1 Update file_attribute table in data/dev/production_like
id,file_id,attribute_id,value,unit_id
5441,95354,455,test Bauhinia,
2.2 Update the production_like.pgdmp
, PR548
ops/scripts/make_pgdmp_production_like.sh
Hints from Rija
I must have forgotten what you said 😞 Right now I am working on to pass the
curation_log
test, here is my scenario:
Background:
Given Gigadb web site is loaded with production-like data
@wip @issue-#457 @javascript
Scenario: Go to a non published dataset found in production-like database
Given I sign in as an admin
And I go to "/adminFile/update/id/xxx"
And I should see some file attributes
When I press "Delete"
And I should not see file attributes
And I go to "dataset/YYY"
And I follow "History"
Then I should not see some file attributes
But I think the above scenario is not a proper way to test. Because, I could not identify the correct
xxx
andYYY
. And even I found thexxx
, this stepAnd I go to "dataset/YYY"
will not pass as errorThe dataset does not exist
will be found.
So, can I have your suggestion on how to pass the
curation_log
test?
Among a dataset’s attributes in the database table there are id
, and identifier
.
Controller actions that alter the dataset expect to have the internal id id
as parameter (that’s your xxx) as that’s the most appropriate one to uniquely identify a row in a database table.
In /adminFile/update/id/xxx
, /id/
is how yii framework knows that we are looking for a dataset whose id
attribute is xxx
identifier
is for the DOI and is the public identifier for the dataset, that’s why it is used in the view as the dataset url is meant to be shared publicly (that’s your yyy
).
So when you pick a dataset as example, select both attributes from the table.
gigadb=# select id, identifier, title from dataset;
id | identifier | title
...
189 | 100133 | Reference data for phage M13 dsDNA generated with the Oxford Nanopore MinION.
204 | 100143 | Software and supporting material for "SMAP: a streamlined methylation pipelinefor bisulphite sequencing".
210 | 100155 | Supporting data for "Sparse whole-genome sequencing identifies two loci for major depressive disorder".
...
Regarding your second point: datasets that are not published cannot be accessible publicly, so going to the public url /dataset/yyy
would result in that error.
You’ve got couple of approaches:
You could add Given steps to change the upload status temporarily away from published, but then you would need to find a way to revert the change after the test has run.
Or you could have the Then steps to check this page: (http://gigadb.gigasciencejournal.com:9170/datasetLog/admin/) or more precisely manually navigate to the last page, and use that in a Then step. It’s not the most robust (the last page may change if we add/remove example datasets from production-like), but it’s the easiest.
A better approach is to use the test database instead of production-like then checking /datasetLog/admin/
’s first page would be enough, but you will need some Given steps to add some file attributes first to a dataset as I think the test database doesn’t have any.
An improved alternative to that latter pre-condition would be to update the test data for the test database to have some file attributes in it so you don’t have to add extra Given steps (I’ve pasted bash code to do that easily in @pli888’s PR 532, you’d just have to update the corresponding CSV file beforehand)