diff --git a/SivStudies/resources/queries/study/additionalDatatypes.query.xml b/SivStudies/resources/queries/study/additionalDatatypes.query.xml index 07aff712..1b446dfd 100644 --- a/SivStudies/resources/queries/study/additionalDatatypes.query.xml +++ b/SivStudies/resources/queries/study/additionalDatatypes.query.xml @@ -4,7 +4,7 @@ - + diff --git a/SivStudies/resources/queries/study/demographics.query.xml b/SivStudies/resources/queries/study/demographics.query.xml index 49f10a6d..63cf4041 100644 --- a/SivStudies/resources/queries/study/demographics.query.xml +++ b/SivStudies/resources/queries/study/demographics.query.xml @@ -5,7 +5,6 @@ - true diff --git a/SivStudies/resources/queries/study/demographics/.qview.xml b/SivStudies/resources/queries/study/demographics/.qview.xml index 677d864d..36ef6723 100644 --- a/SivStudies/resources/queries/study/demographics/.qview.xml +++ b/SivStudies/resources/queries/study/demographics/.qview.xml @@ -13,7 +13,7 @@ - + diff --git a/SivStudies/resources/queries/study/demographics/Expanded.qview.xml b/SivStudies/resources/queries/study/demographics/Expanded.qview.xml index 6cfb780d..1598334f 100644 --- a/SivStudies/resources/queries/study/demographics/Expanded.qview.xml +++ b/SivStudies/resources/queries/study/demographics/Expanded.qview.xml @@ -7,8 +7,10 @@ - + + + diff --git a/SivStudies/resources/queries/study/demographicsChallengeAndArt.query.xml b/SivStudies/resources/queries/study/demographicsChallengeAndArt.query.xml new file mode 100644 index 00000000..135d018b --- /dev/null +++ b/SivStudies/resources/queries/study/demographicsChallengeAndArt.query.xml @@ -0,0 +1,25 @@ + + + +
+ SIV/ART Summary + + + true + true + + + SIV Infection + + + ART + + + Infection Date + + + allInfections +
+ + + diff --git a/SivStudies/resources/queries/study/demographicsChallengeAndArt.sql b/SivStudies/resources/queries/study/demographicsChallengeAndArt.sql new file mode 100644 index 00000000..4e4f9fc7 --- /dev/null +++ b/SivStudies/resources/queries/study/demographicsChallengeAndArt.sql @@ -0,0 +1,17 @@ +SELECT + t.Id, + group_concat(DISTINCT CASE + WHEN t.category = 'SIV Infection' THEN (cast(month(t.date) as varchar) || '/' || cast(dayofmonth(t.date) as varchar) || '/' || cast(year(t.date) as varchar) || ' (' || t.treatment || ')') + ELSE NULL + END, char(10)) as allInfections, + group_concat(DISTINCT CASE + WHEN t.category = 'ART' THEN (cast(month(t.date) as varchar) || '/' || cast(dayofmonth(t.date) as varchar) || '/' || cast(year(t.date) as varchar) || ' (' || t.treatment || ')') + ELSE NULL + END, char(10)) as allART, + min(CASE + WHEN t.category = 'SIV Infection' THEN t.date + ELSE NULL + END) as infectionDate, + +FROM study.treatments t +GROUP BY t.Id \ No newline at end of file diff --git a/SivStudies/resources/queries/study/demographicsProjects.query.xml b/SivStudies/resources/queries/study/demographicsProjects.query.xml index fc8f02e9..ec3dddc0 100644 --- a/SivStudies/resources/queries/study/demographicsProjects.query.xml +++ b/SivStudies/resources/queries/study/demographicsProjects.query.xml @@ -14,6 +14,9 @@ All Studies + + Subgroups/Treatments + RhCMV Vaccines? diff --git a/SivStudies/resources/queries/study/demographicsProjects.sql b/SivStudies/resources/queries/study/demographicsProjects.sql index e01f2a07..853db7d1 100644 --- a/SivStudies/resources/queries/study/demographicsProjects.sql +++ b/SivStudies/resources/queries/study/demographicsProjects.sql @@ -3,6 +3,7 @@ SELECT count(s.Id) as totalProjects, group_concat(DISTINCT s.study, char(10)) as allStudies, group_concat(DISTINCT s.category, char(10)) as categories, + group_concat(DISTINCT s.subgroup, char(10)) as subgroups, GROUP_CONCAT(distinct CASE WHEN s.category = 'RhCMV-Vaccines' THEN 'Yes' ELSE null END, char(10)) as rhCmvVaccines, GROUP_CONCAT(distinct CASE WHEN s.category = 'SIV/ART' THEN 'Yes' ELSE null END, char(10)) as sivArt diff --git a/SivStudies/resources/queries/study/procedures.query.xml b/SivStudies/resources/queries/study/procedures.query.xml index 06cd4bdc..eaa6a960 100644 --- a/SivStudies/resources/queries/study/procedures.query.xml +++ b/SivStudies/resources/queries/study/procedures.query.xml @@ -4,7 +4,7 @@ - + diff --git a/SivStudies/resources/queries/study/studyData.query.xml b/SivStudies/resources/queries/study/studyData.query.xml index 4a1d46d7..e78b0c84 100644 --- a/SivStudies/resources/queries/study/studyData.query.xml +++ b/SivStudies/resources/queries/study/studyData.query.xml @@ -6,6 +6,7 @@ http://cpas.labkey.com/Study#ParticipantId + laboratory/dataBrowser.view?subjectId=${Id} Date @@ -25,6 +26,9 @@ true + + true +
- + true diff --git a/SivStudies/resources/views/participantView.html b/SivStudies/resources/views/participantView.html new file mode 100644 index 00000000..64c6df39 --- /dev/null +++ b/SivStudies/resources/views/participantView.html @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/SivStudies/src/org/labkey/sivstudies/etl/SubjectScopedSelect.java b/SivStudies/src/org/labkey/sivstudies/etl/SubjectScopedSelect.java index a36369ce..6c750b8b 100644 --- a/SivStudies/src/org/labkey/sivstudies/etl/SubjectScopedSelect.java +++ b/SivStudies/src/org/labkey/sivstudies/etl/SubjectScopedSelect.java @@ -9,6 +9,7 @@ import org.labkey.api.data.CompareType; import org.labkey.api.data.Container; import org.labkey.api.data.ContainerManager; +import org.labkey.api.data.DbScope; import org.labkey.api.data.SimpleFilter; import org.labkey.api.data.TableInfo; import org.labkey.api.data.TableSelector; @@ -100,7 +101,7 @@ public boolean isRequired() } } - final int BATCH_SIZE = 100; + final int BATCH_SIZE = 250; private MODE getMode() { @@ -136,127 +137,136 @@ private void checkCancelled(PipelineJob job) private void processBatch(List subjects, Logger log, PipelineJob job) { log.info("processing batch with " + subjects.size() + " subjects"); - TableInfo destinationTable = getDataDestinationTable(); + try (DbScope.Transaction t = DbScope.getLabKeyScope().ensureTransaction()) + { + TableInfo destinationTable = getDataDestinationTable(); - QueryUpdateService qus = destinationTable.getUpdateService(); - qus.setBulkLoad(true); + QueryUpdateService qus = destinationTable.getUpdateService(); + qus.setBulkLoad(true); - try - { - if (getMode() == MODE.TRUNCATE) + try { - // Find / Delete existing values: - Set keyFields = destinationTable.getColumns().stream().filter(ColumnInfo::isKeyField).collect(Collectors.toSet()); - final SimpleFilter subjectFilter = new SimpleFilter(FieldKey.fromString(_settings.get(Settings.targetSubjectColumn.name())), subjects, CompareType.IN); - if (_settings.get(Settings.targetAdditionalFilters.name()) != null) + if (getMode() == MODE.TRUNCATE) { - List additionalFilters = parseAdditionalFilters(_settings.get(Settings.targetAdditionalFilters.name())); - additionalFilters.forEach(subjectFilter::addCondition); - } + // Find / Delete existing values: + Set keyFields = destinationTable.getColumns().stream().filter(ColumnInfo::isKeyField).collect(Collectors.toSet()); + final SimpleFilter subjectFilter = new SimpleFilter(FieldKey.fromString(_settings.get(Settings.targetSubjectColumn.name())), subjects, CompareType.IN); + if (_settings.get(Settings.targetAdditionalFilters.name()) != null) + { + List additionalFilters = parseAdditionalFilters(_settings.get(Settings.targetAdditionalFilters.name())); + additionalFilters.forEach(subjectFilter::addCondition); + } - if (destinationTable.getColumn(FieldKey.fromString(_settings.get(Settings.targetSubjectColumn.name()))) == null) - { - throw new IllegalStateException("Unknown column on table " + destinationTable.getName() + ": " + _settings.get(Settings.targetSubjectColumn.name())); - } + if (destinationTable.getColumn(FieldKey.fromString(_settings.get(Settings.targetSubjectColumn.name()))) == null) + { + throw new IllegalStateException("Unknown column on table " + destinationTable.getName() + ": " + _settings.get(Settings.targetSubjectColumn.name())); + } - List> existingRows = new ArrayList<>(new TableSelector(destinationTable, keyFields, subjectFilter, null).getMapCollection()); - if (!existingRows.isEmpty()) - { - List>> batches = Lists.partition(existingRows, 5000); - log.info("deleting " + existingRows.size() + " rows in " + batches.size() + " batches"); - int i = 0; - for (List> batch : batches) + List> existingRows = new ArrayList<>(new TableSelector(destinationTable, keyFields, subjectFilter, null).getMapCollection()); + if (!existingRows.isEmpty()) { - i++; - log.info("batch " + i); - checkCancelled(job); + List>> batches = Lists.partition(existingRows, 5000); + log.info("deleting " + existingRows.size() + " rows in " + batches.size() + " batches"); + int i = 0; + for (List> batch : batches) + { + i++; + log.info("batch " + i); + checkCancelled(job); - qus.deleteRows(_containerUser.getUser(), _containerUser.getContainer(), batch, new HashMap<>(Map.of(DetailedAuditLogDataIterator.AuditConfigs.AuditBehavior, NONE, QueryUpdateService.ConfigParameters.BulkLoad, true)), null); + qus.deleteRows(_containerUser.getUser(), _containerUser.getContainer(), batch, new HashMap<>(Map.of(DetailedAuditLogDataIterator.AuditConfigs.AuditBehavior, NONE, QueryUpdateService.ConfigParameters.BulkLoad, true)), null); + t.commitAndKeepConnection(); + } + } + else + { + log.info("No rows to delete for this subject batch"); } } else { - log.info("No rows to delete for this subject batch"); + log.info("Using " + getMode().name() + " mode, source records will not be deleted"); } - } - else - { - log.info("Using " + getMode().name() + " mode, source records will not be deleted"); - } - // Query data and import - List> toImportOrUpdate = getRowsToImport(subjects, log); - if (!toImportOrUpdate.isEmpty()) - { - if (getMode() == MODE.TRUNCATE) + // Query data and import + List> toImportOrUpdate = getRowsToImport(subjects, log); + if (!toImportOrUpdate.isEmpty()) { - List>> batches = Lists.partition(toImportOrUpdate, 5000); - log.info("inserting " + toImportOrUpdate.size() + " rows in " + batches.size() + " batches"); - - int i = 0; - for (List> batch : batches) + if (getMode() == MODE.TRUNCATE) { - i++; - log.info("batch " + i); - checkCancelled(job); + List>> batches = Lists.partition(toImportOrUpdate, 5000); + log.info("inserting " + toImportOrUpdate.size() + " rows in " + batches.size() + " batches"); - BatchValidationException bve = new BatchValidationException(); - qus.insertRows(_containerUser.getUser(), _containerUser.getContainer(), batch, bve, new HashMap<>(Map.of(DetailedAuditLogDataIterator.AuditConfigs.AuditBehavior, NONE, QueryUpdateService.ConfigParameters.BulkLoad, true)), null); - if (bve.hasErrors()) + int i = 0; + for (List> batch : batches) { - throw bve; + i++; + log.info("batch " + i); + checkCancelled(job); + + BatchValidationException bve = new BatchValidationException(); + qus.insertRows(_containerUser.getUser(), _containerUser.getContainer(), batch, bve, new HashMap<>(Map.of(DetailedAuditLogDataIterator.AuditConfigs.AuditBehavior, NONE, QueryUpdateService.ConfigParameters.BulkLoad, true)), null); + if (bve.hasErrors()) + { + throw bve; + } + t.commitAndKeepConnection(); } } - } - else if (getMode() == MODE.UPDATE_ONLY) - { - List>> batches = Lists.partition(toImportOrUpdate, 5000); - log.info("updating " + toImportOrUpdate.size() + " rows in " + batches.size() + " batches"); - - int i = 0; - for (List> batch : batches) + else if (getMode() == MODE.UPDATE_ONLY) { + List>> batches = Lists.partition(toImportOrUpdate, 5000); + log.info("updating " + toImportOrUpdate.size() + " rows in " + batches.size() + " batches"); - i++; - log.info("batch " + i); - checkCancelled(job); + int i = 0; + for (List> batch : batches) + { - BatchValidationException bve = new BatchValidationException(); + i++; + log.info("batch " + i); + checkCancelled(job); - Collection keyFields = destinationTable.getPkColumnNames(); - List> keys = batch.stream().map(x -> { - Map map = new HashMap<>(); - for (String keyField : keyFields) - { - if (x.get(keyField) != null) + BatchValidationException bve = new BatchValidationException(); + + Collection keyFields = destinationTable.getPkColumnNames(); + List> keys = batch.stream().map(x -> { + Map map = new HashMap<>(); + for (String keyField : keyFields) { - map.put(keyField, x.get(keyField)); + if (x.get(keyField) != null) + { + map.put(keyField, x.get(keyField)); + } } - } - return map; - }).toList(); + return map; + }).toList(); - qus.updateRows(_containerUser.getUser(), _containerUser.getContainer(), batch, keys, bve, new HashMap<>(Map.of(DetailedAuditLogDataIterator.AuditConfigs.AuditBehavior, NONE, QueryUpdateService.ConfigParameters.BulkLoad, true)), null); - if (bve.hasErrors()) - { - throw bve; + qus.updateRows(_containerUser.getUser(), _containerUser.getContainer(), batch, keys, bve, new HashMap<>(Map.of(DetailedAuditLogDataIterator.AuditConfigs.AuditBehavior, NONE, QueryUpdateService.ConfigParameters.BulkLoad, true)), null); + if (bve.hasErrors()) + { + throw bve; + } + t.commitAndKeepConnection(); } } + else + { + throw new IllegalStateException("Unknown mode: " + getMode()); + } } else { - throw new IllegalStateException("Unknown mode: " + getMode()); + log.info("No rows to import/update for this subject batch"); } } - else + catch (SQLException | InvalidKeyException | BatchValidationException | QueryUpdateServiceException | + DuplicateKeyException e) { - log.info("No rows to import/update for this subject batch"); + throw new IllegalStateException("Error Importing/Updating Rows", e); } - } - catch (SQLException | InvalidKeyException | BatchValidationException | QueryUpdateServiceException | DuplicateKeyException e) - { - throw new IllegalStateException("Error Importing/Updating Rows", e); + + t.commit(); } } diff --git a/SivStudies/src/org/labkey/sivstudies/query/SivStudiesCustomizer.java b/SivStudies/src/org/labkey/sivstudies/query/SivStudiesCustomizer.java index 48b615b8..ebaeb332 100644 --- a/SivStudies/src/org/labkey/sivstudies/query/SivStudiesCustomizer.java +++ b/SivStudies/src/org/labkey/sivstudies/query/SivStudiesCustomizer.java @@ -249,6 +249,13 @@ private void appendDemographicsColumns(AbstractTableInfo parentTable) colInfo.setLabel("Outcomes"); parentTable.addColumn(colInfo); } + + if (parentTable.getColumn("sivART") == null) + { + BaseColumnInfo colInfo = getWrappedIdCol(parentTable.getUserSchema(), "demographicsChallengeAndArt", parentTable, "sivART"); + colInfo.setLabel("SIV/ART Dates"); + parentTable.addColumn(colInfo); + } } private void appendPvlColumns(DatasetTable ds, String subjectColName, String dateColName) diff --git a/mGAP/resources/queries/mGAP/subjectsSource.query.xml b/mGAP/resources/queries/mGAP/subjectsSource.query.xml index 6185f774..7d580fa2 100644 --- a/mGAP/resources/queries/mGAP/subjectsSource.query.xml +++ b/mGAP/resources/queries/mGAP/subjectsSource.query.xml @@ -2,6 +2,7 @@
+ mGAP Subject/Demographics Source DatasubjectName
diff --git a/mGAP/resources/queries/mGAP/subjectsSource.sql b/mGAP/resources/queries/mGAP/subjectsSource.sql index 3a1ed394..ce5a8246 100644 --- a/mGAP/resources/queries/mGAP/subjectsSource.sql +++ b/mGAP/resources/queries/mGAP/subjectsSource.sql @@ -10,9 +10,15 @@ SELECT WHEN s.Id IS NOT NULL THEN 'ONPRC' ELSE NULL END as center, d.status as status, - m.subjectname as originalId + m.subjectname as originalId, + p1.externalAlias as sire, + coalesce(s.Id.parents.sire, d.sire) as originalSire, + p2.externalAlias as dam, + coalesce(s.Id.parents.dam, d.dam) as originalDam, FROM mgap.animalMapping m LEFT JOIN "/Internal/PMR/".study.demographics s ON (m.subjectname = s.Id) LEFT JOIN mgap.demographics d ON (m.subjectname = d.subjectname) +LEFT JOIN mgap.animalMapping p1 ON (p1.subjectname = coalesce(s.Id.parents.sire, d.sire)) +LEFT JOIN mgap.animalMapping p2 ON (p2.subjectname = coalesce(s.Id.parents.dam, d.dam)) WHERE (s.Id IS NOT NULL OR d.subjectname IS NOT NULL) \ No newline at end of file diff --git a/mGAP/resources/views/login.html b/mGAP/resources/views/login.html index 9dd9f23c..ead854e2 100644 --- a/mGAP/resources/views/login.html +++ b/mGAP/resources/views/login.html @@ -1,20 +1,37 @@
-
Sign In
+
Sign In / Register
+
While mGAP is a free NIH-sponsored resource, we require users register to help us track and report usage to our funders. This information is critical to demonstrate the value and impact of the resource. Please request an account if you are not already registered. Thank you for your understanding.
diff --git a/mGAP/resources/views/mgapDataDashboard.html b/mGAP/resources/views/mgapDataDashboard.html index 87cf98a9..5894d4de 100644 --- a/mGAP/resources/views/mgapDataDashboard.html +++ b/mGAP/resources/views/mgapDataDashboard.html @@ -100,7 +100,7 @@ name: 'Subject Information Synced to mGAP', url: LABKEY.ActionURL.buildURL('query', 'executeQuery.view', null, { schemaName: 'mgap', - queryName: 'subjectDatasetsSource' + queryName: 'subjectsSource' }) }] },{ diff --git a/mcc/resources/queries/mcc/animalRequests.js b/mcc/resources/queries/mcc/animalRequests.js index e069b428..0a3f8ec3 100644 --- a/mcc/resources/queries/mcc/animalRequests.js +++ b/mcc/resources/queries/mcc/animalRequests.js @@ -36,9 +36,18 @@ function beforeUpsert(row, oldRow, errors) { row.status = row.status || 'Draft' - if (!triggerHelper.hasPermission(row.status)) { - errors._form = 'Insufficient permissions to update request with status: ' + row.status; + // This logic here is that the user needs update permissions on the original status, and insert permissions to the new one: + if (oldRow) { + if (oldRow.status && !triggerHelper.hasUpdatePermission(oldRow.status)) { + errors._form = 'Insufficient permissions to update request with status: ' + row.status; + } + else if (!oldRow.status) { + console.error('MCC request being submitted without a value for oldRow.status!') + } + } + if (!triggerHelper.hasInsertPermission(row.status)) { + errors._form = 'Insufficient permissions to create request with status: ' + row.status; } } @@ -72,6 +81,7 @@ function beforeDelete(row, errors){ return; } + // if (!triggerHelper.hasPermission(row.status)) { errors._form = 'Insufficient permissions to delete this request'; return; diff --git a/mcc/src/org/labkey/mcc/MccManager.java b/mcc/src/org/labkey/mcc/MccManager.java index 9ce036ca..0fe8763b 100644 --- a/mcc/src/org/labkey/mcc/MccManager.java +++ b/mcc/src/org/labkey/mcc/MccManager.java @@ -50,26 +50,38 @@ public enum RequestStatus Submitted(2, "Submitted", MccRequestorPermission.class), RabReview(3, "RAB Review", MccRequestAdminPermission.class), PendingDecision(4, "Decision Pending", MccFinalReviewPermission.class), - Approved(5, "Approved", MccRequestAdminPermission.class), - Rejected(6, "Rejected", MccRequestAdminPermission.class), + Approved(5, "Approved", MccRequestAdminPermission.class, MccFinalReviewPermission.class), + Rejected(6, "Rejected", MccRequestAdminPermission.class, MccFinalReviewPermission.class), Processing(7, "Processing", MccRequestAdminPermission.class), Fulfilled(8, "Fulfilled", MccRequestAdminPermission.class), Withdrawn(9, "Withdrawn", MccRequestorPermission.class); int sortOrder; String label; - Class editPermission; + Class updatePermission; + Class insertPermission; RequestStatus(int sortOrder, String label, Class editPermission) + { + this(sortOrder, label, editPermission, editPermission); + } + + RequestStatus(int sortOrder, String label, Class updatePermission, Class insertPermission) { this.sortOrder = sortOrder; this.label = label; - this.editPermission = editPermission; + this.updatePermission = updatePermission; + this.insertPermission= insertPermission; + } + + public boolean canUpdate(User u, Container c) + { + return c.hasPermission(u, this.updatePermission); } - public boolean canEdit(User u, Container c) + public boolean canInsert(User u, Container c) { - return c.hasPermission(u, this.editPermission); + return c.hasPermission(u, this.insertPermission); } public String getLabel() diff --git a/mcc/src/org/labkey/mcc/etl/NprcObservationStep.java b/mcc/src/org/labkey/mcc/etl/NprcObservationStep.java index 87a9f7f3..bbfe3f08 100644 --- a/mcc/src/org/labkey/mcc/etl/NprcObservationStep.java +++ b/mcc/src/org/labkey/mcc/etl/NprcObservationStep.java @@ -21,6 +21,7 @@ import org.labkey.api.query.FieldKey; import org.labkey.api.query.InvalidKeyException; import org.labkey.api.query.QueryService; +import org.labkey.api.query.QueryUpdateService; import org.labkey.api.query.QueryUpdateServiceException; import org.labkey.api.query.UserSchema; import org.labkey.api.reader.Readers; @@ -74,6 +75,8 @@ private void processFile(PipelineJob job) throws PipelineJobException { throw new PipelineJobException("Unable to find table: clinical observations"); } + QueryUpdateService qus = clinicalObs.getUpdateService(); + qus.setBulkLoad(true); final List> toInsert = new ArrayList<>(); final List> toUpdate = new ArrayList<>(); @@ -156,7 +159,7 @@ private void processFile(PipelineJob job) throws PipelineJobException job.getLogger().info("Deleting " + toDelete.size() + " rows"); try { - clinicalObs.getUpdateService().deleteRows(_containerUser.getUser(), _containerUser.getContainer(), toDelete, null, null); + qus.deleteRows(_containerUser.getUser(), _containerUser.getContainer(), toDelete, null, null); } catch (InvalidKeyException | BatchValidationException | QueryUpdateServiceException | SQLException e) { @@ -170,7 +173,7 @@ private void processFile(PipelineJob job) throws PipelineJobException try { BatchValidationException bve = new BatchValidationException(); - clinicalObs.getUpdateService().insertRows(_containerUser.getUser(), _containerUser.getContainer(), toInsert, bve, null, null); + qus.insertRows(_containerUser.getUser(), _containerUser.getContainer(), toInsert, bve, null, null); if (bve.hasErrors()) { throw bve; @@ -192,7 +195,7 @@ private void processFile(PipelineJob job) throws PipelineJobException try { List> oldKeys = toUpdate.stream().map(x -> Map.of("objectid", x.get("objectid"))).collect(Collectors.toList()); - clinicalObs.getUpdateService().updateRows(_containerUser.getUser(), _containerUser.getContainer(), toUpdate, oldKeys, null, null); + qus.updateRows(_containerUser.getUser(), _containerUser.getContainer(), toUpdate, oldKeys, null, null); } catch (QueryUpdateServiceException | SQLException | BatchValidationException | InvalidKeyException e) { diff --git a/mcc/src/org/labkey/mcc/query/TriggerHelper.java b/mcc/src/org/labkey/mcc/query/TriggerHelper.java index f36e999e..9df99ae2 100644 --- a/mcc/src/org/labkey/mcc/query/TriggerHelper.java +++ b/mcc/src/org/labkey/mcc/query/TriggerHelper.java @@ -212,11 +212,30 @@ public void cascadeDelete(String schemaName, String queryName, String keyField, } } - public boolean hasPermission(String status) + public boolean hasUpdatePermission(String status) + { + return hasPermission(status, false); + } + + public boolean hasInsertPermission(String status) + { + return hasPermission(status, true); + } + + private boolean hasPermission(String status, boolean forInsert) { try { - return MccManager.RequestStatus.resolveStatus(status).canEdit(_user, _container); + MccManager.RequestStatus s = MccManager.RequestStatus.resolveStatus(status); + if (forInsert) + { + return MccManager.RequestStatus.resolveStatus(status).canInsert(_user, _container); + } + else + { + return MccManager.RequestStatus.resolveStatus(status).canUpdate(_user, _container); + } + } catch (IllegalArgumentException e) { diff --git a/primeseq/src/org/labkey/primeseq/notification/DiskUsageNotification.java b/primeseq/src/org/labkey/primeseq/notification/DiskUsageNotification.java index 799965cf..4ea8e2b9 100644 --- a/primeseq/src/org/labkey/primeseq/notification/DiskUsageNotification.java +++ b/primeseq/src/org/labkey/primeseq/notification/DiskUsageNotification.java @@ -73,7 +73,7 @@ public DateFormat getDateTimeFormat(Container c) @Override public String getCronString() { - return "0 8 * * 1 ?"; + return "0 0 8 ? * MON"; } @Override diff --git a/tcrdb/resources/schemas/dbscripts/postgresql/tcrdb-15.57-15.58.sql b/tcrdb/resources/schemas/dbscripts/postgresql/tcrdb-15.57-15.58.sql new file mode 100644 index 00000000..5c5a9b3f --- /dev/null +++ b/tcrdb/resources/schemas/dbscripts/postgresql/tcrdb-15.57-15.58.sql @@ -0,0 +1,16 @@ +CREATE TABLE tcrdb.repertoire_stats ( + rowid SERIAL, + cdna_id int, + metricName varchar(1000), + value double precision, + qualValue varchar(4000), + comment varchar(4000), + + container entityid, + created timestamp, + createdby int, + modified timestamp, + modifiedby int, + + constraint PK_repertoire_stats PRIMARY KEY (rowid) +); \ No newline at end of file diff --git a/tcrdb/resources/schemas/dbscripts/sqlserver/tcrdb-15.57-15.58.sql b/tcrdb/resources/schemas/dbscripts/sqlserver/tcrdb-15.57-15.58.sql new file mode 100644 index 00000000..5e9c3699 --- /dev/null +++ b/tcrdb/resources/schemas/dbscripts/sqlserver/tcrdb-15.57-15.58.sql @@ -0,0 +1,16 @@ +CREATE TABLE tcrdb.repertoire_stats ( + rowid int IDENTITY(1,1), + cdna_id int, + metricName varchar(1000), + value double precision, + qualValue varchar(4000), + comment varchar(4000), + + container entityid, + created datetime, + createdby int, + modified datetime, + modifiedby int, + + constraint PK_repertoire_stats PRIMARY KEY (rowid) +); \ No newline at end of file diff --git a/tcrdb/resources/schemas/tcrdb.xml b/tcrdb/resources/schemas/tcrdb.xml index 60a93c0a..b6384344 100644 --- a/tcrdb/resources/schemas/tcrdb.xml +++ b/tcrdb/resources/schemas/tcrdb.xml @@ -325,6 +325,60 @@ + + + true + + + true + + + false + false + false + true + true + + + true + + + false + false + false + true + true + + + + + + TCR Repertoire Stats + rowid + + + Row Id + true + + + cDNA ID + + singlecell + cdna_libraries + rowid + + + + Metric Name + + + Value + + + Qualitative Value + + + true diff --git a/tcrdb/src/org/labkey/tcrdb/TCRdbModule.java b/tcrdb/src/org/labkey/tcrdb/TCRdbModule.java index d452b218..1f472626 100644 --- a/tcrdb/src/org/labkey/tcrdb/TCRdbModule.java +++ b/tcrdb/src/org/labkey/tcrdb/TCRdbModule.java @@ -46,7 +46,7 @@ public String getName() @Override public Double getSchemaVersion() { - return 15.57; + return 15.58; } @Override @@ -72,6 +72,8 @@ protected void doStartupAfterSpringConfig(ModuleContext moduleContext) LaboratoryService.get().registerTableCustomizer(this, TCRdbTableCustomizer.class, TCRdbSchema.SEQUENCE_ANALYSIS, "sequence_readsets"); LaboratoryService.get().registerTableCustomizer(this, TCRdbTableCustomizer.class, TCRdbSchema.SEQUENCE_ANALYSIS, "sequence_analyses"); LaboratoryService.get().registerTableCustomizer(this, TCRdbTableCustomizer.class, TCRdbSchema.NAME, TCRdbSchema.TABLE_CLONES); + LaboratoryService.get().registerTableCustomizer(this, TCRdbTableCustomizer.class, TCRdbSchema.NAME, TCRdbSchema.TABLE_CLONE_RESPONSES); + LaboratoryService.get().registerTableCustomizer(this, TCRdbTableCustomizer.class, TCRdbSchema.NAME, TCRdbSchema.TABLE_STIM_EXPERIMENTS); LaboratoryService.get().registerTableCustomizer(this, TCRdbTableCustomizer.class, TCRdbSchema.SINGLE_CELL, TCRdbSchema.TABLE_CDNAS); LDKService.get().registerQueryButton(new ChangeStatusButton(), TCRdbSchema.SINGLE_CELL, "samples"); diff --git a/tcrdb/src/org/labkey/tcrdb/TCRdbTableCustomizer.java b/tcrdb/src/org/labkey/tcrdb/TCRdbTableCustomizer.java index 1a9f0094..44226a3f 100644 --- a/tcrdb/src/org/labkey/tcrdb/TCRdbTableCustomizer.java +++ b/tcrdb/src/org/labkey/tcrdb/TCRdbTableCustomizer.java @@ -12,6 +12,7 @@ import org.labkey.api.data.SimpleFilter; import org.labkey.api.data.Table; import org.labkey.api.data.TableInfo; +import org.labkey.api.data.WrappedColumn; import org.labkey.api.exp.api.ExpProtocol; import org.labkey.api.laboratory.LaboratoryService; import org.labkey.api.ldk.LDKService; @@ -19,6 +20,7 @@ import org.labkey.api.query.DetailsURL; import org.labkey.api.query.ExprColumn; import org.labkey.api.query.FieldKey; +import org.labkey.api.query.QueryForeignKey; import org.labkey.api.query.QueryService; import java.util.Arrays; @@ -48,6 +50,14 @@ else if (matches(ti, TCRdbSchema.NAME, TCRdbSchema.TABLE_CLONES)) { customizeClones(ti); } + else if (matches(ti, TCRdbSchema.NAME, TCRdbSchema.TABLE_CLONE_RESPONSES)) + { + customizeCloneResponses(ti); + } + else if (matches(ti, TCRdbSchema.NAME, TCRdbSchema.TABLE_STIM_EXPERIMENTS)) + { + customizeStims(ti); + } else if (ti instanceof AssayResultTable) { customizeAssayData(ti); @@ -223,6 +233,34 @@ private void addClonotypeForLocusCol(AbstractTableInfo ti, SQLFragment selectSql ti.addColumn(newCol); } + private void customizeCloneResponses(AbstractTableInfo ti) + { + if (ti.getColumn("stimId") == null) + { + WrappedColumn col = new WrappedColumn(ti.getColumn("cDNA_ID"), "stimId"); + col.setReadOnly(true); + col.setUserEditable(false); + col.setLabel("Stim Experiment"); + col.setFk(new QueryForeignKey(ti.getUserSchema(), null, ti.getUserSchema(), null, TCRdbSchema.TABLE_STIM_EXPERIMENTS, "cdna_id", "cdna_id")); + + ti.addColumn(col); + } + } + + private void customizeStims(AbstractTableInfo ti) + { + if (ti.getColumn("controlStim") == null) + { + WrappedColumn col = new WrappedColumn(ti.getColumn("controlStimId"), "controlStim"); + col.setReadOnly(true); + col.setUserEditable(false); + col.setLabel("Control Stim Info"); + col.setFk(new QueryForeignKey(ti.getUserSchema(), null, ti.getUserSchema(), null, TCRdbSchema.TABLE_STIM_EXPERIMENTS, "cdna_id", "cdna_id")); + + ti.addColumn(col); + } + } + private void customizeClones(AbstractTableInfo ti) { LDKService.get().applyNaturalSort(ti, "cloneName"); diff --git a/tcrdb/src/org/labkey/tcrdb/TCRdbUserSchema.java b/tcrdb/src/org/labkey/tcrdb/TCRdbUserSchema.java index 188fcc11..505bd957 100644 --- a/tcrdb/src/org/labkey/tcrdb/TCRdbUserSchema.java +++ b/tcrdb/src/org/labkey/tcrdb/TCRdbUserSchema.java @@ -6,6 +6,7 @@ import org.labkey.api.data.ContainerFilter; import org.labkey.api.data.DbSchema; import org.labkey.api.data.TableInfo; +import org.labkey.api.ldk.table.ContainerScopedTable; import org.labkey.api.ldk.table.SharedDataTable; import org.labkey.api.module.Module; import org.labkey.api.query.DefaultSchema; @@ -43,9 +44,12 @@ protected TableInfo createWrappedTable(String name, @NotNull TableInfo sourceTab { if (TCRdbSchema.TABLE_MIXCR_LIBRARIES.equalsIgnoreCase(name)) { - // TODO: assert cf is null or not default? return new SharedDataTable<>(this, sourceTable).init(); } + else if (TCRdbSchema.TABLE_STIM_EXPERIMENTS.equalsIgnoreCase(name)) + { + return new ContainerScopedTable<>(this, sourceTable, null, "cdna_id").init(); + } return super.createWrappedTable(name, sourceTable, cf); }