From 758154cf2b55b963267fa6f42e63ec881b4852b9 Mon Sep 17 00:00:00 2001 From: bbimber Date: Thu, 27 Aug 2026 18:08:48 -0700 Subject: [PATCH 01/18] Add libraryType to genetics datasets --- SivStudies/resources/etls/siv-studies.xml | 2 +- SivStudies/resources/queries/study/genetics.query.xml | 3 +++ .../referenceStudy/study/datasets/datasets_metadata.xml | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/SivStudies/resources/etls/siv-studies.xml b/SivStudies/resources/etls/siv-studies.xml index c99ffd985..fbd6bcf7e 100644 --- a/SivStudies/resources/etls/siv-studies.xml +++ b/SivStudies/resources/etls/siv-studies.xml @@ -57,7 +57,7 @@ - + diff --git a/SivStudies/resources/queries/study/genetics.query.xml b/SivStudies/resources/queries/study/genetics.query.xml index 334a603e5..07774ea71 100644 --- a/SivStudies/resources/queries/study/genetics.query.xml +++ b/SivStudies/resources/queries/study/genetics.query.xml @@ -14,6 +14,9 @@ Assay Type + + Library Type + Marker/Allele diff --git a/SivStudies/resources/referenceStudy/study/datasets/datasets_metadata.xml b/SivStudies/resources/referenceStudy/study/datasets/datasets_metadata.xml index 2aaf20eac..77f3b4d04 100644 --- a/SivStudies/resources/referenceStudy/study/datasets/datasets_metadata.xml +++ b/SivStudies/resources/referenceStudy/study/datasets/datasets_metadata.xml @@ -427,6 +427,9 @@ varchar + + varchar + varchar From 62c880c2100b64cf89b9dcdb6d65f9473c8682de Mon Sep 17 00:00:00 2001 From: bbimber Date: Mon, 31 Aug 2026 11:01:57 -0700 Subject: [PATCH 02/18] Switch from waitForCompletion to Future.get() --- .../primeseq/pipeline/ClusterMaintenanceTask.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/primeseq/src/org/labkey/primeseq/pipeline/ClusterMaintenanceTask.java b/primeseq/src/org/labkey/primeseq/pipeline/ClusterMaintenanceTask.java index edf0ddd57..480892d1b 100644 --- a/primeseq/src/org/labkey/primeseq/pipeline/ClusterMaintenanceTask.java +++ b/primeseq/src/org/labkey/primeseq/pipeline/ClusterMaintenanceTask.java @@ -46,6 +46,7 @@ import java.util.Date; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.Future; /** * This task is designed to run remotely and will delete orphan working directories on a remote pipeline server @@ -101,7 +102,7 @@ public void run(Logger log) File logFile = FileUtil.appendName(subdir, "Maintenance-" + engine.getType() + "." + FileUtil.getTimestamp() + ".log"); - jr.execute(new Job() + Future future = jr.execute(new Job() { @Override public void run() @@ -116,15 +117,16 @@ public void run() _log.error(e.getMessage(), e); } } - }); + }, 0); + + // Wait for this job to complete: + future.get(); } catch (Exception e) { log.error(e); } } - - jr.waitForCompletion(); } @Override From 3b8372d5e07b326d0ecafe31e584d92dd75bb428 Mon Sep 17 00:00:00 2001 From: bbimber Date: Wed, 2 Sep 2026 11:34:23 -0700 Subject: [PATCH 03/18] Switch mGAP to auto-approve .edu and .gov users --- mGAP/src/org/labkey/mgap/mGAPController.java | 177 ++++++------------- mGAP/src/org/labkey/mgap/mGAPManager.java | 167 ++++++++++++++++- 2 files changed, 219 insertions(+), 125 deletions(-) diff --git a/mGAP/src/org/labkey/mgap/mGAPController.java b/mGAP/src/org/labkey/mgap/mGAPController.java index ed90d1986..9d324c815 100644 --- a/mGAP/src/org/labkey/mgap/mGAPController.java +++ b/mGAP/src/org/labkey/mgap/mGAPController.java @@ -40,10 +40,8 @@ import org.labkey.api.data.CompareType; import org.labkey.api.data.Container; import org.labkey.api.data.ContainerManager; -import org.labkey.api.data.CoreSchema; import org.labkey.api.data.DbSchema; import org.labkey.api.data.DbSchemaType; -import org.labkey.api.data.DbScope; import org.labkey.api.data.Results; import org.labkey.api.data.SimpleFilter; import org.labkey.api.data.Sort; @@ -51,6 +49,7 @@ import org.labkey.api.data.TableInfo; import org.labkey.api.data.TableSelector; import org.labkey.api.exp.api.ExpData; +import org.labkey.api.ldk.LDKService; import org.labkey.api.module.AllowedDuringUpgrade; import org.labkey.api.module.ModuleLoader; import org.labkey.api.pipeline.PipelineUrls; @@ -63,32 +62,26 @@ import org.labkey.api.query.UserSchema; import org.labkey.api.reader.Readers; import org.labkey.api.resource.Resource; -import org.labkey.api.security.AuthenticationManager; -import org.labkey.api.security.Group; -import org.labkey.api.security.GroupManager; import org.labkey.api.security.IgnoresTermsOfUse; -import org.labkey.api.security.MutableSecurityPolicy; import org.labkey.api.security.RequiresNoPermission; import org.labkey.api.security.RequiresPermission; -import org.labkey.api.security.SecurityManager; -import org.labkey.api.security.SecurityPolicyManager; import org.labkey.api.security.User; import org.labkey.api.security.UserManager; import org.labkey.api.security.ValidEmail; import org.labkey.api.security.permissions.AdminPermission; import org.labkey.api.security.permissions.ReadPermission; -import org.labkey.api.security.roles.ReaderRole; import org.labkey.api.sequenceanalysis.SequenceAnalysisService; import org.labkey.api.sequenceanalysis.SequenceOutputFile; import org.labkey.api.sequenceanalysis.pipeline.ReferenceGenome; import org.labkey.api.settings.AppProps; -import org.labkey.api.settings.LookAndFeelProperties; import org.labkey.api.studies.StudiesService; import org.labkey.api.util.ConfigurationException; +import org.labkey.api.util.DOM; import org.labkey.api.util.ExceptionUtil; import org.labkey.api.util.FileUtil; import org.labkey.api.util.GUID; import org.labkey.api.util.HtmlString; +import org.labkey.api.util.HtmlStringBuilder; import org.labkey.api.util.MailHelper; import org.labkey.api.util.PageFlowUtil; import org.labkey.api.util.Path; @@ -98,7 +91,6 @@ import org.labkey.api.view.NotFoundException; import org.labkey.api.view.UnauthorizedException; import org.labkey.mgap.pipeline.mGapSummarizer; -import org.labkey.security.xml.GroupEnumType; import org.springframework.validation.BindException; import org.springframework.validation.Errors; import org.springframework.web.servlet.ModelAndView; @@ -117,6 +109,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.TreeSet; import java.util.zip.ZipEntry; @@ -163,7 +156,7 @@ else if (StringUtils.isEmpty(form.getFirstName()) || StringUtils.isEmpty(form.ge { try { - ValidEmail email = new ValidEmail(form.getEmail()); + ValidEmail email = new ValidEmail(form.getEmail()); //test if valid if (!form.getEmail().equals(form.getEmailConfirmation())) { errors.reject(ERROR_MSG, "The email addresses you have entered do not match. Please verify your email addresses below."); @@ -190,7 +183,7 @@ else if (StringUtils.isEmpty(form.getFirstName()) || StringUtils.isEmpty(form.ge public Object execute(RequestUserForm form, BindException errors) throws Exception { ApiSimpleResponse response = new ApiSimpleResponse(); - + User adminUser = LDKService.get().getBackgroundAdminUser(); try { TableInfo ti = mGAPSchema.getInstance().getSchema().getTable(mGAPSchema.TABLE_USER_REQUESTS); @@ -205,7 +198,7 @@ public Object execute(RequestUserForm form, BindException errors) throws Excepti row.put("reason", form.getReason()); row.put("container", mGAPManager.get().getMGapContainer().getId()); - Table.insert(UserManager.getGuestUser(), ti, row); + row = Table.insert(UserManager.getGuestUser(), ti, row); Set users = mGAPManager.get().getNotificationUsers(); if (users != null && !users.isEmpty()) @@ -227,12 +220,54 @@ public Object execute(RequestUserForm form, BindException errors) throws Excepti } DetailsURL url = DetailsURL.fromString("/query/executeQuery.view?schemaName=mgap&query.queryName=userRequests&query.viewName=Pending Requests", c); - mail.setEncodedHtmlContent("A user requested an account on mGap. Click here to view/approve this request"); - mail.setFrom(getReplyEmail(getContainer())); + HtmlStringBuilder builder = HtmlStringBuilder.of("A user requested an account on mGap. "). + unsafeAppend("Click here to view/approve this request"); + + boolean autoApprove = false; + Integer requestId = null; + if (form.getEmail().toLowerCase().endsWith(".edu") || form.getEmail().toLowerCase().endsWith(".gov")) + { + if (row.get("rowid") == null) + { + _log.error("Unable to find requestId for new mGAP request, will not auto-approve"); + } + else if (adminUser == null) + { + _log.error("LDK Admin User is not set, unable to auto-approve mGAP request"); + } + else + { + autoApprove = true; + requestId = (int)row.get("rowid"); + builder.unsafeAppend(DOM.SPAN(DOM.at(DOM.Attribute.style, "font-weight:bold;"), " This request was automatically approved.").renderToString()); + } + } + + builder.unsafeAppend(DOM.BR().renderToString()); + builder.unsafeAppend(DOM.BR().renderToString()); + builder.unsafeAppend(DOM.TABLE( + DOM.TR(DOM.TD("Name:"), DOM.TD(form.getFirstName() + " " + form.getLastName())), + DOM.TR(DOM.TD("Email:"), DOM.TD(form.getEmail())), + DOM.TR(DOM.TD("Category:"), DOM.TD(form.getCategory())), + DOM.TR(DOM.TD("Institution:"), DOM.TD(form.getInstitution())), + DOM.TR(DOM.TD("Reason:"), DOM.TD(form.getReason())) + ).renderToString()); + + mail.setEncodedHtmlContent(builder.toString()); + mail.setFrom(mGAPManager.get().getReplyEmail(getContainer())); mail.setSubject("mGap Account Request"); - mail.addRecipients(Message.RecipientType.TO, emails.toArray(new Address[emails.size()])); + mail.addRecipients(Message.RecipientType.TO, emails.toArray(new Address[0])); MailHelper.send(mail, getUser(), c); + + if (autoApprove & !errors.hasErrors()) + { + mGAPManager.get().approveUsers(Arrays.asList(requestId), getContainer(), adminUser, getViewContext(), errors); + if (errors.hasErrors()) + { + _log.error("Unable to automatically create mGAP user"); + } + } } catch (Exception e) { @@ -401,121 +436,19 @@ public void validateForm(ApproveUserRequestsForm form, Errors errors) public Object execute(ApproveUserRequestsForm form, BindException errors) throws Exception { ApiSimpleResponse response = new ApiSimpleResponse(); - List newUserStatusList = new ArrayList<>(); - List existingUsersGivenAccess = new ArrayList<>(); - try (DbScope.Transaction transaction = CoreSchema.getInstance().getScope().ensureTransaction()) - { - TableInfo ti = mGAPSchema.getInstance().getSchema().getTable(mGAPSchema.TABLE_USER_REQUESTS); - for (int requestId : form.getRequestIds()) - { - TableSelector ts = new TableSelector(ti, new SimpleFilter(FieldKey.fromString("rowId"), requestId), null); - Map map = ts.getMap(requestId); - - User u; - if (map.get("userId") != null) - { - Integer userId = asInteger(map.get("userId")); - u = UserManager.getUser(userId); - existingUsersGivenAccess.add(u); - } - else - { - ValidEmail ve = new ValidEmail((String) map.get("email")); - u = UserManager.getUser(ve); - if (u != null) - { - existingUsersGivenAccess.add(u); - } - else - { - SecurityManager.NewUserStatus st = SecurityManager.addUser(ve, getUser()); - u = st.getUser(); - u.setFirstName((String) map.get("firstName")); - u.setLastName((String) map.get("lastName")); - UserManager.updateUser(getUser(), u); - - if (st.isLdapOrSsoEmail()) - { - existingUsersGivenAccess.add(st.getUser()); - } - else - { - newUserStatusList.add(st); - } - } - } - - Map row = new HashMap<>(); - row.put("rowId", requestId); - row.put("userId", u.getUserId()); - Table.update(getUser(), ti, row, requestId); - - Container mGapContainer = mGAPManager.get().getMGapContainer(); - if (!mGapContainer.hasPermission(u, ReadPermission.class)) - { - MutableSecurityPolicy policy = new MutableSecurityPolicy(mGapContainer.getPolicy()); - policy.addRoleAssignment(u, ReaderRole.class); - SecurityPolicyManager.savePolicy(policy, getUser()); - } - else - { - _log.info("user already has read permission on mGAP container: " + u.getDisplayName(getUser())); - } - } - - transaction.commit(); - } - - Set allUsers = new HashSet<>(existingUsersGivenAccess); - - //send emails: - for (SecurityManager.NewUserStatus st : newUserStatusList) - { - SecurityManager.sendRegistrationEmail(getViewContext(), st.getEmail(), null, st, null); - allUsers.add(st.getUser()); - } - - Container mGapContainer = mGAPManager.get().getMGapContainer(); - for (User u : existingUsersGivenAccess) - { - boolean isLDAP = AuthenticationManager.isLdapOrSsoEmail(new ValidEmail(u.getEmail())); - - MailHelper.MultipartMessage mail = MailHelper.createMultipartMessage(); - mail.setEncodedHtmlContent("Your account request has been approved for mGAP! " + "Click here to access the site." + (isLDAP ? " Use your normal OHSU email/password to login." : "")); - mail.setFrom(getReplyEmail(getContainer())); - mail.setSubject("mGap Account Request"); - mail.addRecipients(Message.RecipientType.TO, u.getEmail()); - - MailHelper.send(mail, getUser(), getContainer()); - } - - Group g = GroupManager.getGroup(mGapContainer, mGAPManager.GROUP_NAME, GroupEnumType.SITE); - if (g == null) + mGAPManager.get().approveUsers(Arrays.stream(form.getRequestIds()).boxed().toList(), getContainer(), getUser(), getViewContext(), errors); + if (errors.hasErrors()) { - g = SecurityManager.createGroup(ContainerManager.getRoot(), mGAPManager.GROUP_NAME, getUser()); + return null; } - SecurityManager.addMembers(g, allUsers); - response.put("success", !errors.hasErrors()); return response; } } - private String getReplyEmail(Container c) - { - LookAndFeelProperties lfp = LookAndFeelProperties.getInstance(getContainer()); - String email = lfp.getSystemEmailAddress(); - if (email == null) - { - return AppProps.getInstance().getAdministratorContactEmail(true); - } - - return email; - } - public static class ApproveUserRequestsForm { private int[] requestIds; diff --git a/mGAP/src/org/labkey/mgap/mGAPManager.java b/mGAP/src/org/labkey/mgap/mGAPManager.java index fdff5e3e3..90d47a346 100644 --- a/mGAP/src/org/labkey/mgap/mGAPManager.java +++ b/mGAP/src/org/labkey/mgap/mGAPManager.java @@ -16,24 +16,55 @@ package org.labkey.mgap; +import jakarta.mail.Message; import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.labkey.api.data.Container; import org.labkey.api.data.ContainerManager; +import org.labkey.api.data.CoreSchema; +import org.labkey.api.data.DbScope; +import org.labkey.api.data.SimpleFilter; +import org.labkey.api.data.Table; +import org.labkey.api.data.TableInfo; +import org.labkey.api.data.TableSelector; import org.labkey.api.module.Module; import org.labkey.api.module.ModuleLoader; import org.labkey.api.module.ModuleProperty; +import org.labkey.api.query.FieldKey; +import org.labkey.api.security.AuthenticationManager; +import org.labkey.api.security.Group; +import org.labkey.api.security.GroupManager; +import org.labkey.api.security.MutableSecurityPolicy; +import org.labkey.api.security.SecurityManager; +import org.labkey.api.security.SecurityPolicyManager; import org.labkey.api.security.User; import org.labkey.api.security.UserManager; import org.labkey.api.security.ValidEmail; +import org.labkey.api.security.permissions.AdminPermission; +import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.security.roles.ReaderRole; +import org.labkey.api.settings.AppProps; +import org.labkey.api.settings.LookAndFeelProperties; +import org.labkey.api.util.MailHelper; +import org.labkey.api.util.logging.LogHelper; +import org.labkey.api.view.UnauthorizedException; +import org.labkey.api.view.ViewContext; +import org.labkey.security.xml.GroupEnumType; +import org.springframework.validation.BindException; +import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Set; +import static org.labkey.api.action.SpringActionController.ERROR_MSG; +import static org.labkey.api.util.IntegerUtils.asInteger; + public class mGAPManager { - private static final Logger _log = LogManager.getLogger(mGAPManager.class); + private static final Logger _log = LogHelper.getLogger(mGAPManager.class, "mGAPManager Logger"); private static final mGAPManager _instance = new mGAPManager(); public static final String ContainerPropName = "MGAPContainer"; @@ -99,7 +130,7 @@ public Set getNotificationUsers() if (u == null) { - _log.error("Unknown user registered for mGAP notifications: " + username); + _log.error("Unknown user registered for mGAP notifications: {}", username); } if (u != null) @@ -111,6 +142,136 @@ public Set getNotificationUsers() return ret; } + public String getReplyEmail(Container c) + { + LookAndFeelProperties lfp = LookAndFeelProperties.getInstance(c); + String email = lfp.getSystemEmailAddress(); + if (email == null) + { + return AppProps.getInstance().getAdministratorContactEmail(true); + } + + return email; + } + + public void approveUsers(List requestIds, Container c, User adminUser, ViewContext vc, BindException errors) + { + if (!c.hasPermission(adminUser, AdminPermission.class)) + { + throw new UnauthorizedException("User must be an admin to approve users"); + } + + List newUserStatusList = new ArrayList<>(); + List existingUsersGivenAccess = new ArrayList<>(); + try (DbScope.Transaction transaction = CoreSchema.getInstance().getScope().ensureTransaction()) + { + TableInfo ti = mGAPSchema.getInstance().getSchema().getTable(mGAPSchema.TABLE_USER_REQUESTS); + for (int requestId : requestIds) + { + TableSelector ts = new TableSelector(ti, new SimpleFilter(FieldKey.fromString("rowId"), requestId), null); + Map map = ts.getMap(requestId); + + User u; + if (map.get("userId") != null) + { + Integer userId = asInteger(map.get("userId")); + u = UserManager.getUser(userId); + existingUsersGivenAccess.add(u); + } + else + { + ValidEmail ve = new ValidEmail((String) map.get("email")); + u = UserManager.getUser(ve); + if (u != null) + { + existingUsersGivenAccess.add(u); + } + else + { + SecurityManager.NewUserStatus st = SecurityManager.addUser(ve, adminUser); + u = st.getUser(); + u.setFirstName((String) map.get("firstName")); + u.setLastName((String) map.get("lastName")); + UserManager.updateUser(adminUser, u); + + if (st.isLdapOrSsoEmail()) + { + existingUsersGivenAccess.add(st.getUser()); + } + else + { + newUserStatusList.add(st); + } + } + } + + Map row = new HashMap<>(); + row.put("rowId", requestId); + row.put("userId", u.getUserId()); + Table.update(adminUser, ti, row, requestId); + + Container mGapContainer = mGAPManager.get().getMGapContainer(); + if (!mGapContainer.hasPermission(u, ReadPermission.class)) + { + MutableSecurityPolicy policy = new MutableSecurityPolicy(mGapContainer.getPolicy()); + policy.addRoleAssignment(u, ReaderRole.class); + SecurityPolicyManager.savePolicy(policy, adminUser); + } + else + { + _log.info("User already has read permission on mGAP container: {}", u.getDisplayName(adminUser)); + } + } + + transaction.commit(); + } + catch (ValidEmail.InvalidEmailException | SecurityManager.UserManagementException e) + { + errors.reject(ERROR_MSG, e.getMessage()); + _log.error("Error creating mGAP user", e); + } + + Set allUsers = new HashSet<>(existingUsersGivenAccess); + try + { + //send emails: + for (SecurityManager.NewUserStatus st : newUserStatusList) + { + vc = new ViewContext(vc); + vc.setUser(st.getUser()); + SecurityManager.sendRegistrationEmail(vc, st.getEmail(), null, st, null); + allUsers.add(st.getUser()); + } + + Container mGapContainer = mGAPManager.get().getMGapContainer(); + for (User u : existingUsersGivenAccess) + { + boolean isLDAP = AuthenticationManager.isLdapOrSsoEmail(new ValidEmail(u.getEmail())); + + MailHelper.MultipartMessage mail = MailHelper.createMultipartMessage(); + mail.setEncodedHtmlContent("Your account request has been approved for mGAP! " + "Click here to access the site." + (isLDAP ? " Use your normal OHSU email/password to login." : "")); + mail.setFrom(getReplyEmail(c)); + mail.setSubject("mGap Account Request"); + mail.addRecipients(Message.RecipientType.TO, u.getEmail()); + + MailHelper.send(mail, adminUser, c); + } + + Group g = GroupManager.getGroup(mGapContainer, mGAPManager.GROUP_NAME, GroupEnumType.SITE); + if (g == null) + { + g = SecurityManager.createGroup(ContainerManager.getRoot(), mGAPManager.GROUP_NAME, adminUser); + } + + SecurityManager.addMembers(g, allUsers); + } + catch (Exception e) + { + errors.reject(ERROR_MSG, e.getMessage()); + _log.error("Error creating mGAP user", e); + } + } + public String getDefaultSpecies() { return "Rhesus macaque"; From 93dc16300685eaa5b777e40bdb91f42ff3055492 Mon Sep 17 00:00:00 2001 From: bbimber Date: Thu, 3 Sep 2026 12:40:19 -0700 Subject: [PATCH 04/18] Bugfix to mGAP request --- mGAP/src/org/labkey/mgap/mGAPController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mGAP/src/org/labkey/mgap/mGAPController.java b/mGAP/src/org/labkey/mgap/mGAPController.java index 9d324c815..3d56efae5 100644 --- a/mGAP/src/org/labkey/mgap/mGAPController.java +++ b/mGAP/src/org/labkey/mgap/mGAPController.java @@ -238,7 +238,7 @@ else if (adminUser == null) else { autoApprove = true; - requestId = (int)row.get("rowid"); + requestId = Integer.parseInt(row.get("rowid").toString()); builder.unsafeAppend(DOM.SPAN(DOM.at(DOM.Attribute.style, "font-weight:bold;"), " This request was automatically approved.").renderToString()); } } From 933bcfb1feed8edaf0aee20203ae9757668d2cbb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Sep 2026 14:17:22 -0700 Subject: [PATCH 05/18] Bump fast-uri in /mcc in the npm_and_yarn group across 1 directory (#243) Bumps the npm_and_yarn group with 1 update in the /mcc directory: [fast-uri](https://github.com/fastify/fast-uri). Updates `fast-uri` from 3.1.5 to 3.1.7 - [Release notes](https://github.com/fastify/fast-uri/releases) - [Commits](https://github.com/fastify/fast-uri/compare/v3.1.5...v3.1.7) --- updated-dependencies: - dependency-name: fast-uri dependency-version: 3.1.7 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- mcc/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mcc/package-lock.json b/mcc/package-lock.json index 565d44197..f1e1087ce 100644 --- a/mcc/package-lock.json +++ b/mcc/package-lock.json @@ -3286,9 +3286,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", - "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", + "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", "dev": true, "funding": [ { From ceb708b1f5d0bc5d0ee936bc930d3bd75fb2ca51 Mon Sep 17 00:00:00 2001 From: bbimber Date: Thu, 3 Sep 2026 16:29:46 -0700 Subject: [PATCH 06/18] Increase logging in SequenceAnalysisMaintenanceTask --- mGAP/src/org/labkey/mgap/mGAPController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mGAP/src/org/labkey/mgap/mGAPController.java b/mGAP/src/org/labkey/mgap/mGAPController.java index 3d56efae5..2f543909d 100644 --- a/mGAP/src/org/labkey/mgap/mGAPController.java +++ b/mGAP/src/org/labkey/mgap/mGAPController.java @@ -221,7 +221,7 @@ public Object execute(RequestUserForm form, BindException errors) throws Excepti DetailsURL url = DetailsURL.fromString("/query/executeQuery.view?schemaName=mgap&query.queryName=userRequests&query.viewName=Pending Requests", c); HtmlStringBuilder builder = HtmlStringBuilder.of("A user requested an account on mGap. "). - unsafeAppend("Click here to view/approve this request"); + unsafeAppend("Click here to view/approve this request."); boolean autoApprove = false; Integer requestId = null; From 6845c98b5ea4be5321a9a5b531868a013eae83dc Mon Sep 17 00:00:00 2001 From: bbimber Date: Tue, 8 Sep 2026 13:19:07 -0700 Subject: [PATCH 07/18] Bugfix to CacheHaplotypesAction --- .../labkey/genotypeassays/GenotypeAssaysController.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/GenotypeAssays/src/org/labkey/genotypeassays/GenotypeAssaysController.java b/GenotypeAssays/src/org/labkey/genotypeassays/GenotypeAssaysController.java index d71862eee..6b15fa382 100644 --- a/GenotypeAssays/src/org/labkey/genotypeassays/GenotypeAssaysController.java +++ b/GenotypeAssays/src/org/labkey/genotypeassays/GenotypeAssaysController.java @@ -22,10 +22,13 @@ import org.labkey.api.action.ApiSimpleResponse; import org.labkey.api.action.MutatingApiAction; import org.labkey.api.action.SpringActionController; +import org.labkey.api.data.ContainerFilter; +import org.labkey.api.data.ContainerManager; import org.labkey.api.data.ContainerType; import org.labkey.api.exp.api.ExpProtocol; import org.labkey.api.exp.api.ExperimentService; import org.labkey.api.security.RequiresPermission; +import org.labkey.api.security.permissions.ReadPermission; import org.labkey.api.security.permissions.UpdatePermission; import org.labkey.api.util.Pair; import org.springframework.validation.BindException; @@ -64,7 +67,7 @@ public ApiResponse execute(CacheAnalysesForm form, BindException errors) return null; } - if (!protocol.getContainer().getContainerFor(ContainerType.DataType.tabParent).equals(getContainer().getContainerFor(ContainerType.DataType.tabParent))) + if (!new ContainerFilter.CurrentAndSubfoldersPlusShared(getContainer().getContainerFor(ContainerType.DataType.tabParent), getUser()).generateIds(getContainer().getContainerFor(ContainerType.DataType.tabParent), ReadPermission.class, getContextualRoles()).contains(protocol.getContainer().getEntityId())) { errors.reject(ERROR_MSG, "Protocol is from the wrong container: " + form.getProtocolId()); logger.error("CacheAnalysesAction targeted a protocol from the wrong container: {}, from {}, in the container: {}", form.getProtocolId(), protocol.getContainer().getPath(), getContainer().getPath()); @@ -151,7 +154,7 @@ public ApiResponse execute(CacheAnalysesForm form, BindException errors) return null; } - if (!protocol.getContainer().getContainerFor(ContainerType.DataType.tabParent).equals(getContainer().getContainerFor(ContainerType.DataType.tabParent))) + if (!new ContainerFilter.CurrentAndSubfoldersPlusShared(getContainer().getContainerFor(ContainerType.DataType.tabParent), getUser()).generateIds(getContainer().getContainerFor(ContainerType.DataType.tabParent), ReadPermission.class, getContextualRoles()).contains(protocol.getContainer().getEntityId())) { errors.reject(ERROR_MSG, "Protocol is from the wrong container: " + form.getProtocolId()); logger.error("CacheHaplotypesAction targeted a protocol from the wrong container: {}, from {}, in the container: {}", form.getProtocolId(), protocol.getContainer().getPath(), getContainer().getPath()); From f68b1bfb49cb18f5d8a0b964caa122a6628f1be4 Mon Sep 17 00:00:00 2001 From: bbimber Date: Wed, 16 Sep 2026 11:09:14 -0700 Subject: [PATCH 08/18] Update field label --- tcrdb/resources/schemas/tcrdb.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcrdb/resources/schemas/tcrdb.xml b/tcrdb/resources/schemas/tcrdb.xml index a68916e03..1a81a7f71 100644 --- a/tcrdb/resources/schemas/tcrdb.xml +++ b/tcrdb/resources/schemas/tcrdb.xml @@ -269,10 +269,10 @@ Synthesized? - Animals With Clone + Subject(s) With Clone - Responses With Clone + Response(s) With Clone true From 3abf64b4c3dbaab323cf0e6b41b4b405f75f9f9d Mon Sep 17 00:00:00 2001 From: bbimber Date: Thu, 17 Sep 2026 17:19:54 -0700 Subject: [PATCH 09/18] Add more fields to MCC template --- mcc/resources/web/mcc/panel/MccImportPanel.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mcc/resources/web/mcc/panel/MccImportPanel.js b/mcc/resources/web/mcc/panel/MccImportPanel.js index 47373ecc7..f1c8afc77 100644 --- a/mcc/resources/web/mcc/panel/MccImportPanel.js +++ b/mcc/resources/web/mcc/panel/MccImportPanel.js @@ -453,7 +453,8 @@ Ext4.define('MCC.panel.MccImportPanel', { 'breeding partner ID': 'Breeding Partner ID', 'Id/mostRecentObservations/infant_history::observation': 'Infant History', 'Id/mostRecentObservations/fertility_status::observation': 'Fertility Status', - 'Id/mostRecentObservations/medical_history::observation': 'Medical History' + 'Id/genomicData/datatypes': 'Genomic Datasets', + 'Id/genomicData/sra_accession': 'SRA Accession(s)' } LABKEY.Query.selectRows({ @@ -463,8 +464,7 @@ Ext4.define('MCC.panel.MccImportPanel', { scope: this, failure: LDK.Utils.getErrorCallback(), filterArray: [ - LABKEY.Filter.create('colony', colonyName), - LABKEY.Filter.create('calculated_status', 'Alive') + LABKEY.Filter.create('colony', colonyName) ], success: function (results) { Ext4.Msg.hide(); From f0bc048ab7064a8b2d92232635816c3c80feca5d Mon Sep 17 00:00:00 2001 From: bbimber Date: Fri, 18 Sep 2026 11:22:20 -0700 Subject: [PATCH 10/18] Update columns in MCC export --- .../queries/mcc/aggregatedDemographics.sql | 4 ++-- .../mcc/exampleData/MCC_Data_Template.xlsx | Bin 17031 -> 17270 bytes mcc/resources/web/mcc/panel/MccImportPanel.js | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/mcc/resources/queries/mcc/aggregatedDemographics.sql b/mcc/resources/queries/mcc/aggregatedDemographics.sql index 9d1921f6e..5614eddb5 100644 --- a/mcc/resources/queries/mcc/aggregatedDemographics.sql +++ b/mcc/resources/queries/mcc/aggregatedDemographics.sql @@ -137,7 +137,7 @@ FROM "/data/Colonies/UCSD/".study.demographics d o."fertility_status::observation" as fertility_status, o."medical_history::observation" as medical_history, o."usage_current::observation" as usage_current, - o."usage_current::observation" as usage_future, + o."usage_future::observation" as usage_future, o."breeding_partner_id::observation" as breeding_partner_id FROM "/data/Colonies/UCSD/".study.mostRecentObservationsPivoted o ) o ON (o.Id = d.Id) @@ -186,7 +186,7 @@ FROM "/data/Colonies/Other/".study.demographics d o."fertility_status::observation" as fertility_status, o."medical_history::observation" as medical_history, o."usage_current::observation" as usage_current, - o."usage_current::observation" as usage_future, + o."usage_future::observation" as usage_future, o."breeding_partner_id::observation" as breeding_partner_id FROM "/data/Colonies/Other/".study.mostRecentObservationsPivoted o ) o ON (o.Id = d.Id) diff --git a/mcc/resources/web/mcc/exampleData/MCC_Data_Template.xlsx b/mcc/resources/web/mcc/exampleData/MCC_Data_Template.xlsx index 26b4e6ee8e985cd865678f1f147c2cfd388d1874..d60994111c18617b2577b446e736f4765473b528 100644 GIT binary patch delta 9809 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 delta 9508 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 F{|5sPvswTE diff --git a/mcc/resources/web/mcc/panel/MccImportPanel.js b/mcc/resources/web/mcc/panel/MccImportPanel.js index f1c8afc77..affb63499 100644 --- a/mcc/resources/web/mcc/panel/MccImportPanel.js +++ b/mcc/resources/web/mcc/panel/MccImportPanel.js @@ -443,7 +443,7 @@ Ext4.define('MCC.panel.MccImportPanel', { 'Id/MostRecentDeparture/MostRecentDeparture': 'Shipping Date', 'death': 'Death', 'deathCause': 'Cause of Death', - 'dam': 'Material ID', + 'dam': 'Maternal ID', 'sire': 'Paternal ID', 'Id/MostRecentWeight/MostRecentWeightGrams': 'Weight (g)', 'Id/MostRecentWeight/MostRecentWeightDate': 'Date of Weight', @@ -453,6 +453,9 @@ Ext4.define('MCC.panel.MccImportPanel', { 'breeding partner ID': 'Breeding Partner ID', 'Id/mostRecentObservations/infant_history::observation': 'Infant History', 'Id/mostRecentObservations/fertility_status::observation': 'Fertility Status', + 'Id/mostRecentObservations/medical_history::observation': 'Medical History', + 'Id/mostRecentObservations/usage_current::observation': 'Usage (Current)', + 'Id/mostRecentObservations/usage_future::observation': 'Usage (Future)', 'Id/genomicData/datatypes': 'Genomic Datasets', 'Id/genomicData/sra_accession': 'SRA Accession(s)' } From 0ffc12a701b6df4c6e6ca90f2469509b78b2e9d3 Mon Sep 17 00:00:00 2001 From: bbimber Date: Mon, 21 Sep 2026 11:37:42 -0700 Subject: [PATCH 11/18] Add step to prevent user from running ETL in incorrect folder --- mcc/resources/etls/mcc.xml | 6 +++ .../mcc/etl/FailUnlessMccFolderStep.java | 53 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 mcc/src/org/labkey/mcc/etl/FailUnlessMccFolderStep.java diff --git a/mcc/resources/etls/mcc.xml b/mcc/resources/etls/mcc.xml index 1a133c54c..070d3c629 100644 --- a/mcc/resources/etls/mcc.xml +++ b/mcc/resources/etls/mcc.xml @@ -3,6 +3,12 @@ MCC_Aggregation Aggregate MCC Data + + + + + + diff --git a/mcc/src/org/labkey/mcc/etl/FailUnlessMccFolderStep.java b/mcc/src/org/labkey/mcc/etl/FailUnlessMccFolderStep.java new file mode 100644 index 000000000..e764862bc --- /dev/null +++ b/mcc/src/org/labkey/mcc/etl/FailUnlessMccFolderStep.java @@ -0,0 +1,53 @@ +package org.labkey.mcc.etl; + +import org.apache.xmlbeans.XmlException; +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.Container; +import org.labkey.api.di.TaskRefTask; +import org.labkey.api.pipeline.PipelineJob; +import org.labkey.api.pipeline.PipelineJobException; +import org.labkey.api.pipeline.RecordedActionSet; +import org.labkey.api.writer.ContainerUser; +import org.labkey.mcc.MccManager; + +import java.util.List; +import java.util.Map; + +/** + * This step was created to prevent users from making potentially big errors and running this + * step from the incorrect folder: + */ +public class FailUnlessMccFolderStep implements TaskRefTask +{ + protected ContainerUser _containerUser; + + @Override + public RecordedActionSet run(@NotNull PipelineJob job) throws PipelineJobException + { + Container mccContainer = MccManager.get().getMCCContainer(_containerUser.getContainer()); + if (!_containerUser.getContainer().equals(mccContainer)) + { + throw new PipelineJobException("This ETL is being executed from the wrong container, should be: " + mccContainer); + } + + return new RecordedActionSet(); + } + + @Override + public List getRequiredSettings() + { + return List.of(); + } + + @Override + public void setSettings(Map settings) throws XmlException + { + + } + + @Override + public void setContainerUser(ContainerUser containerUser) + { + _containerUser = containerUser; + } +} From d36eae5582c7c6cecc7f99801687f7831b7f1e8e Mon Sep 17 00:00:00 2001 From: bbimber Date: Mon, 21 Sep 2026 12:30:13 -0700 Subject: [PATCH 12/18] Correct ETL fields --- mcc/resources/etls/mcc.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/mcc/resources/etls/mcc.xml b/mcc/resources/etls/mcc.xml index 070d3c629..33b64ee9b 100644 --- a/mcc/resources/etls/mcc.xml +++ b/mcc/resources/etls/mcc.xml @@ -113,7 +113,6 @@ Copy to target - Id yearNo startdate enddate From 335d495edb1f32250ee54163a91ee81afb95a104 Mon Sep 17 00:00:00 2001 From: bbimber Date: Mon, 21 Sep 2026 14:05:52 -0700 Subject: [PATCH 13/18] Update test to match new kinship script --- PMR/test/src/org/labkey/test/tests/pmr/PMRTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/PMR/test/src/org/labkey/test/tests/pmr/PMRTest.java b/PMR/test/src/org/labkey/test/tests/pmr/PMRTest.java index 650b7ffd8..2a762c94f 100644 --- a/PMR/test/src/org/labkey/test/tests/pmr/PMRTest.java +++ b/PMR/test/src/org/labkey/test/tests/pmr/PMRTest.java @@ -22,6 +22,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.labkey.api.util.FileUtil; import org.labkey.remoteapi.query.SelectRowsCommand; import org.labkey.remoteapi.query.TruncateTableCommand; import org.labkey.serverapi.reader.Readers; @@ -63,13 +64,13 @@ protected void doCleanup(boolean afterTest) throws TestTimeoutException @BeforeClass public static void setupProject() throws Exception { - PMRTest init = (PMRTest)getCurrentTest(); + PMRTest init = getCurrentTest(); init.doSetup(); } private File getKinshipPath() { - return new File(TestFileUtils.getDefaultFileRoot(getProjectName()), "kinshipEtlDir"); + return FileUtil.appendName(TestFileUtils.getDefaultFileRoot(getProjectName()), "kinshipEtlDir"); } private void doSetup() @@ -144,7 +145,7 @@ private void testKinshipEtl() throws Exception // Verify data imported, and then delete from the DB SelectRowsCommand select1 = new SelectRowsCommand("ehr", "kinship"); - Assert.assertEquals("Incorrect number of kinship rows", 136, select1.execute(getApiHelper().getConnection(), getProjectName()).getRowCount().intValue()); + Assert.assertEquals("Incorrect number of kinship rows", 104, select1.execute(getApiHelper().getConnection(), getProjectName()).getRowCount().intValue()); new TruncateTableCommand("ehr", "kinship").execute(getApiHelper().getConnection(), getProjectName()); Assert.assertEquals("Incorrect number of kinship rows", 0, select1.execute(getApiHelper().getConnection(), getProjectName()).getRowCount().intValue()); @@ -154,7 +155,7 @@ private void testKinshipEtl() throws Exception goToDataPipeline(); waitForPipelineJobsToComplete(4, "ETL Job: Import PRIMe-seq Kinship Data", false); - Assert.assertEquals("Incorrect number of kinship rows after ETL", 136, select1.execute(getApiHelper().getConnection(), getProjectName()).getRowCount().intValue()); + Assert.assertEquals("Incorrect number of kinship rows after ETL", 104, select1.execute(getApiHelper().getConnection(), getProjectName()).getRowCount().intValue()); } private void createTestPedigreeData() throws Exception From fc622dfdd79f0a6b13437b15f0c6d1ecb1e09faa Mon Sep 17 00:00:00 2001 From: bbimber Date: Tue, 22 Sep 2026 14:13:55 -0700 Subject: [PATCH 14/18] Initial plan for building MCC website into module (#244) * Initial plan for building MCC website into module * Implement fetch-mcc-website script --------- Co-authored-by: Sebastian Benjamin --- mcc/package-lock.json | 14 + mcc/package.json | 6 +- mcc/resources/external/fetch-mcc-website.mjs | 243 ++++++++++++++++++ mcc/resources/external/template.view.xml | 6 + .../org/labkey/test/tests/mcc/MccTest.java | 11 + 5 files changed, 278 insertions(+), 2 deletions(-) create mode 100644 mcc/resources/external/fetch-mcc-website.mjs create mode 100644 mcc/resources/external/template.view.xml diff --git a/mcc/package-lock.json b/mcc/package-lock.json index f1e1087ce..2234bf279 100644 --- a/mcc/package-lock.json +++ b/mcc/package-lock.json @@ -28,6 +28,7 @@ "@types/jest": "^30.0.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", + "degit": "^3.10.0", "rimraf": "^6.1.3" } }, @@ -3005,6 +3006,19 @@ } } }, + "node_modules/degit": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/degit/-/degit-3.10.0.tgz", + "integrity": "sha512-xlFPgJs8X/2wnWNsuV6siWVHRd2mSGUNHYkiJLZYa918Ma9rZT/mM3Y2Rz6juwz3tHTkfNAnlX7szD9OLbcYQg==", + "dev": true, + "license": "MIT", + "bin": { + "degit": "degit" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", diff --git a/mcc/package.json b/mcc/package.json index 004d675b2..9f584257c 100644 --- a/mcc/package.json +++ b/mcc/package.json @@ -6,8 +6,9 @@ "build": "npm run build-dev", "start": "cross-env NODE_ENV=development rspack serve --config node_modules/@labkey/build/configs/watch.config.js", "start-link": "cross-env LINK=true npm run start", - "build-dev": "npm run clean && cross-env NODE_ENV=development rspack build --config node_modules/@labkey/build/configs/dev.config.js", - "build-prod": "npm run clean && cross-env NODE_ENV=production rspack build --config node_modules/@labkey/build/configs/prod.config.js", + "build-dev": "npm run clean && cross-env NODE_ENV=development rspack build --config node_modules/@labkey/build/configs/dev.config.js && npm run download-website", + "build-prod": "npm run clean && cross-env NODE_ENV=production rspack build --config node_modules/@labkey/build/configs/prod.config.js && npm run download-website", + "download-website": "node ./resources/external/fetch-mcc-website.mjs", "clean": "rimraf resources/web/mcc/gen && rimraf resources/web/gen" }, "dependencies": { @@ -31,6 +32,7 @@ "@types/jest": "^30.0.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", + "degit": "^3.10.0", "rimraf": "^6.1.3" } } diff --git a/mcc/resources/external/fetch-mcc-website.mjs b/mcc/resources/external/fetch-mcc-website.mjs new file mode 100644 index 000000000..bc0523d5c --- /dev/null +++ b/mcc/resources/external/fetch-mcc-website.mjs @@ -0,0 +1,243 @@ +/* + * Downloads the MCC public website (https://github.com/bimberlabinternal/mcc-website) and converts it into + * module HTML views, so that LabKey can inject a CSP nonce into each
@@ -22,85 +32,53 @@
- -