Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into fb_javascriptfragm…
Browse files Browse the repository at this point in the history
…ent_asjson
  • Loading branch information
labkey-matthewb committed Jan 19, 2024
2 parents 78439fb + 4cadccd commit 1346e3c
Show file tree
Hide file tree
Showing 19 changed files with 166 additions and 19 deletions.
2 changes: 2 additions & 0 deletions api/src/org/labkey/api/data/JsonTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,14 @@ public void jsonOrgViaJackson() throws IOException
obj.put("str", "hello");
obj.put("arr", new JSONArray(Arrays.asList("one", null, 3, new JSONObject(Collections.singletonMap("four", 4)))));
obj.put("nul", (Object)null);
obj.put("key", "</tricky\tvalue\\");
// obj.put("d", d); //TODO: new JSONObject serializes date-times as ISO

// Verify serializing JSONObject via Jackson is equivalent
String jacksonToString = mapper.writeValueAsString(obj);
String jsonOrgToString = obj.toString();
assertEquals(jsonOrgToString, jacksonToString);
assertTrue(jsonOrgToString.contains("<\\/"));

// Verify deserializing JSONObject via Jackson is equivalent
// NOTE: In both cases, the date value is deserialized as a string because JSON sucks
Expand Down
5 changes: 3 additions & 2 deletions api/src/org/labkey/api/exp/api/ExperimentService.java
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ enum DataTypeForExclusion
SampleType,
DataClass,
AssayDesign,
StorageLocation
StorageLocation,
DashboardSampleType
}

@Nullable
Expand Down Expand Up @@ -962,7 +963,7 @@ List<? extends ExpProtocol> getExpProtocolsWithParameterValue(

Set<String> getDataTypeContainerExclusions(@NotNull DataTypeForExclusion dataType, @NotNull Integer dataTypeRowId);

void ensureContainerDataTypeExclusions(@NotNull DataTypeForExclusion dataType, @Nullable Collection<Integer> excludedDataTypeRowIds, @NotNull String excludedContainerId, User user);
void ensureContainerDataTypeExclusions(@NotNull DataTypeForExclusion dataType, @Nullable DataTypeForExclusion relatedDataType, @Nullable Collection<Integer> excludedDataTypeRowIds, @NotNull String excludedContainerId, User user);

void ensureDataTypeContainerExclusions(@NotNull DataTypeForExclusion dataType, @Nullable Collection<String> excludedContainerIds, @NotNull Integer dataTypeId, User user);

Expand Down
4 changes: 3 additions & 1 deletion api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ public Domain createDomain(GWTDomain domain, @Nullable SampleTypeDomainKindPrope
String category = null;
Map<String, String> aliases = null;
List<String> excludedContainerIds = null;
List<String> excludedDashboardContainerIds = null;

if (arguments != null)
{
Expand All @@ -557,12 +558,13 @@ public Domain createDomain(GWTDomain domain, @Nullable SampleTypeDomainKindPrope
category = StringUtils.trimToNull(arguments.getCategory());
aliases = arguments.getImportAliases();
excludedContainerIds = arguments.getExcludedContainerIds();
excludedDashboardContainerIds = arguments.getExcludedDashboardContainerIds();
}
ExpSampleType st;
try
{
st = SampleTypeService.get().createSampleType(container, user, name, description, properties, indices, idCol1, idCol2, idCol3, parentCol, nameExpression, aliquotNameExpression,
templateInfo, aliases, labelColor, metricUnit, autoLinkTargetContainer, autoLinkCategory, category, domain.getDisabledSystemFields(), excludedContainerIds);
templateInfo, aliases, labelColor, metricUnit, autoLinkTargetContainer, autoLinkCategory, category, domain.getDisabledSystemFields(), excludedContainerIds, excludedDashboardContainerIds);
}
catch (SQLException e)
{
Expand Down
11 changes: 11 additions & 0 deletions api/src/org/labkey/api/exp/api/SampleTypeDomainKindProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public SampleTypeDomainKindProperties(ExpSampleType st)
private Integer parentCol;
private String category;
private List<String> excludedContainerIds;
private List<String> excludedDashboardContainerIds;

//Ignored on import/save, use Domain.name & Domain.description instead
private String name;
Expand Down Expand Up @@ -236,4 +237,14 @@ public void setExcludedContainerIds(List<String> excludedContainerIds)
{
this.excludedContainerIds = excludedContainerIds;
}

public List<String> getExcludedDashboardContainerIds()
{
return excludedDashboardContainerIds;
}

public void setExcludedDashboardContainerIds(List<String> excludedDashboardContainerIds)
{
this.excludedDashboardContainerIds = excludedDashboardContainerIds;
}
}
3 changes: 2 additions & 1 deletion api/src/org/labkey/api/exp/api/SampleTypeService.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ ExpSampleType createSampleType(Container container, User user, String name, Stri
@NotNull
ExpSampleType createSampleType(Container c, User u, String name, String description, List<GWTPropertyDescriptor> properties, List<GWTIndex> indices, int idCol1, int idCol2, int idCol3, int parentCol,
String nameExpression, String aliquotNameExpression, @Nullable TemplateInfo templateInfo, @Nullable Map<String, String> importAliases, @Nullable String labelColor, @Nullable String metricUnit,
@Nullable Container autoLinkTargetContainer, @Nullable String autoLinkCategory, @Nullable String category, @Nullable List<String> disabledSystemField, @Nullable List<String> excludedContainerIds)
@Nullable Container autoLinkTargetContainer, @Nullable String autoLinkCategory, @Nullable String category, @Nullable List<String> disabledSystemField,
@Nullable List<String> excludedContainerIds, @Nullable List<String> excludedDashboardContainerIds)
throws ExperimentException, SQLException;

@NotNull
Expand Down
2 changes: 1 addition & 1 deletion api/src/org/labkey/api/notification/notificationpanel.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
%>
<a id="<%=h(linkId)%>" href="#">
<i class="fa fa-inbox labkey-notification-inbox"></i>
<span id=<%=q(notificationCountId)%>>&nbsp;</span>
<span id="<%=h(notificationCountId)%>">&nbsp;</span>
</a>
</li>

Expand Down
2 changes: 2 additions & 0 deletions api/src/org/labkey/api/reports/report/r/RReport.java
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ public static synchronized String getDefaultRPath()
return DEFAULT_APP_PATH;
}


public static String toR(String s)
{
if (s == null)
Expand Down Expand Up @@ -259,6 +260,7 @@ public static String toR(String s)
return r.toString();
}


// static for access by RserveScriptEngine with no backing report
public static void appendParamList(StringBuilder labkey, Map<String, Object> inputParameters)
{
Expand Down
55 changes: 55 additions & 0 deletions assay/src/org/labkey/assay/PlateController.java
Original file line number Diff line number Diff line change
Expand Up @@ -926,4 +926,59 @@ public Object execute(CreatePlateSetForm form, BindException errors) throws Exce
return null;
}
}

public static class ArchiveForm
{
private List<Integer> _plateSetIds;
private boolean _restore;

public List<Integer> getPlateSetIds()
{
return _plateSetIds;
}

public void setPlateSetIds(List<Integer> plateSetIds)
{
_plateSetIds = plateSetIds;
}

public boolean isRestore()
{
return _restore;
}

public void setRestore(boolean restore)
{
_restore = restore;
}
}

@Marshal(Marshaller.JSONObject)
@RequiresPermission(UpdatePermission.class)
public static class ArchivePlateSetsAction extends MutatingApiAction<ArchiveForm>
{
@Override
public void validateForm(ArchiveForm form, Errors errors)
{
if (form.getPlateSetIds() == null)
errors.reject(ERROR_GENERIC, "\"plateSetIds\" is a required field.");
}

@Override
public Object execute(ArchiveForm form, BindException errors) throws Exception
{
try
{
PlateManager.get().archivePlateSets(getContainer(), getUser(), form.getPlateSetIds(), !form.isRestore());
return success();
}
catch (Exception e)
{
String action = form.isRestore() ? "restore" : "archive";
errors.reject(ERROR_GENERIC, e.getMessage() != null ? e.getMessage() : "Failed to " + action + " plate sets. An error has occurred.");
}

return null;
}
}
}
42 changes: 42 additions & 0 deletions assay/src/org/labkey/assay/plate/PlateManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,11 @@
import org.labkey.api.query.ValidationException;
import org.labkey.api.search.SearchService;
import org.labkey.api.security.User;
import org.labkey.api.security.permissions.DeletePermission;
import org.labkey.api.security.permissions.InsertPermission;
import org.labkey.api.security.permissions.Permission;
import org.labkey.api.security.permissions.ReadPermission;
import org.labkey.api.security.permissions.UpdatePermission;
import org.labkey.api.util.GUID;
import org.labkey.api.util.JunitUtil;
import org.labkey.api.util.Pair;
Expand Down Expand Up @@ -1772,6 +1774,46 @@ public PlateSetImpl createPlateSet(Container container, User user, @NotNull Plat
return plateSet;
}

public void archivePlateSets(Container container, User user, List<Integer> plateSetIds, boolean archive) throws Exception
{
String action = archive ? "archive" : "restore";
Class<? extends Permission> perm = UpdatePermission.class;

if (!container.hasPermission(user, perm))
throw new UnauthorizedException("Failed to " + action + " plate sets. Insufficient permissions.");

if (plateSetIds.isEmpty())
throw new ValidationException("Failed to " + action + " plate sets. No plate sets specified.");

try (DbScope.Transaction tx = ensureTransaction())
{
TableInfo plateSetTable = AssayDbSchema.getInstance().getTableInfoPlateSet();

// Ensure user has permission in all containers
{
SQLFragment sql = new SQLFragment("SELECT DISTINCT container FROM ")
.append(plateSetTable, "PS")
.append(" WHERE rowId ")
.appendInClause(plateSetIds, plateSetTable.getSqlDialect());

for (String containerId : new SqlSelector(plateSetTable.getSchema(), sql).getCollection(String.class))
{
Container c = ContainerManager.getForId(containerId);
if (c != null && !c.hasPermission(user, perm))
throw new UnauthorizedException("Failed to " + action + " plate sets. Insufficient permissions in " + c.getPath());
}
}

SQLFragment sql = new SQLFragment("UPDATE ").append(plateSetTable, "PS")
.append(" SET archived = ?").add(archive)
.append(" WHERE rowId ").appendInClause(plateSetIds, plateSetTable.getSqlDialect());

new SqlExecutor(plateSetTable.getSchema()).execute(sql);

tx.commit();
}
}

public static final class TestCase
{
private static Container container;
Expand Down
13 changes: 13 additions & 0 deletions core/src/org/labkey/core/CoreModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.labkey.core;

import com.fasterxml.jackson.core.io.CharTypes;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
Expand Down Expand Up @@ -317,6 +318,18 @@ public class CoreModule extends SpringModule implements SearchService.DocumentPr

// Register dialect extra early, since we need to initialize the data sources before calling DefaultModule.initialize()
SqlDialectRegistry.register(new PostgreSqlDialectFactory());

try
{
var field = CharTypes.class.getDeclaredField("sOutputEscapes128");
field.setAccessible(true);
((int[])field.get(null))['/'] = '/';
field.setAccessible(false);
}
catch (NoSuchFieldException|IllegalArgumentException|IllegalAccessException x)
{
// pass
}
}

private CoreWarningProvider _warningProvider;
Expand Down
7 changes: 5 additions & 2 deletions core/src/org/labkey/core/admin/AdminController.java
Original file line number Diff line number Diff line change
Expand Up @@ -11120,6 +11120,10 @@ public Object execute(SimpleApiJsonForm form, BindException errors) throws Excep
if (!_log.isWarnEnabled())
return ret;

var userAgent = getViewContext().getRequest().getHeader("User-Agent");
if (PageFlowUtil.isRobotUserAgent(userAgent) && !_log.isDebugEnabled())
return ret;

// NOTE User will always be "guest". Seems like a bad design to force the server to accept guest w/o CSRF here.
var jsonObj = form.getJsonObject();
if (null != jsonObj)
Expand All @@ -11131,9 +11135,8 @@ public Object execute(SimpleApiJsonForm form, BindException errors) throws Excep
if (urlString != null)
{
String path = new URLHelper(urlString).deleteParameters().getPath();
if (null == reports.put(path, Boolean.TRUE))
if (null == reports.put(path, Boolean.TRUE) || _log.isDebugEnabled())
{
var userAgent = getViewContext().getRequest().getHeader("User-Agent");
if (isNotBlank(userAgent))
jsonObj.put("user-agent", userAgent);
var jsonStr = jsonObj.toString(2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ private String getSanitizedUrl(ViewContext context)
private static final String GA4_TRACKING_SCRIPT_TEMPLATE =
"""
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="${GA4_JS:htmlEncode}"></script>
<script async src="${GA4_JS:htmlEncode}" nonce="${SCRIPT_NONCE:htmlEncode}"></script>
<script nonce="${SCRIPT_NONCE:htmlEncode}">
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
Expand Down
4 changes: 2 additions & 2 deletions core/src/org/labkey/core/analytics/analyticsSettings.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@
<td style="padding-left: 1em;">
<strong><label for="customScript">Custom JavaScript Analytics</label></strong>
<p>
Add <label for="ff_trackingScript">custom analytics script</label> to the <code>&lt;head&gt;</code> of every page. Include required <code>&lt;script&gt;</code> tags.
Add <label for="ff_trackingScript">custom analytics script</label> to the <code>&lt;head&gt;</code> of every page. Include required <code>&lt;script&gt;</code> tags. If the server enforces a Content Security Policy, script blocks may need a nonce to function: <code>&lt;script nonce="\${SCRIPT_NONCE:htmlEncode}"&gt;</code>.
</p>
<p>
<strong>NOTE:</strong> You can mess up your site if you make a mistake here. You may want to bookmark this page to aid in making corrections, just in case.
<strong>NOTE:</strong> You can mess up your site if you make a mistake here. You may want to bookmark this page to aid in making corrections, just in case.
</p>
<textarea <%=unsafe(hasAdminOpsPerms?"":"disabled=\"disabled\"")%> style="width:100%; height:15em;" id="ff_trackingScript" name="ff_trackingScript"><%=h(settingsForm.ff_trackingScript)%></textarea>
</td>
Expand Down
2 changes: 1 addition & 1 deletion core/src/org/labkey/core/user/securityAccess.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
However, if this account were re-enabled, it would have the following permissions.</div>
<% } %>

<table id=<%=q(accessRegion.getDomId())%> lk-region-name=<%=q(accessRegion.getName())%> class="labkey-data-region-legacy labkey-show-borders">
<table id="<%=h(accessRegion.getDomId())%>" lk-region-name="<%=h(accessRegion.getName())%>" class="labkey-data-region-legacy labkey-show-borders">
<colgroup><col><col><col></colgroup>
<tr id="dataregion_column_header_row_access">
<th>&nbsp;</th>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8643,12 +8643,13 @@ private Set<Integer> _getContainerDataTypeExclusions(DataTypeForExclusion dataTy
}

@Override
public void ensureContainerDataTypeExclusions(@NotNull DataTypeForExclusion dataType, @Nullable Collection<Integer> excludedDataTypeRowIds, @NotNull String excludedContainerId, User user)
public void ensureContainerDataTypeExclusions(@NotNull DataTypeForExclusion dataType, @Nullable DataTypeForExclusion relatedDataType, @Nullable Collection<Integer> excludedDataTypeRowIds, @NotNull String excludedContainerId, User user)
{
if (excludedDataTypeRowIds == null)
return;

Set<Integer> previousExclusions = _getContainerDataTypeExclusions(dataType, excludedContainerId);
Set<Integer> relatedExclusions = relatedDataType != null ? _getContainerDataTypeExclusions(relatedDataType, excludedContainerId) : null;
Set<Integer> updatedExclusions = new HashSet<>(excludedDataTypeRowIds);

Set<Integer> toAdd = new HashSet<>(updatedExclusions);
Expand All @@ -8660,7 +8661,15 @@ public void ensureContainerDataTypeExclusions(@NotNull DataTypeForExclusion data
if (!toAdd.isEmpty())
{
for (Integer add : toAdd)
{
addDataTypeExclusion(add, dataType, excludedContainerId, user);

// Prevent "double exclusion" for related exclusion types (i.e. if a sample type is excluded from the
// project, then we can delete any "Dashboard Sample Type" exclusions for that same sample type).
// Note that "double exclusions" won't cause any harm, they just aren't necessary and can be cleaned up here.
if (relatedExclusions != null && relatedExclusions.contains(add))
removeDataTypeExclusion(Collections.singleton(add), relatedDataType, excludedContainerId);
}
}

if (!toRemove.isEmpty())
Expand Down
Loading

0 comments on commit 1346e3c

Please sign in to comment.