package org.fluxtream.core.api; import com.wordnik.swagger.annotations.Api; import com.wordnik.swagger.annotations.ApiOperation; import com.wordnik.swagger.annotations.ApiParam; import net.sf.json.JSONObject; import org.apache.velocity.util.StringUtils; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.type.TypeFactory; import org.fluxtream.core.aspects.FlxLogger; import org.fluxtream.core.auth.AuthHelper; import org.fluxtream.core.domain.Dashboard; import org.fluxtream.core.domain.DashboardWidget; import org.fluxtream.core.domain.WidgetSettings; import org.fluxtream.core.mvc.models.DashboardModel; import org.fluxtream.core.mvc.models.DashboardWidgetManifestModel; import org.fluxtream.core.mvc.models.DashboardWidgetModel; import org.fluxtream.core.services.DashboardsService; import org.fluxtream.core.services.WidgetsService; import org.fluxtream.core.utils.Utils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; /** * @author Candide Kemmler (candide@fluxteam.com) */ @Path("/v1/dashboards") @Component("RESTDashboardStore") @Api(value = "/dashboards", description = "Widget dashboards API") @Scope("request") public class DashboardStore { FlxLogger logger = FlxLogger.getLogger(DashboardStore.class); @Autowired DashboardsService dashboardsService; @Autowired WidgetsService widgetsService; @GET @ApiOperation(value = "Get a user's dashboards", response = DashboardModel.class, responseContainer = "Array") @Produces({ MediaType.APPLICATION_JSON }) public Response getDashboards() { long guestId = AuthHelper.getGuestId(); try { List<Dashboard> dashboards = dashboardsService.getDashboards(guestId); Collections.sort(dashboards); List<DashboardModel> dashboardModels = new ArrayList<DashboardModel>(); for (final ListIterator eachDashboard = dashboards.listIterator(); eachDashboard.hasNext(); ) { final Dashboard dashboard = (Dashboard)eachDashboard.next(); DashboardModel dashboardModel = toDashboardModel(dashboard, guestId); dashboardModels.add(dashboardModel); } return Response.ok(dashboardModels).build(); } catch (Exception e){ return Response.serverError().entity("Failed to get dashboards: " + e.getMessage()).build(); } } private DashboardModel toDashboardModel(final Dashboard dashboard, long guestId) { DashboardModel dashboardModel = new DashboardModel(); dashboardModel.id = dashboard.getId(); dashboardModel.name = dashboard.name; dashboardModel.active = dashboard.active; final List<DashboardWidget> availableWidgetsList = widgetsService.getAvailableWidgetsList(guestId); final String[] widgetNames = StringUtils.split(dashboard.widgetNames, ","); List<DashboardWidgetModel> widgetModels = new ArrayList<DashboardWidgetModel>(); there: for (String widgetName : widgetNames) { for (DashboardWidget dashboardWidget : availableWidgetsList) { if (dashboardWidget.WidgetName.equals(widgetName)) { widgetModels.add(toDashboardWidgetModel(dashboardWidget, dashboard, guestId)); continue there; } } } dashboardModel.widgets = widgetModels; return dashboardModel; } private DashboardWidgetModel toDashboardWidgetModel(final DashboardWidget dashboardWidget, final Dashboard dashboard, final Long guestId) { DashboardWidgetManifestModel widgetManifestModel = new DashboardWidgetManifestModel(); widgetManifestModel.WidgetName = dashboardWidget.WidgetName; widgetManifestModel.WidgetRepositoryURL = dashboardWidget.WidgetRepositoryURL; widgetManifestModel.WidgetDescription = dashboardWidget.WidgetDescription; widgetManifestModel.WidgetTitle = dashboardWidget.WidgetTitle; widgetManifestModel.WidgetIcon = dashboardWidget.WidgetIcon; widgetManifestModel.HasSettings = dashboardWidget.HasSettings; widgetManifestModel.RequiredConnectors = dashboardWidget.RequiredConnectors; widgetManifestModel.fullAccess = dashboardWidget.fullAccess; DashboardWidgetModel widgetModel = new DashboardWidgetModel(); widgetModel.manifest = widgetManifestModel; if (dashboard!=null) { final WidgetSettings widgetSettings = widgetsService.getWidgetSettings(guestId, dashboard.getId(), dashboardWidget.WidgetName); widgetModel.settings = widgetSettings.settingsJSON; } return widgetModel; } @POST @ApiOperation(value = "Add a dashboard", response = DashboardModel.class, responseContainer = "Array") @Produces({ MediaType.APPLICATION_JSON }) public Response addDashboard(@ApiParam(value="The dashboard's name", required=true) @FormParam("dashboardName") String dashboardName) throws UnsupportedEncodingException { long guestId = AuthHelper.getGuestId(); try { dashboardsService.addDashboard(guestId, dashboardName); return getDashboards(); } catch (Exception e) { StringBuilder sb = new StringBuilder("module=API component=dashboardStore action=addDashboard") .append(" guestId=").append(guestId) .append(" stackTrace=<![CDATA[").append(Utils.stackTrace(e)).append("]]>"); logger.warn(sb.toString()); return Response.serverError().entity("Failed to add dashboard: " + e.getMessage()).build(); } } @DELETE @Path("/{dashboardId}") @ApiOperation(value = "Delete a dashboard", response = DashboardModel.class, responseContainer = "Array") @Produces({ MediaType.APPLICATION_JSON }) public Response removeDashboard(@PathParam("dashboardId") long dashboardId) throws UnsupportedEncodingException { long guestId = AuthHelper.getGuestId(); try { dashboardsService.removeDashboard(guestId, dashboardId); return getDashboards(); } catch (Exception e) { StringBuilder sb = new StringBuilder("module=API component=dashboardStore action=deleteDashboard") .append(" guestId=").append(guestId) .append(" stackTrace=<![CDATA[").append(Utils.stackTrace(e)).append("]]>"); logger.warn(sb.toString()); return Response.serverError().entity("Failed to delete dashboard: " + e.getMessage()).build(); } } @GET @Path("/{dashboardId}/availableWidgets") @ApiOperation(value = "List available widgets", response = DashboardWidget.class, responseContainer = "Array") @Produces({ MediaType.APPLICATION_JSON }) public Response getAvailableWidgets(@PathParam("dashboardId") long dashboardId) { long guestId = AuthHelper.getGuestId(); try { final List<DashboardWidget> widgetsNotYetInDashboard = new ArrayList<DashboardWidget>(); final List<DashboardWidget> availableWidgetsList = widgetsService.getAvailableWidgetsList(guestId); final Dashboard dashboard = dashboardsService.getDashboard(guestId, dashboardId); final String[] dashboardWidgets = StringUtils.split(dashboard.widgetNames, ","); outerloop: for (DashboardWidget availableWidget : availableWidgetsList) { for (String dashboardWidgetName : dashboardWidgets) { if (availableWidget.WidgetName.equals(dashboardWidgetName)) continue outerloop; } widgetsNotYetInDashboard.add(availableWidget); } return Response.ok(widgetsNotYetInDashboard).build(); } catch (Exception e) { StringBuilder sb = new StringBuilder("module=API component=dashboardStore action=getAvailableWidgets") .append(" guestId=").append(guestId) .append(" stackTrace=<![CDATA[").append(Utils.stackTrace(e)).append("]]>"); logger.warn(sb.toString()); return Response.serverError().entity("Failed to get availableWidgets: " + e.getMessage()).build(); } } @PUT @Path("/{dashboardId}/name") @ApiOperation(value = "Rename a dashboard", response = DashboardModel.class, responseContainer = "Array") @Produces({ MediaType.APPLICATION_JSON }) public Response renameDashboard(@PathParam("dashboardId") long dashboardId, @QueryParam("name") String newName) throws UnsupportedEncodingException { long guestId = AuthHelper.getGuestId(); try { newName = URLDecoder.decode(newName, "UTF-8"); dashboardsService.renameDashboard(guestId, dashboardId, newName); return getDashboards(); } catch (Exception e) { StringBuilder sb = new StringBuilder("module=API component=dashboardStore action=renameDashboard") .append(" guestId=").append(guestId) .append(" stackTrace=<![CDATA[").append(Utils.stackTrace(e)).append("]]>"); logger.warn(sb.toString()); return Response.serverError().entity("Failed to rename dashboard: " + e.getMessage()).build(); } } @PUT @Path("/{dashboardId}/active") @ApiOperation(value = "Set current/active dashboard", response = DashboardModel.class, responseContainer = "Array") @Produces({ MediaType.APPLICATION_JSON }) public Response setActiveDashboard(@PathParam("dashboardId") long dashboardId) throws UnsupportedEncodingException { long guestId = AuthHelper.getGuestId(); try { dashboardsService.setActiveDashboard(guestId, dashboardId); return getDashboards(); } catch (Exception e) { StringBuilder sb = new StringBuilder("module=API component=dashboardStore action=setActiveDashboard") .append(" guestId=").append(guestId) .append(" stackTrace=<![CDATA[").append(Utils.stackTrace(e)).append("]]>"); logger.warn(sb.toString()); return Response.serverError().entity("Failed to set active dashboard: " + e.getMessage()).build(); } } @POST @Path("/{dashboardId}/widgets") @ApiOperation(value = "Add a widget to a dashboard", response = DashboardModel.class, responseContainer = "Array") @Produces({ MediaType.APPLICATION_JSON }) public Response addWidget(@PathParam("dashboardId") long dashboardId, @FormParam("widget") String widgetName, @FormParam("allowedConnectors") String allowedConnectorsJson, @FormParam("fullAccess") boolean fullAccess) throws UnsupportedEncodingException { long guestId = AuthHelper.getGuestId(); try { List<String> allowedConnectors = new ObjectMapper().readValue(allowedConnectorsJson, TypeFactory.defaultInstance().constructCollectionType(List.class, String.class)); System.out.println(allowedConnectors); System.out.println(fullAccess); widgetName = URLDecoder.decode(widgetName, "UTF-8"); dashboardsService.addWidget(guestId, dashboardId, widgetName, allowedConnectors, fullAccess); return getDashboards(); } catch (Exception e) { StringBuilder sb = new StringBuilder("module=API component=dashboardStore action=addWidget") .append(" guestId=").append(guestId) .append(" stackTrace=<![CDATA[").append(Utils.stackTrace(e)).append("]]>"); logger.warn(sb.toString()); return Response.serverError().entity("Failed to add widget: " + e.getMessage()).build(); } } @DELETE @Path("/{dashboardId}/widgets/{widgetName}") @ApiOperation(value = "Remove a widget from a dashboard", response = DashboardModel.class, responseContainer = "Array") @Produces({ MediaType.APPLICATION_JSON }) public Response removeWidget(@PathParam("dashboardId") long dashboardId, @PathParam("widgetName") String widgetName) throws UnsupportedEncodingException { long guestId = AuthHelper.getGuestId(); try { widgetName = URLDecoder.decode(widgetName, "UTF-8"); dashboardsService.removeWidget(guestId, dashboardId, widgetName); return getDashboards(); } catch (Exception e) { StringBuilder sb = new StringBuilder("module=API component=dashboardStore action=removeWidget") .append(" guestId=").append(guestId) .append(" stackTrace=<![CDATA[").append(Utils.stackTrace(e)).append("]]>"); logger.warn(sb.toString()); return Response.serverError().entity("Failed to remove widget: " + e.getMessage()).build(); } } @POST @Path("/{dashboardId}/widgets/reorder") @ApiOperation(value = "Change the order of widgets in a dashboard", response = DashboardModel.class, responseContainer = "Array") @Produces({ MediaType.APPLICATION_JSON }) public Response setWidgetsOrder(@PathParam("dashboardId") long dashboardId, @FormParam("widgetNames") String widgetNames) throws UnsupportedEncodingException { long guestId = AuthHelper.getGuestId(); try { final String[] wNames = StringUtils.split(widgetNames, ","); dashboardsService.setWidgetsOrder(guestId, dashboardId, wNames); return getDashboards(); } catch (Exception e) { StringBuilder sb = new StringBuilder("module=API component=dashboardStore action=setWidgetOrder") .append(" guestId=").append(guestId) .append(" stackTrace=<![CDATA[").append(Utils.stackTrace(e)).append("]]>"); logger.warn(sb.toString()); return Response.serverError().entity("Failed to set widget order: " + e.getMessage()).build(); } } @POST @Path("/reorder") @ApiOperation(value = "Change the order of dashboards", response = DashboardModel.class, responseContainer = "Array") @Produces({ MediaType.APPLICATION_JSON }) public Response setDashboardsOrder(@FormParam("dashboardIds") String dashboardIds) throws UnsupportedEncodingException { long guestId = AuthHelper.getGuestId(); try { //dashboardIds = URLDecoder.decode(dashboardIds, "UTF-8"); final String[] dNames = StringUtils.split(dashboardIds, ","); long[] ids = new long[dNames.length]; int i=0; for (String dName : dNames) { ids[i++] = Long.valueOf(dName); } dashboardsService.setDashboardsOrder(guestId, ids); return getDashboards(); } catch (Exception e) { StringBuilder sb = new StringBuilder("module=API component=dashboardStore action=setDashboardsOrder") .append(" guestId=").append(guestId) .append(" stackTrace=<![CDATA[").append(Utils.stackTrace(e)).append("]]>"); logger.warn(sb.toString()); return Response.serverError().entity("Failed to set dashboard order: " + e.getMessage()).build(); } } @POST @Path("/{dashboardId}/widgets/{widgetName}/settings") @ApiOperation(value = "Save a widget's settings") public Response saveWidgetSettings(@PathParam("dashboardId") long dashboardId, @PathParam("widgetName") String widgetName, @FormParam("settingsJSON") String settingsJSON) throws UnsupportedEncodingException { long guestId = AuthHelper.getGuestId(); try { widgetName = URLDecoder.decode(widgetName, "UTF-8"); widgetsService.saveWidgetSettings(guestId, dashboardId, widgetName, settingsJSON); return Response.ok("Successfully saved widget settings").build(); } catch (Exception e) { StringBuilder sb = new StringBuilder("module=API component=dashboardStore action=saveWidgetSettings") .append(" guestId=").append(guestId) .append(" stackTrace=<![CDATA[").append(Utils.stackTrace(e)).append("]]>"); logger.warn(sb.toString()); return Response.serverError().entity("Failed to save widget settings: " + e.getMessage()).build(); } } @GET @Path("/{dashboardId}/widgets/{widgetName}/settings") @ApiOperation(value = "Get a widget's settings", response = DashboardModel.class, responseContainer = "Array") @Produces({ MediaType.APPLICATION_JSON }) public Response getWidgetSettings(@PathParam("dashboardId") long dashboardId, @PathParam("widgetName") String widgetName) throws UnsupportedEncodingException { long guestId = AuthHelper.getGuestId(); try{ widgetName = URLDecoder.decode(widgetName, "UTF-8"); final WidgetSettings settings = widgetsService.getWidgetSettings(guestId, dashboardId, widgetName); JSONObject jsonSettings = JSONObject.fromObject(settings.settingsJSON); return Response.ok(jsonSettings.toString()).build(); } catch (Exception e){ StringBuilder sb = new StringBuilder("module=API component=dashboardStore action=getWidgetSettings") .append(" guestId=").append(guestId) .append(" stackTrace=<![CDATA[").append(Utils.stackTrace(e)).append("]]>"); logger.warn(sb.toString()); return Response.serverError().entity("Failed to get widget settings: " + e.getMessage()).build(); } } }