package com.QA.businessLogic;
import com.QA.*;
import net.sf.json.JSONObject;
import net.tanesha.recaptcha.ReCaptchaImpl;
import net.tanesha.recaptcha.ReCaptchaResponse;
import org.jblooming.agenda.CompanyCalendar;
import org.jblooming.oql.OqlQuery;
import org.jblooming.persistence.exceptions.*;
import org.jblooming.utilities.JSP;
import org.jblooming.utilities.StringUtilities;
import org.jblooming.waf.exceptions.ActionException;
import org.jblooming.waf.settings.ApplicationState;
import org.jblooming.waf.settings.I18n;
import org.jblooming.waf.view.PageState;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
public class QATalkAction {
PageState pageState = null;
QAOperator logged = null;
public QATalkAction() throws PersistenceException {
pageState = PageState.getCurrentPageState();
logged = (QAOperator) pageState.getLoggedOperator();
}
public JSONObject cmdLikeQuestion(JSONObject jsResponse) throws PersistenceException {
int id = pageState.getEntry("questionId").intValueNoErrorCodeNoExc();
Question question = Question.load(id);
//did you upvote it?
Upvote mine = null;
for (Upvote a : question.getUpvotes()) {
if (a.getOperator() != null && a.getOperator().equals(logged)) {
mine = a;
break;
}
}
if (mine == null) {
Upvote u = new Upvote();
u.setQuestionAndPropagate(question);
question.getUpvotes().add(u);
u.setOperator(logged);
u.store();
question.hitAndNotify(logged, QAEvent.QUESTION_UPVOTE);
}
jsResponse.element("question", question.jsonify(logged, false));
return jsResponse;
}
public JSONObject cmdUnLikeQuestion(JSONObject jsResponse) throws PersistenceException {
int id = pageState.getEntry("questionId").intValueNoErrorCodeNoExc();
Question question = Question.load(id);
Upvote mine = null;
for (Upvote a : question.getUpvotes()) {
if (a.getOperator() != null && a.getOperator().equals(logged)) {
mine = a;
break;
}
}
if (mine != null) {
question.getUpvotes().remove(mine);
mine.remove();
}
jsResponse.element("question", question.jsonify(logged, false));
return jsResponse;
}
public JSONObject cmdCommentQuestion(JSONObject jsResponse) throws PersistenceException, ActionException {
int id = pageState.getEntry("questionId").intValueNoErrorCodeNoExc();
Question question = Question.load(id);
String comm = pageState.getEntry("commentText").stringValue();
if (JSP.ex(comm)) {
Comment c = new Comment();
c.setQuestion(question);
c.setOwner(logged);
c.setText(comm);
c.store();
question.hitAndNotify(logged, QAEvent.QUESTION_COMMENT_CREATE);
jsResponse.element("comment", c.jsonify(logged));
}
return jsResponse;
}
public JSONObject cmdCommentRemove(JSONObject jsResponse) throws PersistenceException, ActionException {
int id = pageState.getEntry("commentId").intValueNoErrorCodeNoExc();
Comment c = Comment.load(id);
c.remove();
jsResponse.element("questionId", c.getQuestion().getId());
return jsResponse;
}
public JSONObject cmdReportQuestion(JSONObject jsResponse) throws PersistenceException {
int id = pageState.getEntry("questionId").intValueNoErrorCodeNoExc();
Question question = Question.load(id);
List<QAOperator> mods = QAOperator.getModerators();
String message = I18n.get("QUESTION_SIGNALLED_BY_%%", "(" + logged.getId() + ") " + logged.getDisplayName()) + ": <a href=\"" + question.getURL().toLinkToHref() + "\">" +
JSP.htmlEncodeApexesAndTags(question.getDescription()) + "</a>";
for (QAOperator mod : mods)
mod.sendNote("QUESTION_SIGNALLED", message, QAEvent.QUESTION_SIGNALLED.toString());
return jsResponse;
}
public JSONObject cmdReportComment(JSONObject jsResponse) throws PersistenceException {
int id = pageState.getEntry("commentId").intValueNoErrorCodeNoExc();
Comment comment = Comment.load(id);
List<QAOperator> mods = QAOperator.getModerators();
String message = I18n.get("COMMENT_SIGNALLED_BY_%%", "(" + logged.getId() + ") " + logged.getDisplayName()) + ": <a href=\"" + comment.getQuestion().getURL().toLinkToHref() + "\">" +
JSP.htmlEncodeApexesAndTags(comment.getText()) + "</a>";
for (QAOperator mod : mods)
mod.sendNote("COMMENT_SIGNALLED", message, QAEvent.COMMENT_SIGNALED.toString());
return jsResponse;
}
public JSONObject cmdCommentAnswer(JSONObject jsResponse) throws PersistenceException, ActionException {
int id = pageState.getEntry("answerId").intValueNoErrorCodeNoExc();
Answer question = Answer.load(id);
String comm = pageState.getEntry("commentText").stringValue();
if (JSP.ex(comm)) {
Comment c = new Comment();
c.setAnswer(question);
c.setOwner(logged);
c.setText(comm);
c.store();
question.hitAndNotify(logged, QAEvent.QUESTION_ANSWER_COMMENT_CREATE);
jsResponse.element("comment", c.jsonify(logged));
}
return jsResponse;
}
public JSONObject cmdCommentAnswerRemove(JSONObject jsResponse) throws PersistenceException, ActionException {
int id = pageState.getEntry("commentId").intValueNoErrorCodeNoExc();
Comment c = Comment.load(id);
c.remove();
jsResponse.element("answerId", c.getAnswer().getId());
return jsResponse;
}
public JSONObject cmdReportAnswerComment(JSONObject jsResponse) throws PersistenceException {
int id = pageState.getEntry("commentId").intValueNoErrorCodeNoExc();
Comment comment = Comment.load(id);
List<QAOperator> mods = QAOperator.getModerators();
String message = I18n.get("COMMENT_ANSWER_SIGNALLED_BY_%%_%%_%%", comment.getText(), "(" + logged.getId() + ")" + logged.getDisplayName(), ": <a href=\"" +
comment.getAnswer().getQuestion().getURL().toLinkToHref() + "\">" + JSP.htmlEncodeApexesAndTags(comment.getText()) + "</a>");
for (QAOperator mod : mods)
mod.sendNote("COMMENT_SIGNALLED", message, QAEvent.COMMENT_SIGNALED.toString());
return jsResponse;
}
public JSONObject cmdBanQuestion(JSONObject jsResponse) throws PersistenceException {
int id = pageState.getEntry("questionId").intValueNoErrorCodeNoExc();
Question question = Question.load(id);
if (logged.isModerator()) {
question.setDeleted(!question.isDeleted());
question.store();
}
return jsResponse;
}
public JSONObject cmdReportAnswer(JSONObject jsResponse) throws PersistenceException {
int id = pageState.getEntry("answerId").intValueNoErrorCodeNoExc();
Answer answer = Answer.load(id);
List<QAOperator> mods = QAOperator.getModerators();
String message = I18n.get("ANSWER_SIGNALLED_BY_%%", "(" + logged.getId() + ") " + logged.getDisplayName()) + ": <a href=\"" + answer.getQuestion().getURL().toLinkToHref() + "\">" +
JSP.htmlEncodeApexesAndTags(answer.getText()) + "</a>";
for (QAOperator mod : mods)
mod.sendNote("ANSWER_SIGNALLED", message, QAEvent.QUESTION_SIGNALLED.toString());
return jsResponse;
}
public JSONObject cmdBanAnswer(JSONObject jsResponse) throws PersistenceException {
int id = pageState.getEntry("answerId").intValueNoErrorCodeNoExc();
Answer answer = Answer.load(id);
if (logged.isModerator()) {
answer.setDeleted(true);
answer.store();
}
return jsResponse;
}
public Question cmdSave() throws PersistenceException, org.jblooming.security.SecurityException, ActionException {
Question question = null;
String sub = pageState.getEntryAndSetRequired("SUBJECT").stringValueNullIfEmpty();
String text = pageState.getEntryAndSetRequired("QUESTION").stringValueNullIfEmpty();
String tags = pageState.getEntryAndSetRequired("TAGS").stringValueNullIfEmpty();
boolean isNew = false;
if (pageState.mainObjectId == null) {
//create new
question = new Question();
question.testPermission(logged, QAPermission.QUESTION_CREATE);
isNew = true;
} else {
question = Question.load(pageState.mainObjectId);
question.testPermission(logged, QAPermission.QUESTION_EDIT);
}
//
if (!isNew && (question.getQuestionRevisions().size() > 0 || !logged.equals(question.getOwner()))) {
QuestionRevision qr = QuestionRevision.createRevision(question, logged);
qr.store();
question.getQuestionRevisions().add(qr);
} else {
question.setOwner(logged);
}
question.setSubject(sub);
question.setDescription(text);
//can create brand new tags?
String grace = ApplicationState.getApplicationSetting("QUESTION_GRACE");
boolean createBrandNewTags = "yes".equals(grace) || logged.isModerator() || logged.getKarma() > QAPermission.TAG_CREATE.reputationRequired;
if (JSP.ex(tags)) {
List<String> tagsL = StringUtilities.splitToList(tags, ",");
question.setTags(new ArrayList<Tag>());
for (String tagname : tagsL) {
if (createBrandNewTags) {
Tag tag1 = Tag.loadOrCreate(tagname);
question.getTags().add(tag1);
} else {
Tag tag1 = Tag.loadByName(tagname);
if (tag1 != null)
question.getTags().add(tag1);
else {
//should tell that could not be created
//pageState.addClientEntry("TAG_NOT_CREATED", JSP.w(pageState.getEntry("TAG_NOT_CREATED").stringValueNullIfEmpty()) + " " + tagname);
pageState.removeEntry("TAGS");
throw new ActionException("USE_ONLY_EXISTING_TAG");
}
}
}
} else {
if (createBrandNewTags)
throw new ActionException("MISSING_TAG");
else
throw new ActionException("PICK_A_TAG");
}
question.store();
question.hit(logged, isNew ? QAEvent.QUESTION_CREATE : QAEvent.QUESTION_EDIT);
return question;
}
public void cmdDelete() throws FindByPrimaryKeyException, RemoveException, StoreException {
Question leaf = Question.load(pageState.mainObjectId);
leaf.setDeleted(true);
leaf.store();
}
public static SearchResults findPopularQuestions(int maxResults, String filter) throws FindException {
String hqlFirstPart = "select count(upvote), question from " + Upvote.class.getName() + " as upvote where upvote.question.deleted=false and upvote.question.contentRating is null ";
String hqlSecondPart = " group by question order by count(upvote) desc, upvote.lastModified desc";
String hql = hqlFirstPart;
boolean hasFilter = JSP.ex(filter);
if (hasFilter) {
hql = hql + " and upvote.question.description like :param";
} else {
hql = hql + " and upvote.question.lastModified>:sixdays";
}
hql = hql + hqlSecondPart;
//String hql = "select sum(hit.weight), operatorId from "+ Hit.class.getName()+" as hit where hit.when>:since group by operatorId order by sum(hit.weight) desc";
OqlQuery oql = new OqlQuery(hql);
if (!hasFilter) {
CompanyCalendar cc = new CompanyCalendar();
cc.add(CompanyCalendar.MONTH, -2);
cc.setAndGetTimeToDayStart();
oql.getQuery().setTimestamp("sixdays", cc.getTime());
} else {
oql.getQuery().setString("param", "%" + filter + "%");
}
oql.getQuery().setMaxResults(maxResults + 1);
List<Object[]> os = oql.list();
SearchResults r = new SearchResults();
int inserted = 0;
for (Object[] o : os) {
Question q = (Question) o[1];
r.add(SearchResultType.QUESTION, q.getDescription(), q);
inserted++;
if (inserted > maxResults)
break;
}
r.hasMore = os.size() > maxResults;
return r;
}
public static SearchResults findQuestions(int maxResults, String filter) throws FindException {
String hqlFirstPart = "select question from " + Question.class.getName() + " as question where question.deleted=false ";
String hqlSecondPart = " order by question.totUpvotesFromQandA desc, question.lastModified desc";
String hql = hqlFirstPart;
hql = hql + " and (question.description like :param or question.subject like :param)";
hql = hql + hqlSecondPart;
OqlQuery oql = new OqlQuery(hql);
oql.getQuery().setString("param", "%" + filter + "%");
oql.getQuery().setMaxResults(maxResults + 1);
List<Question> os = oql.list();
int inserted = 0;
SearchResults r = new SearchResults();
for (Question q : os) {
r.add(SearchResultType.QUESTION, q.getDescription(), q);
inserted++;
if (inserted > maxResults)
break;
}
r.hasMore = os.size() > maxResults;
//inject comments
if (!r.hasMore) {
hqlFirstPart = "select comm from " + Comment.class.getName() + " as comm where comm.question.deleted=false ";
hqlSecondPart = " order by comm.question.totUpvotesFromQandA desc, comm.lastModified desc";
hql = hqlFirstPart;
hql = hql + " and (comm.text like :param)";
hql = hql + hqlSecondPart;
oql = new OqlQuery(hql);
oql.getQuery().setString("param", "%" + filter + "%");
oql.getQuery().setMaxResults(maxResults + 1);
List<Comment> oc = oql.list();
inserted = 0;
for (Comment c : oc) {
r.add(SearchResultType.QUESTION_COMMENT, c.getText(), c.getQuestion());
inserted++;
if (inserted > maxResults)
break;
}
}
return r;
}
public static SearchResults findHotQuestions(int maxResults, String filter) throws FindException {
String hqlFirstPart = "select count(upvote), question from " + Upvote.class.getName() + " as upvote where upvote.question.deleted=false ";
String hqlSecondPart = " group by question order by count(upvote) desc, upvote.question.lastModified desc";
String hql = hqlFirstPart;
boolean hasFilter = JSP.ex(filter);
if (hasFilter) {
hql = hql + " and upvote.question.description like :param";
} else {
hql = hql + " and upvote.question.lastModified>:sixtydays";
}
hql = hql + hqlSecondPart;
//String hql = "select sum(hit.weight), operatorId from "+ Hit.class.getName()+" as hit where hit.when>:since group by operatorId order by sum(hit.weight) desc";
OqlQuery oql = new OqlQuery(hql);
if (!hasFilter) {
CompanyCalendar cc = new CompanyCalendar();
cc.add(CompanyCalendar.MONTH, -2);
cc.setAndGetTimeToDayStart();
oql.getQuery().setTimestamp("sixtydays", cc.getTime());
} else {
oql.getQuery().setString("param", "%" + filter + "%");
}
oql.getQuery().setMaxResults(maxResults + 1);
List<Object[]> os = oql.list();
SearchResults r = new SearchResults();
int inserted = 0;
for (Object[] o : os) {
Question q = (Question) o[1];
r.add(SearchResultType.QUESTION, q.getDescription(), q);
inserted++;
if (inserted > maxResults)
break;
}
r.hasMore = os.size() > maxResults;
return r;
}
public static SearchResults findAnswers(int maxResults, String filter) throws FindException {
String hqlFirstPart = "select ans from " + Answer.class.getName() + " as ans where ans.question.deleted=false and ans.deleted=false ";
String hqlSecondPart = " order by ans.question.totUpvotesFromQandA desc, ans.question.lastModified desc";
String hql = hqlFirstPart;
hql = hql + " and ans.text like :param";
hql = hql + hqlSecondPart;
OqlQuery oql = new OqlQuery(hql);
oql.getQuery().setString("param", "%" + filter + "%");
oql.getQuery().setMaxResults(maxResults + 1);
List<Answer> os = oql.list();
int inserted = 0;
SearchResults r = new SearchResults();
for (Answer answer : os) {
r.add(SearchResultType.ANSWER, answer.getText(), answer.getQuestion());
inserted++;
if (inserted > maxResults)
break;
}
r.hasMore = os.size() > maxResults;
//inject comments
if (!r.hasMore) {
hqlFirstPart = "select comm from " + Comment.class.getName() + " as comm where comm.answer.deleted=false ";
hqlSecondPart = " order by comm.answer.totUpvotesAndAcceptance desc, comm.lastModified desc";
hql = hqlFirstPart;
hql = hql + " and (comm.text like :param)";
hql = hql + hqlSecondPart;
oql = new OqlQuery(hql);
oql.getQuery().setString("param", "%" + filter + "%");
oql.getQuery().setMaxResults(maxResults + 1);
List<Comment> oc = oql.list();
inserted = 0;
for (Comment c : oc) {
r.add(SearchResultType.ANSWER_COMMENT, c.getText(), c.getAnswer().getQuestion());
inserted++;
if (inserted > maxResults)
break;
}
}
return r;
}
public static SearchResults findTags(int maxResults, String filter) throws FindException {
String hql = "select tag from " + Tag.class.getName() + " as tag where tag.name like :filter ";
OqlQuery oql = new OqlQuery(hql);
oql.getQuery().setString("filter", "%" + filter + "%");
oql.getQuery().setMaxResults(maxResults + 1);
List<Tag> os = oql.list();
int inserted = 0;
SearchResults r = new SearchResults();
for (Tag answer : os) {
r.add(SearchResultType.TAG, answer.getName(), answer.getQuestions(1).get(0));
inserted++;
if (inserted > maxResults)
break;
}
r.hasMore = os.size() > maxResults;
return r;
}
public static SearchResults findUsers(int maxResults, String filter) throws FindException {
String hql = "select u from " + QAOperator.class.getName() + " as u where u.enabled=true AND (u.name like :filter OR u.email like :filter OR u.loginName like :filter)";
OqlQuery oql = new OqlQuery(hql);
oql.getQuery().setString("filter", "%" + filter + "%");
oql.getQuery().setMaxResults(maxResults + 1);
List<QAOperator> os = oql.list();
int inserted = 0;
SearchResults r = new SearchResults();
for (QAOperator answer : os) {
r.add(SearchResultType.USER, answer.getId()+"", null);
inserted++;
if (inserted > maxResults)
break;
}
r.hasMore = os.size() > maxResults;
return r;
}
public static SearchResults search(int maxResults, String filter) throws FindException {
SearchResults sr = findQuestions(maxResults, filter);
int remainingToSearch = maxResults - sr.searchResults.size();
if (!sr.hasMore && remainingToSearch > 0) {
SearchResults sra = findAnswers(maxResults, filter);
sr.searchResults.addAll(sra.searchResults);
remainingToSearch = remainingToSearch - sra.searchResults.size();
if (!sra.hasMore && remainingToSearch > 0) {
SearchResults srt = findTags(maxResults, filter);
sr.searchResults.addAll(srt.searchResults);
}
}
SearchResults sru = findUsers(maxResults, filter);
sr.searchResults.addAll(sru.searchResults);
return sr;
}
public JSONObject cmdAcceptAnswer(JSONObject jsResponse) throws FindByPrimaryKeyException, StoreException {
int id = pageState.getEntry("answerId").intValueNoErrorCodeNoExc();
Answer a = Answer.load(id);
Question question = a.getQuestion();
if (question.getOwner().equals(logged) || logged.hasPermissionAsAdmin() ) {
a.setAsAccepted();
a.store();
question.store();
if (!question.getOwner().equals(a.getOwner()))
a.hitAndNotify(question.getOwner(), QAEvent.QUESTION_ANSWER_ACCEPT);
jsResponse.element("answer", a.jsonify(logged, false));
}
return jsResponse;
}
public JSONObject cmdRefuteAnswer(JSONObject jsResponse) throws FindByPrimaryKeyException, StoreException {
int id = pageState.getEntry("answerId").intValueNoErrorCodeNoExc();
Answer a = Answer.load(id);
Question question = a.getQuestion();
if (question.getOwner().equals(logged) || logged.hasPermissionAsAdmin()) {
a.setAsRefuted();
a.store();
question.store();
jsResponse.element("answer", a.jsonify(logged, false));
}
return jsResponse;
}
public JSONObject cmdLikeAnswer(JSONObject jsResponse) throws FindByPrimaryKeyException, StoreException {
int id = pageState.getEntry("answerId").intValueNoErrorCodeNoExc();
Answer answer = Answer.load(id);
//did you upvote it?
Upvote mine = null;
for (Upvote a : answer.getUpvotes()) {
if (a.getOperator() != null && a.getOperator().equals(logged)) {
mine = a;
break;
}
}
if (mine == null) {
Upvote u = new Upvote();
u.setAnswerAndPropagate(answer);
answer.getUpvotes().add(u);
u.setOperator(logged);
u.store();
answer.hitAndNotify(logged, QAEvent.QUESTION_ANSWER_UPVOTE);
}
jsResponse.element("answer", answer.jsonify(logged, false));
return jsResponse;
}
public JSONObject cmdUnLikeAnswer(JSONObject jsResponse) throws PersistenceException {
int id = pageState.getEntry("answerId").intValueNoErrorCodeNoExc();
Answer answer = Answer.load(id);
Upvote mine = null;
for (Upvote a : answer.getUpvotes()) {
if (a.getOperator() != null && a.getOperator().equals(logged)) {
mine = a;
break;
}
}
if (mine != null) {
answer.getUpvotes().remove(mine);
mine.remove();
}
jsResponse.element("answer", answer.jsonify(logged, false));
return jsResponse;
}
public void cmdSaveAnswer(HttpServletRequest request) throws FindByPrimaryKeyException, ActionException, StoreException {
Question q = Question.load(pageState.mainObjectId);
QAOperator logged = (QAOperator) pageState.getLoggedOperator();
String text = pageState.getEntry("yourAnswer").stringValueNullIfEmpty();
if (!JSP.ex(text) || text.trim().length()<20) {
throw new ActionException("QA_ANSWER_TOO_SHORT");
}
Answer a = null;
boolean isNew = true;
int aId = pageState.getEntry("ANSWER_ID").intValueNoErrorCodeNoExc();
if (aId > 0) {
a = Answer.load(aId);
isNew = false;
}
if (logged != null && JSP.ex(text) &&
(((a != null && a.hasPermissionFor(logged, QAPermission.ANSWER_EDIT))) || q.hasPermissionFor(logged, QAPermission.ANSWER_CREATE))
) {
boolean recaptchaNeeded = !("yes".equals(pageState.getSessionState().getAttribute("PASSED_RECAPTCHA"))) && !q.hasPermissionFor(logged, QAPermission.ANSWER_CREATE_NO_RECAPTCHA);
boolean isResponseCorrect = false;
if (recaptchaNeeded) {
ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
reCaptcha.setPrivateKey("6Lc0hQwAAAAAAGxnyfgUo8o5-4NHdiOJ7H5TEGY-");
String challenge = pageState.getEntry("recaptcha_challenge_field").stringValue();
String uresponse = pageState.getEntry("recaptcha_response_field").stringValue();
if (JSP.ex(challenge, uresponse)) {
ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(request.getRemoteAddr(), challenge, uresponse);
isResponseCorrect = reCaptchaResponse.isValid();
}
}
if (!recaptchaNeeded || isResponseCorrect) {
if (isResponseCorrect)
pageState.getSessionState().setAttribute("PASSED_RECAPTCHA", "yes");
if (a == null)
a = new Answer();
a.setQuestion(q);
if (!isNew && (a.getAnswerRevision().size() > 0 || !logged.equals(a.getOwner()))) {
AnswerRevision qr = AnswerRevision.createRevision(a, logged);
qr.store();
a.getAnswerRevision().add(qr);
} else {
a.setOwner(logged);
}
a.setText(text);
a.store();
q.hitAndNotify(logged, QAEvent.QUESTION_ANSWER_CREATE);
pageState.removeEntry("yourAnswer");
pageState.removeEntry("ANSWER_ID");
pageState.addClientEntry("HAPPILY_JUST_SAVED", "yes");
} else {
pageState.getEntry("recaptcha_response_field").errorCode = "RECAPTCHA_FAIL";
}
}
}
public static class SearchResults {
public boolean hasMore = false;
public List<SearchResult> searchResults = new ArrayList();
public void add(SearchResultType type, String abstractz, Question q) {
SearchResult s = new SearchResult();
s.type = type;
s.abstractz = abstractz;
s.reference = q;
searchResults.add(s);
}
}
public enum SearchResultType {QUESTION, QUESTION_COMMENT, ANSWER, ANSWER_COMMENT, TAG, USER};
public static class SearchResult {
public String abstractz;
public SearchResultType type;
public Question reference;
}
}