BrightSide Workbench Full Report + Source Code
ForumCtrl.java
Go to the documentation of this file.
1 /*
2  * TurrĂ³ i Cutiller Foundation. License notice.
3  * Copyright (C) 2020 Lluis TurrĂ³ Cutiller <http://www.turro.org/>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Affero General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Affero General Public License for more details.
14  *
15  * You should have received a copy of the GNU Affero General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 package org.turro.forum.www;
20 
21 import java.io.IOException;
22 import java.util.Date;
23 import java.util.List;
24 import java.util.logging.Level;
25 import java.util.logging.Logger;
26 import org.amic.util.date.CheckDate;
27 import org.turro.string.Strings;
28 import org.turro.activity.ParticipationCatchers;
29 import org.turro.annotation.ElephantPlugin;
30 import org.turro.assistant.ParticipationInfo;
31 import org.turro.auth.Authentication;
32 import org.turro.collections.KeyValueMap;
33 import org.turro.elephant.context.Application;
34 import org.turro.elephant.context.ElephantContext;
35 import org.turro.elephant.context.IConstructor;
36 import org.turro.elephant.db.ElephantPU;
37 import org.turro.elephant.db.WhereClause;
38 import org.turro.elephant.direct.AbstractDirectEntityCtrl;
39 import org.turro.elephant.direct.DirectContent;
40 import org.turro.elephant.entities.db.Post;
41 import org.turro.elephant.entities.db.Topic;
42 import org.turro.entities.Entities;
43 import org.turro.entities.IElephantEntity;
44 import org.turro.forum.Forums;
45 import org.turro.forum.db.UniquePath;
46 import org.turro.html.HTMLEntities;
47 import org.turro.jpa.Dao;
48 import org.turro.marker.ElephantMarker;
49 import org.turro.marker.MarkerHelper;
50 import org.turro.participation.ParticipationReason;
51 import org.turro.plugin.contacts.IContact;
52 import org.turro.util.IdGenerator;
53 
58 @ElephantPlugin(label="forum-ctrl")
59 @DirectContent(identifier="forum-action")
60 public class ForumCtrl extends AbstractDirectEntityCtrl {
61 
62  private List<Topic> topics;
63 
64  public ForumCtrl() {
65  super("forum", "forum");
66  }
67 
68  /* Delete */
69 
70  public boolean canDelete(Topic topic) {
72  Date allowed = new CheckDate().addDays(-1).getDate();
73  return (Application.getApplication().isInRole("contact-comment:delete") ||
74  (topic.getAuthorId().equals(contact.getId()) && allowed.before(topic.getCreation()))) &&
75  topic.getPosts().isEmpty();
76  }
77 
78  public boolean canDelete(Post post) {
80  Date allowed = new CheckDate().addDays(-1).getDate();
81  return (Application.getApplication().isInRole("contact-comment:delete") ||
82  (post.getAuthorId().equals(contact.getId()) && allowed.before(post.getCreation()))) &&
83  post.getPosts().isEmpty();
84  }
85 
86  public String getDeleteLink(Topic topic) {
87  return createRightNowURL("type=delete;topic=" + topic.getId());
88  }
89 
90  public String getDeleteLink(Post post) {
91  return createRightNowURL("type=delete;post=" + post.getId());
92  }
93 
94  @Override
95  protected void prepareCleanMarker(ElephantMarker marker, KeyValueMap map) {
96  throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
97  }
98 
99  /* IEntityCtrl */
100 
101  @Override
102  public boolean hasContent() {
103  getRelatedTopics();
104  return !topics.isEmpty() && super.hasContent();
105  }
106 
107  @Override
108  protected void prepareMarker(ElephantMarker marker) {
109  marker.put("topics", getRelatedTopics());
110  }
111 
112  /* IDirectContent */
113 
114  @Override
115  protected String getIdentifier() {
116  return ForumCtrl.class.getAnnotation(DirectContent.class).identifier();
117  }
118 
119  @Override
120  protected void doExecute(IConstructor constructor, KeyValueMap map) {
121  String type = map.get("type");
122  if("participate".equals(type)) {
123  processParticipate(map, constructor);
124  } else if("new-topic-form". equals(type)) {
125  renderNewTopicForm(map, constructor);
126  } else if("new-topic". equals(type)) {
127  processNewTopic(map, constructor);
128  } else if("reply-form". equals(type)) {
129  renderReplyForm(map, constructor);
130  } else if("reply". equals(type)) {
131  processReply(map, constructor);
132  } else if("delete". equals(type)) {
133  processDelete(map, constructor);
134  }
135  }
136 
137  /* ForumCtrl */
138 
139  public String renderNewTopicContainer(IConstructor constructor) {
140  if(!Strings.isBlank(entityPath)) {
141  ElephantMarker marker = new ElephantMarker(constructor);
142  marker.put("entityPath", entityPath);
143  String containerId = "cic_" + IdGenerator.generate();
144  marker.put("containerId", containerId);
145  marker.put("newTopicLink", getAjaxUrl(containerId,
146  "type=new-topic-form;entityPath=" + entityPath +
147  ";containerId=" + containerId));
148  return marker.parse("forum", "new-topic-container");
149  }
150  return null;
151  }
152 
153  public String renderReplyContainer(IConstructor constructor, Topic topic) {
154  ElephantMarker marker = new ElephantMarker(constructor);
155  marker.put("topic", topic);
156  String containerId = "cic_" + IdGenerator.generate();
157  marker.put("containerId", containerId);
158  marker.put("replyLink", getAjaxUrl(containerId,
159  "type=reply-form;topic=" + topic.getId() +
160  ";containerId=" + containerId));
161  return marker.parse("forum", "reply-container");
162  }
163 
164  public String renderReplyContainer(IConstructor constructor, Post post) {
165  ElephantMarker marker = new ElephantMarker(constructor);
166  marker.put("post", post);
167  String containerId = "cic_" + IdGenerator.generate();
168  marker.put("containerId", containerId);
169  marker.put("replyLink", getAjaxUrl(containerId,
170  "type=reply-form;post=" + post.getId() +
171  ";containerId=" + containerId));
172  return marker.parse("forum", "reply-container");
173  }
174 
175  public String getParticipationLink(Topic topic) {
176  return createPOST("type=participate;topic=" + topic.getId());
177  }
178 
179  public boolean isMine(Topic topic) {
180  IContact contact = Authentication.getIContact();
181  return topic.isParticipant(contact);
182  }
183 
184  private List<Topic> getRelatedTopics() {
185  if(topics == null) {
186  WhereClause wc = new WhereClause();
187  wc.addClause("select c from Topic c");
188  wc.addClause("where c.entityPath = :entityPath");
189  wc.addNamedValue("entityPath", entityPath);
190  topics = getDao().getResultList(wc);
191  }
192  return topics;
193  }
194 
195  private void processParticipate(KeyValueMap map, IConstructor constructor) {
196  Long toid = map.get(Long.class, "topic");
197  Topic topic = getDao().find(Topic.class, toid);
198  if(topic != null && Authentication.hasContact()) {
199  new ParticipationInfo("/topic/" + topic.getId(), ParticipationReason.REASON_PARTICIPATE).check();
200  }
201  }
202 
203  private void renderNewTopicForm(KeyValueMap map, IConstructor constructor) {
204  setEntityPath(map.get("entityPath"));
205  ElephantMarker marker = getCleanMarkerFrom(constructor);
206  addContainerId(marker, false);
207  marker.putAll(map);
208  marker.put("newTopicLink", getAjaxSubmitUrl(map.get("containerId")));
209  try {
210  constructor.getResponse().setContentType("text/html");
211  constructor.getResponse().setCharacterEncoding(ElephantContext.getEncoding());
212  marker.process("forum", "new-topic", constructor.getResponse().getWriter());
213  } catch (IOException ex) {
214  Logger.getLogger(ForumCtrl.class.getName()).log(Level.SEVERE, ElephantContext.logMsg(null), ex);
215  }
216  }
217 
218  private void processNewTopic(KeyValueMap map, IConstructor constructor) {
219  IContact contact = Authentication.getIContact();
220  if(contact != null && contact.isWebUser()) {
221  Topic topic = new Topic();
222  String body = map.get("body"),
223  entityPath = map.get("entityPath");
224  IElephantEntity iee = Entities.getController(entityPath);
225  if(iee.getPath() != null && !Strings.isBlank(body) && body.length() > 100) {
226  topic.setText(HTMLEntities.escape(body));
227  topic.setCreation(new Date());
228  topic.setAuthorId(contact.getId());
229  topic.setEntityPath(entityPath);
230  if(!topic.isEmpty()) {
231  topic = getDao().saveObject(topic);
232  UniquePath.normalizeUniquePaths(topic);
233  Forums.markAsUnseenExceptFor(topic, contact);
234  Forums.notify(topic);
235  ElephantMarker marker = getCleanMarkerFrom(constructor);
236  addContainerId(marker, false);
237  marker.put("topic", topic);
238  marker.put("containerId", map.get("containerId"));
239  try {
240  constructor.getResponse().setContentType("text/html");
241  constructor.getResponse().setCharacterEncoding(ElephantContext.getEncoding());
242  marker.process("forum", "single-related", constructor.getResponse().getWriter());
243  } catch (IOException ex) {
244  Logger.getLogger(ForumCtrl.class.getName()).log(Level.SEVERE, ElephantContext.logMsg(null), ex);
245  }
246  }
247  }
248  }
249  }
250 
251  private void renderReplyForm(KeyValueMap map, IConstructor constructor) {
252  if(map.containsKey("post")) {
253  setEntityPath("/post/" + map.get("post"));
254  } else if(map.containsKey("topic")) {
255  setEntityPath("/topic/" + map.get("topic"));
256  }
257  ElephantMarker marker = getCleanMarkerFrom(constructor);
258  addContainerId(marker, false);
259  marker.putAll(map);
260  marker.put("replyLink", createURL());
261  try {
262  constructor.getResponse().setContentType("text/html");
263  constructor.getResponse().setCharacterEncoding(ElephantContext.getEncoding());
264  marker.process("forum", "reply", constructor.getResponse().getWriter());
265  } catch (IOException ex) {
266  Logger.getLogger(ForumCtrl.class.getName()).log(Level.SEVERE, ElephantContext.logMsg(null), ex);
267  }
268  }
269 
270  private void processReply(KeyValueMap map, IConstructor constructor) {
271  IContact contact = Authentication.getIContact();
272  if(contact != null && contact.isWebUser()) {
273  Post post = new Post();
274  String body = map.get("body");
275  if(!Strings.isBlank(body)) {
276  post.setText(HTMLEntities.escape(body));
277  post.setCreation(new Date());
278  post.setAuthorId(contact.getId());
279  if(map.containsKey("post")) {
280  Post parent = getDao().find(Post.class, map.get(Long.class, "post"));
281  post.setParent(parent);
282  } else if(map.containsKey("topic")) {
283  Topic parent = getDao().find(Topic.class, map.get(Long.class, "topic"));
284  post.setTopic(parent);
285  }
286  if(!post.isEmpty()) {
287  post = getDao().saveObject(post);
288  UniquePath.normalizeUniquePaths(post);
289  Forums.markAsUnseenExceptFor(post, contact);
290  Forums.notify(post);
291  try {
292  constructor.redirect("/user/forums?" + MarkerHelper.setObfuscatedPars("item=" + post.getParentTopic().getId()));
293  } catch (IOException ex) {
294  Logger.getLogger(ForumCtrl.class.getName()).log(Level.SEVERE, ElephantContext.logMsg(null), ex);
295  }
296  }
297  }
298  }
299  }
300 
301  private void processDelete(KeyValueMap map, IConstructor constructor) {
302  IContact contact = Authentication.getIContact();
303  Long redirectId = null;
304  if(contact != null && contact.isWebUser()) {
305  if(map.containsKey("post")) {
306  Post post = getDao().find(Post.class, map.get(Long.class, "post"));
307  if(post != null && post.getPosts(getDao()).isEmpty()) {
308  redirectId = post.getParentTopic().getId();
309  ParticipationCatchers.doDelete(post);
310  getDao().deleteObject(post);
311  }
312  } else if(map.containsKey("topic")) {
313  Topic topic = getDao().find(Topic.class, map.get(Long.class, "topic"));
314  if(topic != null && topic.getPosts(getDao()).isEmpty()) {
315  ParticipationCatchers.doDelete(topic);
316  getDao().deleteObject(topic);
317  }
318  }
319  try {
320  if(redirectId != null) {
321  constructor.redirect("/user/forums?" + MarkerHelper.setObfuscatedPars("item=" + redirectId));
322  } else {
323  constructor.redirect("/user/forums");
324  }
325  } catch (IOException ex) {
326  Logger.getLogger(ForumCtrl.class.getName()).log(Level.SEVERE, ElephantContext.logMsg(null), ex);
327  }
328  }
329  }
330 
331  /* Dao */
332 
333  private Dao _dao;
334 
335  private Dao getDao() {
336  if(_dao == null) {
337  _dao = new ElephantPU();
338  }
339  return _dao;
340  }
341 
342 }
void addNamedValue(String name, Object value)
boolean isParticipant(IContact contact)
Definition: Topic.java:168
String getDeleteLink(Post post)
Definition: ForumCtrl.java:90
void doExecute(IConstructor constructor, KeyValueMap map)
Definition: ForumCtrl.java:120
String renderNewTopicContainer(IConstructor constructor)
Definition: ForumCtrl.java:139
boolean canDelete(Topic topic)
Definition: ForumCtrl.java:70
String renderReplyContainer(IConstructor constructor, Post post)
Definition: ForumCtrl.java:164
void prepareCleanMarker(ElephantMarker marker, KeyValueMap map)
Definition: ForumCtrl.java:95
void prepareMarker(ElephantMarker marker)
Definition: ForumCtrl.java:108
boolean isMine(Topic topic)
Definition: ForumCtrl.java:179
String renderReplyContainer(IConstructor constructor, Topic topic)
Definition: ForumCtrl.java:153
boolean canDelete(Post post)
Definition: ForumCtrl.java:78
String getParticipationLink(Topic topic)
Definition: ForumCtrl.java:175
String getDeleteLink(Topic topic)
Definition: ForumCtrl.java:86
String parse(String rootTmpl, String tmpl)
Object put(Object key, Object value)