diff --git a/.gitignore b/.gitignore index c2b7c44c..de5cca02 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,13 @@ build.properties ################# -## NetBeans +## Blockly Files ################# +# /src/main/**/logback.xml +################# +## NetBeans +################# nb-configuration.xml nbactions.xml target/ @@ -15,7 +19,7 @@ BlocklyProp.iml ################# .idea - +*.iml ################# ## Eclipse diff --git a/pom.xml b/pom.xml index ba680415..97a77be5 100644 --- a/pom.xml +++ b/pom.xml @@ -238,11 +238,25 @@ slf4j-api 1.7.21 + + + ch.qos.logback + logback-classic + 1.1.8 + + + ch.qos.logback + logback-core + 1.1.8 + + + @@ -382,15 +396,15 @@ - net.kencochrane.raven + com.getsentry.raven raven - 6.0.0 + 7.8.1 - net.kencochrane.raven - raven-log4j - 6.0.0 + com.getsentry.raven + raven-logback + 7.8.1 @@ -439,12 +453,19 @@ ${metrics-version} + + io.dropwizard.metrics + metrics-logback + 3.1.2 + + + io.dropwizard.metrics metrics-servlet @@ -517,5 +538,4 @@ --> - \ No newline at end of file diff --git a/src/main/config/default/log4j.xml b/src/main/config/default/log4j.xml deleted file mode 100644 index 7edfdbe0..00000000 --- a/src/main/config/default/log4j.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/java/com/parallax/server/blocklyprop/config/DaoModule.java b/src/main/java/com/parallax/server/blocklyprop/config/DaoModule.java index 6d6bd6ad..bd1f3dde 100644 --- a/src/main/java/com/parallax/server/blocklyprop/config/DaoModule.java +++ b/src/main/java/com/parallax/server/blocklyprop/config/DaoModule.java @@ -15,9 +15,26 @@ import com.parallax.server.blocklyprop.db.dao.impl.SessionDaoImpl; import com.parallax.server.blocklyprop.db.dao.impl.UserDaoImpl; + /** * * @author Michel + * + * AbstractModule: + * A support class for Modules which reduces repetition and results in a more + * readable configuration. Simply extend this class, implement configure(), + * and call the inherited methods which mirror those found in Binder. + * For example: + * + * public class MyModule extends AbstractModule { + * protected void configure() { + * bind(Service.class).to(ServiceImpl.class).in(Singleton.class); + * bind(CreditCardPaymentService.class); + * bind(PaymentService.class).to(CreditCardPaymentService.class); + * bindConstant().annotatedWith(Names.named("port")).to(8080); + * } + * } + * */ public class DaoModule extends AbstractModule { diff --git a/src/main/java/com/parallax/server/blocklyprop/config/PersistenceModule.java b/src/main/java/com/parallax/server/blocklyprop/config/PersistenceModule.java index 5fae250d..5311fe62 100644 --- a/src/main/java/com/parallax/server/blocklyprop/config/PersistenceModule.java +++ b/src/main/java/com/parallax/server/blocklyprop/config/PersistenceModule.java @@ -10,12 +10,13 @@ import com.google.inject.Provides; import com.parallax.server.blocklyprop.db.utils.DataSourceSetup; import java.sql.SQLException; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.sql.DataSource; import org.apache.commons.configuration.Configuration; import org.apache.commons.dbcp2.PoolingDataSource; import org.jooq.SQLDialect; +import java.util.logging.Level; +import java.util.logging.Logger; + /** * @@ -37,6 +38,7 @@ protected void configure() { @Provides PoolingDataSource dataSource() throws ClassNotFoundException { + PoolingDataSource ds = DataSourceSetup.connect(configuration); try { ds.getConnection(); 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 b305c0f5..9cc46b07 100644 --- a/src/main/java/com/parallax/server/blocklyprop/config/SetupConfig.java +++ b/src/main/java/com/parallax/server/blocklyprop/config/SetupConfig.java @@ -21,6 +21,10 @@ import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.DefaultConfigurationBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ch.qos.logback.classic.LoggerContext; + /** * @@ -29,6 +33,7 @@ public class SetupConfig extends GuiceServletContextListener { private Configuration configuration; + private final Logger LOG = LoggerFactory.getLogger(SetupConfig.class); @Override protected Injector getInjector() { @@ -60,15 +65,21 @@ protected void configure() { ); } + /* + * The application configuration is stored in the blocklyprop.properties + * file in user home directory. The config.xml contains the actual file + * name of the configuation file. If the file is not found, the app will + * use a set of default values. + */ private void readConfiguration() { try { - System.out.println("Looking for blocklyprop.properties in: " + System.getProperty("user.home")); + LOG.info("Looking for blocklyprop.properties in: {}", System.getProperty("user.home")); DefaultConfigurationBuilder configurationBuilder = new DefaultConfigurationBuilder(getClass().getResource("/config.xml")); configuration = configurationBuilder.getConfiguration(); } catch (ConfigurationException ce) { - ce.printStackTrace(); + LOG.error("{}", ce.getMessage()); } catch (Throwable t) { - t.printStackTrace(); + LOG.error(t.getMessage()); } } @@ -81,12 +92,20 @@ public void contextDestroyed(ServletContextEvent servletContextEvent) { Driver driver = drivers.nextElement(); try { DriverManager.deregisterDriver(driver); - // LOG.log(Level.INFO, String.format("deregistering jdbc driver: %s", driver)); + LOG.info("deregistering jdbc driver: {}",driver); } catch (SQLException sqlE) { - // LOG.log(Level.SEVERE, String.format("Error deregistering driver %s", driver), e); + LOG.error("Error deregistering driver %s", driver); + LOG.error("{}", sqlE.getSQLState()); } } + + // Shut down the loggers. Assume SLF4J is bound to logback-classic + // in the current environment + LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); + if (loggerContext != null) { + loggerContext.stop(); + } } } diff --git a/src/main/java/com/parallax/server/blocklyprop/converter/ProjectConverter.java b/src/main/java/com/parallax/server/blocklyprop/converter/ProjectConverter.java index 55ec6d4e..5df14e9a 100644 --- a/src/main/java/com/parallax/server/blocklyprop/converter/ProjectConverter.java +++ b/src/main/java/com/parallax/server/blocklyprop/converter/ProjectConverter.java @@ -107,7 +107,6 @@ public JsonObject toJson(ProjectRecord project) { } } - System.out.println("project to json" + result.get("name").getAsString()); return result; } diff --git a/src/main/java/com/parallax/server/blocklyprop/db/dao/ProjectDao.java b/src/main/java/com/parallax/server/blocklyprop/db/dao/ProjectDao.java index 7e46d0b3..60334cc7 100644 --- a/src/main/java/com/parallax/server/blocklyprop/db/dao/ProjectDao.java +++ b/src/main/java/com/parallax/server/blocklyprop/db/dao/ProjectDao.java @@ -73,10 +73,19 @@ List getSharedProjects( Integer offset, Long idUser); + List getSharedProjectsByUser( + TableSort sort, + TableOrder order, + Integer limit, + Integer offset, + Long idUser); + int countUserProjects(Long idUser); int countSharedProjects(Long idUser); + int countSharedProjectsByUser(Long idUser); + ProjectRecord cloneProject(Long idProject); boolean deleteProject(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 481f90e3..3f46d017 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 @@ -20,14 +20,18 @@ import org.jooq.Condition; import org.jooq.DSLContext; import org.jooq.SortField; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * * @author Michel + * + * TODO: add details. */ @Singleton public class ProjectDaoImpl implements ProjectDao { - + private static final Logger LOG = LoggerFactory.getLogger(ProjectDao.class); private DSLContext create; @Inject @@ -35,122 +39,244 @@ public void setDSLContext(DSLContext dsl) { this.create = dsl; } - private ProjectRecord alterReadRecord(ProjectRecord record) { - - String newCode = record.getCode(); - if (record.getType() == ProjectType.SPIN) { - newCode = newCode.replaceAll("block type=\"controls_if\"", "block type=\"controls_boolean_if\""); - newCode = newCode.replaceAll("block type=\"logic_compare\"", "block type=\"logic_boolean_compare\""); - newCode = newCode.replaceAll("block type=\"logic_operation\"", "block type=\"logic_boolean_operation\""); - newCode = newCode.replaceAll("block type=\"logic_negate\"", "block type=\"logic_boolean_negate\""); - newCode = newCode.replaceAll("block type=\"math_number\"", "block type=\"spin_integer\""); - - } else if (record.getType() == ProjectType.PROPC){ - newCode = newCode.replaceAll("field name=\"OP\">ADD + MINUS - MULTIPLY * DIVIDE / MODULUS % AND && AND_NOT && !LT<GT>LTE<=GTE>=EQ==NEQ!=INCHES_inchesCM_cm getUserProjects(Long idUser, TableSort sort, TableOrder order, Integer limit, Integer offset) { + LOG.info("Retreive projects for user {}.", idUser); + SortField orderField = Tables.PROJECT.NAME.asc(); if (TableOrder.desc == order) { orderField = Tables.PROJECT.NAME.desc(); } - return create.selectFrom(Tables.PROJECT).where(Tables.PROJECT.ID_USER.equal(idUser)).orderBy(orderField).limit(limit).offset(offset).fetch(); + + return create.selectFrom(Tables.PROJECT) + .where(Tables.PROJECT.ID_USER.equal(idUser)) + .orderBy(orderField).limit(limit).offset(offset) + .fetch(); } + /** + * TODO: add details. + * + * @param sort + * @param order + * @param limit + * @param offset + * @param idUser + * @return + */ @Override public List getSharedProjects(TableSort sort, TableOrder order, Integer limit, Integer offset, Long idUser) { + LOG.info("Retreive shared projects."); + SortField> orderField = sort == null ? Tables.PROJECT.NAME.asc() : sort.getField().asc(); if (TableOrder.desc == order) { orderField = sort == null ? Tables.PROJECT.NAME.desc() : sort.getField().desc(); @@ -200,16 +371,64 @@ public List getSharedProjects(TableSort sort, TableOrder order, I if (idUser != null) { conditions = conditions.or(Tables.PROJECT.ID_USER.eq(idUser)); } - return create.selectFrom(Tables.PROJECT).where(conditions).orderBy(orderField).limit(limit).offset(offset).fetch(); + return create.selectFrom(Tables.PROJECT) + .where(conditions) + .orderBy(orderField).limit(limit).offset(offset) + .fetch(); } + /** + * TODO: add details. + * + * @param sort + * @param order + * @param limit + * @param offset + * @param idUser + * @return + */ + @Override + public List getSharedProjectsByUser(TableSort sort, TableOrder order, Integer limit, Integer offset, Long idUser) { + LOG.info("Retreive shared projects."); + + SortField> orderField = sort == null ? Tables.PROJECT.NAME.asc() : sort.getField().asc(); + if (TableOrder.desc == order) { + orderField = sort == null ? Tables.PROJECT.NAME.desc() : sort.getField().desc(); + } + Condition conditions = Tables.PROJECT.SHARED.eq(Boolean.TRUE); + if (idUser != null) { + conditions = conditions.and(Tables.PROJECT.ID_USER.eq(idUser)); + } + return create.selectFrom(Tables.PROJECT) + .where(conditions) + .orderBy(orderField).limit(limit).offset(offset) + .fetch(); + } + + /** + * TODO: add details. + * + * @param idUser + * @return + */ @Override public int countUserProjects(Long idUser) { + LOG.info("Count project for user {}.", idUser); + return create.fetchCount(Tables.PROJECT, Tables.PROJECT.ID_USER.equal(idUser)); } + /** + * + * TODO: add details. + * + * @param idUser + * @return + */ @Override public int countSharedProjects(Long idUser) { + LOG.info("Count shared projects for user {}.", idUser); + Condition conditions = Tables.PROJECT.SHARED.equal(Boolean.TRUE); if (idUser != null) { conditions = conditions.or(Tables.PROJECT.ID_USER.eq(idUser)); @@ -217,8 +436,34 @@ public int countSharedProjects(Long idUser) { return create.fetchCount(Tables.PROJECT, conditions); } + /** + * + * TODO: add details. + * + * @param idUser + * @return + */ + @Override + public int countSharedProjectsByUser(Long idUser) { + LOG.info("Count shared projects for user {}.", idUser); + + Condition conditions = Tables.PROJECT.SHARED.equal(Boolean.TRUE); + if (idUser != null) { + conditions = conditions.and(Tables.PROJECT.ID_USER.eq(idUser)); + } + return create.fetchCount(Tables.PROJECT, conditions); + } + + /** + * TODO: add details. + * + * @param idProject + * @return + */ @Override public ProjectRecord cloneProject(Long idProject) { + LOG.info("Clone existing project {} to a new project.", idProject); + ProjectRecord original = getProject(idProject); if (original == null) { throw new NullPointerException("Project doesn't exist"); @@ -230,35 +475,30 @@ public ProjectRecord cloneProject(Long idProject) { return null; } - private ProjectRecord doProjectClone(ProjectRecord original) { - ProjectRecord cloned = createProject( - original.getName(), - original.getDescription(), - original.getDescriptionHtml(), - original.getCode(), - original.getType(), - original.getBoard(), - original.getPrivate(), - original.getShared()); - - cloned.setBasedOn(original.getId()); - cloned.update(); - - create.update(Tables.PROJECT) - .set(Tables.PROJECT.BASED_ON, original.getId()) - .where(Tables.PROJECT.ID.equal(cloned.getId())); - return cloned; - } - + /** + * TODO: add details. + * + * @param idProject + * @return + */ @Override public boolean deleteProject(Long idProject) { + LOG.info("Delete project {}.", idProject); return create.deleteFrom(Tables.PROJECT) .where(Tables.PROJECT.ID.equal(idProject)) .execute() > 0; } + /** + * TODO: add details. + * + * @param idProject + * @param code + * @return + */ @Override public ProjectRecord updateProjectCode(Long idProject, String code) { + LOG.info("Update code for project {}.", idProject); ProjectRecord record = create.selectFrom(Tables.PROJECT) .where(Tables.PROJECT.ID.equal(idProject)) .fetchOne(); @@ -281,19 +521,33 @@ public ProjectRecord updateProjectCode(Long idProject, String code) { cloned.update(); return cloned; } + LOG.error("User {} tried and failed to update project {}.", idUser, idProject); throw new UnauthorizedException(); } } else { + LOG.warn("Unable to project {}. Unknown reason.", idProject); return null; } } + /** + * TODO: add details. + * + * @param idProject + * @param code + * @param newName + * @return + */ @Override public ProjectRecord saveProjectCodeAs(Long idProject, String code, String newName) { + LOG.info("Saving project code as '{}'", newName); + 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"); } + Long idUser = BlocklyPropSecurityUtils.getCurrentUserId(); if (original.getIdUser().equals(idUser) || original.getShared()) { // TODO check if friends ProjectRecord cloned = createProject( @@ -312,4 +566,197 @@ public ProjectRecord saveProjectCodeAs(Long idProject, String code, String newNa return null; } + // Private over-ride of the public getProject() + // + // + private ProjectRecord getProject(Long idProject, boolean toEdit) { + LOG.info("Retreiving project {}.", idProject); + ProjectRecord record = create + .selectFrom(Tables.PROJECT) + .where(Tables.PROJECT.ID.equal(idProject)) + .fetchOne(); + + if (record != null) { + Long idUser = BlocklyPropSecurityUtils.getCurrentUserId(); + + // Return a project if the edit flag is off or the edit flag is + // on and the project owner is the current user + if (!toEdit || record.getIdUser().equals(idUser)) { + + // Todo: Verify that the record was fetched - it sometimes is not. + return alterReadRecord(record); + } else { + LOG.error("User {} attempted to edit project {} without authorization.", + idUser, idProject); + throw new UnauthorizedException(); + } + } + + // Return the project after checking if for depricated blocks + // + // Todo: Verify that the record was fetched - it sometimes is not. + return alterReadRecord(record); + } + + private ProjectRecord doProjectClone(ProjectRecord original) { + ProjectRecord cloned = createProject( + original.getName(), + original.getDescription(), + original.getDescriptionHtml(), + original.getCode(), + original.getType(), + original.getBoard(), + original.getPrivate(), + original.getShared()); + + cloned.setBasedOn(original.getId()); + cloned.update(); + + create.update(Tables.PROJECT) + .set(Tables.PROJECT.BASED_ON, original.getId()) + .where(Tables.PROJECT.ID.equal(cloned.getId())); + return cloned; + } + + + // Evaluate project code and replace any depricated or updated blocks + // + // Return a ProjectRecord object. The code field may be altered to correct + // any old, depricated or updated blocks. The method will throw an + // exception if the ProjectRecord parameter is null or something has gone + // horribly wrong with the string conversions. + // + private ProjectRecord alterReadRecord(ProjectRecord record) { + LOG.info("Verify project block characteristics"); + String currentCode, newCode; + + if (record == null) { + LOG.error("Null project record detected."); + throw new NullPointerException("Cannot alter a null project record."); + } + + try { + currentCode = record.getCode(); + + // Return immediately if there is no code to adjust + if (currentCode == null) { + LOG.warn("Project () code block is empty.", record.getId()); + return record; + } + + /* + * Make a copy of the project. We will use this after the updates + * to determine if anything was changed. This ensures that we do + * not do any database I/O unless we actually changed something. + */ + newCode = currentCode; + + if (record.getType() == ProjectType.SPIN) { + newCode = fixSpinProjectBlocks(newCode); + + } else if (record.getType() == ProjectType.PROPC){ + newCode = fixPropcProjectBlocks(newCode); + } + + // Check for any difference from the original code + if (! currentCode.equals(newCode)) { + LOG.info("Updated depricated project code blocks in project {}.", record.getId()); + record.setCode(newCode); + } + } + + catch (Exception ex) { + LOG.error("Exception trapped. Message is: {}", ex.getMessage()); + } + + return record; + } + + // Correct depricated block details related to Spin blocks + private String fixSpinProjectBlocks(String newCode) { + LOG.info("Looking for depricated Spin blocks."); + + newCode = newCode.replaceAll("block type=\"controls_if\"", + "block type=\"controls_boolean_if\""); + + newCode = newCode.replaceAll("block type=\"logic_compare\"", + "block type=\"logic_boolean_compare\""); + + newCode = newCode.replaceAll("block type=\"logic_operation\"", + "block type=\"logic_boolean_operation\""); + + newCode = newCode.replaceAll("block type=\"logic_negate\"", + "block type=\"logic_boolean_negate\""); + + newCode = newCode.replaceAll("block type=\"math_number\"", + "block type=\"spin_integer\""); + return newCode; + } + + private String fixPropcProjectBlocks(String newCode) { + LOG.info("Looking for depricated PropC blocks."); + + newCode = newCode.replaceAll("field name=\"OP\">ADD + MINUS - MULTIPLY * DIVIDE / MODULUS % AND && AND_NOT && !LT<GT>LTE<=GTE>=EQ==NEQ!=INCHES_inchesCM_cmInternal Server Error,200>Success Response") public class RestSharedProject { + private static final Logger LOG = LoggerFactory.getLogger(RestSharedProject.class); private ProjectService projectService; @@ -55,7 +59,7 @@ public void setProjectConverter(ProjectConverter projectConverter) { @Name("Get all shared projects") @Produces("application/json") public Response get(@QueryParam("sort") TableSort sort, @QueryParam("order") TableOrder order, @QueryParam("limit") Integer limit, @QueryParam("offset") Integer offset) { - System.out.println("Sort: " + sort); + LOG.info("Sort: {}", sort); List projects = projectService.getSharedProjects(sort, order, limit, offset); int projectCount = projectService.countSharedProjects(); @@ -72,21 +76,51 @@ public Response get(@QueryParam("sort") TableSort sort, @QueryParam("order") Tab return Response.ok(result.toString()).build(); } + @GET + @Path("/list/user/{id}") + @Detail("Get shared projects by user") + @Name("Get shared projects by user") + @Produces("application/json") + public Response get(@QueryParam("sort") TableSort sort, @QueryParam("order") TableOrder order, @QueryParam("limit") Integer limit, @QueryParam("offset") Integer offset, @PathParam("id") Long idUser) { + LOG.info("Sort: {}", sort); + + List projects = projectService.getSharedProjectsByUser(sort, order, limit, offset, idUser); + int projectCount = projectService.countSharedProjectsByUser(idUser); + + 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(); + } + + @GET @Path("/get/{id}") @Detail("Get project by id") @Name("Get project by id") @Produces("application/json") public Response get(@HeaderParam("X-Authorization") String authorization, @HeaderParam("X-Timestamp") Long timestamp, @PathParam("id") Long idProject) { - ProjectRecord project = projectService.getProject(idProject); - - if (project == null) { + + try { + ProjectRecord project = projectService.getProject(idProject); + + if (project == null) { + return Response.status(Response.Status.NOT_FOUND).build(); + } + + JsonObject result = projectConverter.toJson(project); + return Response.ok(result.toString()).build(); + } + catch (Exception e) { + LOG.error("Exception in {} detected. Message is: {}", e.getClass(), e.getLocalizedMessage()); return Response.status(Response.Status.NOT_FOUND).build(); } - - JsonObject result = projectConverter.toJson(project); - - return Response.ok(result.toString()).build(); } @GET @@ -95,18 +129,24 @@ public Response get(@HeaderParam("X-Authorization") String authorization, @Heade @Name("Get project by id for editor") @Produces("application/json") public Response getEditor(@HeaderParam("X-Authorization") String authorization, @HeaderParam("X-Timestamp") Long timestamp, @PathParam("id") Long idProject) { - System.out.println("Authorization: " + authorization); + LOG.info("Authorization: {}", authorization); - ProjectRecord project = projectService.getProject(idProject); + try { + ProjectRecord project = projectService.getProject(idProject); - if (project == null) { - return Response.status(Response.Status.NOT_FOUND).build(); - } + if (project == null) { + return Response.status(Response.Status.NOT_FOUND).build(); + } - JsonObject result = projectConverter.toJson(project); - result.addProperty("code", project.getCode()); + JsonObject result = projectConverter.toJson(project); + result.addProperty("code", project.getCode()); - return Response.ok(result.toString()).build(); + return Response.ok(result.toString()).build(); + } + catch (Exception e) { + LOG.error("Exception in {} detected. Message is: {}", e.getClass(), e.getLocalizedMessage()); + return Response.status(Response.Status.NOT_FOUND).build(); + } } } diff --git a/src/main/java/com/parallax/server/blocklyprop/services/ProjectService.java b/src/main/java/com/parallax/server/blocklyprop/services/ProjectService.java index 9c617f62..692e5587 100644 --- a/src/main/java/com/parallax/server/blocklyprop/services/ProjectService.java +++ b/src/main/java/com/parallax/server/blocklyprop/services/ProjectService.java @@ -25,9 +25,13 @@ public interface ProjectService { List getSharedProjects(TableSort tablesSort, TableOrder order, Integer limit, Integer offset); + List getSharedProjectsByUser(TableSort tablesSort, TableOrder order, Integer limit, Integer offset, Long idUser); + int countUserProjects(Long idUser); int countSharedProjects(); + + int countSharedProjectsByUser(Long idUser); ProjectRecord saveProject(Long idProject, String name, String description, String descriptionHtml, boolean privateProject, boolean sharedProject, ProjectType type, String board); 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 45fb8c45..69fcca98 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 @@ -86,6 +86,11 @@ public List getSharedProjects(TableSort sort, TableOrder order, I return projectDao.getSharedProjects(sort, order, limit, offset, BlocklyPropSecurityUtils.getCurrentUserId()); } + @Override + public List getSharedProjectsByUser(TableSort sort, TableOrder order, Integer limit, Integer offset, Long idUser) { + return projectDao.getSharedProjectsByUser(sort, order, limit, offset, idUser); + } + @Override public int countUserProjects(Long idUser) { return projectDao.countUserProjects(idUser); @@ -95,6 +100,11 @@ public int countUserProjects(Long idUser) { public int countSharedProjects() { return projectDao.countSharedProjects(BlocklyPropSecurityUtils.getCurrentUserId()); } + + @Override + public int countSharedProjectsByUser(Long idUser) { + return projectDao.countSharedProjectsByUser(idUser); + } @Override public ProjectRecord saveProject(Long idProject, String name, String description, String descriptionHtml, boolean privateProject, boolean sharedProject, ProjectType type, String board) { diff --git a/src/main/java/com/parallax/server/blocklyprop/servlets/PingServlet.java b/src/main/java/com/parallax/server/blocklyprop/servlets/PingServlet.java index 60e3f863..5aa71aa9 100644 --- a/src/main/java/com/parallax/server/blocklyprop/servlets/PingServlet.java +++ b/src/main/java/com/parallax/server/blocklyprop/servlets/PingServlet.java @@ -20,7 +20,7 @@ public class PingServlet extends HttpServlet { /* - * Get user information + * Respond to a ping request */ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { diff --git a/src/main/java/com/parallax/server/blocklyprop/utils/HttpServletRequestImpl.java b/src/main/java/com/parallax/server/blocklyprop/utils/HttpServletRequestImpl.java index a51703bf..7255be5e 100644 --- a/src/main/java/com/parallax/server/blocklyprop/utils/HttpServletRequestImpl.java +++ b/src/main/java/com/parallax/server/blocklyprop/utils/HttpServletRequestImpl.java @@ -152,9 +152,12 @@ public boolean isRequestedSessionIdFromURL() { throw new UnsupportedOperationException("Not supported."); } + /* + * Depricated as of Java Servlet API version 2.1 + */ @Override public boolean isRequestedSessionIdFromUrl() { - throw new UnsupportedOperationException("Not supported."); + return this.isRequestedSessionIdFromURL(); } @Override @@ -277,9 +280,16 @@ public RequestDispatcher getRequestDispatcher(String path) { throw new UnsupportedOperationException("Not supported."); } + /* + * Depricated as of Java Servlet API version 2.1 + * + * Consider using this in it's place: + * + * servletRequest.getSession().getServletContext().getRealPath("/") + */ @Override public String getRealPath(String path) { - throw new UnsupportedOperationException("Not supported."); + return this.getSession().getServletContext().getRealPath(path); } @Override diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f3cd4ee1..aa0dd28a 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -7,7 +7,36 @@ database.dialect = MYSQL cdnfiles.baseurl = http://localhost:8080/cdn downloadfiles.baseurl = http://localhost:8080/download +offline.enabled = false +offline.downloadfiles.baseurl = http://localhost/downloads + cloudsession.baseurl = http://localhost:5011 cloudsession.server = blocklyprop -cloudcompiler.baseurl = http://localhost:5000 \ No newline at end of file +# OAuth support for Google users +oauth.google.enabled = false +oauth.google.key = hash_key_assigned_by_Google.apps.googleusercontent.com +oauth.google.secret = secret_key_hash_assigned_by_Google + +cloudcompiler.baseurl = http://localhost:5000 + +# Send monitor output to the console. Default: false +monitor.console.enabled = false + +# Console update interval (in seconds). Default: 300 +monitor.console.interval = 15 + +# : default: false (set to true to send to graphite) +monitor.graphite.enabled = false + +# : default: blocklyprop (prefix for the keys) +monitor.graphite.prefix = blocklyprop + +# : default: localhost (location of the graphite carbon server) +monitor.graphite.address = localhost + +# : default: 2003 (graphite carbon server port) +monitor.graphite.port = 2003 + +# : default: 30 (send every x seconds to graphite carbon server) +monitor.graphite.interval = 16 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 9994e8c7..8551b839 100644 --- a/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties +++ b/src/main/resources/com/parallax/server/blocklyprop/internationalization/translations.properties @@ -29,8 +29,8 @@ footer.clientdownloadlink = BlocklyProp-client # Application version numbers. application.major = 0 -application.minor = 94 -application.build = 304 +application.minor = 95 +application.build = 338 html.content_missing = Content missing @@ -121,7 +121,7 @@ project.create.previouslink = Previous project.board.activity-board = Propeller Activity Board WX project.board.s3 = Scribbler Robot project.board.heb = Hackable Electronic Badge -project.board.flip = Propeller Flip +project.board.flip = Propeller FLiP or Project Board project.board.other = Other confirm.request.title = Email confirm request @@ -247,6 +247,7 @@ category.control = Control category.operators = Operators category.operators.numbers = Numbers category.operators.strings = Strings +category.operators.arrays = Arrays category.values = Values category.input-output = Input/Output category.input-output.pin-states = Pin states @@ -264,6 +265,7 @@ category.communicate.WS2812B = RGB LEDs category.sensor-input = Sensor category.sensor-input.LSM9DS1 = LSM9DS1 IMU category.sensor-input.etape = ETape liquid level +category.sensor-input.fingerprint = Fingerprint Scanner category.sensor-input.hmc5883l = HMC5883L category.sensor-input.2axis-joystick = 2-axis Joystick category.sensor-input.memsic-2axis = Memsic 2-axis @@ -295,11 +297,12 @@ category.robot.activitybot = ActivityBot category.robot.servo-diff-drive = Servo Differential Drive category.hackable-electronic-badge = Hackable Electronic Badge category.hackable-electronic-badge.led_control = LED Control -category.hackable-electronic-badge.oled = OLED +category.hackable-electronic-badge.oled = Display category.hackable-electronic-badge.ir-communication = IR Communication -category.hackable-electronic-badge.eeprom = EEPROM +category.hackable-electronic-badge.eeprom = Memory category.hackable-electronic-badge.accelerometer = Accelerometer category.hackable-electronic-badge.touchpad-control = Touchpad Control +category.hackable-electronic-badge.text-to-speech = Text to Speech category.functions = Functions category.variables = Variables category.s3-simple = Simple Scribbler diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 00000000..3d19c558 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + ${APP_LOG_PATH}/${APP_LOG_FILE_BASE}.log + + %date %level [%thread] %logger{10} [%file:%line] %msg%n + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/includes/pageparts/editor-menu.jsp b/src/main/webapp/WEB-INF/includes/pageparts/editor-menu.jsp index 96dff12b..b855f30f 100644 --- a/src/main/webapp/WEB-INF/includes/pageparts/editor-menu.jsp +++ b/src/main/webapp/WEB-INF/includes/pageparts/editor-menu.jsp @@ -28,16 +28,22 @@ + + + + + + - + - + diff --git a/src/main/webapp/WEB-INF/properties.tld b/src/main/webapp/WEB-INF/properties.tld index de0dd926..13c238a7 100644 --- a/src/main/webapp/WEB-INF/properties.tld +++ b/src/main/webapp/WEB-INF/properties.tld @@ -9,15 +9,24 @@ 1.0 http://blocklyprop.parallax.com/properties + downloadfiles com.parallax.server.blocklyprop.jsp.Properties String getDownloadFilesBaseUrl(java.lang.String) + oauth com.parallax.server.blocklyprop.jsp.Properties boolean isOauthEnabled(java.lang.String) - \ No newline at end of file + + + + experimentalmenu + com.parallax.server.blocklyprop.jsp.Properties + boolean isExperimentalMenu(java.lang.Boolean) + + diff --git a/src/main/webapp/WEB-INF/servlet/public-profile.jsp b/src/main/webapp/WEB-INF/servlet/public-profile.jsp index 0b3a6970..14909bbf 100644 --- a/src/main/webapp/WEB-INF/servlet/public-profile.jsp +++ b/src/main/webapp/WEB-INF/servlet/public-profile.jsp @@ -20,15 +20,97 @@ : <%= request.getAttribute("screenname")%> - - - + + + - + - + + + + + Projects: + + + @@ -37,7 +119,9 @@ + <%@ include file="/WEB-INF/includes/pageparts/footer.jsp"%> +