diff --git a/api/src/org/labkey/api/action/PermissionCheckableAction.java b/api/src/org/labkey/api/action/PermissionCheckableAction.java index 5795a2e2693..984aa69a8a4 100644 --- a/api/src/org/labkey/api/action/PermissionCheckableAction.java +++ b/api/src/org/labkey/api/action/PermissionCheckableAction.java @@ -16,6 +16,7 @@ package org.labkey.api.action; import jakarta.servlet.http.HttpServletResponse; +import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; import org.labkey.api.data.Container; import org.labkey.api.module.IgnoresForbiddenProjectCheck; @@ -39,6 +40,7 @@ import org.labkey.api.security.roles.RoleManager; import org.labkey.api.util.ConfigurationException; import org.labkey.api.util.HttpUtil; +import org.labkey.api.util.logging.LogHelper; import org.labkey.api.view.BadRequestException; import org.labkey.api.view.NotFoundException; import org.labkey.api.view.RedirectException; @@ -55,6 +57,7 @@ public abstract class PermissionCheckableAction implements Controller, PermissionCheckable, HasViewContext { + private static final Logger LOG = LogHelper.getLogger(PermissionCheckableAction.class, "Permission checks for actions"); private static final HttpUtil.Method[] arrayGetPost = new HttpUtil.Method[] {Method.GET, Method.POST}; private ViewContext _context = null; UnauthorizedException.Type _unauthorizedType = UnauthorizedException.Type.redirectToLogin; @@ -148,6 +151,8 @@ private void _checkActionPermissions(Set contextualRoles) throws Unauthori Container c = context.getContainer(); User user = context.getUser(); Class actionClass = getClass(); + if (LOG.isDebugEnabled()) + LOG.debug(actionClass.getName() + ": checking permissions for user " + (user == null ? "" : user.getName() + " (impersonated=" + user.isImpersonated() + ")")); if (!actionClass.isAnnotationPresent(IgnoresForbiddenProjectCheck.class)) c.throwIfForbiddenProject(user); @@ -159,18 +164,22 @@ private void _checkActionPermissions(Set contextualRoles) throws Unauthori methodsAllowed = methodsAllowedAnnotation.value(); if (Arrays.stream(methodsAllowed).noneMatch(s -> s.equals(method))) { - throw new BadRequestException("Method Not Allowed: " + method, null, HttpServletResponse.SC_METHOD_NOT_ALLOWED); + String msg = "Method Not Allowed: " + method; + LOG.debug(msg); + throw new BadRequestException(msg, null, HttpServletResponse.SC_METHOD_NOT_ALLOWED); } boolean requiresSiteAdmin = actionClass.isAnnotationPresent(RequiresSiteAdmin.class); if (requiresSiteAdmin && !user.hasSiteAdminPermission()) { + LOG.debug(actionClass.getName() + ": action requires site admin permissions"); throw new UnauthorizedException(); } boolean requiresLogin = actionClass.isAnnotationPresent(RequiresLogin.class); if (requiresLogin && user.isGuest()) { + LOG.debug(actionClass.getName() + ": action requires login (non-guest)"); throw new UnauthorizedException(); } @@ -214,7 +223,10 @@ private void _checkActionPermissions(Set contextualRoles) throws Unauthori // Must have all permissions in permissionsRequired if (!SecurityManager.hasAllPermissions(this.getClass().getName()+"_checkActionPermissions", c, user, permissionsRequired, contextualRoles)) + { + LOG.debug(actionClass.getName() + ": action requires all permissions: " + permissionsRequired); throw new UnauthorizedException(); + } CSRF.Method csrfCheck = actionClass.isAnnotationPresent(CSRF.class) ? actionClass.getAnnotation(CSRF.class).value() : CSRF.Method.POST; csrfCheck.validate(context); @@ -228,7 +240,10 @@ private void _checkActionPermissions(Set contextualRoles) throws Unauthori Collections.addAll(permissionsAnyOf, requiresAnyOf.value()); if (!SecurityManager.hasAnyPermissions(this.getClass().getName() + "_checkActionPermissions", c, user, permissionsAnyOf, contextualRoles)) + { + LOG.debug(actionClass.getName() + ": action requires any permissions: " + permissionsAnyOf); throw new UnauthorizedException(); + } } boolean requiresNoPermission = actionClass.isAnnotationPresent(RequiresNoPermission.class); diff --git a/api/src/org/labkey/api/data/Container.java b/api/src/org/labkey/api/data/Container.java index b2ca3dd25f2..0d5186156a7 100644 --- a/api/src/org/labkey/api/data/Container.java +++ b/api/src/org/labkey/api/data/Container.java @@ -41,6 +41,7 @@ import org.labkey.api.query.QueryService; import org.labkey.api.security.HasPermission; import org.labkey.api.security.SecurableResource; +import org.labkey.api.security.SecurityLogger; import org.labkey.api.security.SecurityManager; import org.labkey.api.security.SecurityPolicy; import org.labkey.api.security.SecurityPolicyManager; @@ -550,7 +551,11 @@ private boolean handleForbiddenProject(User user, Set contextualRoles, boo if (null != impersonationProject && !impersonationProject.equals(currentProject)) { if (shouldThrow) - throw new ForbiddenProjectException("You are not allowed to access this folder while impersonating within a different project."); + { + String msg = "You are not allowed to access this folder while impersonating within a different project."; + SecurityLogger.log(msg, user, null, null); + throw new ForbiddenProjectException(msg); + } return true; } @@ -563,7 +568,11 @@ private boolean handleForbiddenProject(User user, Set contextualRoles, boo if (lockState.isLocked() && ContainerManager.LOCKED_PROJECT_HANDLER.isForbidden(currentProject, user, contextualRoles, lockState)) { if (shouldThrow) - throw new ForbiddenProjectException("You are not allowed to access this folder; it is " + lockState.getDescription() + "."); + { + String msg = "You are not allowed to access this folder; it is " + lockState.getDescription() + "."; + SecurityLogger.log(msg, user, null, null); + throw new ForbiddenProjectException(msg); + } return true; } diff --git a/api/src/org/labkey/api/data/URLDisplayColumn.java b/api/src/org/labkey/api/data/URLDisplayColumn.java index 55bb96d703d..4b5e202fc2c 100644 --- a/api/src/org/labkey/api/data/URLDisplayColumn.java +++ b/api/src/org/labkey/api/data/URLDisplayColumn.java @@ -182,7 +182,7 @@ public Renderable createThumbnailImage() String thumbnailUrl = _fileIconUrl != null ? ensureAbsoluteUrl(_ctx, _fileIconUrl) : ensureAbsoluteUrl(_ctx, _url); return IMG(at( - style, "display:block; vertical-align:middle;" + (renderSize ? (_thumbnailWidth != null ? " width:" + _thumbnailWidth : " max-width:32px" + "; ") + (_thumbnailHeight != null ? " height:" + _thumbnailHeight : " height:auto" + ";") : ""), + style, "display:block; vertical-align:middle;" + (renderSize ? (_thumbnailWidth != null ? " width:" + _thumbnailWidth : " max-width:32px") + "; " + (_thumbnailHeight != null ? " height:" + _thumbnailHeight : " height:auto") + ";" : ""), src, thumbnailUrl, title, _displayName )); } diff --git a/api/src/org/labkey/api/exp/list/ListImportProgress.java b/api/src/org/labkey/api/dataiterator/ImportProgress.java similarity index 81% rename from api/src/org/labkey/api/exp/list/ListImportProgress.java rename to api/src/org/labkey/api/dataiterator/ImportProgress.java index 0210a1fd341..f118003f82c 100644 --- a/api/src/org/labkey/api/exp/list/ListImportProgress.java +++ b/api/src/org/labkey/api/dataiterator/ImportProgress.java @@ -1,27 +1,22 @@ -/* - * Copyright (c) 2009-2014 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.labkey.api.exp.list; - -/* -* User: adam -* Date: Dec 23, 2009 -* Time: 3:05:51 PM -*/ -public interface ListImportProgress -{ - void setTotalRows(int rows); - void setCurrentRow(int currentRow); -} +/* + * Copyright (c) 2009-2014 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.labkey.api.dataiterator; + +public interface ImportProgress +{ + void setTotalRows(int rows); + void setCurrentRow(int currentRow); +} diff --git a/api/src/org/labkey/api/dataiterator/Pump.java b/api/src/org/labkey/api/dataiterator/Pump.java index fd15dd76940..83e5b41cfa8 100644 --- a/api/src/org/labkey/api/dataiterator/Pump.java +++ b/api/src/org/labkey/api/dataiterator/Pump.java @@ -17,7 +17,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.labkey.api.exp.list.ListImportProgress; import org.labkey.api.query.BatchValidationException; import java.io.IOException; @@ -34,7 +33,7 @@ public class Pump implements Runnable final BatchValidationException _errors; int _errorLimit = Integer.MAX_VALUE; long _rowCount = 0; - ListImportProgress _progress = null; + ImportProgress _progress = null; public Pump(DataIterator it, DataIteratorContext context) { @@ -50,7 +49,7 @@ public Pump(DataIteratorBuilder builder, DataIteratorContext context) _errors = context.getErrors(); } - public void setProgress(ListImportProgress progress) + public void setProgress(ImportProgress progress) { _progress = progress; } diff --git a/api/src/org/labkey/api/exp/list/ListDefinition.java b/api/src/org/labkey/api/exp/list/ListDefinition.java index 69d4473c22b..9963ad6b0bd 100644 --- a/api/src/org/labkey/api/exp/list/ListDefinition.java +++ b/api/src/org/labkey/api/exp/list/ListDefinition.java @@ -23,6 +23,7 @@ import org.labkey.api.data.ContainerFilter; import org.labkey.api.data.LookupResolutionType; import org.labkey.api.data.TableInfo; +import org.labkey.api.dataiterator.ImportProgress; import org.labkey.api.exp.DomainNotFoundException; import org.labkey.api.exp.PropertyType; import org.labkey.api.exp.property.Domain; @@ -269,8 +270,8 @@ public static BodySetting getForValue(int value) ListItem getListItemForEntityId(String entityId, User user); int insertListItems(User user, Container container, List listItems) throws IOException; - int insertListItems(User user, Container container, DataLoader loader, @NotNull BatchValidationException errors, @Nullable VirtualFile attachmentDir, @Nullable ListImportProgress progress, boolean supportAutoIncrementKey, LookupResolutionType lookupResolutionType) throws IOException; - int importListItems(User user, Container container, DataLoader loader, @NotNull BatchValidationException errors, @Nullable VirtualFile attachmentDir, @Nullable ListImportProgress progress, boolean supportAutoIncrementKey, LookupResolutionType lookupResolutionType, QueryUpdateService.InsertOption insertOption) throws IOException; + int insertListItems(User user, Container container, DataLoader loader, @NotNull BatchValidationException errors, @Nullable VirtualFile attachmentDir, @Nullable ImportProgress progress, boolean supportAutoIncrementKey, LookupResolutionType lookupResolutionType) throws IOException; + int importListItems(User user, Container container, DataLoader loader, @NotNull BatchValidationException errors, @Nullable VirtualFile attachmentDir, @Nullable ImportProgress progress, boolean supportAutoIncrementKey, LookupResolutionType lookupResolutionType, QueryUpdateService.InsertOption insertOption) throws IOException; @Nullable TableInfo getTable(User user); @Nullable TableInfo getTable(User user, Container c); diff --git a/api/src/org/labkey/api/migration/DatabaseMigrationConfiguration.java b/api/src/org/labkey/api/migration/DatabaseMigrationConfiguration.java index 49cd45b4ff5..60a48a6e791 100644 --- a/api/src/org/labkey/api/migration/DatabaseMigrationConfiguration.java +++ b/api/src/org/labkey/api/migration/DatabaseMigrationConfiguration.java @@ -7,7 +7,10 @@ import org.labkey.api.data.DbScope; import org.labkey.api.data.TableInfo; import org.labkey.api.data.TableSelector; +import org.labkey.api.util.GUID; +import org.labkey.api.util.Pair; +import java.io.PrintWriter; import java.util.Set; import java.util.function.Predicate; @@ -21,5 +24,8 @@ default void beforeMigration(){} Predicate getColumnNameFilter(); @Nullable TableSelector getTableSelector(DbSchemaType schemaType, TableInfo sourceTable, TableInfo targetTable, Set selectColumnNames, MigrationSchemaHandler schemaHandler, @Nullable MigrationTableHandler tableHandler); default void copyAttachments(DbSchema sourceSchema, DbSchema targetSchema, MigrationSchemaHandler schemaHandler){} - default void afterMigration(){} + default @Nullable Pair> initializeFilePathWriter() + { + return null; + } } diff --git a/api/src/org/labkey/api/migration/DefaultMigrationSchemaHandler.java b/api/src/org/labkey/api/migration/DefaultMigrationSchemaHandler.java index 36fb4089026..5eb1348abc3 100644 --- a/api/src/org/labkey/api/migration/DefaultMigrationSchemaHandler.java +++ b/api/src/org/labkey/api/migration/DefaultMigrationSchemaHandler.java @@ -306,15 +306,15 @@ public static void afterMigration() throws InterruptedException if (unseen.isEmpty()) LOG.info("All AttachmentTypes have been seen"); else - throw new ConfigurationException("These AttachmentTypes have not been seen: " + unseen.stream().map(type -> type.getClass().getSimpleName()).collect(Collectors.joining(", "))); + LOG.error("These AttachmentTypes have not been seen: {}", unseen.stream().map(type -> type.getClass().getSimpleName()).collect(Collectors.joining(", "))); // Shut down the attachment JobRunner LOG.info("Waiting for attachments background transfer to complete"); ATTACHMENT_JOB_RUNNER.shutdown(); - if (ATTACHMENT_JOB_RUNNER.awaitTermination(1, TimeUnit.HOURS)) + if (ATTACHMENT_JOB_RUNNER.awaitTermination(2, TimeUnit.HOURS)) LOG.info("Attachments background transfer is complete"); else - LOG.error("Attachments background transfer did not complete after one hour! Giving up."); + LOG.error("Attachments background transfer did not complete after two hours! Giving up."); } @Override @@ -332,4 +332,9 @@ public void afterSchema(DatabaseMigrationConfiguration configuration, DbSchema s public void afterMigration(DatabaseMigrationConfiguration configuration) { } + + @Override + public void writeFilePaths(FilePathWriter writer, Set guids) + { + } } diff --git a/api/src/org/labkey/api/migration/FilePathWriter.java b/api/src/org/labkey/api/migration/FilePathWriter.java new file mode 100644 index 00000000000..b034541c009 --- /dev/null +++ b/api/src/org/labkey/api/migration/FilePathWriter.java @@ -0,0 +1,42 @@ +package org.labkey.api.migration; + +import org.labkey.api.data.ContainerManager; +import org.labkey.api.files.FileContentService; + +import java.io.Closeable; +import java.io.File; +import java.io.PrintWriter; +import java.nio.file.Path; + +public class FilePathWriter implements Closeable +{ + private final PrintWriter _out; + private final Path _rootPath; + + public FilePathWriter(PrintWriter out) + { + _out = out; + _rootPath = FileContentService.get().getFileRoot(ContainerManager.getRoot()).toPath(); + } + + public void write(File file) + { + _out.println(_rootPath.relativize(file.toPath()).normalize()); + } + + public void println(String s) + { + _out.println(s); + } + + public void println() + { + _out.println(); + } + + @Override + public void close() + { + _out.close(); + } +} diff --git a/api/src/org/labkey/api/migration/MigrationSchemaHandler.java b/api/src/org/labkey/api/migration/MigrationSchemaHandler.java index daa6aaa02e3..ebb41405841 100644 --- a/api/src/org/labkey/api/migration/MigrationSchemaHandler.java +++ b/api/src/org/labkey/api/migration/MigrationSchemaHandler.java @@ -12,6 +12,7 @@ import org.labkey.api.query.FieldKey; import org.labkey.api.util.GUID; +import java.io.PrintWriter; import java.util.Collection; import java.util.List; import java.util.Set; @@ -57,4 +58,6 @@ public interface MigrationSchemaHandler @NotNull Collection getAttachmentTypes(); void afterMigration(DatabaseMigrationConfiguration configuration); + + void writeFilePaths(FilePathWriter writer, Set guids); } diff --git a/api/src/org/labkey/api/module/ModuleLoader.java b/api/src/org/labkey/api/module/ModuleLoader.java index 49d5743d602..b8839fd0947 100644 --- a/api/src/org/labkey/api/module/ModuleLoader.java +++ b/api/src/org/labkey/api/module/ModuleLoader.java @@ -678,9 +678,6 @@ private void doInit(Execution execution) throws ServletException _log.info("Server installation GUID: {}, server session GUID: {}", AppProps.getInstance().getServerGUID(), AppProps.getInstance().getServerSessionGUID()); _log.info("Deploying to context path {}", AppProps.getInstance().getContextPath()); - // Temporary logging to help track down issues we're having with upgrading XMLBeans from v5.2.0. TODO: Remove after upgrade - _log.info("XMLBeans version: {}", XmlBeans.getVersion()); - synchronized (_modulesLock) { checkForRenamedModules(); diff --git a/api/src/org/labkey/api/premium/AntiVirusService.java b/api/src/org/labkey/api/premium/AntiVirusService.java index 20a31e5d897..5e15f09145e 100644 --- a/api/src/org/labkey/api/premium/AntiVirusService.java +++ b/api/src/org/labkey/api/premium/AntiVirusService.java @@ -35,6 +35,7 @@ public interface AntiVirusService { // NOTE purposefully this is not the same as the standard test file: ...EICAR-STANDARD-ANTIVIRUS-TEST-FILE... String TEST_VIRUS_CONTENT="X5O!P%@AP[4\\PZX54(P^)7CC)7}$LABKEY-ANTIVIRUS-TEST-FILE!$H+H*"; + String MALICIOUS_FILE_ERROR_MESSAGE = "For security reasons, we did not upload this file. Please contact your internal IT or Information Security department for assistance in dealing with this potentially harmful file."; static @Nullable AntiVirusService get() { diff --git a/core/src/org/labkey/core/webdav/DavController.java b/core/src/org/labkey/core/webdav/DavController.java index 58c7bbb0112..6c680148437 100644 --- a/core/src/org/labkey/core/webdav/DavController.java +++ b/core/src/org/labkey/core/webdav/DavController.java @@ -3002,7 +3002,7 @@ public void closeInputStream() throws IOException if (result.result == AntiVirusService.Result.CONFIGURATION_ERROR) throw new ConfigurationException(result.message); else - throw new DavException(WebdavStatus.SC_BAD_REQUEST, result.message); + throw new DavException(WebdavStatus.SC_BAD_REQUEST, result.message + ". " + AntiVirusService.MALICIOUS_FILE_ERROR_MESSAGE); } } diff --git a/experiment/src/org/labkey/experiment/DataClassMigrationSchemaHandler.java b/experiment/src/org/labkey/experiment/DataClassMigrationSchemaHandler.java index 2e93cba7b5d..296b2b349b5 100644 --- a/experiment/src/org/labkey/experiment/DataClassMigrationSchemaHandler.java +++ b/experiment/src/org/labkey/experiment/DataClassMigrationSchemaHandler.java @@ -24,6 +24,7 @@ import org.labkey.api.migration.DatabaseMigrationService.DataFilter; import org.labkey.api.migration.DefaultMigrationSchemaHandler; import org.labkey.api.migration.ExperimentDeleteService; +import org.labkey.api.migration.FilePathWriter; import org.labkey.api.query.FieldKey; import org.labkey.api.util.GUID; import org.labkey.api.util.StringUtilsLabKey; @@ -95,8 +96,8 @@ public void afterTable(TableInfo sourceTable, TableInfo targetTable, SimpleFilte // Select all ObjectIds associated with the not-copied rows from the source database SQLFragment objectIdSql = new SQLFragment("SELECT ObjectId FROM exp.Data d INNER JOIN ") - .appendIdentifier(sourceTable.getSelectName()) - .append(" dc ON d.LSID = dc.LSID"); + .appendIdentifier(sourceTable.getSelectName()) + .append(" dc ON d.LSID = dc.LSID"); // Don't create an empty IN clause; need to work around issue where "NOT xxx IN (NULL)" evaluates to NULL. if (!copiedLsids.isEmpty()) @@ -134,7 +135,7 @@ public void afterTable(TableInfo sourceTable, TableInfo targetTable, SimpleFilte } }) .forEach(SEQUENCE_IDS::add); - LOG.info("{} added to the SequenceIdentity set", + LOG.info(" {} added to the SequenceIdentity set", StringUtilsLabKey.pluralize(SEQUENCE_IDS.size() - startSize, "unique SequenceId was", "unique SequenceIds were")); } } @@ -202,4 +203,11 @@ public FilterClause getTableFilterClause(TableInfo sourceTable, Set contai { return List.of(ExpDataClassType.get()); } + + @Override + public void writeFilePaths(FilePathWriter writer, Set guids) + { + // TODO: Enumerate FileLink fields in data classes in the filtered containers (guids) and write out those file + // paths. Current client has none. + } } diff --git a/experiment/src/org/labkey/experiment/ExperimentMigrationSchemaHandler.java b/experiment/src/org/labkey/experiment/ExperimentMigrationSchemaHandler.java index 3a1bfb1d6bb..6d844f2864b 100644 --- a/experiment/src/org/labkey/experiment/ExperimentMigrationSchemaHandler.java +++ b/experiment/src/org/labkey/experiment/ExperimentMigrationSchemaHandler.java @@ -261,6 +261,15 @@ public FilterClause getContainerClause(TableInfo sourceTable, Set containe .appendInClause(containers, sourceTable.getSqlDialect()) .append(")") ); + case "MaterialAliasMap" -> new AndClause( + new InClause(FieldKey.fromParts("Container"), containers), + // The below effectively matches the "Material" conditions above, since MaterialAliasMap has an FK to Material + new InClause(FieldKey.fromParts("LSID", "Container"), containers), + new OrClause( + new CompareClause(FieldKey.fromParts("LSID", "RunId"), CompareType.ISBLANK, null), + new InClause(FieldKey.fromParts("LSID", "RunId", "Container"), containers) + ) + ); case "ObjectLegacyNames" -> new SQLClause( new SQLFragment("ObjectId IN (SELECT ObjectId FROM exp.Object WHERE Container") .appendInClause(containers, sourceTable.getSqlDialect()) diff --git a/experiment/src/org/labkey/experiment/SampleTypeMigrationSchemaHandler.java b/experiment/src/org/labkey/experiment/SampleTypeMigrationSchemaHandler.java index 4c2d2f89d42..0aae0fa7aa6 100644 --- a/experiment/src/org/labkey/experiment/SampleTypeMigrationSchemaHandler.java +++ b/experiment/src/org/labkey/experiment/SampleTypeMigrationSchemaHandler.java @@ -14,6 +14,7 @@ import org.labkey.api.exp.api.SampleTypeDomainKind; import org.labkey.api.migration.DatabaseMigrationService.DataFilter; import org.labkey.api.migration.DefaultMigrationSchemaHandler; +import org.labkey.api.migration.FilePathWriter; import org.labkey.api.util.GUID; import org.labkey.api.util.logging.LogHelper; @@ -168,4 +169,11 @@ public void afterTable(TableInfo sourceTable, TableInfo targetTable, SimpleFilte ExperimentMigrationSchemaHandler.deleteObjectIds(objectIdClause); } } + + @Override + public void writeFilePaths(FilePathWriter writer, Set guids) + { + // TODO: Enumerate FileLink fields in sample types in the filtered containers (guids) and write out those file + // paths. Current client has none. + } } diff --git a/experiment/src/org/labkey/experiment/api/ExperimentServiceImpl.java b/experiment/src/org/labkey/experiment/api/ExperimentServiceImpl.java index b9b8859e1e4..e84d8b3738e 100644 --- a/experiment/src/org/labkey/experiment/api/ExperimentServiceImpl.java +++ b/experiment/src/org/labkey/experiment/api/ExperimentServiceImpl.java @@ -230,6 +230,7 @@ import org.labkey.api.util.StringUtilsLabKey; import org.labkey.api.util.SubstitutionFormat; import org.labkey.api.util.TestContext; +import org.labkey.api.util.URIUtil; import org.labkey.api.util.UnexpectedException; import org.labkey.api.util.logging.LogHelper; import org.labkey.api.view.ActionURL; @@ -774,7 +775,17 @@ public ExpDataImpl createData(URI uri, XarSource source) throws XarFormatExcepti { path = FileUtil.stringToPath(source.getXarContext().getContainer(), source.getCanonicalDataFileURL(FileUtil.pathToString(path))); - pathStr = FileUtil.relativizeUnix(source.getRootPath(), path, false); + + // Only convert to a relative path if this is a descendant of the root: + path = path.normalize(); + if (URIUtil.isDescendant(source.getRootPath().toUri(), path.toUri())) + { + pathStr = FileUtil.relativizeUnix(source.getRootPath(), path, false); + } + else + { + pathStr = FileUtil.pathToString(path); + } } catch (IOException e) { diff --git a/list/src/org/labkey/list/model/ListDefinitionImpl.java b/list/src/org/labkey/list/model/ListDefinitionImpl.java index 764607d36b3..b63b108c2e9 100644 --- a/list/src/org/labkey/list/model/ListDefinitionImpl.java +++ b/list/src/org/labkey/list/model/ListDefinitionImpl.java @@ -30,13 +30,13 @@ import org.labkey.api.data.SimpleFilter; import org.labkey.api.data.TableInfo; import org.labkey.api.data.TableSelector; +import org.labkey.api.dataiterator.ImportProgress; import org.labkey.api.exp.DomainNotFoundException; import org.labkey.api.exp.Lsid; import org.labkey.api.exp.ObjectProperty; import org.labkey.api.exp.TemplateInfo; import org.labkey.api.exp.api.ExperimentService; import org.labkey.api.exp.list.ListDefinition; -import org.labkey.api.exp.list.ListImportProgress; import org.labkey.api.exp.list.ListItem; import org.labkey.api.exp.property.Domain; import org.labkey.api.exp.property.DomainProperty; @@ -610,13 +610,13 @@ public int insertListItems(User user, Container container, List listIt @Override - public int insertListItems(User user, Container container, DataLoader loader, @NotNull BatchValidationException errors, @Nullable VirtualFile attachmentDir, @Nullable ListImportProgress progress, boolean supportAutoIncrementKey, LookupResolutionType lookupResolutionType) + public int insertListItems(User user, Container container, DataLoader loader, @NotNull BatchValidationException errors, @Nullable VirtualFile attachmentDir, @Nullable ImportProgress progress, boolean supportAutoIncrementKey, LookupResolutionType lookupResolutionType) { return importListItems(user, container, loader, errors, attachmentDir, progress, supportAutoIncrementKey, lookupResolutionType, QueryUpdateService.InsertOption.INSERT); } @Override - public int importListItems(User user, Container container, DataLoader loader, @NotNull BatchValidationException errors, @Nullable VirtualFile attachmentDir, @Nullable ListImportProgress progress, boolean supportAutoIncrementKey, LookupResolutionType lookupResolutionType, QueryUpdateService.InsertOption insertOption) + public int importListItems(User user, Container container, DataLoader loader, @NotNull BatchValidationException errors, @Nullable VirtualFile attachmentDir, @Nullable ImportProgress progress, boolean supportAutoIncrementKey, LookupResolutionType lookupResolutionType, QueryUpdateService.InsertOption insertOption) { ListQuerySchema schema = new ListQuerySchema(user, container); TableInfo table = schema.getTable(_def.getName()); diff --git a/list/src/org/labkey/list/model/ListQueryUpdateService.java b/list/src/org/labkey/list/model/ListQueryUpdateService.java index 9e6fae5c12f..8848d3d8b76 100644 --- a/list/src/org/labkey/list/model/ListQueryUpdateService.java +++ b/list/src/org/labkey/list/model/ListQueryUpdateService.java @@ -42,11 +42,11 @@ import org.labkey.api.dataiterator.DataIteratorBuilder; import org.labkey.api.dataiterator.DataIteratorContext; import org.labkey.api.dataiterator.DetailedAuditLogDataIterator; +import org.labkey.api.dataiterator.ImportProgress; import org.labkey.api.exp.ObjectProperty; import org.labkey.api.exp.PropertyType; import org.labkey.api.exp.api.ExperimentService; import org.labkey.api.exp.list.ListDefinition; -import org.labkey.api.exp.list.ListImportProgress; import org.labkey.api.exp.list.ListItem; import org.labkey.api.exp.list.ListService; import org.labkey.api.exp.property.Domain; @@ -229,7 +229,7 @@ private User getListUser(User user, Container container) } public int insertUsingDataIterator(DataLoader loader, User user, Container container, BatchValidationException errors, @Nullable VirtualFile attachmentDir, - @Nullable ListImportProgress progress, boolean supportAutoIncrementKey, InsertOption insertOption, LookupResolutionType lookupResolutionType) + @Nullable ImportProgress progress, boolean supportAutoIncrementKey, InsertOption insertOption, LookupResolutionType lookupResolutionType) { if (!_list.isVisible(user)) throw new UnauthorizedException("You do not have permission to insert data into this table."); diff --git a/query/src/org/labkey/query/controllers/InternalViewForm.java b/query/src/org/labkey/query/controllers/InternalViewForm.java index c8bc14c560a..0a8612e3b96 100644 --- a/query/src/org/labkey/query/controllers/InternalViewForm.java +++ b/query/src/org/labkey/query/controllers/InternalViewForm.java @@ -69,7 +69,8 @@ public static void checkEdit(ViewContext context, CstmView view) } else { - if (view.getCustomViewOwner().intValue() != context.getUser().getUserId()) + // must be owner or site admin + if (!context.getUser().hasSiteAdminPermission() && view.getCustomViewOwner().intValue() != context.getUser().getUserId()) { throw new UnauthorizedException(); } diff --git a/query/src/org/labkey/query/view/manageViews.jsp b/query/src/org/labkey/query/view/manageViews.jsp index e5196c99437..d4f52746f04 100644 --- a/query/src/org/labkey/query/view/manageViews.jsp +++ b/query/src/org/labkey/query/view/manageViews.jsp @@ -59,14 +59,16 @@ QueryManager mgr = QueryManager.get(); List views = new ArrayList<>(); - if (getViewContext().hasPermission(UpdatePermission.class)) + if (getViewContext().getUser().hasSiteAdminPermission()) { - views.addAll(mgr.getCstmViews(c, schemaName, queryName, null, null, false, true)); + views.addAll(mgr.getCstmViews(c, schemaName, queryName, null, null, false, false)); } - - if (!user.isGuest()) + else { - views.addAll(mgr.getCstmViews(c, schemaName, queryName, null, user, false, false)); + if (getViewContext().hasPermission(UpdatePermission.class)) + views.addAll(mgr.getCstmViews(c, schemaName, queryName, null, null, false, true)); + if (!user.isGuest()) + views.addAll(mgr.getCstmViews(c, schemaName, queryName, null, user, false, false)); } // UNDONE: Requires queryName and schemaName for now. We need a method to get all session views in a container. @@ -107,22 +109,25 @@ <% } %>

- +
- - - - - - - - - + + + + + + + + + + <% if (getViewContext().hasPermission(UpdatePermission.class)) { + int count = 1; for (CstmView view : views) { + count++; List flags = new ArrayList<>(); if (view.getCustomViewId() == 0) flags.add("session"); @@ -133,7 +138,7 @@ if (mgr.isSnapshot(view.getFlags())) flags.add("shapshot"); %> - +
SchemaQueryView NameFlagsOwnerCreatedCreated ByModifiedModified BySchemaQueryView NameFlagsOwnerCreatedCreated ByModifiedModified By
<%=h(view.getSchema())%> <%=h(view.getQueryName())%> diff --git a/search/src/org/labkey/search/SearchModule.java b/search/src/org/labkey/search/SearchModule.java index d4cd37bca6e..f12c4ea4294 100644 --- a/search/src/org/labkey/search/SearchModule.java +++ b/search/src/org/labkey/search/SearchModule.java @@ -29,6 +29,7 @@ import org.labkey.api.data.UpgradeCode; import org.labkey.api.mbean.LabKeyManagement; import org.labkey.api.mbean.SearchMXBean; +import org.labkey.api.migration.DatabaseMigrationConfiguration; import org.labkey.api.migration.DatabaseMigrationService; import org.labkey.api.migration.DefaultMigrationSchemaHandler; import org.labkey.api.module.DefaultModule; @@ -195,6 +196,13 @@ public List getTablesToCopy() { return List.of(); // Leave empty -- target server will re-index all documents } + + @Override + public void afterMigration(DatabaseMigrationConfiguration configuration) + { + // Clear index and all last indexed tracking + SearchService.get().deleteIndex("Database was just migrated"); + } }); } diff --git a/specimen/src/org/labkey/specimen/importer/SpecimenImporter.java b/specimen/src/org/labkey/specimen/importer/SpecimenImporter.java index 13e5ed7ba1b..86e5d0465a8 100644 --- a/specimen/src/org/labkey/specimen/importer/SpecimenImporter.java +++ b/specimen/src/org/labkey/specimen/importer/SpecimenImporter.java @@ -57,6 +57,7 @@ import org.labkey.api.dataiterator.DataIteratorBuilder; import org.labkey.api.dataiterator.DataIteratorContext; import org.labkey.api.dataiterator.DataIteratorUtil; +import org.labkey.api.dataiterator.ImportProgress; import org.labkey.api.dataiterator.ListofMapsDataIterator; import org.labkey.api.dataiterator.LoggingDataIterator; import org.labkey.api.dataiterator.MapDataIterator; @@ -69,7 +70,6 @@ import org.labkey.api.exp.api.ExpSampleType; import org.labkey.api.exp.api.ExperimentService; import org.labkey.api.exp.api.SampleTypeService; -import org.labkey.api.exp.list.ListImportProgress; import org.labkey.api.iterator.MarkableIterator; import org.labkey.api.pipeline.PipelineJob; import org.labkey.api.query.DefaultSchema; @@ -1993,7 +1993,7 @@ public Object getValue(Map row) DataIteratorBuilder standardEtl = StandardDataIteratorBuilder.forInsert(target, specimenWrapped, getContainer(), getUser(), dix); DataIteratorBuilder persist = ((UpdateableTableInfo)target).persistRows(standardEtl, dix); Pump pump = new Pump(persist, dix); - pump.setProgress(new ListImportProgress() + pump.setProgress(new ImportProgress() { long heartBeat = HeartBeat.currentTimeMillis();