Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validator and metrics for non-standard date-time display formats #5841

Merged
merged 15 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions api/src/org/labkey/api/admin/AdminUrls.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,21 @@ public interface AdminUrls extends UrlProvider
ActionURL getNotificationsURL(Container c);
ActionURL getExportFolderURL(Container c);
ActionURL getImportFolderURL(Container c);
ActionURL getFolderSettingsURL(Container c);
ActionURL getFileRootsURL(Container c);

/**
* Get the appropriate settings page for the passed in container (root, project, or folder)
*/
ActionURL getLookAndFeelSettingsURL(Container c);
ActionURL getSiteLookAndFeelSettingsURL();
ActionURL getProjectSettingsURL(Container c);
ActionURL getProjectSettingsMenuURL(Container c);
ActionURL getProjectSettingsFileURL(Container c);
ActionURL getFolderSettingsURL(Container c);

ActionURL getCreateProjectURL(@Nullable ActionURL returnURL);
ActionURL getCreateFolderURL(Container c, @Nullable ActionURL returnURL);
ActionURL getMemTrackerURL();
ActionURL getLookAndFeelSettingsURL();
ActionURL getProjectSettingsURL(Container c);
ActionURL getProjectSettingsMenuURL(Container c);
ActionURL getProjectSettingsFileURL(Container c);
ActionURL getCustomizeEmailURL(Container c, Class<? extends EmailTemplate> selectedTemplate, URLHelper returnURL);
ActionURL getFilesSiteSettingsURL(boolean upgrade);
ActionURL getSessionLoggingURL();
Expand Down
19 changes: 4 additions & 15 deletions api/src/org/labkey/api/data/PropertyManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,6 @@
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;


/**
* User: mbellew
* Date: Apr 26, 2004
* Time: 9:57:10 AM
*/
public class PropertyManager
{
public static final User SHARED_USER = User.guest; // Shared properties are saved with the guest user
Expand All @@ -66,19 +60,16 @@ private PropertyManager()
{
}


public static PropertyStore getNormalStore()
{
return STORE;
}


public static PropertyStore getEncryptedStore()
{
return ENCRYPTED_STORE;
}


/**
* For global system properties that are attached to the root container
* Returns an empty map if property set hasn't been created
Expand Down Expand Up @@ -156,10 +147,10 @@ public static void registerEncryptionMigrationHandler()

/**
* This is designed to coalesce up the container hierarchy, returning the first non-null value
* If a userId is provided, it first traverses containers using that user. If no value is found,
* it then default to all users (ie. User.guest), then retry all containers
* If a userId is provided, it first traverses containers using that user. If no value is found,
* it then defaults to all users (i.e. User.guest), then retry all containers
*
* NOTE: this does not test permissions. Callers should ensure the requested user has the appropriate
* NOTE: this does not test permissions. Callers should ensure the requested user has the appropriate
* permissions to read these properties
*/
public static String getCoalescedProperty(User user, Container c, String category, String name, boolean includeNullUser)
Expand Down Expand Up @@ -233,7 +224,7 @@ public static String getProperty(User user, Container container, String category

/**
* Get a list of categories optionally filtered by user, container, and category prefix.
* eturns entries from unencrypted store only.
* Returns entries from unencrypted store only.
*
* @param user User of the property. If null properties for all users (NOT JUST THE NULL USER) will be found.
* @param container Container to search for. If null properties of all containers will be found
Expand Down Expand Up @@ -780,7 +771,6 @@ public Collection<String> getCategories()
});
}


private void testPropertyStore(PropertyStore store, PropertyStoreTest test)
{
TestContext context = TestContext.get();
Expand Down Expand Up @@ -811,7 +801,6 @@ private void testPropertyStore(PropertyStore store, PropertyStoreTest test)
}
}


private void testProperties(PropertyStore store, User user, Container test, String category)
{
PropertyMap m = store.getWritableProperties(user, test, category, true);
Expand Down
1 change: 0 additions & 1 deletion api/src/org/labkey/api/exp/OntologyManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import org.labkey.api.data.*;
import org.labkey.api.data.DbScope.Transaction;
import org.labkey.api.data.dialect.SqlDialect;
import org.labkey.api.dataiterator.AbstractMapDataIterator;
import org.labkey.api.dataiterator.DataIterator;
import org.labkey.api.dataiterator.DataIteratorContext;
import org.labkey.api.dataiterator.DataIteratorUtil;
Expand Down
3 changes: 0 additions & 3 deletions api/src/org/labkey/api/exp/PropertyType.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@
import java.util.TimeZone;

/**
* User: migra
* Date: Oct 25, 2005
*
* TODO: Add more types? Entity, Lsid, User, ...
*/
public enum PropertyType
Expand Down
4 changes: 3 additions & 1 deletion api/src/org/labkey/api/query/QueryDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.labkey.api.query;

import jakarta.servlet.http.HttpServletRequest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.labkey.api.data.ColumnInfo;
Expand All @@ -29,8 +30,8 @@
import org.labkey.api.util.StringExpression;
import org.labkey.api.view.ActionURL;
import org.labkey.data.xml.TableType;
import org.labkey.data.xml.TablesDocument;

import jakarta.servlet.http.HttpServletRequest;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
Expand Down Expand Up @@ -115,6 +116,7 @@ public interface QueryDefinition

String getSql();
String getMetadataXml();
TablesDocument getMetadataTablesDocument();
String getDescription();
String getModuleName();

Expand Down
6 changes: 1 addition & 5 deletions api/src/org/labkey/api/query/QueryUrls.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@
import org.labkey.api.action.UrlProvider;
import org.labkey.api.data.Container;
import org.labkey.api.view.ActionURL;
/*
* User: Karl Lum
* Date: Jul 15, 2008
* Time: 2:53:11 PM
*/

public interface QueryUrls extends UrlProvider
{
Expand All @@ -42,4 +37,5 @@ public interface QueryUrls extends UrlProvider
* @param query Query name
*/
ActionURL urlExecuteQuery(Container c, String schema, String query);
ActionURL urlMetadataQuery(Container c, String schemaName, String queryName);
}
25 changes: 9 additions & 16 deletions api/src/org/labkey/api/reports/report/ModuleReportResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,22 @@
*/
package org.labkey.api.reports.report;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.xmlbeans.XmlException;
import org.labkey.api.data.ContainerManager;
import org.labkey.api.resource.Resource;
import org.labkey.api.util.DateUtil;
import org.labkey.api.util.PageFlowUtil;
import org.labkey.api.util.Path;
import org.labkey.api.util.logging.LogHelper;
import org.labkey.query.xml.ReportDescriptorType;

import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
* User: dax
* Date: 3/14/14
*/
public class ModuleReportResource
{
private static final Logger LOG = LogHelper.getLogger(ModuleReportResource.class, "Module report loading and parsing problems");
protected final Resource _sourceFile;
protected final ReportDescriptor _reportDescriptor;
protected final Resource _metaDataFile;
Expand All @@ -61,7 +55,7 @@ public void loadScript()
}
catch(IOException e)
{
LogManager.getLogger(ModuleReportResource.class).warn("Unable to load report script from source file " + _sourceFile, e);
LOG.warn("Unable to load report script from source file {}", _sourceFile, e);
}
}

Expand All @@ -78,25 +72,24 @@ public ReportDescriptorType loadMetaData()

if (createdDateStr != null)
{
DateFormat format = new SimpleDateFormat(DateUtil.getDateFormatString(ContainerManager.getRoot()));
try
{
Date createdDate = format.parse(createdDateStr);
Date createdDate = new Date(DateUtil.parseISODateTime(createdDateStr));
_reportDescriptor.setCreated(createdDate);
}
catch (ParseException e)
catch (Exception e)
{
LogManager.getLogger(ModuleReportResource.class).warn("Unable to parse moduleReportCreatedDate \"" + createdDateStr + "\" from file " + _sourceFile, e);
LOG.warn("Unable to parse moduleReportCreatedDate \"{}\" from file {}", createdDateStr, _sourceFile, e);
}
}
}
catch(IOException e)
{
LogManager.getLogger(ModuleReportResource.class).warn("Unable to load report metadata from file " + _metaDataFile, e);
LOG.warn("Unable to load report metadata from file {}", _metaDataFile, e);
}
catch(XmlException e)
{
LogManager.getLogger(ModuleReportResource.class).warn("Unable to load query report metadata from file " + _sourceFile, e);
LOG.warn("Unable to load query report metadata from file {}", _sourceFile, e);
}
}
return d;
Expand Down
2 changes: 0 additions & 2 deletions api/src/org/labkey/api/settings/AbstractSettingsGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@

/**
* Base class for configuration properties persisted through the "prop" schema.
* User: adam
* Date: Aug 2, 2008
*/
public abstract class AbstractSettingsGroup
{
Expand Down
6 changes: 0 additions & 6 deletions api/src/org/labkey/api/settings/FolderSettingsCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,6 @@
import java.util.Collection;
import java.util.Collections;

/**
* User: adam
* Date: 12/15/13
* Time: 10:31 AM
*/

// Folder settings inherit all the way up the folder tree. All the property sets involved should be cached, but the walk
// up the tree is a potentially expensive operation just to format a date or number. So, we cache the set of resolved
// properties on a per-container basis and clear the entire cache on every change of look and feel settings.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@
import org.labkey.api.data.Container;
import org.labkey.api.util.DateUtil;

import static org.labkey.api.settings.LookAndFeelProperties.Properties.*;
import static org.labkey.api.settings.LookAndFeelProperties.Properties.extraDateParsingPattern;
import static org.labkey.api.settings.LookAndFeelProperties.Properties.extraDateTimeParsingPattern;
import static org.labkey.api.settings.LookAndFeelProperties.Properties.extraTimeParsingPattern;
import static org.labkey.api.settings.LookAndFeelProperties.Properties.restrictedColumnsEnabled;

/**
* Container-specific configuration settings, primarily related to look-and-feel or parsing options
* that are not necessarily consistent across an entire project.
*/
public class LookAndFeelFolderProperties extends AbstractWriteableSettingsGroup
{
static final String LOOK_AND_FEEL_SET_NAME = "LookAndFeel";
public static final String LOOK_AND_FEEL_SET_NAME = "LookAndFeel";

// These are the legacy property names for the format patterns
protected static final String defaultDateFormatString = "defaultDateFormatString";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,15 @@

import java.text.DecimalFormat;

import static org.labkey.api.settings.LookAndFeelFolderProperties.defaultTimeFormatString;
import static org.labkey.api.settings.LookAndFeelProperties.LOOK_AND_FEEL_SET_NAME;

import static org.labkey.api.settings.LookAndFeelFolderProperties.defaultDateFormatString;
import static org.labkey.api.settings.LookAndFeelFolderProperties.defaultDateTimeFormatString;
import static org.labkey.api.settings.LookAndFeelFolderProperties.defaultNumberFormatString;

import static org.labkey.api.settings.LookAndFeelProperties.Properties.*;

/**
* User: adam
* Date: Aug 1, 2008
* Time: 9:35:40 PM
*/
import static org.labkey.api.settings.LookAndFeelFolderProperties.defaultTimeFormatString;
import static org.labkey.api.settings.LookAndFeelProperties.LOOK_AND_FEEL_SET_NAME;
import static org.labkey.api.settings.LookAndFeelProperties.Properties.extraDateParsingPattern;
import static org.labkey.api.settings.LookAndFeelProperties.Properties.extraDateTimeParsingPattern;
import static org.labkey.api.settings.LookAndFeelProperties.Properties.extraTimeParsingPattern;
import static org.labkey.api.settings.LookAndFeelProperties.Properties.restrictedColumnsEnabled;

// Handles only the properties that can be set at the folder level
public class WriteableFolderLookAndFeelProperties extends AbstractWriteableSettingsGroup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,6 @@

import static org.labkey.api.settings.LookAndFeelProperties.Properties.*;

/**
* User: adam
* Date: Aug 1, 2008
* Time: 9:35:40 PM
*/

// Handles all the properties that can be set at the project or site level
public class WriteableLookAndFeelProperties extends WriteableFolderLookAndFeelProperties
{
Expand Down
43 changes: 43 additions & 0 deletions api/src/org/labkey/api/util/DateUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -82,6 +83,48 @@ private DateUtil()
private static final String[] SIMPLE_TIME_FORMATS_WITH_AMPM = {"hh:mm:ss.SSS a", "hh:mm:ss a", "hh:mm a"};
private static final String[] SIMPLE_TIME_FORMATS_NO_AMPM = {"HH:mm:ss.SSS", "HH:mm:ss", "HH:mm"};

public static final Set<String> STANDARD_DATE_DISPLAY_FORMATS = PageFlowUtil.set(
"yyyy-MM-dd",
"yyyy-MMM-dd",
"dd-MMM-yyyy",
"dd-MMM-yy",
"ddMMMyyyy",
"ddMMMyy"
);

public static final Set<String> STANDARD_TIME_DISPLAY_FORMATS = PageFlowUtil.set(
"HH:mm:ss",
"HH:mm",
"HH:mm:ss.SSS",
"hh:mm a"
);

public static boolean isStandardDateDisplayFormat(String dateFormat)
{
return STANDARD_DATE_DISPLAY_FORMATS.contains(dateFormat);
}

public static boolean isStandardDateTimeDisplayFormat(String dateTimeFormat)
{
// Tolerate any amount of whitespace between the parts
String[] parts = dateTimeFormat.split("\\s+");

// If one part, must be standard date format
// If two parts, must be standard date format followed by standard time format
// Otherwise, it's non-standard
return switch (parts.length)
{
case 1 -> isStandardDateDisplayFormat(parts[0]);
case 2 -> isStandardDateDisplayFormat(parts[0]) && isStandardTimeDisplayFormat(parts[1]);
default -> false;
};
}

public static boolean isStandardTimeDisplayFormat(String timeFormat)
{
return STANDARD_TIME_DISPLAY_FORMATS.contains(timeFormat);
}

/**
* GregorianCalendar is expensive because it calls computeTime() in setTimeInMillis()
* (which is called in the constructor)
Expand Down
4 changes: 4 additions & 0 deletions api/src/org/labkey/api/util/PageFlowUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -2175,6 +2175,10 @@ public static JSONObject jsInitObject(ContainerUser context, @Nullable PageConfi
String numberFormat = Formats.getNumberFormatString(settingsContainer);
if (null != numberFormat)
json.put("extDefaultNumberFormat", ExtUtil.toExtNumberFormat(numberFormat));
json.put("standardDisplayFormats", Map.of(
"dateFormats", DateUtil.STANDARD_DATE_DISPLAY_FORMATS,
"timeFormats", DateUtil.STANDARD_TIME_DISPLAY_FORMATS
));

json.put("useMDYDateParsing", LookAndFeelProperties.getInstance(ContainerManager.getRoot()).getDateParsingMode().getDayMonth() == DateUtil.MonthDayOption.MONTH_DAY);

Expand Down
Loading