From d072cfd3b2b8f690cc3f23e266f94d4a9b0dff55 Mon Sep 17 00:00:00 2001
From: Jim Ewald
Date: Wed, 30 Jan 2019 00:27:30 -0800
Subject: [PATCH 04/69] Issue #1638 - Update Help URI to point to help system
hosted on learn.parallax.com.
---
src/main/webapp/editor/blocklyc.jsp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/webapp/editor/blocklyc.jsp b/src/main/webapp/editor/blocklyc.jsp
index 6f7a599c..7fd53794 100644
--- a/src/main/webapp/editor/blocklyc.jsp
+++ b/src/main/webapp/editor/blocklyc.jsp
@@ -171,7 +171,7 @@
-
+
From 424b39df082a6da6bd52607689bb0a5902f14b52 Mon Sep 17 00:00:00 2001
From: Jim Ewald
Date: Wed, 30 Jan 2019 01:02:47 -0800
Subject: [PATCH 05/69] #1641 - Depricated the embedded help system. Plan to
remove the related source file in version 1.3.
---
.../parallax/server/blocklyprop/config/ServletsModule.java | 5 -----
.../com/parallax/server/blocklyprop/config/SetupConfig.java | 5 -----
.../server/blocklyprop/servlets/HelpSearchServlet.java | 4 ++++
.../parallax/server/blocklyprop/servlets/HelpServlet.java | 3 +++
.../server/blocklyprop/utils/HelpFileInitializer.java | 3 +++
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/main/java/com/parallax/server/blocklyprop/config/ServletsModule.java b/src/main/java/com/parallax/server/blocklyprop/config/ServletsModule.java
index 5ff2e753..66eca1ea 100644
--- a/src/main/java/com/parallax/server/blocklyprop/config/ServletsModule.java
+++ b/src/main/java/com/parallax/server/blocklyprop/config/ServletsModule.java
@@ -27,8 +27,6 @@
import com.parallax.server.blocklyprop.servlets.PrivacyPolicyServlet;
import com.parallax.server.blocklyprop.servlets.ConfirmRequestServlet;
import com.parallax.server.blocklyprop.servlets.ConfirmServlet;
-import com.parallax.server.blocklyprop.servlets.HelpSearchServlet;
-import com.parallax.server.blocklyprop.servlets.HelpServlet;
import com.parallax.server.blocklyprop.servlets.NewOAuthUserServlet;
import com.parallax.server.blocklyprop.servlets.OAuthGoogleServlet;
import com.parallax.server.blocklyprop.servlets.PasswordResetRequestServlet;
@@ -130,9 +128,6 @@ protected void configureServlets() {
serve("/public/clientinstructions").with(TextileClientInstructionsServlet.class);
serve("/public/changelog").with(TextileChangeLogServlet.class);
- // Help
- serve("/public/help").with(HelpServlet.class);
- serve("/public/helpsearch").with(HelpSearchServlet.class);
// OAuth
serve("/oauth/newuser").with(NewOAuthUserServlet.class);
diff --git a/src/main/java/com/parallax/server/blocklyprop/config/SetupConfig.java b/src/main/java/com/parallax/server/blocklyprop/config/SetupConfig.java
index f4e28f13..10bafdf9 100644
--- a/src/main/java/com/parallax/server/blocklyprop/config/SetupConfig.java
+++ b/src/main/java/com/parallax/server/blocklyprop/config/SetupConfig.java
@@ -29,7 +29,6 @@
import com.parallax.server.blocklyprop.SessionData;
import com.parallax.server.blocklyprop.jsp.Properties;
import com.parallax.server.blocklyprop.monitoring.Monitor;
-import com.parallax.server.blocklyprop.utils.HelpFileInitializer;
import java.sql.Driver;
import java.sql.DriverManager;
import java.util.Enumeration;
@@ -40,9 +39,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-// import java.sql.SQLException;
-// import ch.qos.logback.classic.LoggerContext;
-
/**
*
@@ -73,7 +69,6 @@ protected void configure() {
bind(SessionData.class);
bind(Properties.class).asEagerSingleton();
- bind(HelpFileInitializer.class).asEagerSingleton();
bind(Monitor.class).asEagerSingleton();
// Configure the backend data store
diff --git a/src/main/java/com/parallax/server/blocklyprop/servlets/HelpSearchServlet.java b/src/main/java/com/parallax/server/blocklyprop/servlets/HelpSearchServlet.java
index 0d5b1ba7..644048f5 100644
--- a/src/main/java/com/parallax/server/blocklyprop/servlets/HelpSearchServlet.java
+++ b/src/main/java/com/parallax/server/blocklyprop/servlets/HelpSearchServlet.java
@@ -33,7 +33,11 @@
/**
*
* @author Michel
+ *
+ * @deprecated The help system has been moved to learn.parallax.com
+ *
*/
+@Deprecated
@Singleton
public class HelpSearchServlet extends HttpServlet {
diff --git a/src/main/java/com/parallax/server/blocklyprop/servlets/HelpServlet.java b/src/main/java/com/parallax/server/blocklyprop/servlets/HelpServlet.java
index cf1f42e8..55a85432 100644
--- a/src/main/java/com/parallax/server/blocklyprop/servlets/HelpServlet.java
+++ b/src/main/java/com/parallax/server/blocklyprop/servlets/HelpServlet.java
@@ -23,7 +23,10 @@
/**
*
* @author Michel
+ *
+ * @deprecated Help system is now hosted on learn.parallax.com
*/
+@Deprecated
@Singleton
public class HelpServlet extends HttpServlet {
diff --git a/src/main/java/com/parallax/server/blocklyprop/utils/HelpFileInitializer.java b/src/main/java/com/parallax/server/blocklyprop/utils/HelpFileInitializer.java
index efbdfede..256707bb 100644
--- a/src/main/java/com/parallax/server/blocklyprop/utils/HelpFileInitializer.java
+++ b/src/main/java/com/parallax/server/blocklyprop/utils/HelpFileInitializer.java
@@ -37,7 +37,10 @@
/**
*
* @author Michel
+ *
+ * @deprecated The help system has been moved to learn.parallax.com
*/
+@Deprecated
@Singleton
public class HelpFileInitializer {
From c135b92195f891279f0ee0373106cbf5707e12a3 Mon Sep 17 00:00:00 2001
From: Jim Ewald
Date: Wed, 30 Jan 2019 01:03:46 -0800
Subject: [PATCH 06/69] Corrected an error in the HTML declaration.
---
src/main/webapp/my/projects.jsp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/main/webapp/my/projects.jsp b/src/main/webapp/my/projects.jsp
index 1f4af0d9..303cec9a 100644
--- a/src/main/webapp/my/projects.jsp
+++ b/src/main/webapp/my/projects.jsp
@@ -5,8 +5,7 @@
--%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/includes/include.jsp"%>
-
-
+
From 8ae7a5305f08d76643757740b0e4d8ed9e2bf59d Mon Sep 17 00:00:00 2001
From: Jim Ewald
Date: Fri, 1 Feb 2019 11:26:42 -0800
Subject: [PATCH 07/69] Clean up various warning messages.
---
.../WEB-INF/includes/pageparts/menu.jsp | 106 +++++++++++-------
src/main/webapp/WEB-INF/servlet/index.jsp | 29 ++++-
2 files changed, 91 insertions(+), 44 deletions(-)
diff --git a/src/main/webapp/WEB-INF/includes/pageparts/menu.jsp b/src/main/webapp/WEB-INF/includes/pageparts/menu.jsp
index efd2df01..91605ca3 100644
--- a/src/main/webapp/WEB-INF/includes/pageparts/menu.jsp
+++ b/src/main/webapp/WEB-INF/includes/pageparts/menu.jsp
@@ -1,7 +1,30 @@
+<%--
+ ~ Copyright (c) 2019 Parallax Inc.
+ ~
+ ~ Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ ~ and associated documentation files (the “Software”), to deal in the Software without
+ ~ restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ ~ distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ ~ Software is furnished to do so, subject to the following conditions:
+ ~
+ ~ The above copyright notice and this permission notice shall be included in all copies or
+ ~ substantial portions of the Software.
+ ~
+ ~ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ ~ SOFTWARE.
+ --%>
+
<%--
Document : menu
Created on : 4-nov-2015, 20:39:22
Author : Michel
+
+ Display the horizontal menu across the top of the banner
--%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/includes/include.jsp"%>
@@ -18,51 +41,53 @@
<%-- Projects and privacy notice links --%>
-
-
-
- ">
-
- <%-- Include the user projects if the user is logged in --%>
-
-
- ">
-
-
-
- ">
-
-
- ">
-
-
-
- <%-- Register / Login --%>
-
-
- <%-- Menu items for an anonymous user --%>
-
-
- ">
-
-
- <%-- Menu items for an authenticated user --%>
-
-
-
-
-
">
-
-
">
-
-
+
+
+ ">
+
+
+ <%-- Include the user projects if the user is logged in --%>
+
+
+ ">
+
+
+
+
+ ">
+
+
+ ">
+
+
+
+ <%-- Register / Login / Help --%>
+
+ <%-- Menu items for an anonymous user --%>
+
+
+ ">
+
+
+
+ <%-- Menu items for an authenticated user --%>
+
+
<%-- Help link to the Learn reference section --%>
- <%--
" target="_blank">
--%>
- <%--
+ <%-- Set the launguage for the site
--%>
-
diff --git a/src/main/webapp/WEB-INF/servlet/index.jsp b/src/main/webapp/WEB-INF/servlet/index.jsp
index 25c6f14a..227131f7 100644
--- a/src/main/webapp/WEB-INF/servlet/index.jsp
+++ b/src/main/webapp/WEB-INF/servlet/index.jsp
@@ -1,7 +1,30 @@
+<%--
+ ~ Copyright (c) 2019 Parallax Inc.
+ ~
+ ~ Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ ~ and associated documentation files (the “Software”), to deal in the Software without
+ ~ restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ ~ distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ ~ Software is furnished to do so, subject to the following conditions:
+ ~
+ ~ The above copyright notice and this permission notice shall be included in all copies or
+ ~ substantial portions of the Software.
+ ~
+ ~ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ ~ SOFTWARE.
+ --%>
+
<%--
Document : login
Created on : 24-mei-2015, 18:41:02
Author : Michel
+
+ This is the site home page
--%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/includes/include.jsp"%>
@@ -22,14 +45,13 @@
" />
" />
" />
+ BlocklyProp
" >
">
" >
-
<%@ include file="/WEB-INF/includes/pageparts/menu.jsp"%>
-
@@ -37,7 +59,8 @@
BlocklyProp
Blockly for Propeller Multicore: Making amazing projects and learning to code just became easier
-
">
+
"
+ alt="Home page banner image">
From 63db37ee968015f6d84a9672646ea4c5bbfcffff Mon Sep 17 00:00:00 2001
From: Jim Ewald
Date: Mon, 4 Feb 2019 14:19:54 -0800
Subject: [PATCH 08/69] Add code to detect a missing user id where it is
required.
---
.../db/dao/impl/ProjectDaoImpl.java | 32 +++++++++++++++++--
.../server/blocklyprop/rest/RestProject.java | 26 ++++++++++++++-
.../services/impl/ProjectServiceImpl.java | 17 ++++++++++
3 files changed, 71 insertions(+), 4 deletions(-)
diff --git a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java
index 2dbbaf5f..2c8d0ede 100644
--- a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java
+++ b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java
@@ -412,8 +412,10 @@ public List getUserProjects(
* @param order
* @param limit
* @param offset
- * @param idUser
+
* @return
+ * Returns a list of ProjectRecord objects corresponding to the projects
+ * matching the selection creiteria
*/
@Override
public List getSharedProjects(
@@ -563,24 +565,42 @@ public boolean deleteProject(Long idProject) {
}
/**
- * TODO: add details.
+ * Update the code block in the specified project
*
* @param idProject
* @param code
+ *
* @return
*/
@Override
public ProjectRecord updateProjectCode(Long idProject, String code) {
LOG.info("Update code for project {}.", idProject);
+
+ // Retrieve the specified project
ProjectRecord record = create.selectFrom(Tables.PROJECT)
.where(Tables.PROJECT.ID.equal(idProject))
.fetchOne();
+ // Get a timestamp used to update the modified field of the project record
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(new java.util.Date());
if (record != null) {
+ // Found the project. Verify that the current user owns it
Long idUser = BlocklyPropSecurityUtils.getCurrentUserId();
+
+ // TODO: Detecting a zero user id
+ if (idUser == 0) {
+ LOG.error("Detected current user ID is zero for project {}", idProject);
+ return null;
+ }
+
+ if (record.getIdUser() == 0) {
+ LOG.error("Detected project user ID is zero for project {}", idProject);
+ return null;
+ }
+
+ // Update the project if the current user owns it
if (record.getIdUser().equals(idUser)) {
record.setCode(code);
record.setModified(cal);
@@ -588,14 +608,18 @@ public ProjectRecord updateProjectCode(Long idProject, String code) {
record.update();
return record;
} else {
+ // If the project is a shared project, allow the current user
+ // to clone the project into their library
if (record.getShared()) {
ProjectRecord cloned = doProjectClone(record);
cloned.setCode(code);
cloned.setModified(cal);
cloned.setCodeBlockVersion(BLOCKLY_LIBRARY_VERSION);
+ cloned.setIdUser(idUser); // The logged in user owns this copy of the project
cloned.update();
return cloned;
}
+
LOG.error("User {} tried and failed to update project {}.", idUser, idProject);
throw new UnauthorizedException();
}
@@ -605,6 +629,8 @@ public ProjectRecord updateProjectCode(Long idProject, String code) {
}
}
+
+
/**
* Save the current project as a new project
*
@@ -700,7 +726,7 @@ private ProjectRecord doProjectClone(ProjectRecord original) {
original.getBoard(),
original.getPrivate(),
original.getShared(),
- original.getId()
+ original.getId() // set the parent project id
);
// cloned.setBasedOn(original.getId());
diff --git a/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java b/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java
index e0c73742..097a97ab 100644
--- a/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java
+++ b/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java
@@ -54,6 +54,7 @@ public class RestProject {
// Connector to project converter object
private ProjectConverter projectConverter;
+
/**
* Connect to the project service object
* @param projectService
@@ -63,6 +64,7 @@ public void setProjectService(ProjectService projectService) {
this.projectService = projectService;
}
+
/**
* Connect to the project converter object
* @param projectConverter
@@ -72,6 +74,7 @@ public void setProjectConverter(ProjectConverter projectConverter) {
this.projectConverter = projectConverter;
}
+
/**
* Return a list of projects owned by the currently authenticated user.
*
@@ -124,10 +127,13 @@ public Response get(
JsonObject result = new JsonObject();
JsonArray jsonProjects = new JsonArray();
+
+ // Loop through user projects and build a Json array
for (ProjectRecord project : userProjects) {
jsonProjects.add(projectConverter.toListJson(project));
}
+ // Add payload details
result.add("rows", jsonProjects);
result.addProperty("total", projectCount);
@@ -139,9 +145,15 @@ public Response get(
LOG.warn("Error is {}", ex.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
-
}
+
+ /**
+ * Retreive a project based on the supplied project ID
+ *
+ * @param idProject
+ * @return
+ */
@GET
@Path("/get/{id}")
@Detail("Get project by id")
@@ -177,6 +189,7 @@ public Response get(@PathParam("id") @ParameterDetail("Project identifier") Long
}
}
+
/**
* Update the code in an existing project.
*
@@ -202,11 +215,13 @@ public Response saveProjectCode(
LOG.debug("Code for project {} has been saved", idProject);
JsonObject result = projectConverter.toJson(savedProject,false);
+
LOG.debug("Returning JSON: {}", result);
result.addProperty("success", true);
return Response.ok(result.toString()).build();
+
} catch (AuthorizationException ae) {
LOG.warn("Project code not saved. Not Authorized");
return Response.status(Response.Status.UNAUTHORIZED).build();
@@ -217,6 +232,15 @@ public Response saveProjectCode(
}
}
+
+ /**
+ *
+ * @param idProject
+ * @param code
+ * @param newName
+ * @param newBoard
+ * @return
+ */
@POST
@Path("/code-as")
@Detail("Save project code")
diff --git a/src/main/java/com/parallax/server/blocklyprop/services/impl/ProjectServiceImpl.java b/src/main/java/com/parallax/server/blocklyprop/services/impl/ProjectServiceImpl.java
index 0cf372c8..ad3ada24 100644
--- a/src/main/java/com/parallax/server/blocklyprop/services/impl/ProjectServiceImpl.java
+++ b/src/main/java/com/parallax/server/blocklyprop/services/impl/ProjectServiceImpl.java
@@ -252,11 +252,28 @@ public boolean deleteProject(Long idProject) {
return projectDao.deleteProject(idProject);
}
+
+ /**
+ * Update the code block in the specified project
+ *
+ * @param idProject
+ * @param code
+ * @return
+ */
@Override
public ProjectRecord saveProjectCode(Long idProject, String code) {
return projectDao.updateProjectCode(idProject, code);
}
+
+ /**
+ *
+ * @param idProject
+ * @param code
+ * @param newName
+ * @param newBoard
+ * @return
+ */
@Override
public ProjectRecord saveProjectCodeAs(Long idProject, String code, String newName, String newBoard) {
return projectDao.saveProjectCodeAs(idProject, code, newName, newBoard);
From 696988ce450d722826c15454833e3054b708f8a6 Mon Sep 17 00:00:00 2001
From: Jim Ewald
Date: Wed, 6 Feb 2019 08:52:50 -0800
Subject: [PATCH 09/69] Correct issue where new projects were orphaned.
Refactor code, add comments.
---
.../db/dao/impl/ProjectDaoImpl.java | 16 +-
.../blocklyprop/rest/RestSharedProject.java | 183 ++++++++++++++----
2 files changed, 159 insertions(+), 40 deletions(-)
diff --git a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java
index 2c8d0ede..c4b01220 100644
--- a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java
+++ b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java
@@ -643,16 +643,21 @@ public ProjectRecord updateProjectCode(Long idProject, String code) {
@Override
public ProjectRecord saveProjectCodeAs(Long idProject, String code, String newName, String newBoard) {
- LOG.info("Saving project code as '{}'", newName);
+ LOG.info("Saving project code from project {} as '{}'", idProject, newName);
// Retreive the source project
ProjectRecord original = getProject(idProject);
+
if (original == null) {
LOG.error("Original project {} is missing. Unable to save code as...", idProject);
throw new NullPointerException("Project doesn't exist");
- } else if (newBoard == null) {
+ }
+
+ // Use the board type from the parent project if it was not provided
+ if (newBoard == null) {
newBoard = original.getBoard();
}
+
// Obtain the current bp user record.
Long idUser = BlocklyPropSecurityUtils.getCurrentUserId();
@@ -663,6 +668,7 @@ public ProjectRecord saveProjectCodeAs(Long idProject, String code, String newNa
// shared or community project
// --------------------------------------------------------------------
if (original.getIdUser().equals(idUser) || original.getShared()) {
+
ProjectRecord cloned = createProject(
newName,
original.getDescription(),
@@ -674,7 +680,13 @@ public ProjectRecord saveProjectCodeAs(Long idProject, String code, String newNa
false, // Set project unshared
original.getId());
+ if (cloned == null) {
+ LOG.warn("Unable to create a copy og the project.");
+ }
return cloned;
+ } else {
+ LOG.warn("Unable to copy the project. UID: {}, PUID: {}, Shared: {}",
+ idUser, original.getIdUser(), original.getShared());
}
} else {
LOG.info("Unable to retreive BP user id");
diff --git a/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java b/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java
index e053fa9f..dd48281d 100644
--- a/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java
+++ b/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018 Parallax Inc.
+ * Copyright (c) 2019 Parallax Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the “Software”), to deal in the Software without
@@ -16,7 +16,7 @@
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
+ * SOFTWARE.
*/
package com.parallax.server.blocklyprop.rest;
@@ -42,35 +42,67 @@
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
+import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
+ * Manage requests for public projects
*
* @author Michel
+ *
+ * NOTE:
+ * The concept of 'shared' projects has changed over time. A project
+ * can be private or public. A project can also be associated with a
+ * specific project sharing URL, regardless of its public/private status.
*/
@Path("/shared/project")
@Group(name = "/shared/project", title = "Project management")
@HttpCode("500>Internal Server Error,200>Success Response")
public class RestSharedProject {
+ /**
+ * Get a connection to the logging system
+ */
private static final Logger LOG = LoggerFactory.getLogger(RestSharedProject.class);
+
+ /**
+ * Get a handle to project services
+ */
private ProjectService projectService;
+
+ /**
+ * Get a handle to a project converter
+ */
private ProjectConverter projectConverter;
+
+ /**
+ * Inject project services
+ *
+ * @param projectService
+ * An instance of the ProjectService object
+ */
@Inject
public void setProjectService(ProjectService projectService) {
this.projectService = projectService;
}
+
+ /**
+ * Inject project conversion services
+ * @param projectConverter
+ * An instance of the ProjectConverter object
+ */
@Inject
public void setProjectConverter(ProjectConverter projectConverter) {
this.projectConverter = projectConverter;
}
+
/**
* Return a list of community projects.
*
@@ -101,16 +133,16 @@ public Response get(
@QueryParam("limit") Integer limit,
@QueryParam("offset") Integer offset) {
- LOG.info("REST:/shared/project/list/ endpoint activated");
- LOG.debug("REST:/shared/project/list/ Sort parameter is '{}'", sort);
- LOG.debug("REST:/shared/project/list/ Sort parameter is '{}'", sort);
+ String endPoint = "REST:/shared/project/list/";
+
+ LOG.info("{} endpoint activated", endPoint);
boolean parametersValid = false;
// Sort flag evaluation
if (sort != null) {
for (TableSort t : TableSort.values()) {
- LOG.debug("REST:/shared/project/list/ Sort test for '{}'", t);
+ LOG.debug("{} Sort test for '{}'",endPoint, t);
if (sort == t) {
parametersValid = true;
@@ -118,8 +150,8 @@ public Response get(
}
}
- if (parametersValid == false) {
- LOG.warn("REST:/shared/project/list/ Sort parameter failed");
+ if (!parametersValid) {
+ LOG.warn("{} Sort parameter failed", endPoint);
return Response.status(Response.Status.NOT_ACCEPTABLE).build();
}
}
@@ -127,7 +159,7 @@ public Response get(
// Sort order evaluation
if (order != null) {
parametersValid = false;
- LOG.debug("REST:/shared/project/list/ Checking order");
+ LOG.debug("{} Checking order", endPoint);
for (TableOrder t : TableOrder.values()) {
if (order == t) {
@@ -136,14 +168,14 @@ public Response get(
}
}
- if (parametersValid == false) {
+ if (!parametersValid) {
return Response.status(Response.Status.NOT_ACCEPTABLE).build();
}
}
// Limit result set value
if ( (limit == null) || (limit > 50)) {
- LOG.info("REST:/shared/project/list/ Limit throttle to 50 entries");
+ LOG.info("{} Limit throttle to 50 entries", endPoint);
limit = 50;
}
@@ -151,26 +183,37 @@ public Response get(
if ((offset == null) || (offset < 0)) {
offset = 0;
}
-
+
+ // Get a block of projects
List projects
= projectService.getSharedProjects(sort, order, limit, offset);
// Obtain a count of the total number of community projects available
int projectCount = projectService.countSharedProjects();
- JsonObject result = new JsonObject();
- JsonArray jsonProjects = new JsonArray();
-
- for (ProjectRecord project : projects) {
- jsonProjects.add(projectConverter.toListJson(project));
- }
-
- result.add("rows", jsonProjects);
- result.addProperty("total", projectCount);
-
- return Response.ok(result.toString()).build();
+ return Response.ok(returnProjectsJson(projects, projectCount)).build();
}
+
+ /**
+ * Get a list of projects owned by a specific user
+ *
+ * @param sort
+ * The project field used to evaluate the sort
+ *
+ * @param order
+ * Specify the sort order - ascending or descending
+ *
+ * @param limit
+ * Specify the maximum number of rows to return
+ *
+ * @param offset
+ * Specify the beginning row to return
+ *
+ * @return
+ * Return a response object that contains either the data requested
+ * or a JSON string containing the error details
+ */
@GET
@Path("/list/user/{id}")
@Detail("Get shared projects by user")
@@ -183,25 +226,44 @@ public Response get(
@QueryParam("offset") Integer offset,
@PathParam("id") Long idUser) {
- LOG.info("REST:/shared/project/list/user/ Get request received for user '{}'", idUser);
+ String endPoint = "REST:/shared/project/list/user/";
- List projects = projectService.getSharedProjectsByUser(sort, order, limit, offset, idUser);
- int projectCount = projectService.countSharedProjectsByUser(idUser);
+ LOG.info("{} Get request received for user '{}'", endPoint, idUser);
- JsonObject result = new JsonObject();
- JsonArray jsonProjects = new JsonArray();
-
- for (ProjectRecord project : projects) {
- jsonProjects.add(projectConverter.toListJson(project));
+ // Limit result set value
+ if ( (limit == null) || (limit > 50)) {
+ LOG.info("{} Limit throttle to 50 entries", endPoint);
+ limit = 50;
+ }
+
+ // Check ofset from the beginning of the record set
+ if ((offset == null) || (offset < 0)) {
+ offset = 0;
}
- result.add("rows", jsonProjects);
- result.addProperty("total", projectCount);
- return Response.ok(result.toString()).build();
+ List projects = projectService.getSharedProjectsByUser(sort, order, limit, offset, idUser);
+ int projectCount = projectService.countSharedProjectsByUser(idUser);
+
+ return Response.ok(returnProjectsJson(projects, projectCount)).build();
+
}
+ /**
+ *
+ * @param authorization
+ * Authorization header token
+ *
+ * @param timestamp
+ * A timestamp
+ *
+ * @param idProject
+ * The project key ID
+ *
+ * @return
+ * Returns a Json string containing the project details
+ */
@GET
@Path("/get/{id}")
@Detail("Get project by id")
@@ -212,10 +274,11 @@ public Response get(
@HeaderParam("X-Timestamp") Long timestamp,
@PathParam("id") Long idProject) {
- LOG.info("REST:/rest/shared/project/get/ Get request received for projecet '{}'", idProject);
+ String endPoint = "REST:/rest/shared/project/get/";
+
+ LOG.info("{} Get request received for project '{}'", endPoint, idProject);
try {
- LOG.info("Getting project record.");
ProjectRecord project = projectService.getProject(idProject);
if (project == null) {
@@ -223,9 +286,9 @@ public Response get(
return Response.status(Response.Status.NOT_FOUND).build();
}
- LOG.info("Converting project to JSON string");
+ LOG.info("Converting project {} to JSON string", idProject);
JsonObject result = projectConverter.toJson(project, false);
- LOG.info("REST: /get/" + idProject.toString() + "/ returning project {}.", project.getId());
+ LOG.info("{}" + idProject.toString() + "/ returning project {}.", endPoint, project.getId());
return Response.ok(result.toString()).build();
}
@@ -235,6 +298,22 @@ public Response get(
}
}
+
+ /**
+ * Get project details, including the project code payload
+ *
+ * @param authorization
+ * Request authorization header
+ *
+ * @param timestamp
+ * A timestamp
+ *
+ * @param idProject
+ * The project key ID
+ *
+ * @return
+ * A string containing a Json object representing the requested project
+ */
@GET
@Path("/editor/{id}")
@Detail("Get project by id for editor")
@@ -267,4 +346,32 @@ public Response getEditor(
}
}
+
+ /**
+ * Iterate a list of projects into an array of Json objects
+ *
+ * @param projects
+ * A List of ProjectRecord objects
+ *
+ * @param projectCount
+ * The number of projects available. This may not be the same value as
+ * the number of records contained in the passed list of ProjectRecords.
+ *
+ * @return
+ * A String containing the array of the converted Json objects
+ */
+ private String returnProjectsJson(@NotNull List projects, int projectCount) {
+ JsonObject result = new JsonObject();
+ JsonArray jsonProjects = new JsonArray();
+
+ for (ProjectRecord project : projects) {
+ jsonProjects.add(projectConverter.toListJson(project));
+ }
+
+ result.add("rows", jsonProjects);
+ result.addProperty("total", projectCount);
+
+ return result.toString();
+ }
+
}
From 773ea554cfcd4c15baa52c01af952d4082382d20 Mon Sep 17 00:00:00 2001
From: Jim Ewald
Date: Wed, 6 Feb 2019 11:51:59 -0800
Subject: [PATCH 10/69] Refactor code into a utility class. Set list hard limit
to 100 records.
---
.../db/dao/impl/ProjectDaoImpl.java | 7 +
.../server/blocklyprop/rest/RestProject.java | 185 ++++++++++++++----
.../blocklyprop/rest/RestSharedProject.java | 108 +++++-----
.../blocklyprop/utils/RestProjectUtils.java | 64 ++++++
.../translations.properties | 2 +-
5 files changed, 274 insertions(+), 92 deletions(-)
create mode 100644 src/main/java/com/parallax/server/blocklyprop/utils/RestProjectUtils.java
diff --git a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java
index c4b01220..a42966bf 100644
--- a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java
+++ b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java
@@ -571,6 +571,13 @@ public boolean deleteProject(Long idProject) {
* @param code
*
* @return
+ * Returns the specified project record, otherwise it returns a null if
+ * the current user does not own the project and the project is not shared
+ * or public, or the requested project record was not found.
+ *
+ * @implNote This method will actually create a new project record based on the
+ * existing project under specific conditions. Since this is an update record method,
+ * the creation of a new project my be unexpected at higher layers of the application.
*/
@Override
public ProjectRecord updateProjectCode(Long idProject, String code) {
diff --git a/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java b/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java
index 097a97ab..d8cf3c97 100644
--- a/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java
+++ b/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java
@@ -1,8 +1,24 @@
/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright (c) 2019 Parallax Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the “Software”), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
*/
+
package com.parallax.server.blocklyprop.rest;
import com.cuubez.visualizer.annotation.Detail;
@@ -16,6 +32,7 @@
import com.google.inject.Inject;
import com.parallax.server.blocklyprop.TableOrder;
import com.parallax.server.blocklyprop.TableSort;
+import com.parallax.server.blocklyprop.utils.RestProjectUtils;
import com.parallax.server.blocklyprop.converter.ProjectConverter;
import com.parallax.server.blocklyprop.db.enums.ProjectType;
import com.parallax.server.blocklyprop.db.generated.tables.records.ProjectRecord;
@@ -31,6 +48,7 @@
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import org.apache.shiro.authz.AuthorizationException;
+import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -45,19 +63,36 @@
@Group(name = "/project", title = "Project management")
@HttpCode("500>Internal Server Error,200>Success Response")
public class RestProject {
- // Get a logger instance
+
+ /**
+ * Get a logger instance
+ */
private static final Logger LOG = LoggerFactory.getLogger(RestProject.class);
- // Connector to project services object
+
+ /**
+ * Connector to project services object
+ */
private ProjectService projectService;
- // Connector to project converter object
+
+ /**
+ * Connector to project converter object
+ */
private ProjectConverter projectConverter;
+ /**
+ * Limit the number of records that can be returned in list functions
+ */
+ final int REQUEST_LIMIT = 100;
+
+
/**
* Connect to the project service object
- * @param projectService
+ *
+ * @param projectService
+ * An instance of the ProjectService object
*/
@Inject
public void setProjectService(ProjectService projectService) {
@@ -67,7 +102,9 @@ public void setProjectService(ProjectService projectService) {
/**
* Connect to the project converter object
- * @param projectConverter
+ *
+ * @param projectConverter
+ * An instance of the ProjectConverter object
*/
@Inject
public void setProjectConverter(ProjectConverter projectConverter) {
@@ -77,13 +114,22 @@ public void setProjectConverter(ProjectConverter projectConverter) {
/**
* Return a list of projects owned by the currently authenticated user.
- *
+ *
* @param sort
+ * The project field used to evaluate the sort
+ *
* @param order
+ * Specify the sort order - ascending or descending
+ *
* @param limit
+ * Specify the maximum number of rows to return
+ *
* @param offset
- *
- * @return JSON formatted list of project details
+ * Specify the beginning row to return
+ *
+ * @return
+ * Return a response object that contains either the data requested
+ * or a JSON string containing the error details
*/
@GET
@Path("/list")
@@ -95,49 +141,62 @@ public Response get(
@QueryParam("order") @ParameterDetail("Sort order") @M() TableOrder order,
@QueryParam("limit") @ParameterDetail("Number of rows to return") @M() Integer limit,
@QueryParam("offset") @ParameterDetail("Offset to next row returned") @M() Integer offset) {
-
- LOG.info("REST:/rest/project/list/ Get request received");
-
+
+ String endPoint = "REST:/rest/project/list/";
+
+ LOG.info("{} Get request received", endPoint);
+ RestProjectUtils restProjectUtils = new RestProjectUtils();
+
try {
// Get the logged in user id for the current session
Long idUser = BlocklyPropSecurityUtils.getCurrentUserId();
-
+
+ // Return FORBIDDEN if we cannot identify the current user. This could
+ // mean that the user is not logged in or that some underlying issue
+ // is causing the authentication system to fail.
if (idUser == 0) {
// Current session is not logged in.
- return Response.status(Response.Status.NOT_FOUND).build();
+ return Response.status(Response.Status.FORBIDDEN).build();
}
//Sanity checks - is the request reasonable
- if (sort == null)
- sort = TableSort.modified;
-
- if (order == null)
- order = TableOrder.asc;
-
- if (limit == null)
- limit = 20;
-
- if (offset == null)
- offset = 0;
- List userProjects =
- projectService.getUserProjects(idUser, sort, order, limit, offset);
-
- int projectCount = projectService.countUserProjects(idUser);
+ // Sort flag evaluation
+ if (!restProjectUtils.ValidateSortType(sort)) {
+ LOG.warn("{} Sort parameter failed", endPoint);
+ return Response.status(Response.Status.NOT_ACCEPTABLE).build();
+ }
+
+ // Sort order evaluation
+ if (!restProjectUtils.ValidateSortOrder(order)) {
+ LOG.warn("{} Sort order parameter failed", endPoint);
+ return Response.status(Response.Status.NOT_ACCEPTABLE).build();
+ }
- JsonObject result = new JsonObject();
- JsonArray jsonProjects = new JsonArray();
+ // Limit result set value
+ if ( (limit == null) || (limit > REQUEST_LIMIT)) {
+ LOG.info("{} Limit throttle to {} entries", endPoint, REQUEST_LIMIT);
+ limit = REQUEST_LIMIT;
+ }
- // Loop through user projects and build a Json array
- for (ProjectRecord project : userProjects) {
- jsonProjects.add(projectConverter.toListJson(project));
+ // Check ofset from the beginning of the record set
+ if ((offset == null) || (offset < 0)) {
+ offset = 0;
}
- // Add payload details
- result.add("rows", jsonProjects);
- result.addProperty("total", projectCount);
+ // Obtain a list of the user's projects
+ List userProjects = projectService.getUserProjects(idUser, sort, order, limit, offset);
- return Response.ok(result.toString()).build();
+ // Tell the caller that there is nothing to see here
+ if (userProjects == null) {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+
+ return Response.ok(
+ returnProjectsJson(
+ userProjects,
+ projectService.countUserProjects(idUser)))
+ .build();
}
catch(Exception ex) {
@@ -152,7 +211,11 @@ public Response get(
* Retreive a project based on the supplied project ID
*
* @param idProject
+ * The project key ID
+ *
* @return
+ * Return a string representation of the project in Json format if successful, otherwise
+ * return a Json string containing an error status message
*/
@GET
@Path("/get/{id}")
@@ -197,7 +260,10 @@ public Response get(@PathParam("id") @ParameterDetail("Project identifier") Long
*
* @param idProject
* @param code
- * @return
+ * @return
+ * Returns a Json string containing the project details if the update was successful
+ * or an error message upon failure
+ *
*/
@POST
@Path("/code")
@@ -211,12 +277,19 @@ public Response saveProjectCode(
LOG.info("REST:/rest/project/code/ POST request received for project '{}'", idProject);
try {
+
+ /* WARNING:
+ * =================================================================================
+ * This call can create a new project record under specific circumstances and does
+ * not appear to provide any notification that this has occurred.
+ * =================================================================================
+ */
ProjectRecord savedProject = projectService.saveProjectCode(idProject, code);
+
LOG.debug("Code for project {} has been saved", idProject);
JsonObject result = projectConverter.toJson(savedProject,false);
- LOG.debug("Returning JSON: {}", result);
result.addProperty("success", true);
@@ -332,4 +405,32 @@ public Response saveProject(
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
}
+
+ /**
+ * Iterate a list of projects into an array of Json objects
+ *
+ * @param projects
+ * A List of ProjectRecord objects
+ *
+ * @param projectCount
+ * The number of projects available. This may not be the same value as
+ * the number of records contained in the passed list of ProjectRecords.
+ *
+ * @return
+ * A String containing the array of the converted Json objects
+ */
+ private String returnProjectsJson(@NotNull List projects, int projectCount) {
+ JsonObject result = new JsonObject();
+ JsonArray jsonProjects = new JsonArray();
+
+ for (ProjectRecord project : projects) {
+ jsonProjects.add(projectConverter.toListJson(project));
+ }
+
+ result.add("rows", jsonProjects);
+ result.addProperty("total", projectCount);
+
+ return result.toString();
+ }
+
}
diff --git a/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java b/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java
index dd48281d..12491f3f 100644
--- a/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java
+++ b/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java
@@ -30,6 +30,7 @@
import com.google.inject.Inject;
import com.parallax.server.blocklyprop.TableOrder;
import com.parallax.server.blocklyprop.TableSort;
+import com.parallax.server.blocklyprop.utils.RestProjectUtils;
import com.parallax.server.blocklyprop.converter.ProjectConverter;
import com.parallax.server.blocklyprop.db.generated.tables.records.ProjectRecord;
import com.parallax.server.blocklyprop.services.ProjectService;
@@ -80,6 +81,12 @@ public class RestSharedProject {
private ProjectConverter projectConverter;
+ /**
+ * Limit the number of records that can be returned in list functions
+ */
+ final int REQUEST_LIMIT = 100;
+
+
/**
* Inject project services
*
@@ -95,6 +102,7 @@ public void setProjectService(ProjectService projectService) {
/**
* Inject project conversion services
* @param projectConverter
+ *
* An instance of the ProjectConverter object
*/
@Inject
@@ -133,50 +141,27 @@ public Response get(
@QueryParam("limit") Integer limit,
@QueryParam("offset") Integer offset) {
- String endPoint = "REST:/shared/project/list/";
+ RestProjectUtils restProjectUtils = new RestProjectUtils();
+ String endPoint = "REST:/shared/project/list/";
LOG.info("{} endpoint activated", endPoint);
- boolean parametersValid = false;
-
// Sort flag evaluation
- if (sort != null) {
- for (TableSort t : TableSort.values()) {
- LOG.debug("{} Sort test for '{}'",endPoint, t);
-
- if (sort == t) {
- parametersValid = true;
- break;
- }
- }
-
- if (!parametersValid) {
- LOG.warn("{} Sort parameter failed", endPoint);
- return Response.status(Response.Status.NOT_ACCEPTABLE).build();
- }
+ if (!restProjectUtils.ValidateSortType(sort)) {
+ LOG.warn("{} Sort parameter failed", endPoint);
+ return Response.status(Response.Status.NOT_ACCEPTABLE).build();
}
// Sort order evaluation
- if (order != null) {
- parametersValid = false;
- LOG.debug("{} Checking order", endPoint);
-
- for (TableOrder t : TableOrder.values()) {
- if (order == t) {
- parametersValid = true;
- break;
- }
- }
-
- if (!parametersValid) {
- return Response.status(Response.Status.NOT_ACCEPTABLE).build();
- }
+ if (!restProjectUtils.ValidateSortOrder(order)) {
+ LOG.warn("{} Sort order parameter failed", endPoint);
+ return Response.status(Response.Status.NOT_ACCEPTABLE).build();
}
-
+
// Limit result set value
- if ( (limit == null) || (limit > 50)) {
- LOG.info("{} Limit throttle to 50 entries", endPoint);
- limit = 50;
+ if ( (limit == null) || (limit > REQUEST_LIMIT)) {
+ LOG.info("{} Limit throttle to {} entries", endPoint, REQUEST_LIMIT);
+ limit = REQUEST_LIMIT;
}
// Check ofset from the beginning of the record set
@@ -185,13 +170,18 @@ public Response get(
}
// Get a block of projects
- List projects
- = projectService.getSharedProjects(sort, order, limit, offset);
-
- // Obtain a count of the total number of community projects available
- int projectCount = projectService.countSharedProjects();
+ List projects = projectService.getSharedProjects(sort, order, limit, offset);
- return Response.ok(returnProjectsJson(projects, projectCount)).build();
+ // Tell the caller that there is nothing to see here
+ if (projects == null) {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+
+ return Response.ok(
+ returnProjectsJson(
+ projects,
+ projectService.countSharedProjects()))
+ .build();
}
@@ -226,14 +216,27 @@ public Response get(
@QueryParam("offset") Integer offset,
@PathParam("id") Long idUser) {
- String endPoint = "REST:/shared/project/list/user/";
+ RestProjectUtils restProjectUtils = new RestProjectUtils();
+ String endPoint = "REST:/shared/project/list/user/";
LOG.info("{} Get request received for user '{}'", endPoint, idUser);
+ // Sort flag evaluation
+ if (!restProjectUtils.ValidateSortType(sort)) {
+ LOG.warn("{} Sort parameter failed", endPoint);
+ return Response.status(Response.Status.NOT_ACCEPTABLE).build();
+ }
+
+ // Sort order evaluation
+ if (!restProjectUtils.ValidateSortOrder(order)) {
+ LOG.warn("{} Sort order parameter failed", endPoint);
+ return Response.status(Response.Status.NOT_ACCEPTABLE).build();
+ }
+
// Limit result set value
- if ( (limit == null) || (limit > 50)) {
- LOG.info("{} Limit throttle to 50 entries", endPoint);
- limit = 50;
+ if ( (limit == null) || (limit > REQUEST_LIMIT)) {
+ LOG.info("{} Limit throttle to {} entries", endPoint, REQUEST_LIMIT);
+ limit = REQUEST_LIMIT;
}
// Check ofset from the beginning of the record set
@@ -241,12 +244,18 @@ public Response get(
offset = 0;
}
-
List projects = projectService.getSharedProjectsByUser(sort, order, limit, offset, idUser);
- int projectCount = projectService.countSharedProjectsByUser(idUser);
- return Response.ok(returnProjectsJson(projects, projectCount)).build();
+ // Tell the caller that there is nothing to see here
+ if (projects == null) {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+ return Response.ok(
+ returnProjectsJson(
+ projects,
+ projectService.countSharedProjectsByUser(idUser)))
+ .build();
}
@@ -275,7 +284,6 @@ public Response get(
@PathParam("id") Long idProject) {
String endPoint = "REST:/rest/shared/project/get/";
-
LOG.info("{} Get request received for project '{}'", endPoint, idProject);
try {
@@ -287,7 +295,9 @@ public Response get(
}
LOG.info("Converting project {} to JSON string", idProject);
+
JsonObject result = projectConverter.toJson(project, false);
+
LOG.info("{}" + idProject.toString() + "/ returning project {}.", endPoint, project.getId());
return Response.ok(result.toString()).build();
diff --git a/src/main/java/com/parallax/server/blocklyprop/utils/RestProjectUtils.java b/src/main/java/com/parallax/server/blocklyprop/utils/RestProjectUtils.java
new file mode 100644
index 00000000..3114d070
--- /dev/null
+++ b/src/main/java/com/parallax/server/blocklyprop/utils/RestProjectUtils.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019 Parallax Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the “Software”), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.parallax.server.blocklyprop.utils;
+
+import com.parallax.server.blocklyprop.TableOrder;
+import com.parallax.server.blocklyprop.TableSort;
+
+public class RestProjectUtils {
+
+
+ public boolean ValidateSortType(TableSort sort) {
+
+ boolean parametersValid = false;
+
+ if (sort != null) {
+ for (TableSort t : TableSort.values()) {
+
+ if (sort == t) {
+ parametersValid = true;
+ break;
+ }
+ }
+ }
+
+ return parametersValid;
+ }
+
+ public boolean ValidateSortOrder(TableOrder order) {
+
+ boolean parametersValid = false;
+
+ if (order != null) {
+ for (TableOrder t : TableOrder.values()) {
+ if (order == t) {
+ parametersValid = true;
+ break;
+ }
+ }
+ }
+
+ return parametersValid;
+ }
+}
+
+
diff --git a/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties b/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties
index 245ed8c0..079a7f2a 100644
--- a/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties
+++ b/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties
@@ -28,7 +28,7 @@ footer.clientdownloadlink = BlocklyProp-client
# Application version numbers.
application.major = 1
application.minor = 1
-application.build = 449
+application.build = 451
html.content_missing = Content missing
From 19415c9720436a7733ab6d1fe27a492dbf3631e6 Mon Sep 17 00:00:00 2001
From: Jim Ewald
Date: Wed, 6 Feb 2019 12:29:18 -0800
Subject: [PATCH 11/69] Add support for defaul sort order for project lists.
---
.../server/blocklyprop/rest/RestSharedProject.java | 8 ++++----
.../server/blocklyprop/utils/RestProjectUtils.java | 14 ++++++++------
.../internationalization/translations.properties | 2 +-
3 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java b/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java
index 12491f3f..574d2f03 100644
--- a/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java
+++ b/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java
@@ -148,14 +148,14 @@ public Response get(
// Sort flag evaluation
if (!restProjectUtils.ValidateSortType(sort)) {
- LOG.warn("{} Sort parameter failed", endPoint);
- return Response.status(Response.Status.NOT_ACCEPTABLE).build();
+ LOG.warn("{} Sort parameter failed. Defaulting to sort by project name", endPoint);
+ sort = TableSort.name;
}
// Sort order evaluation
if (!restProjectUtils.ValidateSortOrder(order)) {
- LOG.warn("{} Sort order parameter failed", endPoint);
- return Response.status(Response.Status.NOT_ACCEPTABLE).build();
+ LOG.warn("{} Sort order parameter failed. Defaulting to ascending order", endPoint);
+ order = TableOrder.asc;
}
// Limit result set value
diff --git a/src/main/java/com/parallax/server/blocklyprop/utils/RestProjectUtils.java b/src/main/java/com/parallax/server/blocklyprop/utils/RestProjectUtils.java
index 3114d070..5cfa9ed6 100644
--- a/src/main/java/com/parallax/server/blocklyprop/utils/RestProjectUtils.java
+++ b/src/main/java/com/parallax/server/blocklyprop/utils/RestProjectUtils.java
@@ -27,21 +27,23 @@
public class RestProjectUtils {
+ /**
+ *
+ * @param sort
+ * @return
+ * Return true if the provided sort is a valid item, otherwise return false
+ */
public boolean ValidateSortType(TableSort sort) {
- boolean parametersValid = false;
-
if (sort != null) {
for (TableSort t : TableSort.values()) {
-
if (sort == t) {
- parametersValid = true;
- break;
+ return true;
}
}
}
- return parametersValid;
+ return false;
}
public boolean ValidateSortOrder(TableOrder order) {
diff --git a/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties b/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties
index 079a7f2a..1b24368a 100644
--- a/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties
+++ b/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties
@@ -28,7 +28,7 @@ footer.clientdownloadlink = BlocklyProp-client
# Application version numbers.
application.major = 1
application.minor = 1
-application.build = 451
+application.build = 452
html.content_missing = Content missing
From 60988ee459a4b474380b58e1a4737a142c17be2b Mon Sep 17 00:00:00 2001
From: Jim Ewald
Date: Wed, 6 Feb 2019 12:51:35 -0800
Subject: [PATCH 12/69] Add copyright messsage and additional logging detail.
---
.../servlets/ConfirmRequestServlet.java | 22 ++++++++--
.../blocklyprop/servlets/ConfirmServlet.java | 33 ++++++++++++---
.../servlets/PasswordResetRequestServlet.java | 22 ++++++++--
.../servlets/PasswordResetServlet.java | 40 ++++++++++++++++---
4 files changed, 100 insertions(+), 17 deletions(-)
diff --git a/src/main/java/com/parallax/server/blocklyprop/servlets/ConfirmRequestServlet.java b/src/main/java/com/parallax/server/blocklyprop/servlets/ConfirmRequestServlet.java
index fd3afd17..5241b3ea 100644
--- a/src/main/java/com/parallax/server/blocklyprop/servlets/ConfirmRequestServlet.java
+++ b/src/main/java/com/parallax/server/blocklyprop/servlets/ConfirmRequestServlet.java
@@ -1,8 +1,24 @@
/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright (c) 2019 Parallax Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the “Software”), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
*/
+
package com.parallax.server.blocklyprop.servlets;
import com.google.common.base.Strings;
diff --git a/src/main/java/com/parallax/server/blocklyprop/servlets/ConfirmServlet.java b/src/main/java/com/parallax/server/blocklyprop/servlets/ConfirmServlet.java
index f34f0c1f..dd240019 100644
--- a/src/main/java/com/parallax/server/blocklyprop/servlets/ConfirmServlet.java
+++ b/src/main/java/com/parallax/server/blocklyprop/servlets/ConfirmServlet.java
@@ -1,8 +1,24 @@
/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright (c) 2019 Parallax Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the “Software”), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
*/
+
package com.parallax.server.blocklyprop.servlets;
import com.google.common.base.Strings;
@@ -33,6 +49,9 @@
@Singleton
public class ConfirmServlet extends HttpServlet {
+ /**
+ *
+ */
private static Logger LOG = LoggerFactory.getLogger(ConfirmServlet.class);
private final TextileReader textileFileReader = new TextileReader();
@@ -76,21 +95,22 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
public void confirmToken(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
- // Retreive the registration token
+ // Retrieve the registration token
String token = req.getParameter("token");
req.setAttribute("token", token == null ? "" : token);
- // Retreive the requestor's email address
+ // Retrieve the requester's email address
String email = req.getParameter("email");
req.setAttribute("email", email == null ? "" : email);
// Return to the confirmation web page is we're missing data
if (Strings.isNullOrEmpty(token) || Strings.isNullOrEmpty(email)) {
+ LOG.info("Confirmation data for {} is incomplete. Reloading request page", email);
req.getRequestDispatcher("WEB-INF/servlet/confirm/confirm.jsp")
.forward(req, resp);
} else {
try {
- LOG.info("Trying to confirm: {}, {}", email, token);
+ LOG.info("Trying to confirm: {}", email);
// Validate the email and token with the Cloud Session server
if (cloudSessionLocalUserService.doConfirm(email, token)) {
@@ -101,6 +121,7 @@ public void confirmToken(HttpServletRequest req, HttpServletResponse resp)
// req.getRequestDispatcher("WEB-INF/servlet/confirm/confirmed.jsp").forward(req, resp);
showTextilePage(req, resp, ConfirmPage.CONFIRMED);
} else {
+ LOG.info("Failed to verify the token for email address {}", email);
req.setAttribute("invalidToken", "Invalid token");
req.getRequestDispatcher("WEB-INF/servlet/confirm/confirm.jsp").forward(req, resp);
}
diff --git a/src/main/java/com/parallax/server/blocklyprop/servlets/PasswordResetRequestServlet.java b/src/main/java/com/parallax/server/blocklyprop/servlets/PasswordResetRequestServlet.java
index f1f9e4f5..08b69e2d 100644
--- a/src/main/java/com/parallax/server/blocklyprop/servlets/PasswordResetRequestServlet.java
+++ b/src/main/java/com/parallax/server/blocklyprop/servlets/PasswordResetRequestServlet.java
@@ -1,8 +1,24 @@
/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright (c) 2019 Parallax Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the “Software”), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
*/
+
package com.parallax.server.blocklyprop.servlets;
import com.google.common.base.Strings;
diff --git a/src/main/java/com/parallax/server/blocklyprop/servlets/PasswordResetServlet.java b/src/main/java/com/parallax/server/blocklyprop/servlets/PasswordResetServlet.java
index 9bc747be..0949d461 100644
--- a/src/main/java/com/parallax/server/blocklyprop/servlets/PasswordResetServlet.java
+++ b/src/main/java/com/parallax/server/blocklyprop/servlets/PasswordResetServlet.java
@@ -1,8 +1,24 @@
/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright (c) 2019 Parallax Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the “Software”), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
*/
+
package com.parallax.server.blocklyprop.servlets;
import com.google.common.base.Strings;
@@ -57,6 +73,8 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Se
String email = req.getParameter("email");
req.setAttribute("token", token == null ? "" : token);
req.setAttribute("email", email == null ? "" : email);
+
+ LOG.info("Redirecting to the reset password page");
req.getRequestDispatcher("WEB-INF/servlet/password-reset/do-reset.jsp").forward(req, resp);
}
@@ -69,8 +87,12 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S
String email = req.getParameter("email");
req.setAttribute("token", token == null ? "" : token);
req.setAttribute("email", email == null ? "" : email);
+
+
String password = req.getParameter("password");
String confirmPassword = req.getParameter("confirmpassword");
+
+ LOG.info("Processing the results from the reset pasword page");
if (Strings.isNullOrEmpty(token) || Strings.isNullOrEmpty(email) || Strings.isNullOrEmpty(password) || Strings.isNullOrEmpty(confirmPassword)) {
req.getRequestDispatcher("WEB-INF/servlet/password-reset/do-reset.jsp").forward(req, resp);
@@ -107,8 +129,16 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S
}
}
- public void showTextilePage(HttpServletRequest req, HttpServletResponse resp, PasswordResetPage passwordResetPage) throws ServletException, IOException {
- String html = textileFileReader.readFile("password-reset/" + passwordResetPage.getPage(), ServletUtils.getLocale(req), req.isSecure());
+ public void showTextilePage(
+ HttpServletRequest req,
+ HttpServletResponse resp,
+ PasswordResetPage passwordResetPage) throws ServletException, IOException {
+
+ String html = textileFileReader.readFile(
+ "password-reset/" + passwordResetPage.getPage(),
+ ServletUtils.getLocale(req),
+ req.isSecure());
+
req.setAttribute("html", html);
req.getRequestDispatcher("/WEB-INF/servlet/html.jsp").forward(req, resp);
}
From 13ca4513ca178bfa628c5ab57631c72e1a6b6ef8 Mon Sep 17 00:00:00 2001
From: Jim Ewald
Date: Wed, 6 Feb 2019 14:21:03 -0800
Subject: [PATCH 13/69] Correct error in projects listing introduced during
recent refactoring.
---
.gitignore | 3 +++
pom.xml | 9 ++++++++-
.../parallax/server/blocklyprop/rest/RestProject.java | 8 ++++----
.../internationalization/translations.properties | 2 +-
4 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/.gitignore b/.gitignore
index 7c438576..bf6ce5ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,9 @@ nb*
# /src/main/java/com/parallax/server/blocklyprop/db/generated/*
#
+*.sh
+
+
#################
## NetBeans
#################
diff --git a/pom.xml b/pom.xml
index 6fc0a3f6..2656d85a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -549,5 +549,12 @@
4.12test
-
+
+
+
+ org.jetbrains
+ annotations
+ 17.0.0
+
+
\ No newline at end of file
diff --git a/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java b/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java
index d8cf3c97..398fd560 100644
--- a/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java
+++ b/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java
@@ -163,14 +163,14 @@ public Response get(
// Sort flag evaluation
if (!restProjectUtils.ValidateSortType(sort)) {
- LOG.warn("{} Sort parameter failed", endPoint);
- return Response.status(Response.Status.NOT_ACCEPTABLE).build();
+ LOG.warn("{} Sort parameter failed. Defaulting to sort by project name", endPoint);
+ sort = TableSort.name;
}
// Sort order evaluation
if (!restProjectUtils.ValidateSortOrder(order)) {
- LOG.warn("{} Sort order parameter failed", endPoint);
- return Response.status(Response.Status.NOT_ACCEPTABLE).build();
+ LOG.warn("{} Sort order parameter failed. Defaulting to ascending order", endPoint);
+ order = TableOrder.asc;
}
// Limit result set value
diff --git a/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties b/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties
index 1b24368a..21ca1370 100644
--- a/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties
+++ b/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties
@@ -28,7 +28,7 @@ footer.clientdownloadlink = BlocklyProp-client
# Application version numbers.
application.major = 1
application.minor = 1
-application.build = 452
+application.build = 453
html.content_missing = Content missing
From a30cfcdb6348853600bae0b568d336d2fb43756e Mon Sep 17 00:00:00 2001
From: Jim Ewald
Date: Thu, 7 Feb 2019 11:22:01 -0800
Subject: [PATCH 14/69] Issue #1500, Added code to support detection of an
active shared project link for a target project.
---
.../blocklyprop/db/dao/ProjectSharingDao.java | 54 +++++++++++++++++--
.../db/dao/impl/ProjectDaoImpl.java | 23 ++++++--
.../db/dao/impl/ProjectSharingDaoImpl.java | 33 +++++++++++-
.../server/blocklyprop/rest/RestProject.java | 10 ++--
.../blocklyprop/rest/RestSharedProject.java | 7 +--
.../services/ProjectSharingService.java | 5 +-
.../impl/ProjectSharingServiceImpl.java | 36 +++++++++++--
.../blocklyprop/utils/RestProjectUtils.java | 4 +-
8 files changed, 152 insertions(+), 20 deletions(-)
diff --git a/src/main/java/com/parallax/server/blocklyprop/db/dao/ProjectSharingDao.java b/src/main/java/com/parallax/server/blocklyprop/db/dao/ProjectSharingDao.java
index b613d88d..4d74e827 100644
--- a/src/main/java/com/parallax/server/blocklyprop/db/dao/ProjectSharingDao.java
+++ b/src/main/java/com/parallax/server/blocklyprop/db/dao/ProjectSharingDao.java
@@ -5,6 +5,7 @@
*/
package com.parallax.server.blocklyprop.db.dao;
+import com.parallax.server.blocklyprop.db.generated.tables.ProjectSharing;
import com.parallax.server.blocklyprop.db.generated.tables.records.ProjectSharingRecord;
import java.util.List;
@@ -14,17 +15,64 @@
*/
public interface ProjectSharingDao {
+ /**
+ * Retrieve a project
+ * @param idProject
+ * @param accessKey
+ * @return
+ */
ProjectSharingRecord getProject(Long idProject, String accessKey);
+
+ /**
+ * Share an existing project
+ * @param idProject
+ * @param shareKey
+ * @return
+ */
ProjectSharingRecord shareProject(Long idProject, String shareKey);
+
+ /**
+ * Disable the shared link to a project
+ * @param idProject
+ * @return
+ */
int revokeSharing(Long idProject);
- public List getSharingInfo(Long idProject);
+
+ /**
+ * Get a project sharing record
+ * @param idProject
+ * @return
+ */
+ List getSharingInfo(Long idProject);
// Set the active flag in an existing shared project record
- public ProjectSharingRecord activateProject(Long idProject);
+
+ /**
+ * Enable the project sharing link
+ *
+ * @param idProject
+ * @return
+ */
+ ProjectSharingRecord activateProject(Long idProject);
// Remove a project sharing link record
- public boolean deleteProjectSharingRecord(Long idProject);
+
+ /**
+ * Delete a project sharing record
+ *
+ * @param idProject
+ * @return
+ */
+ boolean deleteProjectSharingRecord(Long idProject);
+
+
+ /**
+ * Is the project sharing feature enabled for a project
+ * @param idProject
+ * @return
+ */
+ boolean isProjectSharingActive(Long idProject);
}
diff --git a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java
index a42966bf..93c7308a 100644
--- a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java
+++ b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectDaoImpl.java
@@ -13,10 +13,14 @@
import com.parallax.server.blocklyprop.db.generated.tables.records.ProjectRecord;
import com.parallax.server.blocklyprop.security.BlocklyPropSecurityUtils;
+//import com.parallax.server.blocklyprop.services.impl.ProjectSharingServiceImpl;
+import com.parallax.server.blocklyprop.services.ProjectSharingService;
+
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.GregorianCalendar;
import java.util.List;
+
import org.apache.shiro.authz.UnauthorizedException;
import org.jooq.Condition;
import org.jooq.DSLContext;
@@ -72,7 +76,15 @@ public void setDSLContext(DSLContext dsl) {
this.create = dsl;
}
-
+
+ private ProjectSharingService projectSharingService;
+
+ @Inject
+ public void setProjectSharingContext(ProjectSharingService projectSharingService) {
+ this.projectSharingService = projectSharingService;
+ }
+
+
/**
*
* Retrieve a new project record based from an existing project.
@@ -674,7 +686,12 @@ public ProjectRecord saveProjectCodeAs(Long idProject, String code, String newNa
// by the current user OR if the source project is designated as a
// shared or community project
// --------------------------------------------------------------------
- if (original.getIdUser().equals(idUser) || original.getShared()) {
+ boolean sharedStatus = projectSharingService.isProjectShared(idProject);
+ LOG.info("Project shared status: {}", sharedStatus);
+
+ if (original.getIdUser().equals(idUser) || // Project is owned by currently logged in user
+ sharedStatus || // Project is shared
+ (!original.getPrivate())) { // Project is public
ProjectRecord cloned = createProject(
newName,
@@ -688,7 +705,7 @@ public ProjectRecord saveProjectCodeAs(Long idProject, String code, String newNa
original.getId());
if (cloned == null) {
- LOG.warn("Unable to create a copy og the project.");
+ LOG.warn("Unable to create a copy of the project.");
}
return cloned;
} else {
diff --git a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectSharingDaoImpl.java b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectSharingDaoImpl.java
index 4a0804a7..b962e71c 100644
--- a/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectSharingDaoImpl.java
+++ b/src/main/java/com/parallax/server/blocklyprop/db/dao/impl/ProjectSharingDaoImpl.java
@@ -7,9 +7,11 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
+
import com.parallax.server.blocklyprop.db.dao.ProjectSharingDao;
import com.parallax.server.blocklyprop.db.generated.Tables;
import com.parallax.server.blocklyprop.db.generated.tables.records.ProjectSharingRecord;
+
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -61,7 +63,8 @@ public ProjectSharingRecord getProject(Long idProject, String accessKey) {
/**
- *
+ * Create a project sharing record
+ *
* @param idProject
* @param shareKey
* @return
@@ -178,4 +181,32 @@ public boolean deleteProjectSharingRecord(Long idProject) {
}
+
+ /**
+ * Determine the on/off state of the project's shared link URL
+ *
+ * @param idProject
+ * @return
+ */
+ @Override
+ public boolean isProjectSharingActive(Long idProject) {
+
+ LOG.info("Retrieving sharing record for project {}", idProject);
+
+ ProjectSharingRecord project = create
+ .selectFrom(Tables.PROJECT_SHARING)
+ .where((Tables.PROJECT_SHARING.ID_PROJECT
+ .equal(idProject)))
+ .fetchOne();
+
+ if (project == null) {
+ LOG.info("The sharing record for project {} was not found", idProject);
+ // Record not found
+ return false;
+ }
+
+ LOG.info("Project {} sharing is {}", idProject, project.getActive());
+ return project.getActive();
+ }
+
}
diff --git a/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java b/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java
index 398fd560..30490097 100644
--- a/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java
+++ b/src/main/java/com/parallax/server/blocklyprop/rest/RestProject.java
@@ -145,7 +145,7 @@ public Response get(
String endPoint = "REST:/rest/project/list/";
LOG.info("{} Get request received", endPoint);
- RestProjectUtils restProjectUtils = new RestProjectUtils();
+// RestProjectUtils restProjectUtils = new RestProjectUtils();
try {
// Get the logged in user id for the current session
@@ -162,13 +162,13 @@ public Response get(
//Sanity checks - is the request reasonable
// Sort flag evaluation
- if (!restProjectUtils.ValidateSortType(sort)) {
+ if (!RestProjectUtils.ValidateSortType(sort)) {
LOG.warn("{} Sort parameter failed. Defaulting to sort by project name", endPoint);
sort = TableSort.name;
}
// Sort order evaluation
- if (!restProjectUtils.ValidateSortOrder(order)) {
+ if (!RestProjectUtils.ValidateSortOrder(order)) {
LOG.warn("{} Sort order parameter failed. Defaulting to ascending order", endPoint);
order = TableOrder.asc;
}
@@ -343,12 +343,14 @@ public Response saveProjectCodeAs(
result.addProperty("success", true);
return Response.ok(result.toString()).build();
- } catch (AuthorizationException ae) {
+ }
+ catch (AuthorizationException ae) {
LOG.warn("Project code not saved. Not Authorized");
return Response.status(Response.Status.UNAUTHORIZED).build();
}
catch (Exception ex) {
LOG.error("General exception encountered. Message is: ", ex.getMessage());
+ LOG.error("Error: {}", ex.getStackTrace().toString());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
}
diff --git a/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java b/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java
index 574d2f03..c757d8cd 100644
--- a/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java
+++ b/src/main/java/com/parallax/server/blocklyprop/rest/RestSharedProject.java
@@ -28,12 +28,14 @@
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.inject.Inject;
+
import com.parallax.server.blocklyprop.TableOrder;
import com.parallax.server.blocklyprop.TableSort;
import com.parallax.server.blocklyprop.utils.RestProjectUtils;
import com.parallax.server.blocklyprop.converter.ProjectConverter;
import com.parallax.server.blocklyprop.db.generated.tables.records.ProjectRecord;
import com.parallax.server.blocklyprop.services.ProjectService;
+
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
@@ -141,19 +143,18 @@ public Response get(
@QueryParam("limit") Integer limit,
@QueryParam("offset") Integer offset) {
- RestProjectUtils restProjectUtils = new RestProjectUtils();
String endPoint = "REST:/shared/project/list/";
LOG.info("{} endpoint activated", endPoint);
// Sort flag evaluation
- if (!restProjectUtils.ValidateSortType(sort)) {
+ if (!RestProjectUtils.ValidateSortType(sort)) {
LOG.warn("{} Sort parameter failed. Defaulting to sort by project name", endPoint);
sort = TableSort.name;
}
// Sort order evaluation
- if (!restProjectUtils.ValidateSortOrder(order)) {
+ if (!RestProjectUtils.ValidateSortOrder(order)) {
LOG.warn("{} Sort order parameter failed. Defaulting to ascending order", endPoint);
order = TableOrder.asc;
}
diff --git a/src/main/java/com/parallax/server/blocklyprop/services/ProjectSharingService.java b/src/main/java/com/parallax/server/blocklyprop/services/ProjectSharingService.java
index de0e017c..19d4ced0 100644
--- a/src/main/java/com/parallax/server/blocklyprop/services/ProjectSharingService.java
+++ b/src/main/java/com/parallax/server/blocklyprop/services/ProjectSharingService.java
@@ -28,6 +28,9 @@ public interface ProjectSharingService {
ProjectRecord getSharedProject(Long idProject, String shareKey);
// Delete a project sharing record
- public boolean deleteSharedProject(Long idProject);
+ boolean deleteSharedProject(Long idProject);
+
+ // Get current active state of a project share link
+ boolean isProjectShared(Long idProject);
}
diff --git a/src/main/java/com/parallax/server/blocklyprop/services/impl/ProjectSharingServiceImpl.java b/src/main/java/com/parallax/server/blocklyprop/services/impl/ProjectSharingServiceImpl.java
index 16de708c..a6e7ec32 100644
--- a/src/main/java/com/parallax/server/blocklyprop/services/impl/ProjectSharingServiceImpl.java
+++ b/src/main/java/com/parallax/server/blocklyprop/services/impl/ProjectSharingServiceImpl.java
@@ -32,16 +32,34 @@ public class ProjectSharingServiceImpl implements ProjectSharingService {
*/
private static final Logger LOG = LoggerFactory.getLogger(ProjectSharingService.class);
+
+ /**
+ *
+ */
private ProjectDao projectDao;
- private ProjectSharingDao projectSharingDao;
- // Inject dao connection to the project table
+
+ /**
+ * Inject dao connection to the project table
+ * @param projectDao
+ */
@Inject
public void setProjectDao(ProjectDao projectDao) {
this.projectDao = projectDao;
}
- // Inject connection to the project_sharing table
+
+ /**
+ *
+ */
+ private ProjectSharingDao projectSharingDao;
+
+
+ /**
+ * Inject connection to the project_sharing table
+ *
+ * @param projectSharingDao
+ */
@Inject
public void setProjectSharingDao(ProjectSharingDao projectSharingDao) {
this.projectSharingDao = projectSharingDao;
@@ -154,4 +172,16 @@ public boolean deleteSharedProject(Long idProject) {
LOG.info("Deleting project share link for project {}", idProject);
return projectSharingDao.deleteProjectSharingRecord(idProject);
}
+
+
+ /**
+ *
+ * @param idProject
+ * @return
+ */
+ @Override
+ public boolean isProjectShared(Long idProject) {
+ LOG.info("Evaluating project {} sharing status.", idProject);
+ return projectSharingDao.isProjectSharingActive(idProject);
+ }
}
diff --git a/src/main/java/com/parallax/server/blocklyprop/utils/RestProjectUtils.java b/src/main/java/com/parallax/server/blocklyprop/utils/RestProjectUtils.java
index 5cfa9ed6..014dbe67 100644
--- a/src/main/java/com/parallax/server/blocklyprop/utils/RestProjectUtils.java
+++ b/src/main/java/com/parallax/server/blocklyprop/utils/RestProjectUtils.java
@@ -33,7 +33,7 @@ public class RestProjectUtils {
* @return
* Return true if the provided sort is a valid item, otherwise return false
*/
- public boolean ValidateSortType(TableSort sort) {
+ public static boolean ValidateSortType(TableSort sort) {
if (sort != null) {
for (TableSort t : TableSort.values()) {
@@ -46,7 +46,7 @@ public boolean ValidateSortType(TableSort sort) {
return false;
}
- public boolean ValidateSortOrder(TableOrder order) {
+ public static boolean ValidateSortOrder(TableOrder order) {
boolean parametersValid = false;
From 4cd0ebcf4592e10d31a4c8102c6e30aabbd52792 Mon Sep 17 00:00:00 2001
From: Jim Ewald
Date: Thu, 7 Feb 2019 11:22:54 -0800
Subject: [PATCH 15/69] Update build number for release relative to issue
#1500.
---
.../blocklyprop/internationalization/translations.properties | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties b/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties
index 21ca1370..66a1ce1d 100644
--- a/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties
+++ b/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties
@@ -28,7 +28,7 @@ footer.clientdownloadlink = BlocklyProp-client
# Application version numbers.
application.major = 1
application.minor = 1
-application.build = 453
+application.build = 455
html.content_missing = Content missing
From 5bddb9605e97ef1f492339b56031d7e033c35bba Mon Sep 17 00:00:00 2001
From: Jim Ewald
Date: Thu, 14 Feb 2019 09:44:21 -0800
Subject: [PATCH 16/69] Fully documented class to help better understand Shiro
session implementation.
---
.../security/BlocklyPropSessionDao.java | 189 +++++++++++++++---
1 file changed, 161 insertions(+), 28 deletions(-)
diff --git a/src/main/java/com/parallax/server/blocklyprop/security/BlocklyPropSessionDao.java b/src/main/java/com/parallax/server/blocklyprop/security/BlocklyPropSessionDao.java
index 87282b2f..df1a3258 100644
--- a/src/main/java/com/parallax/server/blocklyprop/security/BlocklyPropSessionDao.java
+++ b/src/main/java/com/parallax/server/blocklyprop/security/BlocklyPropSessionDao.java
@@ -7,6 +7,7 @@
import com.parallax.server.blocklyprop.db.generated.tables.records.SessionRecord;
import com.parallax.server.blocklyprop.services.impl.SessionServiceImpl;
+
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
@@ -14,11 +15,13 @@
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
+
import org.apache.commons.lang.SerializationUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.SessionDAO;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -26,15 +29,50 @@
* Session persistence manager
*
* @author Michel
+ *
+ * @implNote
+ * Notes from the Shiro JavaDocs:
+ * Data Access Object design pattern specification to enable Session access to an EIS
+ * (Enterprise Information System). It provides your four typical CRUD methods:
+ * create(org.apache.shiro.session.Session),
+ * readSession(java.io.Serializable),
+ * update(org.apache.shiro.session.Session),
+ * and delete(org.apache.shiro.session.Session).
+ *
+ * The remaining getActiveSessions() method exists as a support mechanism to pre-emptively
+ * orphaned sessions, typically by ValidatingSessionManagers), and should be as efficient
+ * as possible, especially if there are thousands of active sessions. Large scale/high
+ * performance implementations will often return a subset of the total active sessions and
+ * perform validation a little more frequently, rather than return a massive set and
+ * infrequently validate.
*/
public class BlocklyPropSessionDao implements SessionDAO {
- // Get a logger instance
+
+ /**
+ * Get an instance of the logger initialized to this class
+ */
private static final Logger LOG = LoggerFactory.getLogger(SessionServiceImpl.class);
/**
- *
+ * Inserts a new Session record into the underling EIS (a relational database in this
+ * implementation).
+ *
* @param session
- * @return
+ * the Session object to create in the EIS.
+ *
+ * @return
+ * the EIS id (e.g. primary key) of the created Session object.
+ *
+ * @implNote
+ * After this method is invoked, the Session.getId() method executed on the argument
+ * must return a valid session identifier. That is, the following should always be
+ * true:
+ *
+ * Serializable id = create( session );
+ * id.equals( session.getId() ) == true
+ *
+ * Implementations are free to throw any exceptions that might occur due to integrity
+ * violation constraints or other EIS related errors.
*/
@Override
public Serializable create(Session session) {
@@ -44,32 +82,48 @@ public Serializable create(Session session) {
session.setTimeout(28800000);
SimpleSession simpleSession = (SimpleSession) session;
+
+ // Create a unique string and save into the session object
String uuid = UUID.randomUUID().toString();
-
simpleSession.setId(uuid);
+
+ // Get a reference to the static session service and create
+ // a session record from the session object and store it in the
+ // sessionDao backing store
SessionServiceImpl.getSessionService().create(convert(simpleSession));
- LOG.debug("Session timeout is: {}", simpleSession.getTimeout());
LOG.info("Creating session: {}", simpleSession.getId());
+ // Return a unique session identifier
return uuid;
}
/**
- *
+ * Retrieves the session from the EIS uniquely identified by the specified sessionId.
+ *
* @param sessionId
+ * the system-wide unique identifier of the Session object to retrieve from the EIS.
+ *
* @return
- * @throws UnknownSessionException
+ * the persisted session in the EIS identified by sessionId.
+ *
+ * @throws UnknownSessionException
+ * if there is no EIS record for any session with the specified sessionId
*/
@Override
public Session readSession(Serializable sessionId) throws UnknownSessionException {
+
LOG.debug("Reading session: {}", sessionId);
+ // Check parameter for sanity
+ if (sessionId == null) {
+ LOG.warn("Attempt to retrieve session with a null UUID parameter");
+ throw new UnknownSessionException();
+ }
+
try {
// Obtain an existing session object
SessionRecord sessionRecord
- = SessionServiceImpl
- .getSessionService()
- .readSession(sessionId.toString());
+ = SessionServiceImpl.getSessionService().readSession(sessionId.toString());
if (sessionRecord != null) {
return convert(sessionRecord);
@@ -84,13 +138,26 @@ public Session readSession(Serializable sessionId) throws UnknownSessionExceptio
}
/**
- *
+ * Updates (persists) data from a previously created Session instance in the EIS identified
+ * by {@link Session#getId() session.getId()}. This effectively propagates the data in the
+ * argument to the EIS record previously saved.
+ *
* @param session
- * @throws UnknownSessionException
+ * session - the Session to update
+ *
+ * @throws UnknownSessionException
+ * if no existing EIS session record exists with the identifier of session.getSessionId()
+ *
+ * @implNote
+ * In addition to UnknownSessionException, implementations are free to throw any other
+ * exceptions that might occur due to integrity violation constraints or other EIS related
+ * errors.
*/
@Override
public void update(Session session) throws UnknownSessionException {
+
LOG.debug("Update session: {}", session.getId());
+
try {
// updateSession() can throw a NullPointerException if something goes wrong
SessionServiceImpl.getSessionService().updateSession(convert(session));
@@ -102,54 +169,110 @@ public void update(Session session) throws UnknownSessionException {
}
/**
- *
- * @param session
+ * Deletes the associated EIS record of the specified session. If there never existed a
+ * session EIS record with the identifier of session.getId(), then this method does nothing.
+ *
+ * @param session
+ * session - the session to delete.
*/
@Override
public void delete(Session session) {
+
LOG.debug("Removing session {}", session.getId());
+
SessionServiceImpl.getSessionService().deleteSession(session.getId().toString());
}
/**
- *
- * @return
+ * Returns all sessions in the EIS that are considered active, meaning all sessions that
+ * have not been stopped or expired. This is primarily used to validate potential orphans.
+ *
+ * @return
+ * a Collection of Sessions that are considered active, or an empty collection or null if
+ * there are no active sessions.
+ *
+ * @implNote
+ * This method should be as efficient as possible, especially in larger systems where there
+ * might be thousands of active sessions. Large scale/high performance implementations will
+ * often return a subset of the total active sessions and perform validation a little more
+ * frequently, rather than return a massive set and validate infrequently. If efficient and
+ * possible, it would make sense to return the oldest unstopped sessions available, ordered
+ * by lastAccessTime.
+ *
+ * Ideally this method would only return active sessions that the EIS was certain should be
+ * invalided. Typically that is any session that is not stopped and where its
+ * lastAccessTimestamp is older than the session timeout. For example, if sessions were
+ * backed by a relational database or SQL-92 'query-able' enterprise cache, you might return
+ * something similar to the results returned by this query (assuming SimpleSessions were
+ * being stored):
+ *
+ * select *
+ * from sessions s
+ * where s.lastAccessTimestamp < ? and s.stopTimestamp is null
+ *
+ * where the ? parameter is a date instance equal to 'now' minus the session timeout
+ * (e.g. now - 30 minutes).
*/
@Override
public Collection getActiveSessions() {
+
LOG.debug("Getting all active sessions");
Collection sessionRecords = SessionServiceImpl.getSessionService().getActiveSessions();
- List sessions = new ArrayList();
+ List sessions = new ArrayList<>();
+
for (SessionRecord sessionRecord : sessionRecords) {
sessions.add(convert(sessionRecord));
}
+
return sessions;
}
- protected SessionRecord convert(Session session) {
+
+ /**
+ * Convert a Session object into a SessionRecord object
+ *
+ * @param session
+ * the session to convert into a SessionRecord
+ *
+ * @return
+ * a SessionRecord object containing the details necessary to persist the object
+ * into an EIS.
+ */
+ private SessionRecord convert(Session session) {
LOG.debug("Converting session {} to a SessionRecord object", session.getId());
-
+
+ // Cast the Session parameter into a SimpleSession reference
SimpleSession ssession = (SimpleSession) session;
+
SessionRecord sessionRecord = new SessionRecord();
sessionRecord.setIdsession(session.getId().toString());
sessionRecord.setStarttimestamp(new Timestamp(session.getStartTimestamp().getTime()));
sessionRecord.setLastaccesstime(new Timestamp(session.getLastAccessTime().getTime()));
sessionRecord.setTimeout(session.getTimeout());
sessionRecord.setHost(session.getHost());
+
+ // Gather the session attributes into a HashMap that can be persisted into the
+ // SessionRecord object
if (ssession.getAttributes() != null) {
HashMap