diff --git a/.gitignore b/.gitignore index 9ea8c7c44..3b3797eae 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ src/main/webapp/font/ src/main/webapp/js/jquery/jquery-plugins*.js versions.txt /target +jsp-compilation diff --git a/pom.xml b/pom.xml index 5037cc4e3..d2758c458 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ br.com.caelum vraptor - 4.0.0-beta-3-SNAPSHOT + 4.0.0-beta-3 org.hamcrest @@ -42,17 +42,13 @@ org.hamcrest hamcrest-integration - - guava - com.google.guava - - - org.jboss.weld.servlet - weld-servlet - 2.1.0.Final - + + org.jboss.weld.servlet + weld-servlet + 2.1.0.Final + @@ -133,6 +129,7 @@ + @@ -158,9 +155,9 @@ 5.0.0.Final - org.hibernate - hibernate-validator-cdi - 5.0.0.Final + org.hibernate + hibernate-validator-cdi + 5.0.0.Final org.hibernate @@ -391,6 +388,12 @@ + + br.com.caelum.vraptor + vraptor-test + 2.0.0 + test + junit junit @@ -445,6 +448,11 @@ + + org.jsoup + jsoup + 1.7.3 + @@ -635,7 +643,8 @@ - + org.eclipse.m2e lifecycle-mapping diff --git a/src/integration/java/br/com/caelum/brutal/integration/scene/EditAnswerTest.java b/src/integration/java/br/com/caelum/brutal/integration/scene/EditAnswerTest.java deleted file mode 100644 index cb5502763..000000000 --- a/src/integration/java/br/com/caelum/brutal/integration/scene/EditAnswerTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package br.com.caelum.brutal.integration.scene; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -import br.com.caelum.brutal.integration.pages.QuestionPage; - -public class EditAnswerTest extends AuthenticatedAcceptanceTest { - - @Test - public void should_edit_answer_of_other_author() throws Exception { - loginAsModerator(); - home().toNewQuestionPage().newQuestion("question question question question", - "description description description description description", "java") - .answer("answer answer answer answer answer answer answer answer"); - logout(); - - loginWithALotOfKarma(); - - QuestionPage questionPage = home().toFirstQuestionPage() - .toEditFirstAnswerPage() - .edit("new answer with more than 30 characters aw yeah !!!", - "any comment"); - - boolean containsConfirmationMessage = questionPage - .confirmationMessages() - .contains(message("status.pending")); - - assertTrue(containsConfirmationMessage); - } - - @Test - public void should_edit_and_automatically_approve_author_edit() throws Exception { - loginWithALotOfKarma(); - - String newDescription = "my new description of the first answer also with more than 30 characters"; - home().toNewQuestionPage() - .newQuestion("question title question title question title", - "question description question description question description question description ", - "java") - .answer("my new answer with more than 30 characters hahahahaha"); - QuestionPage questionPage = home().toFirstQuestionPage() - .toEditFirstAnswerPage() - .edit(newDescription, "'cause I have to test it"); - - boolean firstAnswerHasDescription = questionPage.firstAnswerHasDescription(newDescription); - - boolean containsConfirmationMessage = questionPage.confirmationMessages() - .contains(message("status.no_need_to_approve")); - - assertTrue(firstAnswerHasDescription); - assertTrue(containsConfirmationMessage); - } - - @Test - public void should_edit_and_automatically_approve_moderator() throws Exception { - loginWithALotOfKarma(); - home().toNewQuestionPage() - .newQuestion("question title question title question title", - "question description question description question description question description ", - "java") - .answer("my new answer with more than 30 characters hahahahaha"); - logout(); - loginAsModerator(); - - String newDescription = "yeah yeah yeah yeah yeah yeah yeah yeah"; - QuestionPage questionPage = home().toFirstQuestionWithAnswerPage() - .toEditFirstAnswerPage() - .edit(newDescription,"'cause I need to test it!"); - - questionPage.confirmationMessages().contains(message("status.no_need_to_approve")); - questionPage.firstAnswerHasDescription(newDescription); - } -} diff --git a/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/AnswerQuestionTest.java b/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/AnswerQuestionTest.java new file mode 100644 index 000000000..da59d59b6 --- /dev/null +++ b/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/AnswerQuestionTest.java @@ -0,0 +1,81 @@ +package br.com.caelum.brutal.integration.scene.vraptor; + +import static br.com.caelum.vraptor.test.http.Parameters.initWith; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.jsoup.select.Elements; +import org.junit.Assert; +import org.junit.Test; + +import br.com.caelum.brutal.model.Answer; +import br.com.caelum.brutal.model.AnswerAndVotes; +import br.com.caelum.brutal.model.Question; +import br.com.caelum.vraptor.test.VRaptorTestResult; +import br.com.caelum.vraptor.test.requestflow.UserFlow; + +public class AnswerQuestionTest extends CustomVRaptorIntegration { + + @Test + public void should_answer_when_logged_in() { + Question question = createQuestionWithDao(moderator(), + "Titulo da questao hahaha", + "Descricao da questao longa demais", tag("java")); + + String description = "Resposta da questao do teste de edicao"; + + UserFlow navigation = login(navigate(), "karma.nigga@caelum.com.br"); + navigation = answerQuestionWithFlow(navigation, question, description, false); + + VRaptorTestResult questionAnswered = navigation.followRedirect().execute(); + questionAnswered.wasStatus(200).isValid(); + + AnswerAndVotes answerAndVotes = questionAnswered.getObject("answers"); + List answers = new ArrayList(answerAndVotes.getVotes().keySet()); + Assert.assertEquals(description, answers.get(0).getDescription()); + } + + @Test + public void should_not_display_answer_form_when_not_logged_in() { + Question question = createQuestionWithDao(moderator(), + "Titulo da questao hahaha", + "Descricao da questao longa demais", tag("java")); + + UserFlow navigation = goToQuestionPage(navigate(), question); + + VRaptorTestResult questionPage = navigation.followRedirect().execute(); + questionPage.wasStatus(200).isValid(); + + Elements answerForm = getElementsByClass(questionPage.getResponseBody(), "answer-form"); + assertTrue(answerForm.isEmpty()); + } + + @Test + public void should_not_display_answer_form_when_already_answered() { + Question question = createQuestionWithDao(moderator(), + "Titulo da questao hahaha", + "Descricao da questao longa demais", tag("java")); + + answerQuestionWithDao(karmaNigga(), question, + "Resposta da questao do teste de edicao", false); + + UserFlow navigation = login(navigate(), "karma.nigga@caelum.com.br"); + navigation = goToQuestionPage(navigation, question); + + VRaptorTestResult questionPage = navigation.followRedirect().execute(); + questionPage.wasStatus(200).isValid(); + + Elements answerForm = getElementsByClass(questionPage.getResponseBody(), "answer-form"); + assertTrue(answerForm.isEmpty()); + } + + private UserFlow goToQuestionPage(UserFlow navigation, Question question) { + String url = String.format("/%s-mock", question.getId()); + return navigation.get(url, + initWith("question", question) + .add("sluggedTitle", question.getSluggedTitle())); + } + +} diff --git a/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/CommentAnswerTest.java b/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/CommentAnswerTest.java new file mode 100644 index 000000000..ab43aaca4 --- /dev/null +++ b/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/CommentAnswerTest.java @@ -0,0 +1,11 @@ +package br.com.caelum.brutal.integration.scene.vraptor; + +import org.junit.Test; + +public class CommentAnswerTest extends CustomVRaptorIntegration { + + @Test + public void should_comment_answer_after_login() throws Exception { + + } +} diff --git a/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/CustomVRaptorIntegration.java b/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/CustomVRaptorIntegration.java new file mode 100644 index 000000000..aeecc307c --- /dev/null +++ b/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/CustomVRaptorIntegration.java @@ -0,0 +1,198 @@ +package br.com.caelum.brutal.integration.scene.vraptor; + +import static br.com.caelum.vraptor.test.http.Parameters.initWith; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import org.hibernate.Session; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.select.Elements; + +import br.com.caelum.brutal.builder.QuestionBuilder; +import br.com.caelum.brutal.dao.AnswerDAO; +import br.com.caelum.brutal.dao.InvisibleForUsersRule; +import br.com.caelum.brutal.dao.LoginMethodDAO; +import br.com.caelum.brutal.dao.QuestionDAO; +import br.com.caelum.brutal.dao.TagDAO; +import br.com.caelum.brutal.dao.UserDAO; +import br.com.caelum.brutal.integration.util.AppMessages; +import br.com.caelum.brutal.model.Answer; +import br.com.caelum.brutal.model.AnswerInformation; +import br.com.caelum.brutal.model.LoggedUser; +import br.com.caelum.brutal.model.LoginMethod; +import br.com.caelum.brutal.model.Question; +import br.com.caelum.brutal.model.Tag; +import br.com.caelum.brutal.model.User; +import br.com.caelum.brutal.util.DataImport; +import br.com.caelum.brutal.util.ScriptSessionCreator; +import br.com.caelum.vraptor.environment.ServletBasedEnvironment; +import br.com.caelum.vraptor.test.VRaptorIntegration; +import br.com.caelum.vraptor.test.VRaptorTestResult; +import br.com.caelum.vraptor.test.requestflow.UserFlow; +import br.com.caelum.vraptor.validator.I18nMessage; + +public class CustomVRaptorIntegration extends VRaptorIntegration { + + private static boolean runDataImport = true; + private Session session; + + private AppMessages messages = new AppMessages(); + private Random randomizer = new Random(); + + { + System.setProperty(ServletBasedEnvironment.ENVIRONMENT_PROPERTY, "acceptance"); + if (runDataImport) { + try { + new DataImport().run(); + } catch (IOException e) { + e.printStackTrace(); + } + runDataImport = false; + } + ScriptSessionCreator sessionFactoryCreator = new ScriptSessionCreator(); + session = sessionFactoryCreator.getSession(); + session.beginTransaction(); + } + + protected String message(String key) { + return messages.getMessage(key); + } + + protected List messagesList(VRaptorTestResult result) { + List confirmationMessages = result.getObject("messages"); + List messages = new ArrayList<>(); + for (I18nMessage message : confirmationMessages) { + messages.add(message.getMessage()); + } + return messages; + } + + protected Elements getElementsByClass(String html, String cssClass) { + Document document = Jsoup.parse(html); + Elements elements = document.getElementsByClass(cssClass); + return elements; + } + + /*** USER FLOW LOGIC ***/ + protected UserFlow logout(UserFlow navigation) { + return navigation.post("/logout"); + } + + protected UserFlow login(UserFlow navigation, String email) { + return navigation.post("/login", + initWith("email", email).add("password", "123456")); + } + + protected User randomUser() { + String email = String.format("acceptance%f@brutal.com", randomizer.nextFloat()); + User user = new User("Acceptance Test User", email); + LoginMethod brutalLogin = LoginMethod.brutalLogin(user, email, "123456"); + user.add(brutalLogin); + userDao().save(user); + new LoginMethodDAO(session).save(brutalLogin); + + return user; + } + + protected UserFlow createQuestionWithFlow(UserFlow navigation, + String title, String description, String tagNames, boolean watching) { + return navigation.post("/perguntar", + initWith("title", title) + .add("description", description) + .add("tagNames", tagNames) + .add("watching", watching)); + } + + protected UserFlow editQuestionWithFlow(UserFlow navigation, + Long questionId, String title, String description, String comment, + String tags) { + String url = String.format("/pergunta/editar/%s", questionId); + return navigation.post(url, + initWith("title", title) + .add("description", description) + .add("comment", comment) + .add("tagNames", tags)); + } + + protected UserFlow answerQuestionWithFlow(UserFlow navigation, Question question, + String description, boolean watching) { + String url = String.format("/responder/%s", question.getId()); + return navigation.post(url, + initWith("question", question) + .add("description", description) + .add("watching", watching)); + } + + protected UserFlow editAnswerWithFlow(UserFlow navigation, Answer answer, + String description, String comment) { + String url = String.format("/resposta/editar/%s", answer.getId()); + return navigation.post(url, + initWith("original", answer) + .add("description", description) + .add("comment", comment)); + } + + /*** DAO LOGIC ***/ + protected QuestionDAO questionDao() { + InvisibleForUsersRule invisible = new InvisibleForUsersRule(new LoggedUser(null, null)); + return new QuestionDAO(session, invisible); + } + + protected AnswerDAO answerDao() { + InvisibleForUsersRule invisible = new InvisibleForUsersRule(new LoggedUser(null, null)); + return new AnswerDAO(session, invisible); + } + + protected void commit() { + session.getTransaction().commit(); + session.beginTransaction(); + } + + protected UserDAO userDao() { + return new UserDAO(session); + } + + protected Tag tag(String name) { + return new TagDAO(this.session).findByName(name); + } + + protected User moderator() { + return userDao().findByMailAndPassword("moderator@caelum.com.br", "123456"); + } + + protected User karmaNigga() { + return userDao().findByMailAndPassword("karma.nigga@caelum.com.br", + "123456"); + } + + protected User user(String email) { + return userDao().findByMailAndPassword(email, "123456"); + } + + protected Question createQuestionWithDao(User author, String title, + String description, Tag... tags) { + Question question = new QuestionBuilder().withTitle(title) + .withDescription(description).withTags(Arrays.asList(tags)) + .withAuthor(author).build(); + questionDao().save(question); + commit(); + return question; + } + + protected Answer answerQuestionWithDao(User author, Question question, + String description, boolean watching) { + LoggedUser loggedUser = new LoggedUser(author, null); + AnswerInformation information = new AnswerInformation(description, + loggedUser, "new answer"); + Answer answer = new Answer(information, question, author); + answerDao().save(answer); + commit(); + return answer; + } + +} diff --git a/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/EditAnswerTest.java b/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/EditAnswerTest.java new file mode 100644 index 000000000..a3a5a5784 --- /dev/null +++ b/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/EditAnswerTest.java @@ -0,0 +1,94 @@ +package br.com.caelum.brutal.integration.scene.vraptor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import br.com.caelum.brutal.model.Answer; +import br.com.caelum.brutal.model.AnswerAndVotes; +import br.com.caelum.brutal.model.Question; +import br.com.caelum.vraptor.test.VRaptorTestResult; +import br.com.caelum.vraptor.test.requestflow.UserFlow; + +public class EditAnswerTest extends CustomVRaptorIntegration { + + @Test + public void should_edit_answer_of_other_author() throws Exception { + Question question = createQuestionWithDao(moderator(), + "Titulo da questao hahaha", + "Descricao da questao longa demais", tag("java")); + + Answer answer = answerQuestionWithDao(moderator(), question, + "Resposta da questao do teste de edicao", false); + + String newDescription = "my new description of the first answer"; + + UserFlow navigation = login(navigate(), "karma.nigga@caelum.com.br"); + navigation = editAnswerWithFlow(navigation, answer, newDescription, + "comment"); + + VRaptorTestResult answerEdited = navigation.followRedirect().execute(); + answerEdited.wasStatus(200).isValid(); + + List messagesList = messagesList(answerEdited); + assertTrue(messagesList.contains(message("status.pending"))); + } + + @Test + public void should_edit_and_automatically_approve_author_edit() + throws Exception { + Question question = createQuestionWithDao(moderator(), + "Titulo da questao hahaha", + "Descricao da questao longa demais", tag("java")); + + Answer answer = answerQuestionWithDao(karmaNigga(), question, + "Resposta da questao do teste de edicao", false); + + String newDescription = "my new description of the first answer"; + + UserFlow navigation = login(navigate(), "karma.nigga@caelum.com.br"); + navigation = editAnswerWithFlow(navigation, answer, newDescription, + "comment"); + + VRaptorTestResult answerEdited = navigation.followRedirect().execute(); + answerEdited.wasStatus(200).isValid(); + + List messagesList = messagesList(answerEdited); + assertTrue(messagesList.contains(message("status.no_need_to_approve"))); + + AnswerAndVotes answerAndVotes = answerEdited.getObject("answers"); + List answers = new ArrayList(answerAndVotes.getVotes().keySet()); + assertEquals(newDescription, answers.get(0).getDescription()); + } + + @Test + public void should_edit_and_automatically_approve_moderator() throws Exception { + Question question = createQuestionWithDao(moderator(), + "Titulo da questao hahaha", + "Descricao da questao longa demais", tag("java")); + + Answer answer = answerQuestionWithDao(karmaNigga(), question, + "Resposta da questao do teste de edicao", false); + + String newDescription = "my new description of the first answer"; + + UserFlow navigation = login(navigate(), "moderator@caelum.com.br"); + navigation = editAnswerWithFlow(navigation, answer, newDescription, + "comment"); + + VRaptorTestResult answerEdited = navigation.followRedirect().execute(); + answerEdited.wasStatus(200).isValid(); + + List messagesList = messagesList(answerEdited); + assertTrue(messagesList.contains(message("status.no_need_to_approve"))); + + AnswerAndVotes answerAndVotes = answerEdited.getObject("answers"); + List answers = new ArrayList(answerAndVotes.getVotes().keySet()); + assertEquals(newDescription, answers.get(0).getDescription()); + } + +} diff --git a/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/EditQuestionTest.java b/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/EditQuestionTest.java new file mode 100644 index 000000000..e6e895dce --- /dev/null +++ b/src/integration/java/br/com/caelum/brutal/integration/scene/vraptor/EditQuestionTest.java @@ -0,0 +1,105 @@ +package br.com.caelum.brutal.integration.scene.vraptor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.jsoup.select.Elements; +import org.junit.Ignore; +import org.junit.Test; + +import br.com.caelum.brutal.model.Question; +import br.com.caelum.brutal.model.User; +import br.com.caelum.vraptor.test.VRaptorTestResult; +import br.com.caelum.vraptor.test.requestflow.UserFlow; + +public class EditQuestionTest extends CustomVRaptorIntegration { + + @Test + public void should_edit_question_of_other_author() throws Exception { + Question question = createQuestionWithDao(moderator(), + "Title title title title title title title", + "Description description description description description", tag("java")); + + String newTitle = "NEW title title title title title title title"; + String newDescription = "NEW description description description description description"; + UserFlow navigation = login(navigate(), "karma.nigga@caelum.com.br"); + navigation = editQuestionWithFlow(navigation, question.getId(), + newTitle, newDescription, "edited question woots!", "java"); + + VRaptorTestResult editedQuestion = navigation.followRedirect().execute(); + editedQuestion.wasStatus(200).isValid(); + + List messagesList = messagesList(editedQuestion); + assertTrue(messagesList.contains(message("status.pending"))); + } + + @Test + public void should_edit_and_automatically_approve_author_edit() throws Exception { + Question question = createQuestionWithDao(karmaNigga(), + "Title title title title title title title", + "Description description description description description", tag("java")); + + String newTitle = "NEW title title title title title title title"; + String newDescription = "NEW description description description description description"; + UserFlow navigation = login(navigate(), "karma.nigga@caelum.com.br"); + navigation = editQuestionWithFlow(navigation, question.getId(), + newTitle, newDescription, "edited question woots!", "java"); + + VRaptorTestResult editedQuestion = navigation.followRedirect().execute(); + editedQuestion.wasStatus(200).isValid(); + + List messagesList = messagesList(editedQuestion); + assertTrue(messagesList.contains(message("status.no_need_to_approve"))); + + Question fetchQuestion = editedQuestion.getObject("question"); + assertEquals(newTitle, fetchQuestion.getTitle()); + assertEquals(newDescription, fetchQuestion.getDescription()); + } + + @Test + public void should_edit_and_automatically_approve_moderator() throws Exception { + Question question = createQuestionWithDao(karmaNigga(), + "Title title title title title title title", + "Description description description description description", tag("java")); + + String newTitle = "NEW title title title title title title title"; + String newDescription = "NEW description description description description description"; + UserFlow navigation = login(navigate(), "moderator@caelum.com.br"); + navigation = editQuestionWithFlow(navigation, question.getId(), + newTitle, newDescription, "edited question woots!", "java"); + + VRaptorTestResult editedQuestion = navigation.followRedirect().execute(); + editedQuestion.wasStatus(200).isValid(); + + List messagesList = messagesList(editedQuestion); + assertTrue(messagesList.contains(message("status.no_need_to_approve"))); + + Question fetchQuestion = editedQuestion.getObject("question"); + assertEquals(newTitle, fetchQuestion.getTitle()); + assertEquals(newDescription, fetchQuestion.getDescription()); + } + + @Ignore + @Test + public void should_touch_question() throws Exception { + User user = randomUser(); + + Question question = createQuestionWithDao(user(user.getEmail()), "Question question question question question", + "Description description description description description", tag("java")); + + UserFlow navigation = login(navigate(), user.getEmail()); + navigation = editQuestionWithFlow(navigation, question.getId(), "ASdoA sodi aosido iasod iOASIDoIASOdi", "asd oiasudo iausdoi uasoid uaosiduasoduoasi udaiosud oiasud oiasud oisa", "so diaos diaosi d", "java"); + VRaptorTestResult editedQuestion = navigation.followRedirect().execute(); + editedQuestion.wasStatus(200).isValid(); + + Elements questionElement = getElementsByClass(editedQuestion.getResponseBody(), + "edited-touch"); +// assertTrue(questionElement.); + +// WebElement edited = byClassName("post-touchs").findElement(By.cssSelector(".touch.edited-touch")); +// return isElementPresent(tagName("img"), edited); + } + +} diff --git a/src/main/java/br/com/caelum/brutal/controllers/VoteController.java b/src/main/java/br/com/caelum/brutal/controllers/VoteController.java index b1783e646..f12862d1c 100644 --- a/src/main/java/br/com/caelum/brutal/controllers/VoteController.java +++ b/src/main/java/br/com/caelum/brutal/controllers/VoteController.java @@ -43,6 +43,22 @@ public void voteDown(Long id, String type) { tryToVoteVotable(id, VoteType.DOWN, mapping.getClassFor(type)); } + + @SimpleBrutauthRules({ModeratorOrKarmaRule.class}) + @AccessLevel(PermissionRulesConstants.VOTE_UP) + @Post("/{type}/{id}/voto/remove/positivo") + public void voteUpRemoval(Long id, String type) { + tryToRemoveVoteVotable(id, VoteType.UP, mapping.getClassFor(type)); + loggedUser.getCurrent().votedUp(); + } + + @SimpleBrutauthRules({ModeratorOrKarmaRule.class}) + @AccessLevel(PermissionRulesConstants.VOTE_DOWN) + @Post("/{type}/{id}/voto/remove/negativo") + public void voteDownRemoval(Long id, String type) { + tryToRemoveVoteVotable(id, VoteType.DOWN, mapping.getClassFor(type)); + + } @SuppressWarnings("rawtypes") private void tryToVoteVotable(Long id, VoteType voteType, Class votableType) { @@ -57,4 +73,18 @@ private void tryToVoteVotable(Long id, VoteType voteType, Class votableType) { return; } } + + @SuppressWarnings("rawtypes") + private void tryToRemoveVoteVotable(Long id, VoteType voteType, Class votableType) { + try { + Votable votable = votes.loadVotable(votableType, id); + Vote current = new Vote(currentUser.getCurrent(), voteType); + votingMachine.unRegister(votable, current, votableType); +// votes.save(current); + result.use(Results.json()).withoutRoot().from(votable.getVoteCount()).serialize(); + } catch (IllegalArgumentException e) { + result.use(Results.http()).sendError(409); + return; + } + } } \ No newline at end of file diff --git a/src/main/java/br/com/caelum/brutal/model/Answer.java b/src/main/java/br/com/caelum/brutal/model/Answer.java index 15c07a715..63649eae7 100644 --- a/src/main/java/br/com/caelum/brutal/model/Answer.java +++ b/src/main/java/br/com/caelum/brutal/model/Answer.java @@ -132,6 +132,12 @@ public void substitute(Vote previous, Vote vote) { this.voteCount += vote.substitute(previous, votes); this.question.addUserInteraction(vote.getAuthor()); } + + public void remove(Vote previous) { + votes.remove(previous); + this.voteCount -= previous.getCountValue(); +// addUserInteraction(vote.getAuthor()); + } @Override public boolean equals(Object obj) { diff --git a/src/main/java/br/com/caelum/brutal/model/Comment.java b/src/main/java/br/com/caelum/brutal/model/Comment.java index 3def389b5..304651c0e 100644 --- a/src/main/java/br/com/caelum/brutal/model/Comment.java +++ b/src/main/java/br/com/caelum/brutal/model/Comment.java @@ -148,6 +148,12 @@ public boolean alreadyFlaggedBy(User user) { public void substitute(Vote previous, Vote vote) { this.voteCount += vote.substitute(previous, votes); } + + public void remove(Vote previous) { + votes.remove(previous); + this.voteCount -= previous.getCountValue(); +// addUserInteraction(vote.getAuthor()); + } @Override public long getVoteCount() { diff --git a/src/main/java/br/com/caelum/brutal/model/News.java b/src/main/java/br/com/caelum/brutal/model/News.java index a9dc6e48d..0911bcf72 100644 --- a/src/main/java/br/com/caelum/brutal/model/News.java +++ b/src/main/java/br/com/caelum/brutal/model/News.java @@ -97,6 +97,12 @@ public News(NewsInformation newsInformation, User author) { public void substitute(Vote previous, Vote current) { this.voteCount += current.substitute(previous, votes); } + + public void remove(Vote previous) { + votes.remove(previous); + this.voteCount -= previous.getCountValue(); +// addUserInteraction(vote.getAuthor()); + } @Override public User getAuthor() { diff --git a/src/main/java/br/com/caelum/brutal/model/Question.java b/src/main/java/br/com/caelum/brutal/model/Question.java index f04d3694e..45595f8b2 100644 --- a/src/main/java/br/com/caelum/brutal/model/Question.java +++ b/src/main/java/br/com/caelum/brutal/model/Question.java @@ -102,7 +102,7 @@ public class Question extends Moderatable implements Post, Taggable, ViewCountab joinColumns=@JoinColumn(name="Question_id") ) @ManyToMany - private final Set userInteractions= new HashSet<>(); + private final Set userInteractions = new HashSet<>(); public static final long SPAM_BOUNDARY = -5; @@ -209,6 +209,12 @@ public void substitute(Vote previous, Vote vote) { this.voteCount += vote.substitute(previous, votes); addUserInteraction(vote.getAuthor()); } + + public void remove(Vote previous) { + votes.remove(previous); + this.voteCount -= previous.getCountValue(); +// addUserInteraction(vote.getAuthor()); + } @Override public long getVoteCount() { diff --git a/src/main/java/br/com/caelum/brutal/model/interfaces/Votable.java b/src/main/java/br/com/caelum/brutal/model/interfaces/Votable.java index ab8825642..a32321063 100644 --- a/src/main/java/br/com/caelum/brutal/model/interfaces/Votable.java +++ b/src/main/java/br/com/caelum/brutal/model/interfaces/Votable.java @@ -9,6 +9,7 @@ public interface Votable { void substitute(Vote previous, Vote current); + void remove(Vote previous); User getAuthor(); Serializable getId(); long getVoteCount(); diff --git a/src/main/java/br/com/caelum/brutal/model/vote/VotingMachine.java b/src/main/java/br/com/caelum/brutal/model/vote/VotingMachine.java index 9ab440c6f..f9a33d28c 100644 --- a/src/main/java/br/com/caelum/brutal/model/vote/VotingMachine.java +++ b/src/main/java/br/com/caelum/brutal/model/vote/VotingMachine.java @@ -65,8 +65,44 @@ public void register(Votable votable, Vote current, Class votableType) { if (votable.getVoteCount() <= -5) { votable.getQuestion().remove(); - retrieveDownvote.retrieveKarma(votable.getVotes()); + retrieveDownvote.retrieveKarma(votable.getVotes()); } } + + public void unRegister(Votable votable, Vote current, Class votableType) { + User voter = current.getAuthor(); + User votableAuthor = votable.getAuthor(); + ReputationEventContext eventContext = votes.contextOf(votable); + if (votable.getAuthor().getId().equals(voter.getId())) { + throw new IllegalArgumentException("an author can't unvote its own votable since it can't even vote on it"); + } + + Vote previous = votes.previousVoteFor(votable.getId(), voter, votableType); + + boolean shouldCountKarma = voteChecker.shouldCountKarma(voter, votableAuthor, current); + + /* O previous vai sempre existir nessa caso !! ( o ideal :] ) */ + if (previous != null) { + ReputationEvent receivedVote = new ReceivedVoteEvent(previous.getType(), votable, eventContext, shouldCountKarma).reputationEvent(); + votableAuthor.descreaseKarma(karmaCalculator.karmaFor(receivedVote)); + ReputationEvent votedAtSomething = new VotedAtSomethingEvent(previous, eventContext).reputationEvent(); + voter.descreaseKarma(karmaCalculator.karmaFor(votedAtSomething)); + reputationEvents.delete(receivedVote); + reputationEvents.delete(votedAtSomething); + votable.remove(previous); + } + +// ReputationEvent receivedVote = new ReceivedVoteEvent(current.getType(), votable, eventContext, shouldCountKarma).reputationEvent(); +// votableAuthor.increaseKarma(karmaCalculator.karmaFor(receivedVote)); +// ReputationEvent votedAtSomething = new VotedAtSomethingEvent(current, eventContext).reputationEvent(); +// voter.increaseKarma(karmaCalculator.karmaFor(votedAtSomething)); +// reputationEvents.save(receivedVote); +// reputationEvents.save(votedAtSomething); + +// if (votable.getVoteCount() <= -5) { +// votable.getQuestion().remove(); +// retrieveDownvote.retrieveKarma(votable.getVotes()); +// } + } } diff --git a/src/main/java/br/com/caelum/brutal/weld/WeldListener.java b/src/main/java/br/com/caelum/brutal/weld/WeldListener.java new file mode 100644 index 000000000..ff54b73a8 --- /dev/null +++ b/src/main/java/br/com/caelum/brutal/weld/WeldListener.java @@ -0,0 +1,18 @@ +package br.com.caelum.brutal.weld; + +import java.util.Arrays; + +import org.jboss.weld.environment.Container; +import org.jboss.weld.environment.ContainerContext; +import org.jboss.weld.environment.jetty.JettyContainer; +import org.jboss.weld.environment.servlet.Listener; + + +public class WeldListener extends Listener { + + @Override + protected Container findContainer(ContainerContext cc, StringBuilder dump) { + return checkContainers(cc, dump, Arrays.asList(JettyContainer.INSTANCE)); + } + +} diff --git a/src/main/resources/log4j.xml b/src/main/resources/log4j.xml index 115e91a7a..5f5f430ee 100644 --- a/src/main/resources/log4j.xml +++ b/src/main/resources/log4j.xml @@ -42,6 +42,11 @@ + + + + + diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 7f9137ad4..f2e6e353a 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -444,6 +444,11 @@ moderation.flags = flags: {0} moderation.edits = edições: {0} moderation.flagged.posts = Postagens marcadas moderation.flagged.lots = Esse post tem 5 ou mais flags +moderation.flagged.answers.empty = Não existem questões para moderação +moderation.flagged.questions.empty = Não existem perguntas para moderação +moderation.flagged.comments.empty = Não existem comentários para moderação +moderation.edit.questions.empty = Não existem perguntas para editar +moderation.edit.answers.empty = Não existem respostas para editar moderation.accept = Aceitar moderation.reject = Rejeitar moderation.select_version = Selecione a versão diff --git a/src/main/webapp/WEB-INF/jsp/coda.jspf b/src/main/webapp/WEB-INF/jsp/coda.jspf index 5d8ebd3ec..22f77eb56 100644 --- a/src/main/webapp/WEB-INF/jsp/coda.jspf +++ b/src/main/webapp/WEB-INF/jsp/coda.jspf @@ -80,7 +80,7 @@ $.ajaxPrefilter(function(options, originalOptions, jqXHR) { function errorPopup(text, target, clazz){ clazz = clazz || ""; - if(!$(".validation-error.popup").is(":visible")){ + if(!$(".validation-error.popup").is(":visible")) { var errorPopup = $(""); errorPopup.insertAfter(target).show(); } diff --git a/src/main/webapp/WEB-INF/jsp/question/showQuestion.jsp b/src/main/webapp/WEB-INF/jsp/question/showQuestion.jsp index 6d390bed6..23fa8f677 100644 --- a/src/main/webapp/WEB-INF/jsp/question/showQuestion.jsp +++ b/src/main/webapp/WEB-INF/jsp/question/showQuestion.jsp @@ -1,4 +1,4 @@ -