This is an automated email from the ASF dual-hosted git repository.
dominikriemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git
The following commit(s) were added to refs/heads/dev by this push:
new dd42d00372 fix(#4687): kiosk mode does not show data for logged out
users (#4689)
dd42d00372 is described below
commit dd42d003721aa6e8fa164cdc79d8dcaad42b44b3
Author: Philipp Zehnder <[email protected]>
AuthorDate: Mon Jul 6 21:39:19 2026 +0200
fix(#4687): kiosk mode does not show data for logged out users (#4689)
---
.../datalake/KioskDashboardDataLakeResource.java | 27 --------
.../service/core/UnauthenticatedInterfaces.java | 2 +-
ui/cypress/support/utils/dashboard/Inspector.ts | 36 ++++++++++-
ui/cypress/tests/chart/publicDashboardLink.spec.ts | 71 ++++++++++++++++------
.../src/lib/apis/dashboard-kiosk.service.ts | 12 ----
.../lib/query/data-view-query-generator.service.ts | 28 ---------
6 files changed, 89 insertions(+), 87 deletions(-)
diff --git
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/KioskDashboardDataLakeResource.java
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/KioskDashboardDataLakeResource.java
index b513405bff..401e3ac7af 100644
---
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/KioskDashboardDataLakeResource.java
+++
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/KioskDashboardDataLakeResource.java
@@ -71,33 +71,6 @@ public class KioskDashboardDataLakeResource extends
AbstractAuthGuardedRestResou
this.permissionStorage = resourceManager.managePermissions().getDb();
}
- @PostMapping(path = "/{dashboardId}/{widgetId}/data",
- consumes = MediaType.APPLICATION_JSON_VALUE,
- produces = MediaType.APPLICATION_JSON_VALUE)
- @PreAuthorize("this.hasReadAuthorityOrAnonymous(#dashboardId) and
hasPermission(#dashboardId, 'READ')")
- public ResponseEntity<?> getData(@PathVariable("dashboardId") String
dashboardId,
- @PathVariable("widgetId") String widgetId,
- @RequestBody Map<String, String>
queryParams) {
- var dashboard = dashboardStorage.getElementById(dashboardId);
- if (dashboard.getWidgets().stream().noneMatch(w ->
w.getDataViewElementId().equals(widgetId))) {
- return badRequest(String.format("Widget with id %s not found in
dashboard", widgetId));
- }
- var widget = dataExplorerWidgetStorage.getElementById(widgetId);
- var measureName = queryParams.get("measureName");
- if (!checkMeasureNameInWidget(widget, measureName)) {
- return badRequest("Measure name not found in widget configuration");
- } else {
- ProvidedRestQueryParams sanitizedParams = new
ProvidedRestQueryParams(measureName, queryParams);
- try {
- SpQueryResult result =
- this.dataExplorerQueryManagement.getData(sanitizedParams, true);
- return ok(result);
- } catch (RuntimeException e) {
- return badRequest(SpLogMessage.from(e));
- }
- }
- }
-
@PostMapping(path = "/{dashboardId}/data",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
diff --git
a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/UnauthenticatedInterfaces.java
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/UnauthenticatedInterfaces.java
index 774de0c1ea..a151eca694 100644
---
a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/UnauthenticatedInterfaces.java
+++
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/UnauthenticatedInterfaces.java
@@ -47,7 +47,7 @@ public class UnauthenticatedInterfaces {
"/streampipes-backend/index.html",
// anonymous dashboard access is allowed
"/api/v3/datalake/dashboard/*/composite",
- "/api/v3/datalake/dashboard/kiosk/*/*/data"
+ "/api/v3/datalake/dashboard/kiosk/*/data"
);
}
}
diff --git a/ui/cypress/support/utils/dashboard/Inspector.ts
b/ui/cypress/support/utils/dashboard/Inspector.ts
index 8f862fb981..d5075efd5f 100644
--- a/ui/cypress/support/utils/dashboard/Inspector.ts
+++ b/ui/cypress/support/utils/dashboard/Inspector.ts
@@ -42,7 +42,22 @@ export class Inspector {
cy.visit(`#/dashboard-kiosk/${dashboardId}`);
}
- public static validateDashboardKioskWithTableChart(dashboardName: string) {
+ public static openDashboardKioskAsLoggedOutUser(dashboardId: string) {
+ cy.clearLocalStorage();
+ cy.clearCookies();
+ cy.visit(`#/dashboard-kiosk/${dashboardId}`, {
+ onBeforeLoad: win => {
+ win.localStorage.clear();
+ win.sessionStorage.clear();
+ expect(win.localStorage.getItem('auth-token')).to.equal(null);
+ },
+ });
+ }
+
+ public static validateDashboardKioskWithTableChart(
+ dashboardName: string,
+ expectedColumns: string[] = [],
+ ) {
cy.contains('.dashboard-title', dashboardName, {
timeout: 10000,
}).should('be.visible');
@@ -56,5 +71,24 @@ export class Inspector {
)
.filter(':visible')
.should('have.length.at.least', 1);
+
+ expectedColumns.forEach(column => {
+ if (column === 'time') {
+ cy.dataCy('data-explorer-table-row-timestamp', {
+ timeout: 10000,
+ })
+ .filter(':visible')
+ .should('have.length.at.least', 1);
+ } else {
+ cy.dataCy(`data-explorer-table-header-${column}`, {
+ timeout: 10000,
+ }).should('be.visible');
+ cy.dataCy(`data-explorer-table-row-${column}`, {
+ timeout: 10000,
+ })
+ .filter(':visible')
+ .should('have.length.at.least', 1);
+ }
+ });
}
}
diff --git a/ui/cypress/tests/chart/publicDashboardLink.spec.ts
b/ui/cypress/tests/chart/publicDashboardLink.spec.ts
index e88dceaea9..a2e506c92e 100644
--- a/ui/cypress/tests/chart/publicDashboardLink.spec.ts
+++ b/ui/cypress/tests/chart/publicDashboardLink.spec.ts
@@ -17,33 +17,68 @@
*/
import { ChartUtils } from '../../support/utils/chart/ChartUtils';
+import { DataLakeSeedUtils } from
'../../support/utils/dataset/DataLakeSeedUtils';
import { Inspector } from '../../support/utils/dashboard/Inspector';
import { PermissionUtils } from '../../support/utils/user/PermissionUtils';
-describe('Public dashboard links', () => {
- const dashboardName = 'public-dashboard';
- const chartName = 'public-dashboard-chart';
+const dashboardName = 'public-dashboard';
+const chartName = 'public-dashboard-chart';
+const tableColumns = ['time', 'randombool', 'randomnumber', 'randomtext'];
+describe('Public dashboard links', () => {
beforeEach('Setup Test', () => {
cy.initStreamPipesTest();
- ChartUtils.loadDataIntoDataLake('datalake/sample.csv');
+ DataLakeSeedUtils.importCsvData({
+ headers: ['timestamp', 'randombool', 'randomnumber', 'randomtext'],
+ rows: kioskTableRows(),
+ measurementName: ChartUtils.ADAPTER_NAME,
+ timestampColumn: 'timestamp',
+ columnOverrides: {
+ randomtext: {
+ propertyScope: 'DIMENSION_PROPERTY',
+ },
+ },
+ });
});
- it('allows anonymous users to view a dashboard with a chart', () => {
- ChartUtils.addDataViewAndTableWidget(ChartUtils.ADAPTER_NAME);
- ChartUtils.saveDataViewConfiguration(false, false, chartName);
+ it('allows logged-out users to view all table columns in kiosk mode', ()
=> {
+ createPublicDashboardWithTableChart();
- ChartUtils.goToDashboard();
- ChartUtils.createAndEditDashboard(dashboardName);
- ChartUtils.addDataViewToDashboard(chartName, true);
- ChartUtils.saveDashboardConfiguration();
-
- PermissionUtils.markElementAsAnonymousPublic(dashboardName);
- PermissionUtils.validateAnonymousPublicLinkIsEnabled(dashboardName);
-
- Inspector.getDashboardIdByName(dashboardName).then(dashboardId => {
- Inspector.openDashboardKioskAsAnonymous(dashboardId);
- Inspector.validateDashboardKioskWithTableChart(dashboardName);
+ getDashboardId().then(dashboardId => {
+ cy.logout();
+ cy.location('hash', { timeout: 10000 }).should('eq', '#/login');
+ Inspector.openDashboardKioskAsLoggedOutUser(dashboardId);
+ Inspector.validateDashboardKioskWithTableChart(
+ dashboardName,
+ tableColumns,
+ );
});
});
});
+
+function createPublicDashboardWithTableChart(): void {
+ ChartUtils.addDataViewAndTableWidget(ChartUtils.ADAPTER_NAME);
+ ChartUtils.saveDataViewConfiguration(false, false, chartName);
+
+ ChartUtils.goToDashboard();
+ ChartUtils.createAndEditDashboard(dashboardName);
+ ChartUtils.addDataViewToDashboard(chartName, true);
+ ChartUtils.saveDashboardConfiguration();
+
+ PermissionUtils.markElementAsAnonymousPublic(dashboardName);
+ PermissionUtils.validateAnonymousPublicLinkIsEnabled(dashboardName);
+}
+
+function getDashboardId() {
+ return Inspector.getDashboardIdByName(dashboardName);
+}
+
+function kioskTableRows(): string[][] {
+ const baseTimestamp = Date.now() - 60_000;
+
+ return [
+ [baseTimestamp.toString(), 'true', '62.0', 'c'],
+ [(baseTimestamp + 1_000).toString(), 'false', '46.0', 'a'],
+ [(baseTimestamp + 2_000).toString(), 'true', '41.0', 'b'],
+ ];
+}
diff --git
a/ui/projects/streampipes/platform-services/src/lib/apis/dashboard-kiosk.service.ts
b/ui/projects/streampipes/platform-services/src/lib/apis/dashboard-kiosk.service.ts
index f1f2b3a0ef..a794ad579f 100644
---
a/ui/projects/streampipes/platform-services/src/lib/apis/dashboard-kiosk.service.ts
+++
b/ui/projects/streampipes/platform-services/src/lib/apis/dashboard-kiosk.service.ts
@@ -36,18 +36,6 @@ export class DashboardKioskRestService {
private http = inject(HttpClient);
private platformServicesCommons = inject(PlatformServicesCommons);
- getData(
- dashboardId: string,
- widgetId: string,
- queryParams: DatalakeQueryParameters,
- ): Observable<SpQueryResult> {
- const context = new HttpContext().set(NGX_LOADING_BAR_IGNORED, true);
- const url =
`${this.dashboardKioskBasePath}/${dashboardId}/${widgetId}/data`;
- return this.http.post<SpQueryResult>(url, queryParams, {
- context,
- });
- }
-
performMultiQuery(
dashboardId: string,
requests: DashboardKioskDataQuery[],
diff --git
a/ui/projects/streampipes/platform-services/src/lib/query/data-view-query-generator.service.ts
b/ui/projects/streampipes/platform-services/src/lib/query/data-view-query-generator.service.ts
index e68b52f966..86054d815b 100644
---
a/ui/projects/streampipes/platform-services/src/lib/query/data-view-query-generator.service.ts
+++
b/ui/projects/streampipes/platform-services/src/lib/query/data-view-query-generator.service.ts
@@ -26,7 +26,6 @@ import {
import { SpQueryResult } from '../model/gen/streampipes-model';
import { DatalakeQueryParameters } from
'../model/datalake/DatalakeQueryParameters';
import { DatalakeQueryParameterBuilder } from
'./DatalakeQueryParameterBuilder';
-import { DashboardKioskRestService } from '../apis/dashboard-kiosk.service';
import { DashboardDataRequestCoordinatorService } from
'./dashboard-data-request-coordinator.service';
@Injectable({
@@ -34,7 +33,6 @@ import { DashboardDataRequestCoordinatorService } from
'./dashboard-data-request
})
export class DataViewQueryGeneratorService {
protected dataLakeRestService = inject(DatalakeRestService);
- protected dashboardKioskRestService = inject(DashboardKioskRestService);
protected dashboardDataRequestCoordinator = inject(
DashboardDataRequestCoordinatorService,
);
@@ -62,32 +60,6 @@ export class DataViewQueryGeneratorService {
});
}
- generateObservablesForKioskMode(
- startTime: number,
- endTime: number,
- dataConfig: DataExplorerDataConfig,
- dashboardId: string,
- widgetId: string,
- maximumResultingEvents = -1,
- ): Observable<SpQueryResult>[] {
- return dataConfig.sourceConfigs.map(sourceConfig => {
- const dataLakeConfiguration = this.generateQuery(
- startTime,
- endTime,
- sourceConfig,
- dataConfig.ignoreMissingValues,
- maximumResultingEvents,
- true,
- );
-
- return this.dashboardKioskRestService.getData(
- dashboardId,
- widgetId,
- dataLakeConfiguration,
- );
- });
- }
-
generateBatchedObservables(
startTime: number,
endTime: number,