All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openremote.manager.dashboard.DashboardResourceImpl Maven / Gradle / Ivy

/*
 * Copyright 2024, OpenRemote Inc.
 *
 * See the CONTRIBUTORS.txt file in the distribution for a
 * full listing of individual contributors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see .
 */
package org.openremote.manager.dashboard;

import jakarta.ws.rs.WebApplicationException;
import org.openremote.container.message.MessageBrokerService;
import org.openremote.container.timer.TimerService;
import org.openremote.manager.security.ManagerIdentityService;
import org.openremote.manager.web.ManagerWebResource;
import org.openremote.model.Constants;
import org.openremote.model.dashboard.Dashboard;
import org.openremote.model.dashboard.DashboardAccess;
import org.openremote.model.dashboard.DashboardResource;
import org.openremote.model.http.RequestParams;
import org.openremote.model.query.DashboardQuery;
import org.openremote.model.query.filter.RealmPredicate;
import org.openremote.model.security.ClientRole;
import org.openremote.model.util.ValueUtil;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;

import static jakarta.ws.rs.core.Response.Status.*;

public class DashboardResourceImpl extends ManagerWebResource implements DashboardResource {

    public static final Logger LOG = Logger.getLogger(DashboardResourceImpl.class.getName());

    protected final DashboardStorageService dashboardStorageService;
    protected final MessageBrokerService messageBrokerService;

    public DashboardResourceImpl(TimerService timerService, ManagerIdentityService identityService, DashboardStorageService dashboardStorageService, MessageBrokerService messageBrokerService) {
        super(timerService, identityService);
        this.dashboardStorageService = dashboardStorageService;
        this.messageBrokerService = messageBrokerService;
    }

    @Override
    public Dashboard[] getAllRealmDashboards(RequestParams requestParams, String realm) {
        if(realm == null) {
            throw new WebApplicationException(BAD_REQUEST);
        }
        if(!isRealmActiveAndAccessible(realm)) {
            throw new WebApplicationException(FORBIDDEN);
        }
        return dashboardStorageService.query(this.createDashboardQuery(realm), getUserId());
    }

    @Override
    public Dashboard get(RequestParams requestParams, String realm, String dashboardId) {
        if(realm == null) {
            throw new WebApplicationException(BAD_REQUEST);
        }
        Dashboard[] dashboards = dashboardStorageService.query(
                this.createDashboardQuery(realm).ids(dashboardId).limit(1),
                getUserId()
        );
        // If no dashboards were returned, check whether it existed, and return a different response.
        if(dashboards.length == 0) {
            if(this.dashboardStorageService.exists(dashboardId, realm)) {
                throw new WebApplicationException(FORBIDDEN);
            } else {
                throw new WebApplicationException(NOT_FOUND);
            }
        }

        return dashboards[0];
    }

    @Override
    public Dashboard[] query(RequestParams requestParams, DashboardQuery query) {
        if(query == null) {
            query = this.createDashboardQuery(getRequestRealmName());
        }
        if(query.realm == null || query.realm.name == null) {
            query.realm(new RealmPredicate(getRequestRealmName()));
        }
        if(isAuthenticated() && !isSuperUser() && !(getAuthenticatedRealmName().equals(query.realm.name))) {
            throw new WebApplicationException(FORBIDDEN);
        }

        return dashboardStorageService.query(query, getUserId());
    }

    @Override
    public Dashboard create(RequestParams requestParams, Dashboard dashboard) {
        String realm = dashboard.getRealm();
        if(realm == null) {
            throw new WebApplicationException(BAD_REQUEST);
        }
        if(!isRealmActiveAndAccessible(dashboard.getRealm())) {
            throw new WebApplicationException(FORBIDDEN);
        }
        try {
            dashboard.setOwnerId(getUserId());
            dashboard.setViewAccess(DashboardAccess.SHARED);
            dashboard.setEditAccess(DashboardAccess.SHARED);

            return this.dashboardStorageService.createNew(ValueUtil.clone(dashboard));

        } catch (IllegalStateException ex) {
            ex.printStackTrace();
            throw new WebApplicationException(ex, INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    public Dashboard update(RequestParams requestParams, Dashboard dashboard) {
        String realm = dashboard.getRealm();
        if(realm == null) {
            throw new WebApplicationException(BAD_REQUEST);
        }
        if(!isRealmActiveAndAccessible(realm)) {
            throw new WebApplicationException(FORBIDDEN);
        }
        try {
            return this.dashboardStorageService.update(ValueUtil.clone(dashboard), realm, getUserId());
        } catch (IllegalArgumentException ex) {
            throw new WebApplicationException(ex, NOT_FOUND);
        } catch (IllegalStateException ex) {
            ex.printStackTrace();
            throw new WebApplicationException(ex, INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    public void delete(RequestParams requestParams, String realm, String dashboardId) {
        if(realm == null) {
            throw new WebApplicationException(BAD_REQUEST);
        }
        if(!isRealmActiveAndAccessible(realm)) {
            throw new WebApplicationException(FORBIDDEN);
        }
        try {
            this.dashboardStorageService.delete(dashboardId, realm, getUserId());
        } catch (IllegalArgumentException ex) {
            throw new WebApplicationException(ex, NOT_FOUND);
        } catch (IllegalStateException ex) {
            ex.printStackTrace();
            throw new WebApplicationException(ex, INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * Function that builds an {@link DashboardQuery} object, based on user permissions.
     * Automatically fills NULL values, adjusts access filters based on roles, etc.
     *
     * @param realm
     * @return An instantiated DashboardQuery with the correct permissions based on the user.
     */
    protected DashboardQuery createDashboardQuery(String realm) {
        if(realm == null) {
            realm = getRequestRealmName();
        }
        DashboardQuery query = new DashboardQuery().realm(new RealmPredicate(realm));
        Set userViewAccess = new HashSet<>(Set.of(query.conditions.getDashboard().getViewAccess()));
        Set userEditAccess = new HashSet<>(Set.of(query.conditions.getDashboard().getEditAccess()));
        Set assetAccess = new HashSet<>(Set.of(query.conditions.getAsset().getAccess()));

        // Detect cross realm access
        if(isAuthenticated() && !isSuperUser() && !realm.equals(getAuthenticatedRealmName())) {
            throw new WebApplicationException(FORBIDDEN);
        }

        // User always has access to public dashboards
        userViewAccess.add(DashboardAccess.PUBLIC);
        userEditAccess.add(DashboardAccess.PUBLIC);
        assetAccess.add(DashboardQuery.AssetAccess.REALM);

        // Adjust query object based on user roles/permissions
        if (isAuthenticated()) {
            assetAccess.add(DashboardQuery.AssetAccess.LINKED);
            if (hasResourceRole(ClientRole.READ_INSIGHTS.getValue(), Constants.KEYCLOAK_CLIENT_ID)) {
                Collections.addAll(userViewAccess, DashboardAccess.SHARED, DashboardAccess.PRIVATE);
            }
            if (hasResourceRole(ClientRole.WRITE_INSIGHTS.getValue(), Constants.KEYCLOAK_CLIENT_ID)) {
                Collections.addAll(userEditAccess, DashboardAccess.SHARED, DashboardAccess.PRIVATE);
            }
            if (isRestrictedUser()) {
                assetAccess = new HashSet<>(Set.of(DashboardQuery.AssetAccess.RESTRICTED));
            }
        }

        // If not logged in, force only public read/write access
        else {
            userViewAccess = new HashSet<>(Set.of(DashboardAccess.PUBLIC));
            userEditAccess = new HashSet<>(Set.of(DashboardAccess.PUBLIC));
            assetAccess = new HashSet<>(Set.of(DashboardQuery.AssetAccess.REALM));
        }

        // Build query object and return
        return query.conditions(new DashboardQuery.Conditions(
                        new DashboardQuery.DashboardConditions()
                                .viewAccess(userViewAccess.toArray(new DashboardAccess[0]))
                                .editAccess(userEditAccess.toArray(new DashboardAccess[0])),
                        new DashboardQuery.AssetConditions()
                                .access(assetAccess.toArray(new DashboardQuery.AssetAccess[0]))
                )
        );
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy