diff --git a/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java b/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java index 71c58c1aa7f6ada6dd27a6831e02380f41cd9398..3392a85aeda56ffa4affd1c777d0a874412d8709 100755 --- a/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java +++ b/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java @@ -55,20 +55,7 @@ import javax.validation.ConstraintViolationException; import javax.ws.rs.core.HttpHeaders; import no.nibio.vips.logic.authenticate.PasswordValidationException; -import no.nibio.vips.logic.entity.Country; -import no.nibio.vips.logic.entity.ForecastConfiguration; -import no.nibio.vips.logic.entity.MapLayer; -import no.nibio.vips.logic.entity.MessageLocale; -import no.nibio.vips.logic.entity.Observation; -import no.nibio.vips.logic.entity.Organization; -import no.nibio.vips.logic.entity.OrganizationGroup; -import no.nibio.vips.logic.entity.PointOfInterest; -import no.nibio.vips.logic.entity.UserAuthentication; -import no.nibio.vips.logic.entity.UserAuthenticationPK; -import no.nibio.vips.logic.entity.UserAuthenticationType; -import no.nibio.vips.logic.entity.UserUuid; -import no.nibio.vips.logic.entity.UserUuidPK; -import no.nibio.vips.logic.entity.VipsLogicUser; +import no.nibio.vips.logic.entity.*; import no.nibio.vips.logic.entity.misc.UserResources; import no.nibio.vips.logic.i18n.SessionLocaleUtil; import no.nibio.vips.logic.messaging.MessagingBean; @@ -143,6 +130,10 @@ public class UserBean { return null; } } + + public VipsLogicRole getVipsLogicRole(Integer vipsLogicRoleId){ + return em.find(VipsLogicRole.class, vipsLogicRoleId); + } /** * Gets a user with get given userName and type of authentication diff --git a/src/main/java/no/nibio/vips/logic/service/LogicService.java b/src/main/java/no/nibio/vips/logic/service/LogicService.java index 8e424b9065f83dc0a7ee64564f8c7969658ca454..7335b48ee2af97db528261d645e871abd2e7230d 100755 --- a/src/main/java/no/nibio/vips/logic/service/LogicService.java +++ b/src/main/java/no/nibio/vips/logic/service/LogicService.java @@ -19,30 +19,27 @@ package no.nibio.vips.logic.service; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.ibm.icu.util.ULocale; import com.webcohesion.enunciate.metadata.Facet; import com.webcohesion.enunciate.metadata.rs.TypeHint; -import java.util.TimeZone; + +import java.io.IOException; +import java.util.*; + import de.micromata.opengis.kml.v_2_2_0.Kml; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.logging.Logger; import java.util.stream.Collectors; import javax.ejb.EJB; +import javax.persistence.NonUniqueResultException; import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; +import javax.ws.rs.*; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.WebTarget; @@ -53,37 +50,25 @@ import javax.ws.rs.core.Response.Status; import no.nibio.vips.coremanager.service.ManagerResource; import no.nibio.vips.entity.WeatherObservation; import no.nibio.vips.logic.authenticate.PasswordValidationException; -import no.nibio.vips.logic.controller.session.ForecastBean; -import no.nibio.vips.logic.controller.session.MessageBean; -import no.nibio.vips.logic.controller.session.OrganismBean; -import no.nibio.vips.logic.controller.session.PointOfInterestBean; -import no.nibio.vips.logic.controller.session.UserBean; -import no.nibio.vips.logic.entity.CropCategory; -import no.nibio.vips.logic.entity.CropPest; -import no.nibio.vips.logic.entity.ForecastResult; +import no.nibio.vips.logic.controller.servlet.UserController; +import no.nibio.vips.logic.controller.session.*; +import no.nibio.vips.logic.entity.*; import no.nibio.vips.logic.i18n.SessionLocaleUtil; -import no.nibio.vips.logic.entity.ForecastConfiguration; -import no.nibio.vips.logic.entity.ForecastModelConfiguration; -import no.nibio.vips.logic.entity.Message; -import no.nibio.vips.logic.entity.MessageTag; -import no.nibio.vips.logic.entity.ModelInformation; -import no.nibio.vips.logic.entity.Organism; -import no.nibio.vips.logic.entity.Organization; -import no.nibio.vips.logic.entity.PointOfInterest; -import no.nibio.vips.logic.entity.PointOfInterestType; -import no.nibio.vips.logic.entity.PointOfInterestWeatherStation; -import no.nibio.vips.logic.entity.VipsLogicUser; +import no.nibio.vips.logic.util.Globals; import no.nibio.vips.logic.util.SystemTime; import no.nibio.vips.observationdata.ObservationDataBean; import no.nibio.vips.util.CSVPrintUtil; import no.nibio.vips.util.ServletUtil; import no.nibio.vips.util.SolarRadiationUtil; +import no.nibio.web.forms.FormValidationException; import org.jboss.resteasy.annotations.GZIP; import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; import org.jboss.resteasy.spi.HttpRequest; +import org.apache.commons.validator.routines.EmailValidator; + /** - * @copyright 2013-2022 <a href="http://www.nibio.no/">NIBIO</a> + * @copyright 2013-2023 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ @Path("rest") @@ -1337,6 +1322,139 @@ public class LogicService { return retVal != null ? Response.ok().entity(retVal).build() : Response.status(Response.Status.NOT_FOUND).entity("ERROR: Could not find model with id=" + modelId).build(); } + + + /** + * Registers a user and grants limited access to certain functionalities in the VIPSLogic system: + * <ul> + * <li>Adding observations - default not approved</li> + * <li>Adding POIs (Points Of Interest)</li> + * </ul> + * The user must be approved + * @param userInfoBody + * @return + */ + @POST + @Path("user/register") + @Consumes("application/json;charset=UTF-8") + @Produces("application/json;charset=UTF-8") + public Response registerNewLimitedUser(String userInfoBody) + { + + try { + HashMap<String, Object> userInfo = new ObjectMapper().readValue(userInfoBody, new TypeReference<HashMap<String, Object>>() { + }); + // Input control + List<String> errorMessages = new ArrayList<>(); + // Email + + String email = ((String) userInfo.get("email")).toLowerCase(); + // Set? + if(email == null || email.isBlank()) + { + errorMessages.add("Email must be set"); + } + // Must be valid email + else if(!EmailValidator.getInstance().isValid(email)) + { + errorMessages.add(email + " is not a valid email address"); + } + else + { + // Must be unique + Boolean emailAlreadyInUse = false; + try { + VipsLogicUser foundUser = userBean.getUserByEmail(email); + emailAlreadyInUse = (foundUser != null); + } catch (NonUniqueResultException ex) { + emailAlreadyInUse = true; + } + if (emailAlreadyInUse) { + errorMessages.add("Email " + email + " is already in use"); + } + } + + // Username + String username = (String) userInfo.get("username"); + // Set? + if(username == null || username.isBlank()) + { + errorMessages.add("Username must be set"); + } + else + { + // Existing username? + Boolean usernameExists = false; + try + { + VipsLogicUser foundUser = userBean.getUser(username, UserAuthenticationType.TYPE_PASSWORD); + usernameExists = (foundUser != null); + } + catch(NonUniqueResultException ex) + { + usernameExists = true; + } + if(usernameExists) + { + errorMessages.add("Username " + username + " already exists"); + } + } + + // First name + String firstName = (String) userInfo.get("firstName"); + if(firstName == null || firstName.isBlank()) + { + errorMessages.add("First name must be set"); + } + + // Last name + String lastName = (String) userInfo.get("lastName"); + if(lastName == null || lastName.isBlank()) + { + errorMessages.add("Last name must be set"); + } + + + // Password + String password = (String) userInfo.get("password"); + if(password == null || password.isBlank()) + { + errorMessages.add("Password must be set"); + } + + if(errorMessages.size() > 0) + { + Map<String, List<String>> errorMsg = Map.of("errorMessages",errorMessages); + return Response.status(Status.BAD_REQUEST).entity(errorMsg).build(); + } + + VipsLogicUser user = new VipsLogicUser(); + user.setFirstName(firstName.trim()); + user.setLastName(lastName.trim()); + user.setEmail(email.trim()); + user.setPhoneCountryCode((String) userInfo.get("phoneCountryCode")); + user.setPreferredLocale((String) userInfo.get("preferredLocale")); + user.setOrganizationId(userBean.getOrganization((Integer) userInfo.get("organizationId"))); + user.setApprovalApplication("Registered in app"); + user.setUserStatusId(Globals.USER_STATUS_AWAITING_EMAIL_VERIFICATION); + // Add observer role + user.setVipsLogicRoles(Set.of(userBean.getVipsLogicRole(VipsLogicRole.OBSERVER))); + // Set user authentication + UserAuthenticationType uat = userBean.createUserAuthenticationTypeInstance(UserAuthenticationType.TYPE_PASSWORD); + UserAuthentication ua = new UserAuthentication(); + ua.setUserAuthenticationType(uat); + ua.setUsername(username.trim()); + ua.setPassword(userBean.getMD5EncryptedString(password.trim())); + userBean.storeUserFirstTime(user, ua); + userBean.sendUserEmailVerification(user, SessionLocaleUtil.getI18nBundle(httpServletRequest), ServletUtil.getServerName(httpServletRequest)); + + return Response.status(Status.OK).entity(user).build(); + } + catch(FormValidationException | IOException ex) + { + return Response.status(Status.BAD_REQUEST).entity("INPUT ERROR: " + ex.getMessage()).build(); + } + } /** * Get the client to use for calling VIPSCoreManager REST services programmatically