/*
* Copyright 2011 Michele Mancioppi [michele.mancioppi@gmail.com]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cave.nice.testMessage.resources;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import cave.nice.testMessage.TestMessageConstants;
import cave.nice.testMessage.data.CannotRetrieveEntitiesException;
import cave.nice.testMessage.data.DataManager;
import cave.nice.testMessage.data.UnknownUnverifiedAccountException;
import cave.nice.testMessage.data.UnknownVerifiedAccountException;
import cave.nice.testMessage.data.UnverifiedAccount;
import cave.nice.testMessage.data.VerifiedAccount;
import cave.nice.testMessage.templates.TemplateException;
import cave.nice.testMessage.templates.TemplateManager;
import cave.nice.testMessage.templates.TemplateManager.TemplateType;
import com.google.common.collect.Maps;
@Path("/unverifiedAccounts")
public class UnverifiedAccountResource extends Resource {
@Context
private UriInfo uriInfo;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getUnverifiedAccounts() {
DataManager dataManager = getDataManager();
try {
return Response.ok(dataManager.getUnverifiedAccounts()).build();
} catch (CannotRetrieveEntitiesException e) {
// TODO Log error, not return it
throw new WebApplicationException(Response.serverError().entity(e)
.build());
} finally {
dataManager.close();
}
}
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response addUnverifiedAccount(@Context ServletContext context,
@FormParam("emailAddress") InternetAddress emailAddress)
throws WebApplicationException {
if(emailAddress == null) {
throw new MissingRequiredParameterException("emailAddress");
}
DataManager dataManager = getDataManager();
UnverifiedAccount newAccount = null;
try {
UnverifiedAccount unverifiedAccount = dataManager
.getUnverifiedAccount(emailAddress);
throw new WebApplicationException(
Response.status(Status.BAD_REQUEST)
.entity("The submitted email address '"
+ emailAddress
+ "' results already registered (but not yet verified!) since "
+ unverifiedAccount.getRegistrationDate())
.build());
} catch (UnknownUnverifiedAccountException e1) {
try {
VerifiedAccount verifiedAccount = dataManager
.getVerifiedAccount(emailAddress);
throw new WebApplicationException(Response
.status(Status.BAD_REQUEST)
.entity("The submitted email address '" + emailAddress
+ "' results already registered since "
+ verifiedAccount.getRegistrationDate())
.build());
} catch (UnknownVerifiedAccountException e) {
/*
* All right, that is how we like it ;-)
*/
try {
newAccount = dataManager
.createUnverifiedAccount(emailAddress);
performSendConfirmation(context, newAccount);
URI accountURI = uriInfo.getBaseUri().resolve(
"/resources/unverifiedAccounts/"
+ newAccount.getEmailAddress());
return Response.created(accountURI).build();
} catch (WebApplicationException e2) {
dataManager.removeAccount(newAccount);
throw e2;
}
}
} finally {
dataManager.close();
}
}
@POST
@Path("/withMethodOverride")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processMethodOvveride(@Context ServletContext context,
@FormParam("_method") String method,
@FormParam("emailAddress") InternetAddress emailAddress,
@FormParam("challenge") UUID challenge)
throws WebApplicationException {
if(method == null) {
throw new MissingRequiredParameterException("_method");
}
if(emailAddress == null) {
throw new MissingRequiredParameterException("emailAddress");
}
String methodLC = method.toLowerCase();
if (methodLC.equals("put")) {
return verifyAccount(emailAddress, challenge);
} else if (methodLC.equals("delete")) {
return deleteUnverifiedAccount(emailAddress);
}
throw new WebApplicationException(Response
.status(Status.BAD_REQUEST)
.entity("Unrecognize value for the parameter '_method': "
+ method).build());
}
@PUT
@Path("/{emailAddress}/confirmation")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response verifyAccount(
@PathParam("emailAddress") InternetAddress emailAddress,
@FormParam("challenge") UUID challenge)
throws WebApplicationException {
if (challenge == null) {
throw new WebApplicationException(Response
.status(Status.BAD_REQUEST)
.entity("Mandatory parameter 'challenge' not set").build());
}
DataManager dataManager = getDataManager();
try {
dataManager.verifyAccount(emailAddress, challenge);
return Response.ok().build();
} catch (Exception e) {
throw new WebApplicationException(
Response.status(Status.BAD_REQUEST)
.entity("Could not verify account with challenge '"
+ challenge
+ "'. Either the challenge is wrong, or the email address specified is not pending verification (it may altogether not existing in the system).")
.build());
} finally {
dataManager.close();
}
}
@POST
@Path("/{emailAddress}/verificationMessageRequest")
public void sendConfirmation(@Context ServletContext context,
@PathParam("emailAddress") InternetAddress emailAddress)
throws WebApplicationException {
DataManager dataManager = getDataManager();
try {
performSendConfirmation(context,
dataManager.getUnverifiedAccount(emailAddress));
} catch (UnknownUnverifiedAccountException e) {
throw new WebApplicationException(Status.NOT_FOUND);
} finally {
dataManager.close();
}
}
@DELETE
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response deleteUnverifiedAccount(
@FormParam("emailAddress") InternetAddress emailAddress)
throws WebApplicationException {
try {
// TODO Fix validation
emailAddress.validate();
} catch (AddressException e1) {
throw new InvalidEmailAddressException(emailAddress);
}
DataManager dataManager = getDataManager();
try {
UnverifiedAccount account = dataManager
.getUnverifiedAccount(emailAddress);
dataManager.removeAccount(account);
/*
* We return a 202 "Accepted" instead of a 204 "No content" because
* the modification could date some time to be propagated
*/
return Response.status(Status.ACCEPTED).build();
} catch (UnknownUnverifiedAccountException e) {
throw new WebApplicationException(e);
} finally {
dataManager.close();
}
}
public void performSendConfirmation(ServletContext context,
UnverifiedAccount unverifiedAccount) throws WebApplicationException {
InternetAddress appInternetAddress = null;
try {
appInternetAddress = new InternetAddress(
TestMessageConstants.NOTIFICATIONS_EMAIL_ADDRESS,
TestMessageConstants.TEST_MESSAGE_SENDER_NAME);
} catch (UnsupportedEncodingException e) {
throw new WebApplicationException(
Response.serverError()
.entity("Error while creating the app internet address using the email '"
+ TestMessageConstants.NOTIFICATIONS_EMAIL_ADDRESS
+ "' and the personal name '"
+ TestMessageConstants.TEST_MESSAGE_SENDER_NAME
+ "'").entity(e).build());
}
DataManager dataManager = getDataManager();
try {
Session session = Session
.getDefaultInstance(new Properties(), null);
String notificationMailAddress = unverifiedAccount
.getEmailAddress();
Message msg = null;
try {
msg = new MimeMessage(session);
msg.setFrom(appInternetAddress);
msg.addRecipient(Message.RecipientType.TO, new InternetAddress(
notificationMailAddress));
msg.setReplyTo(new InternetAddress[] { appInternetAddress });
msg.setSubject("Confirm the registration of your account '"
+ unverifiedAccount.getEmailAddress()
+ "' to Test Message");
msg.setContent(
getConfirmationEmail(context, unverifiedAccount),
"text/html");
Transport.send(msg);
} catch (Exception e) {
throw new WebApplicationException(Response
.status(Status.INTERNAL_SERVER_ERROR)
.entity("Error while sending the report to '"
+ notificationMailAddress + "': " + msg)
.entity(e).build());
}
} finally {
dataManager.close();
}
}
private String getConfirmationEmail(ServletContext context,
UnverifiedAccount account) throws TemplateException {
Map<String, Object> params = Maps.newHashMap();
params.put("username", getCurrentUser().getNickname());
params.put("emailAddress", account.getEmailAddress());
URI confirmationURI = uriInfo.getBaseUri().resolve(
"/confirmEmailAccount.jsp?emailAddress=" + account.getEmailAddress()
+ "&challenge=" + account.getChallenge());
params.put("confirmationUrl", confirmationURI.toString());
URI setupURI = uriInfo.getBaseUri().resolve("/instructions.jsp");
params.put("setupUrl", setupURI.toString());
return TemplateManager.getInstance(context).applyTemplate(
TemplateType.CONFIRMATION_REGISTRATION, params);
}
}