Skip to content

Commit 59df489

Browse files
committed
Add server-side action to facilitate readset file archival
1 parent 0a65541 commit 59df489

File tree

6 files changed

+281
-0
lines changed

6 files changed

+281
-0
lines changed

SequenceAnalysis/resources/queries/sequenceanalysis/sequence_readsets/SRA Info.qview.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
<column name="workbook" />
1818
<column name="sraRuns" />
1919
<column name="isArchived" />
20+
<column name="totalFiles" />
21+
<column name="readdataWithoutSra" />
2022
<column name="files" />
2123
</columns>
2224
<sorts>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
Ext4.define('SequenceAnalysis.window.ArchiveReadsetsWindow', {
2+
extend: 'Ext.window.Window',
3+
4+
statics: {
5+
buttonHandler: function(dataRegionName){
6+
Ext4.create('SequenceAnalysis.window.ArchiveReadsetsWindow', {
7+
dataRegionName: dataRegionName,
8+
readsetIds: LABKEY.DataRegions[dataRegionName].getChecked()
9+
}).show();
10+
}
11+
},
12+
13+
initComponent: function() {
14+
Ext4.apply(this, {
15+
modal: true,
16+
title: 'Archive Readsets',
17+
width: 600,
18+
bodyStyle: 'padding: 5px;',
19+
defaults: {
20+
border: false
21+
},
22+
items: [{
23+
html: 'This helper will delete the actual FASTQ files associated with the selected readsets. It will error unless each readdata row has an SRA accession listed. You selected ' + this.readsetIds.length + ' readsets.',
24+
style: 'padding-bottom: 10px;'
25+
}],
26+
buttons: [{
27+
text: 'Submit',
28+
scope: this,
29+
handler: this.onSubmit
30+
},{
31+
text: 'Cancel',
32+
handler: function(btn){
33+
btn.up('window').close();
34+
}
35+
}]
36+
});
37+
38+
this.callParent(arguments);
39+
},
40+
41+
onSubmit: function(btn){
42+
if (!this.readsetIds.length) {
43+
Ext4.Msg.alert('Error', 'No readsets selected!');
44+
return;
45+
}
46+
47+
Ext4.Msg.wait('Saving...');
48+
LABKEY.Ajax.request({
49+
url: LABKEY.ActionURL.buildURL('sequenceanalysis', 'archiveReadsets', null),
50+
method: 'POST',
51+
jsonData: {
52+
readsetIds: this.readsetIds
53+
},
54+
scope: this,
55+
success: function(){
56+
Ext4.Msg.hide();
57+
this.close();
58+
Ext4.Msg.alert('Success', 'Readsets archived!', function(){
59+
if (this.dataRegionName){
60+
LABKEY.DataRegions[this.dataRegionName].clearSelected();
61+
}
62+
63+
LABKEY.DataRegions[this.dataRegionName].refresh();
64+
}, this);
65+
},
66+
failure: LABKEY.Utils.getCallbackWrapper(LDK.Utils.getErrorCallback())
67+
});
68+
}
69+
});

SequenceAnalysis/src/org/labkey/sequenceanalysis/SequenceAnalysisController.java

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
import org.labkey.api.exp.api.ExperimentService;
7878
import org.labkey.api.files.FileContentService;
7979
import org.labkey.api.laboratory.NavItem;
80+
import org.labkey.api.laboratory.security.LaboratoryAdminPermission;
8081
import org.labkey.api.module.Module;
8182
import org.labkey.api.module.ModuleHtmlView;
8283
import org.labkey.api.module.ModuleLoader;
@@ -5128,4 +5129,157 @@ public void setDataFileUrl(String dataFileUrl)
51285129
_dataFileUrl = dataFileUrl;
51295130
}
51305131
}
5132+
5133+
@RequiresPermission(UpdatePermission.class)
5134+
public static class ArchiveReadsetsAction extends MutatingApiAction<ArchiveReadsetsForm>
5135+
{
5136+
@Override
5137+
public ApiResponse execute(ArchiveReadsetsForm form, BindException errors) throws Exception
5138+
{
5139+
if (form.getReadsetIds() == null || form.getReadsetIds().length == 0)
5140+
{
5141+
errors.reject(ERROR_MSG, "No readset Ids provided");
5142+
return null;
5143+
}
5144+
5145+
TableInfo readData = QueryService.get().getUserSchema(getUser(), getContainer(), SequenceAnalysisSchema.SCHEMA_NAME).getTable(SequenceAnalysisSchema.TABLE_READ_DATA);
5146+
for (int readsetId : form.getReadsetIds())
5147+
{
5148+
Readset rs = SequenceAnalysisService.get().getReadset(readsetId, getUser());
5149+
Container c = ContainerManager.getForId(rs.getContainer());
5150+
if (!getContainer().equals(c))
5151+
{
5152+
Container toTest = c.isWorkbook() ? c.getParent() : c;
5153+
if (!getContainer().equals(toTest))
5154+
{
5155+
errors.reject(ERROR_MSG, "Readset is not from this container: " + readsetId);
5156+
return null;
5157+
}
5158+
}
5159+
5160+
if (!c.hasPermission(getUser(), LaboratoryAdminPermission.class))
5161+
{
5162+
errors.reject(ERROR_MSG, "Insufficient permissions to archive readsets in the folder: " + c.getPath());
5163+
return null;
5164+
}
5165+
5166+
Set<File> toDelete = new HashSet<>();
5167+
List<Map<String, Object>> toUpdate = new ArrayList<>();
5168+
for (ReadData rd : rs.getReadData())
5169+
{
5170+
if (rd.getSra_accession() == null)
5171+
{
5172+
errors.reject(ERROR_MSG, "Cannot mark a readdata as archived that does not have an SRA accession: " + readsetId + " / " + rd.getRowid());
5173+
return null;
5174+
}
5175+
5176+
toUpdate.add(new CaseInsensitiveHashMap<>(Map.of("rowid", rd.getRowid(), "archived", true, "container", rd.getContainer())));
5177+
5178+
// File 1:
5179+
ExpData d1 = ExperimentService.get().getExpData(rd.getFileId1());
5180+
if (d1 != null)
5181+
{
5182+
File file1 = d1.getFile();
5183+
if (file1 != null && file1.exists())
5184+
{
5185+
toDelete.add(file1);
5186+
}
5187+
5188+
// find matching readdata:
5189+
SimpleFilter filter = new SimpleFilter(FieldKey.fromString("fileid1/dataFileUrl"), d1.getDataFileUrl()).addCondition(FieldKey.fromString("rowid"), rd.getRowid(), CompareType.NEQ);
5190+
TableSelector ts = new TableSelector(readData, PageFlowUtil.set("rowid", "container"), filter, null);
5191+
if (ts.exists())
5192+
{
5193+
ts.forEachResults(r -> {
5194+
toUpdate.add(new CaseInsensitiveHashMap<>(Map.of("rowid", r.getInt(FieldKey.fromString("rowid")), "archived", true, "container", r.getString(FieldKey.fromString("container")))));
5195+
});
5196+
}
5197+
}
5198+
5199+
if (rd.getFileId2() != null)
5200+
{
5201+
ExpData d2 = ExperimentService.get().getExpData(rd.getFileId2());
5202+
if (d2 != null)
5203+
{
5204+
File file2 = d2.getFile();
5205+
if (file2 != null)
5206+
{
5207+
if (file2.exists())
5208+
{
5209+
toDelete.add(file2);
5210+
}
5211+
5212+
// find matching readdata:
5213+
SimpleFilter filter = new SimpleFilter(FieldKey.fromString("fileid2/dataFileUrl"), d2.getDataFileUrl()).addCondition(FieldKey.fromString("rowid"), rd.getRowid(), CompareType.NEQ);
5214+
TableSelector ts = new TableSelector(readData, PageFlowUtil.set("rowid", "container"), filter, null);
5215+
if (ts.exists())
5216+
{
5217+
ts.forEachResults(r -> {
5218+
toUpdate.add(new CaseInsensitiveHashMap<>(Map.of("rowid", r.getInt(FieldKey.fromString("rowid")), "archived", true, "container", r.getString(FieldKey.fromString("container")))));
5219+
});
5220+
}
5221+
}
5222+
}
5223+
}
5224+
}
5225+
5226+
if (!toUpdate.isEmpty())
5227+
{
5228+
List<Map<String, Object>> keys = new ArrayList<>();
5229+
toUpdate.forEach(row -> {
5230+
5231+
keys.add(new CaseInsensitiveHashMap<>(Map.of("rowid", row.get("rowid"))));
5232+
});
5233+
5234+
try
5235+
{
5236+
readData.getUpdateService().updateRows(getUser(), getContainer(), toUpdate, keys, null, null);
5237+
}
5238+
catch (Exception e)
5239+
{
5240+
_log.error(e);
5241+
errors.reject(ERROR_MSG, "Error archiving readset: " + readsetId + ", " + e.getMessage());
5242+
return null;
5243+
}
5244+
}
5245+
5246+
if (!toDelete.isEmpty())
5247+
{
5248+
for (File f : toDelete)
5249+
{
5250+
_log.info("Deleting archived file: " + f.getPath());
5251+
f.delete();
5252+
}
5253+
}
5254+
}
5255+
5256+
return new ApiSimpleResponse("Success", true);
5257+
}
5258+
}
5259+
5260+
public static class ArchiveReadsetsForm
5261+
{
5262+
private int[] _readsetIds;
5263+
private boolean _doNotRequireSra;
5264+
5265+
public int[] getReadsetIds()
5266+
{
5267+
return _readsetIds;
5268+
}
5269+
5270+
public void setReadsetIds(int... readsetIds)
5271+
{
5272+
_readsetIds = readsetIds;
5273+
}
5274+
5275+
public boolean isDoNotRequireSra()
5276+
{
5277+
return _doNotRequireSra;
5278+
}
5279+
5280+
public void setDoNotRequireSra(boolean doNotRequireSra)
5281+
{
5282+
_doNotRequireSra = doNotRequireSra;
5283+
}
5284+
}
51315285
}

SequenceAnalysis/src/org/labkey/sequenceanalysis/SequenceAnalysisModule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import org.labkey.sequenceanalysis.analysis.SbtGeneCountHandler;
5959
import org.labkey.sequenceanalysis.analysis.UnmappedSequenceBasedGenotypeHandler;
6060
import org.labkey.sequenceanalysis.button.AddSraRunButton;
61+
import org.labkey.sequenceanalysis.button.ArchiveReadsetsButton;
6162
import org.labkey.sequenceanalysis.button.ChangeReadsetStatusButton;
6263
import org.labkey.sequenceanalysis.button.ChangeReadsetStatusForAnalysesButton;
6364
import org.labkey.sequenceanalysis.button.DownloadSraButton;
@@ -396,6 +397,7 @@ public void doStartupAfterSpringConfig(ModuleContext moduleContext)
396397
LDKService.get().registerQueryButton(new AddSraRunButton(), SequenceAnalysisSchema.SCHEMA_NAME, SequenceAnalysisSchema.TABLE_READSETS);
397398
LDKService.get().registerQueryButton(new RunMultiQCButton(), SequenceAnalysisSchema.SCHEMA_NAME, SequenceAnalysisSchema.TABLE_READSETS);
398399
LDKService.get().registerQueryButton(new DownloadSraButton(), SequenceAnalysisSchema.SCHEMA_NAME, SequenceAnalysisSchema.TABLE_READSETS);
400+
LDKService.get().registerQueryButton(new ArchiveReadsetsButton(), SequenceAnalysisSchema.SCHEMA_NAME, SequenceAnalysisSchema.TABLE_READSETS);
399401

400402
LDKService.get().registerQueryButton(new ChangeReadsetStatusForAnalysesButton(), "sequenceanalysis", "sequence_analyses");
401403
LDKService.get().registerQueryButton(new ChangeReadsetStatusButton(), "sequenceanalysis", "sequence_readsets");
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.labkey.sequenceanalysis.button;
2+
3+
import org.labkey.api.laboratory.security.LaboratoryAdminPermission;
4+
import org.labkey.api.ldk.table.SimpleButtonConfigFactory;
5+
import org.labkey.api.module.ModuleLoader;
6+
import org.labkey.api.security.permissions.AdminPermission;
7+
import org.labkey.api.security.permissions.UpdatePermission;
8+
import org.labkey.api.view.template.ClientDependency;
9+
import org.labkey.sequenceanalysis.SequenceAnalysisModule;
10+
11+
import java.util.Arrays;
12+
13+
/**
14+
* Created by bimber on 7/12/2017.
15+
*/
16+
public class ArchiveReadsetsButton extends SimpleButtonConfigFactory
17+
{
18+
public ArchiveReadsetsButton()
19+
{
20+
super(ModuleLoader.getInstance().getModule(SequenceAnalysisModule.class), "Archive Readsets", "SequenceAnalysis.window.ArchiveReadsetsWindow.buttonHandler(dataRegionName);", Arrays.asList(ClientDependency.supplierFromModuleName("ldk"), ClientDependency.supplierFromModuleName("laboratory"), ClientDependency.supplierFromPath("sequenceanalysis/window/ArchiveReadsetsWindow.js")));
21+
setPermission(LaboratoryAdminPermission.class);
22+
}
23+
}

singlecell/resources/views/singleCellDataManagement.html

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,37 @@
6868
'query.isArchived~eq': 0
6969
}
7070
)
71+
},{
72+
name: 'CITE-seq/Hashing Readsets Possibly Needing Archival',
73+
url: LABKEY.ActionURL.buildURL('query', 'executeQuery.view', null, {
74+
schemaName: 'sequenceanalysis',
75+
queryName: 'sequence_readsets',
76+
viewName: 'SRA Info',
77+
'query.totalForwardReads~isnonblank': null,
78+
'query.application~containsoneof': 'Cell Hashing;CITE-Seq',
79+
'query.totalOutputs~gt': 0,
80+
'query.isArchived~eq': 0,
81+
'query.readdataWithoutSra~eq': 0,
82+
'query.sort': 'name'
83+
}
84+
)
85+
},{
86+
name: 'TCR Readsets Possibly Needing Archival',
87+
url: LABKEY.ActionURL.buildURL('query', 'executeQuery.view', null, {
88+
schemaName: 'sequenceanalysis',
89+
queryName: 'sequence_readsets',
90+
viewName: 'SRA Info',
91+
'query.totalForwardReads~isnonblank': null,
92+
'query.isArchived~eq': 0,
93+
'query.readdataWithoutSra~eq': 0,
94+
'query.totalAlignments~gt': 0,
95+
'query.application~contains': 'single',
96+
'query.status~isblank': null,
97+
'query.librarytype~doesnotcontain': 'BCR',
98+
'query.librarytype~contains': 'VDJ',
99+
'query.sort': 'name'
100+
}
101+
)
71102
}, {
72103
name: 'Analyses Using Old Readsets',
73104
url: LABKEY.ActionURL.buildURL('query', 'executeQuery.view', null, {

0 commit comments

Comments
 (0)