BrightSide Workbench Full Report + Source Code
DossierContentIterator.java
Go to the documentation of this file.
1 /*
2  * TurrĂ³ i Cutiller Foundation. License notice.
3  * Copyright (C) 2018 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.dossier.content;
20 
21 import java.io.Writer;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.EnumSet;
25 import java.util.List;
26 import java.util.Set;
27 import org.turro.string.Strings;
28 import org.turro.attach.www.AttachCtrl;
29 import org.turro.charts.Data;
30 import org.turro.collections.ItemOf;
31 import org.turro.collections.SetOf;
32 import org.turro.dossier.command.DossierAction;
33 import org.turro.dossier.db.DossierPU;
34 import org.turro.dossier.dossier.ProjectContext;
35 import org.turro.dossier.dw.DWIssueModel;
36 import org.turro.dossier.dw.DWWebChart;
37 import org.turro.dossier.entity.Category;
38 import org.turro.dossier.entity.Dossier;
39 import org.turro.dossier.entity.DossierStatus;
40 import org.turro.dossier.entity.DossierType;
41 import org.turro.dossier.entity.IssueResolution;
42 import org.turro.dossier.entity.IssueStatus;
43 import org.turro.dossier.entity.IssueType;
44 import org.turro.dossier.entity.ParticipantRole;
45 import org.turro.dossier.search.CategoryResults;
46 import org.turro.dossier.www.CategoriesTree;
47 import org.turro.dossier.www.KnowledgeBaseDashboard;
48 import org.turro.dossier.www.PhaseHtmlFilter;
49 import org.turro.elephant.context.Application;
50 import org.turro.elephant.context.ElephantContext;
51 import org.turro.elephant.context.IConstructor;
52 import org.turro.elephant.db.WhereClause;
53 import org.turro.elephant.impl.repository.Repository;
54 import org.turro.elephant.impl.repository.RepositoryFile;
55 import org.turro.elephant.web.SocialImageMap;
56 import org.turro.elephant.web.SocialNet;
57 import org.turro.entities.Entities;
58 import org.turro.file.util.FileAttach;
59 import org.turro.i18n.I_;
60 import org.turro.indicator.Statistics;
61 import org.turro.jpa.content.EntityDaoContentIterator;
62 import org.turro.jpa.search.DaoHtmlSearch;
63 import org.turro.jpa.search.DaoSearchKey;
64 import org.turro.marker.ElephantMarker;
65 import org.turro.phase.PhaseDefinitions;
66 import org.turro.plugin.contacts.IContact;
67 import org.turro.polls.PollsCtrl;
68 import org.turro.tags.TagCloud;
69 import org.turro.util.Arrays;
70 import org.turro.visual.DossierVisualElements;
71 import org.turro.visual.VisualElements;
72 import org.turro.www.commentit.CommentItCtrl;
73 import org.turro.www.describeit.DescribeItCtrl;
74 import org.turro.www.starit.StarItCtrl;
75 import org.turro.www.voteit.VoteItCtrl;
76 
81 public class DossierContentIterator extends EntityDaoContentIterator<Dossier, Long> {
82 
83  private String allowedCategories, issuePath, pendingWorths;
84  private long categoryId, dossierId, lastCategoryId = -1;
85  private List<String> dossierTypes, dossierStatus, projectPhases;
86  private boolean showSubject;
87  private boolean all, direct;
88  private Collection<IContact> related;
89  private PhaseHtmlFilter phaseFilter;
90 
91  public DossierContentIterator(IConstructor constructor, Writer writer, IContact contact, boolean mail, String pubPath) {
92  super(new DossierPU(), constructor, writer, contact, mail, pubPath);
93  this.all = contact.getPermissions().isInRole("dossier:all");
94  }
95 
96  public void setCategoryId(long categoryId) {
97  this.categoryId = categoryId;
98  }
99 
100  public void setDossierId(long dossierId) {
101  this.dossierId = dossierId;
102  }
103 
104  public void setDossierTypes(List<String> dossierTypes) {
105  this.dossierTypes = dossierTypes;
106  }
107 
108  public void setDossierStatus(List<String> dossierStatus) {
109  this.dossierStatus = dossierStatus;
110  }
111 
112  public List<String> getProjectPhases() {
113  return projectPhases;
114  }
115 
116  public void setProjectPhases(List<String> projectPhases) {
117  this.projectPhases = projectPhases;
118  }
119 
120  public boolean isShowSubject() {
121  return showSubject;
122  }
123 
124  public void setShowSubject(boolean showSubject) {
125  this.showSubject = showSubject;
126  }
127 
128  public void setAllowedCategories(String allowedCategories) {
129  this.allowedCategories = allowedCategories;
130  }
131 
132  public String getIssuePath() {
133  return issuePath;
134  }
135 
136  public void setIssuePath(String issuePath) {
137  this.issuePath = issuePath;
138  }
139 
141  return phaseFilter;
142  }
143 
144  public void setPhaseFilter(PhaseHtmlFilter phaseFilter) {
145  this.phaseFilter = phaseFilter;
146  }
147 
148  public boolean isDirect() {
149  return direct;
150  }
151 
152  public void setDirect(boolean direct) {
153  this.direct = direct;
154  }
155 
156  public void setRelated(Collection<IContact> related) {
157  this.related = related;
158  }
159 
160  public String getPendingWorths() {
161  return pendingWorths;
162  }
163 
164  public void setPendingWorths(String pendingWorths) {
165  this.pendingWorths = pendingWorths;
166  }
167 
168  @Override
170  WhereClause wc = new WhereClause();
171  wc.addClause("select distinct dossier from Dossier as dossier");
172  wc.addClause("left outer join dossier.participants participant");
173  wc.addClause("left outer join dossier.project project");
174  return Statistics.load(constructor, "DossierRanking", "DossierContactMatching", wc)
175  .allowMatching(isAllowMatching())
176  .allowRanking(isAllowRanking())
177  .doMatching(isDoMatching())
178  .setContact(getContact())
179  .setEntityFields("dossier", "id")
180  .setDefaultSorting("dossier.description")
181  .onCriteria(w -> addCriteria(w, true))
182  .getClause();
183  }
184 
185  @Override
187  WhereClause wc = new WhereClause();
188  wc.addClause("select count(distinct dossier) from Dossier as dossier");
189  wc.addClause("left outer join dossier.participants participant");
190  wc.addClause("left outer join dossier.project project");
191  addCriteria(wc, true);
192  return wc;
193  }
194 
195  @Override
196  protected void renderSummary(ElephantMarker marker, Dossier e, int page) {
197  if(e != null) {
198  marker.put("dossier", e);
199  if(e.getCategory() != null) {
200  marker.put("newCategory", e.getCategory().getId() != lastCategoryId);
201  lastCategoryId = e.getCategory().getId();
202  } else {
203  lastCategoryId = 0;
204  }
205  prepareValues(e, page);
206  marker.put("restricted", isRestricted());
207  }
209  }
210 
211  @Override
212  protected void renderItem(ElephantMarker marker, Dossier e, int page) {
213  marker.put("dossier", e);
214  prepareValues(e, page);
215  marker.put("restricted", isRestricted());
217  }
218 
219  @Override
220  protected String entityRoot() {
221  return "dossier";
222  }
223 
224  @Override
225  protected Dossier entity(Long value) {
226  WhereClause wc = new WhereClause();
227  wc.addClause("select distinct dossier from Dossier as dossier");
228  wc.addClause("left outer join dossier.participants participant");
229  wc.addClause("left outer join dossier.project project");
230  addCriteria(wc, true);
231  wc.addClause("and dossier.id = :id");
232  wc.addNamedValue("id", value);
233  return (Dossier) dao.getSingleResultOrNull(wc);
234  }
235 
236  @Override
237  protected Long getIdentifier() {
238  Long identifier = getIDFromURL("/dossier");
239  if(identifier == null) {
240  identifier = super.getIdentifier();
241  }
242  return identifier;
243  }
244 
245  private void addCriteria(WhereClause wc, boolean filterPhase) {
246  addCategories(wc);
247  if(isSearchOption()) {
249  if(dhs != null) {
250  DaoSearchKey dsk = dhs.get("search-value");
251  if(dsk != null) {
252  dsk.applyToQuery(wc, Arrays.objects("dossier.description"), true);
253  }
254  }
255  if(filterPhase) {
256  PhaseHtmlFilter phf = PhaseHtmlFilter.getInstance(constructor, ElephantContext.getContextVariable(constructor));
257  if(phf != null && !phf.isEmpty()) {
258  int phase = Integer.valueOf(phf.getPhase());
259  if(phase > -1) {
260  String par = "phase" + wc.getUniqueSuffix();
261  wc.addClause("and dossier.project.phase = :" + par);
262  wc.addNamedValue(par, phase);
263  }
264  }
265  }
266  }
267  if(!isRestricted()) {
268  wc.addClause("and dossier.publishable = TRUE");
269  }
270  if(!Strings.isBlank(pendingWorths)) {
271  wc.addClause("and not exists (");
272  wc.addClause("select v from WorthValue v");
273  wc.addClause("where v.dossier = dossier");
274  wc.addClause("and v.worthDefinition.id in (" + pendingWorths + ")");
275  wc.addClause("and v.idContact = :pendContact");
276  wc.addNamedValue("pendContact", getContact().getId());
277  wc.addClause(")");
278  }
279  if(categoryId > 0) {
280  wc.addClause("and dossier.category.id in (" + getCategories(categoryId) + ")");
281  } else if(dossierId > 0) {
282  wc.addClause("and dossier.id = " + dossierId);
283  } else if(!Strings.isBlank(allowedCategories)) {
284  if(!wantItem()) {
285  String selCat = CategoriesTree.getSelectedItem(constructor, ElephantContext.getContextVariable(constructor));
286  if(!Strings.isBlank(selCat)) {
287  wc.addClause("and dossier.category.fullDescription like '" + Category.getPathToFullDescription(selCat + "%'"));
288  }
289  }
290  if(!"all".equals(allowedCategories)) {
291  CategoryResults.addExistsCategoryAffiliance(wc, allowedCategories, "dossier");
292  }
293  }
294  if(dossierTypes != null && dossierTypes.size() > 0) {
295  wc.addClause("and (");
296  String sep = "";
297  for(String s : dossierTypes) {
298  DossierType dt = DossierType.valueOf(s);
299  if(dt != null) {
300  String par = "type" + wc.getUniqueSuffix();
301  wc.addClause(sep + "dossier.type = :" + par);
302  wc.addNamedValue(par, dt);
303  sep = " or ";
304  }
305  }
306  wc.addClause(")");
307  }
308  if(dossierStatus != null && dossierStatus.size() > 0) {
309  wc.addClause("and (");
310  String sep = "";
311  for(String s : dossierStatus) {
312  DossierStatus ds = DossierStatus.valueOf(s);
313  if(ds != null) {
314  String par = "status" + wc.getUniqueSuffix();
315  wc.addClause(sep + "dossier.status = :" + par);
316  wc.addNamedValue(par, ds);
317  sep = " or ";
318  }
319  }
320  wc.addClause(")");
321  }
322  if(filterPhase) {
323  if(projectPhases != null && !projectPhases.isEmpty()) {
324  List<Integer> indexes = PhaseDefinitions.instance().stream()
325  .filter(pd -> pd.anyStringMatch(projectPhases))
326  .map(pd -> pd.getIndex()).toList();
327  wc.addClause("and dossier.project.phase in (:phases)");
328  wc.addNamedValue("phases", indexes);
329  }
330  }
331  if(TagCloud.hasSelected(constructor, "dossier")) {
332  wc.addIn("and", "dossier.id", TagCloud.getIdentifiersAsLong(constructor, "dossier"));
333  }
334  }
335 
336  @Override
337  protected boolean isValid(Dossier e) {
338  if(isRestricted() && e != null) {
339  return all || e.getFullParticipants().isParticipant(getContact());
340  } else {
341  return super.isValid(e);
342  }
343  }
344 
345  @Override
346  protected VisualElements loadVisuals() {
347  return DossierVisualElements.load();
348  }
349 
350  private String getCategories(long categoryId) {
351  String result = null;
352  Category category = dao.find(Category.class, Long.valueOf(categoryId));
353  return addCategory(category, result);
354  }
355 
356  private String addCategory(Category category, String result) {
357  if(category != null) {
358  result = (String) (((result == null) ? "" : result + ",") + category.getId());
359  for(Category c : category.getChildren()) {
360  result = addCategory(c, result);
361  }
362  }
363  return result;
364  }
365 
366  private void prepareValues(final Dossier dossier, int page) {
367  prepareControls(dossier, page);
368 
369  marker.put("dossierClass", "dossier" +
370  (dossier.getStatus().equals(DossierStatus.DOSSIER_OPENED) ? " openned" : "") +
371  (dossier.getStatus().equals(DossierStatus.DOSSIER_CLOSED) ? " closed" : "") +
372  (dossier.getStatus().equals(DossierStatus.DOSSIER_FROZEN) ? " frozen" : ""));
373 
374  if(!Strings.isBlank(issuePath)) {
375  marker.put("issuePath", ElephantContext.getRootWebPath() + issuePath);
376  } else if(dossier.getFullParticipants().isShowAllIssues(getContact())) {
377  marker.put("issuePath", ElephantContext.getRootWebPath() + "/user/kbase");
378  }
379 
380  final DWIssueModel issueModel = new DWIssueModel();
381  issueModel.setDossierId(dossier.getId());
382  marker.put("issueModel", issueModel);
383  DWWebChart type = new DWWebChart(constructor) {
384  @Override
385  protected void onCreate(Data data, Object[] pars) {
386  data.setLink(ElephantContext.getRootWebPath() + KnowledgeBaseDashboard.createLink("*", false,
387  (Set<IssueType>) EnumSet.of((IssueType) pars[0]), null, null, dossier.getId()));
388  }
389  @Override
390  protected void loadData() {
391  setData(I_.get("Type"), issueModel.getByType());
392  }
393  };
394  marker.put("typeChart", type);
395  DWWebChart status = new DWWebChart(constructor) {
396  @Override
397  protected void onCreate(Data data, Object[] pars) {
398  data.setLink(ElephantContext.getRootWebPath() + KnowledgeBaseDashboard.createLink("*", false, null,
399  (Set<IssueStatus>) EnumSet.of((IssueStatus) pars[0]), null, dossier.getId()));
400  }
401  @Override
402  protected void loadData() {
403  setData(I_.get("Status"), issueModel.getByStatus());
404  }
405  };
406  marker.put("statusChart", status);
407  DWWebChart resolution = new DWWebChart(constructor) {
408  @Override
409  protected void onCreate(Data data, Object[] pars) {
410  data.setLink(ElephantContext.getRootWebPath() + KnowledgeBaseDashboard.createLink("*", false, null, null,
411  (Set<IssueResolution>) EnumSet.of((IssueResolution) pars[0]), dossier.getId()));
412  }
413  @Override
414  protected void loadData() {
415  setData(I_.get("Resolution"), issueModel.getByResolution());
416  }
417  };
418  marker.put("resolutionChart", resolution);
419 
420  marker.put("actions", new DossierAction());
421 
422  marker.put("projectContext", new ProjectContext());
423  //marker.put("visual", new ProjectVisualElements(dossier));
424  marker.put("dve", DossierVisualElements.load());
425 
426  }
427 
428  @Override
429  protected String title(Dossier e) {
430  if(!Strings.isBlank(e.getFullDescription(showSubject))) {
431  return e.getFullDescription(showSubject);
432  }
433  return null;
434  }
435 
436  @Override
437  protected Collection<String> metas(Dossier e) {
438  ArrayList<RepositoryFile> files = new ArrayList<>();
439  String path = getItemLink(e);
440  if(!SocialImageMap.hasImage(path)) {
443  files.addAll(repository.getRepositoryFiles("*_social.png,*_social.jpg"));
444  files.addAll(repository.getRepositoryFiles("*.png,*.jpg"));
445  }
446  SocialNet sn;
447  if(e.getProject() != null) {
448  sn = new SocialNet(path, e.getDescription(), e.getProject().getGoal(), files);
449  } else {
450  sn = new SocialNet(path, e.getDescription(), e.getFullDescription(), files);
451  }
452  return sn.getMetas();
453  }
454 
455  private void addCategories(WhereClause wc) {
456  if(direct) {
457  if(getContact() == null || !getContact().isValid()) {
458  wc.addClause("where 1=2");
459  } else {
460  wc.addClause("where (");
461  wc.addClause("participant.idContact = :idContact");
462  wc.addNamedValue("idContact", getContact().getId());
463  wc.addClause("and (participant.role = :cpdrole1 or participant.role = :cpdrole2)");
464  wc.addNamedValue("cpdrole1", ParticipantRole.PARTICIPANT_OWNER);
465  wc.addNamedValue("cpdrole2", ParticipantRole.PARTICIPANT_ASSISTANT);
466  wc.addClause(")");
467  }
468  } else if(related != null) {
469  if(related.isEmpty()) {
470  wc.addClause("where 1=2");
471  } else {
472  wc.addClause("where (");
473  wc.addClause("participant.idContact in (:idContact)");
474  wc.addNamedValue("idContact", new SetOf<IContact, String>(related, new ItemOf<IContact, String>() {
475  @Override
476  public String getFrom(IContact e) {
477  return e.getId();
478  }
479  }));
480  wc.addClause("and (participant.role = :cpdrole1 or participant.role = :cpdrole2)");
481  wc.addNamedValue("cpdrole1", ParticipantRole.PARTICIPANT_OWNER);
482  wc.addNamedValue("cpdrole2", ParticipantRole.PARTICIPANT_ASSISTANT);
483  wc.addClause(")");
484  }
485  } else if(isRestricted() && !Application.getApplication().isInRole("dossier:all")) {
486  if(getContact() == null || !getContact().isValid()) {
487  wc.addClause("where 1=2");
488  } else {
489  wc.addClause("where ((");
490  wc.addClause("participant.idContact = :idContact");
491  wc.addNamedValue("idContact", getContact().getId());
492  wc.addClause("and (participant.role = :cpdrole1 or participant.role = :cpdrole2)");
493  wc.addNamedValue("cpdrole1", ParticipantRole.PARTICIPANT_OWNER);
494  wc.addNamedValue("cpdrole2", ParticipantRole.PARTICIPANT_ASSISTANT);
495  wc.addClause(")");
496  CategoryResults.addParticipantAffiliance(wc, "or", getContact().getId(), "dossier");
497  wc.addClause(")");
498  }
499  } else {
500  wc.addClause("where 1=1");
501  }
502  }
503 
504  @Override
505  protected String getTemplateRoot() {
506  return isMail() ? "content/newsletter/sections/dossiers" : "dossier";
507  }
508 
509  @Override
510  protected Object doVotesCtrl(Dossier e) {
513  }
514 
515  @Override
516  protected Object doInterestCtrl(Dossier e) {
519  }
520 
521  @Override
522  protected Object doCommentsCtrl(Dossier e) {
525  }
526 
527  @Override
528  protected Object doAttachmentsCtrl(Dossier e) {
531  }
532 
533  @Override
534  protected Object doFilesCtrl(Dossier e) {
537  }
538 
539  @Override
540  protected Object doDescriptionsCtrl(Dossier e) {
543  }
544 
545  @Override
546  protected Object doPollsCtrl(Dossier e) {
549  }
550 
551  @Override
552  protected String getItemLink(Dossier dossier) {
553  if(getContextPath() == null) {
554  String link = dossier.getDossierURL();
555  if(link != null) {
556  return ElephantContext.getRootWebPath() + link;
557  }
558  }
559  return doItemLink(dossier, dossier.getId(), true);
560  }
561 
562  @Override
563  protected String getReadAllLink() {
564  String path = getContextPath();
565  if(Strings.isBlank(path)) {
566  path = ElephantContext.getEntityWebContext("/" + getTypePath());
567  }
568  if(Strings.isBlank(path)) {
569  return getRestrictedLink();
570  }
571  return path;
572  }
573 
574  @Override
575  protected String getRestrictedLink() {
576  return "/user/my" + getTypePath() + "s";
577  }
578 
579  private String getTypePath() {
580  if(dossierTypes != null && dossierTypes.size() == 1 &&
581  dossierTypes.contains(DossierType.TYPE_PROJECT.toString())) {
582  return "project";
583  } else {
584  return "dossier";
585  }
586  }
587 
588 }
void renderSummary(ElephantMarker marker, Dossier e, int page)
void renderItem(ElephantMarker marker, Dossier e, int page)
DossierContentIterator(IConstructor constructor, Writer writer, IContact contact, boolean mail, String pubPath)
static String getObjectPath(Object object)
Definition: DossierPU.java:66
ParticipantSet< IDossierParticipant > getFullParticipants()
Definition: Dossier.java:399
static String getContextVariable(IConstructor constructor)
static String getEntityWebContext(String path)
void addIn(String operator, String field, List values)
void addNamedValue(String name, Object value)
static boolean hasImage(String url)
static IElephantEntity getController(String path)
Definition: Entities.java:78
Repository getPublishableRepository(IConstructor constructor)
Definition: FileAttach.java:47
static Statistics load(IConstructor constructor, String rankingInstance, String matchingInstance, WhereClause wc)
Object getSingleResultOrNull(SqlClause sc)
Definition: Dao.java:419
String doItemLink(E entity, ID id, boolean obfuscated)
static DaoHtmlSearch getInstance(IConstructor constructor, String context)
boolean applyToQuery(WhereClause wc, List< String > fields, boolean withSynonyms)
void process(String rootTmpl, String tmpl)
Object put(Object key, Object value)
Object configureCtrl(Object ctrl, IContact contact)