package info.interactivesystems.gamificationengine.api;
import info.interactivesystems.gamificationengine.api.exeption.ApiError;
import info.interactivesystems.gamificationengine.api.exeption.CredentialException;
import info.interactivesystems.gamificationengine.dao.AccountDAO;
import info.interactivesystems.gamificationengine.entities.Account;
import info.interactivesystems.gamificationengine.utils.SecurityTools;
import java.util.Optional;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.hibernate.validator.constraints.Email;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.rs.TypeHint;
/**
* An Account has to be created for at least one manager or developer. It
* is identified by a unique email address. The password ensures the
* identity. Optionally an account may have information about the user in form
* of her/his first name and last name.
* It is possible to change the password, the first name or last name
* at a later point of time. In addition to creating an account another
* possible request is to get the created account but only with the
* correct credentials.
* In the response of all requests the hashed password isn't returned because
* of security reasons.
*/
@Path("/account")
@Stateless
@Produces(MediaType.APPLICATION_JSON)
public class AccountApi {
private static final Logger LOGGER = LoggerFactory.getLogger(AccountApi.class);
@Inject
AccountDAO accountDao;
/**
* Creates a new account. For this an unique email address and a
* password are mandatory. By the creation of an organisation this
* email address is connected with it. Optionally the first and last
* name can also be set.
* In the response the password isn't returned because of security
* reasons.
*
* @param email
* A required valid email address.
* @param password
* Required query parameter to connect it with the given
* email address.
* @param firstName
* Optionally the first name of the Account's owner can be set.
* @param lastName
* Optionally the last name of the Account's owner can be set.
* @return A Response of Account in JSON.
*/
@POST
@Path("/")
@TypeHint(Account.class)
public Response create(@QueryParam("email") @NotNull @Email String email, @QueryParam("password") @NotNull String password,
@QueryParam("firstName") String firstName, @QueryParam("lastName") String lastName) {
LOGGER.debug("create account requested");
if(accountDao.getAccount(email)!=null){
throw new ApiError(Response.Status.FORBIDDEN, "This mail address is already used.");
}
Account account = new Account(email);
account.setPassword(SecurityTools.encryptWithSHA512(password));
account.setFirstName(firstName);
account.setLastName(lastName);
accountDao.persist(account);
LOGGER.debug("Persisted account: %s", account);
return ResponseSurrogate.created(account);
}
/**
* Returns an account corresponding to the given email address but only
* if the combination with password is correct. By the creation of an
* organisation this email address is connected with it.
* So the method requires valid credentials otherwise a warning with the
* hint for wrong credentials is returned.
* In the response the password isn't returned because of security
* reasons.
*
* @param email
* A required valid unique email address.
* @param password
* Required header parameter associated with the email address.
* @return A Response of Account in JSON.
*/
@GET
@Path("/")
@TypeHint(Account.class)
public Response get(@QueryParam("email") @NotNull @Email String email, @HeaderParam("password") @NotNull String password) {
LOGGER.debug("get account requested");
String encryptedPassword = SecurityTools.encryptWithSHA512(password);
if (!accountDao.checkCredentials(email, encryptedPassword)) {
LOGGER.warn("Account with wrong credentials (email:\"%s\", pass:\"%s\") requested", email, password);
throw new CredentialException(email);
}
Account account = accountDao.getAccount(email, encryptedPassword);
LOGGER.debug("Account requested: %s", account);
return ResponseSurrogate.of(account);
}
/**
* Updates the first and last name of an existing account. For this the
* specific email address and associated password are mandatory.
* Otherwise a warning with the hint for wrong credentials is returned.
* In the response the password isn't returned because of security
* reasons.
*
* @param email
* A required valid email address.
* @param password
* Required header parameter to connect it with the given
* email address.
* @param firstName
* Optionally the first name of the Account's owner can be set.
* @param lastName
* Optionally the last name of the Account's owner can be set.
*
* @return A Response of Account in JSON.
*/
@PUT
@Path("/")
@TypeHint(Account.class)
public Response update(@QueryParam("email") @NotNull @Email String email, @HeaderParam("password") @NotNull String password,
@QueryParam("firstName") String firstName, @QueryParam("lastName") String lastName) {
LOGGER.debug("update account requested");
String encryptedPassword = SecurityTools.encryptWithSHA512(password);
if (!accountDao.checkCredentials(email, encryptedPassword)) {
LOGGER.warn("Account with wrong credentials (email:\"%s\", pass:\"%s\") requested", email, password);
throw new CredentialException(email);
}
Account account = accountDao.getAccount(email, encryptedPassword);
Optional.ofNullable(encryptedPassword).ifPresent(account::setPassword);
Optional.ofNullable(firstName).ifPresent(account::setFirstName);
Optional.ofNullable(lastName).ifPresent(account::setLastName);
accountDao.persist(account);
LOGGER.debug("Updated account: %s", account);
return ResponseSurrogate.updated(account);
}
}