diff --git a/api/resources/queries/core/DocumentsGroupedByParentTypeAdmin.query.xml b/api/resources/queries/core/DocumentsGroupedByParentTypeAdmin.query.xml
new file mode 100644
index 00000000000..9ae9c9126f8
--- /dev/null
+++ b/api/resources/queries/core/DocumentsGroupedByParentTypeAdmin.query.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ admin-attachmentsForType.view?core.ParentType~eq=${ParentType}&core.containerFilterName=${containerFilterName}
+ #,##0
+
+
+
+
+
+
diff --git a/api/resources/queries/core/DocumentsGroupedByParentTypeAdmin.sql b/api/resources/queries/core/DocumentsGroupedByParentTypeAdmin.sql
new file mode 100644
index 00000000000..84423cf106a
--- /dev/null
+++ b/api/resources/queries/core/DocumentsGroupedByParentTypeAdmin.sql
@@ -0,0 +1,5 @@
+-- Identical to DocumentsGroupedByParentType, but this query's .query.xml provides an admin-console-specific Count URL
+SELECT ParentType, COUNT(*) AS "Count"
+FROM Documents
+GROUP BY ParentType
+ORDER BY ParentType
diff --git a/api/src/org/labkey/api/attachments/AttachmentService.java b/api/src/org/labkey/api/attachments/AttachmentService.java
index 10541a07aff..5524e0aa545 100644
--- a/api/src/org/labkey/api/attachments/AttachmentService.java
+++ b/api/src/org/labkey/api/attachments/AttachmentService.java
@@ -138,8 +138,6 @@ static AttachmentService get()
**/
Collection getAttachmentParentTypes();
- HttpView> getAdminView(ActionURL currentUrl);
-
HttpView> getFindAttachmentParentsView();
class DuplicateFilenameException extends IOException implements SkipMothershipLogging
diff --git a/core/src/org/labkey/core/admin/AdminController.java b/core/src/org/labkey/core/admin/AdminController.java
index 64d05aac816..19266ce4987 100644
--- a/core/src/org/labkey/core/admin/AdminController.java
+++ b/core/src/org/labkey/core/admin/AdminController.java
@@ -64,6 +64,7 @@
import org.labkey.api.action.Marshaller;
import org.labkey.api.action.MutatingApiAction;
import org.labkey.api.action.QueryViewAction;
+import org.labkey.api.action.QueryViewAction.QueryExportForm;
import org.labkey.api.action.ReadOnlyApiAction;
import org.labkey.api.action.ReturnUrlForm;
import org.labkey.api.action.SimpleApiJsonForm;
@@ -105,6 +106,7 @@
import org.labkey.api.data.ConnectionWrapper;
import org.labkey.api.data.Container;
import org.labkey.api.data.Container.ContainerException;
+import org.labkey.api.data.ContainerFilter;
import org.labkey.api.data.ContainerManager;
import org.labkey.api.data.ContainerType;
import org.labkey.api.data.ConvertHelper;
@@ -171,11 +173,9 @@
import org.labkey.api.products.ProductRegistry;
import org.labkey.api.query.DefaultSchema;
import org.labkey.api.query.FieldKey;
-import org.labkey.api.query.QueryParam;
import org.labkey.api.query.QuerySchema;
import org.labkey.api.query.QueryService;
import org.labkey.api.query.QuerySettings;
-import org.labkey.api.query.QueryUrls;
import org.labkey.api.query.QueryView;
import org.labkey.api.query.RuntimeValidationException;
import org.labkey.api.query.SchemaKey;
@@ -189,6 +189,7 @@
import org.labkey.api.security.AdminConsoleAction;
import org.labkey.api.security.CSRF;
import org.labkey.api.security.Directive;
+import org.labkey.api.security.ElevatedUser;
import org.labkey.api.security.Group;
import org.labkey.api.security.GroupManager;
import org.labkey.api.security.IgnoresTermsOfUse;
@@ -477,9 +478,7 @@ public static void registerAdminConsoleLinks()
// Diagnostics
AdminConsole.addLink(Diagnostics, "actions", new ActionURL(ActionsAction.class, root));
- AdminConsole.addLink(Diagnostics, "attachments", PageFlowUtil.urlProvider(QueryUrls.class).urlExecuteQuery(root, "core", "DocumentsGroupedByParentType")
- .addParameter("query." + QueryParam.containerFilterName, "AllFolders"), ApplicationAdminPermission.class);
- AdminConsole.addLink(Diagnostics, "attachments - old", new ActionURL(AttachmentsAction.class, root));
+ AdminConsole.addLink(Diagnostics, "attachments", new ActionURL(AttachmentsAction.class, root));
AdminConsole.addLink(Diagnostics, "caches", new ActionURL(CachesAction.class, root));
AdminConsole.addLink(Diagnostics, "check database", new ActionURL(DbCheckerAction.class, root), AdminOperationsPermission.class);
AdminConsole.addLink(Diagnostics, "credits", new ActionURL(CreditsAction.class, root));
@@ -2609,14 +2608,17 @@ public void addNavTrail(NavTree root)
}
}
- private abstract class AbstractPostgresAction extends QueryViewAction
+ private abstract class AbstractPostgresAction extends AbstractAdminQueryAction
{
- private final String _queryName;
-
protected AbstractPostgresAction(String queryName)
{
- super(QueryExportForm.class);
- _queryName = queryName;
+ super("query", queryName);
+ }
+
+ @Override
+ protected UserSchema getUserSchema()
+ {
+ return new PostgresUserSchema(getUser(), getContainer());
}
@Override
@@ -2624,34 +2626,18 @@ protected QueryView createQueryView(QueryExportForm form, BindException errors,
{
if (!CoreSchema.getInstance().getSqlDialect().isPostgreSQL())
{
- throw new NotFoundException("Only available with Postgres as the primary database");
+ throw new NotFoundException("Available only with Postgres as the primary database");
}
- QuerySettings qSettings = new QuerySettings(getViewContext(), "query", _queryName);
- QueryView result = new QueryView(new PostgresUserSchema(getUser(), getContainer()), qSettings, errors)
- {
- @Override
- public DataView createDataView()
- {
- // Troubleshooters don't have normal read access to the root container so grant them special access
- // for these queries
- DataView view = super.createDataView();
- view.getRenderContext().getViewContext().addContextualRole(ReaderRole.class);
- return view;
- }
- };
- result.setTitle(_queryName);
- result.setFrame(WebPartView.FrameType.PORTAL);
- return result;
+ return super.createQueryView(form, errors, forExport, dataRegion);
}
@Override
public void addNavTrail(NavTree root)
{
setHelpTopic("postgresActivity");
- addAdminNavTrail(root, "Postgres " + _queryName, this.getClass());
+ addAdminNavTrail(root, "Postgres " + getQueryName(), this.getClass());
}
-
}
@AdminConsoleAction
@@ -3581,22 +3567,96 @@ public URLHelper getSuccessURL(SystemMaintenanceForm form)
}
}
+ private abstract static class AbstractAdminQueryAction extends QueryViewAction
+ {
+ private final String _schemaName;
+ private final String _queryName;
+
+ protected AbstractAdminQueryAction(String schemaName, String queryName)
+ {
+ super(QueryExportForm.class);
+ _schemaName = schemaName;
+ _queryName = queryName;
+ }
+
+ @Override
+ public void setViewContext(ViewContext context)
+ {
+ // Troubleshooters don't have read permissions but DataRegion requires it. I don't love poking an elevated
+ // user into the ViewContext, but this is the only way I could get DataRegion to see read permission on
+ // tables that are wrapped by a query (e.g., core.Documents used by DocumentsGroupedByParentType.sql).
+ context.setUser(ElevatedUser.getElevatedUser(context.getUser(), ReaderRole.class));
+ super.setViewContext(context);
+ }
+
+ @Override
+ protected QueryView createQueryView(QueryExportForm form, BindException errors, boolean forExport, @Nullable String dataRegion) throws Exception
+ {
+ QuerySettings qSettings = new QuerySettings(getViewContext(), _schemaName, _queryName);
+ if (qSettings.getContainerFilterName() == null)
+ qSettings.setContainerFilterName(ContainerFilter.Type.AllFolders.name());
+ QueryView result = new QueryView(getUserSchema(), qSettings, errors);
+ result.setTitle(_queryName);
+ result.setFrame(WebPartView.FrameType.PORTAL);
+ return result;
+ }
+
+ protected String getQueryName()
+ {
+ return _queryName;
+ }
+
+ abstract protected UserSchema getUserSchema();
+ }
+
@AdminConsoleAction
- public class AttachmentsAction extends SimpleViewAction