package org.ambraproject.action.annotation;
import org.ambraproject.Constants;
import org.ambraproject.action.BaseSessionAwareActionSupport;
import org.ambraproject.util.ProfanityCheckingService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Required;
import java.util.List;
/**
* An action to create an article discussion entity (either a top-level response to an article, or a reply to another
* annotation).
* <p/>
* TODO: Pull {@link org.ambraproject.action.BaseActionSupport#addProfaneMessages} down
*/
public abstract class DiscussionAction extends BaseSessionAwareActionSupport {
private ProfanityCheckingService profanityCheckingService;
protected String commentTitle;
protected String ciStatement;
protected String comment;
protected boolean isCompetingInterest = false;
/**
* Persist the discussion entity with the data in this action's fields.
*/
protected abstract void create();
/**
* Set this action's messages in response to an error.
*
* @param e exception representing the error
*/
protected abstract void error(Exception e);
/**
* Set this action's messages to indicate success.
*/
protected abstract void success();
/**
* {@inheritDoc} Also does some profanity check for commentTitle and comment before creating the annotation.
*/
@Override
public String execute() {
if (isInvalid())
return INPUT;
try {
final List<String> profaneWordsInTitle = profanityCheckingService.validate(commentTitle);
final List<String> profaneWordsInBody = profanityCheckingService.validate(comment);
final List<String> profaneWordsCiStatement = profanityCheckingService.validate(ciStatement);
if (profaneWordsInBody.isEmpty() && profaneWordsInTitle.isEmpty() && profaneWordsCiStatement.isEmpty()) {
create();
} else {
addProfaneMessages(profaneWordsInBody, "comment", "comment");
addProfaneMessages(profaneWordsInTitle, "commentTitle", "title");
addProfaneMessages(profaneWordsCiStatement, "ciStatement", "statement");
return INPUT;
}
} catch (Exception e) {
error(e);
return ERROR;
}
success();
return SUCCESS;
}
private boolean isInvalid() {
/**
* This is a little odd that part of validation happens here and
* part of it occurs as validators on the object properties
* TODO: Revisit and recombine? Or perhaps author a generic validator that can handle
* the logic defined below
**/
boolean invalid = false;
invalid |= validateField("commentTitle", commentTitle, Constants.Length.COMMENT_TITLE_MAX,
"title", "A title is required.");
invalid |= validateField("comment", comment, Constants.Length.COMMENT_BODY_MAX,
"comment", "You must say something in your comment.");
if (this.isCompetingInterest) {
invalid |= validateField("statement", ciStatement, Constants.Length.CI_STATEMENT_MAX,
"competing interest statement", "You must say something in your competing interest statement.");
}
return invalid;
}
/**
* Add a field error if a user-submitted string was invalid.
*
* @param fieldName the identity of the field being checked
* @param fieldValue the value that the user submitted
* @param maxCharacters the maximum length of a valid value
* @param humanReadableFieldName how to describe the field to the user
* @param emptyMessage the message to show the user if the value is blank
* @return {@code true} if invalid; {@code false} if valid
*/
private boolean validateField(String fieldName, String fieldValue, int maxCharacters,
String humanReadableFieldName, String emptyMessage) {
if (StringUtils.isEmpty(fieldValue)) {
addFieldError(fieldName, emptyMessage);
return true;
}
int length = fieldValue.length();
if (length > maxCharacters) {
String lengthMessage = String.format("Your %s is %d characters long; it cannot be longer than %d characters.",
humanReadableFieldName, length, maxCharacters);
addFieldError(fieldName, lengthMessage);
return true;
}
return false;
}
/**
* Set the profanityCheckingService
*
* @param profanityCheckingService profanityCheckingService
*/
@Required
public void setProfanityCheckingService(ProfanityCheckingService profanityCheckingService) {
this.profanityCheckingService = profanityCheckingService;
}
/**
* Set the commentTitle of the annotation
*
* @param commentTitle commentTitle
*/
public void setCommentTitle(String commentTitle) {
this.commentTitle = commentTitle;
}
/**
* Set the comment of the annotation
*
* @param comment comment
*/
public void setComment(String comment) {
this.comment = comment;
}
/**
* Set the competing interest statement of the annotation
*
* @param ciStatement Statement
*/
public void setCiStatement(String ciStatement) {
this.ciStatement = ciStatement;
}
/**
* @param isCompetingInterest does this annotation have competing interests?
*/
public void setIsCompetingInterest(boolean isCompetingInterest) {
this.isCompetingInterest = isCompetingInterest;
}
}