BrightSide Workbench Full Report + Source Code
DirectoryContentIterator.java
Go to the documentation of this file.
1 /*
2  * TurrĂ³ i Cutiller Foundation. License notice.
3  * Copyright (C) 2021 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.contacts.content;
20 
21 import java.io.Writer;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Date;
26 import java.util.EnumSet;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Set;
30 import java.util.stream.Collectors;
31 import org.turro.string.Strings;
32 import org.turro.attach.www.AttachCtrl;
33 import org.turro.collections.ExpressionSet;
34 import org.turro.contacts.Contact;
35 import org.turro.contacts.ContactType;
36 import org.turro.contacts.db.ContactsPU;
37 import org.turro.contacts.profile.ProfileContext;
38 import org.turro.contacts.relation.FuzzyRelationTypes;
39 import org.turro.elephant.context.ElephantContext;
40 import org.turro.elephant.context.IConstructor;
41 import org.turro.elephant.db.WhereClause;
42 import org.turro.elephant.impl.repository.Repository;
43 import org.turro.elephant.impl.repository.RepositoryFile;
44 import org.turro.elephant.security.IUser;
45 import org.turro.elephant.web.SocialImageMap;
46 import org.turro.elephant.web.SocialNet;
47 import org.turro.entities.Entities;
48 import org.turro.file.util.FileAttach;
49 import org.turro.indicator.Statistics;
50 import org.turro.jpa.content.EntityDaoContentIterator;
51 import org.turro.jpa.search.DaoHtmlSearch;
52 import org.turro.jpa.search.DaoSearchKey;
53 import org.turro.marker.ElephantMarker;
54 import org.turro.plugin.contacts.IContact;
55 import org.turro.polls.PollsCtrl;
56 import org.turro.skills.tags.SkillCloud;
57 import org.turro.skills.tags.SkillSet;
58 import org.turro.skills.tags.SkillTags;
59 import org.turro.www.commentit.CommentItCtrl;
60 import org.turro.www.describeit.DescribeItCtrl;
61 import org.turro.www.starit.StarItCtrl;
62 import org.turro.www.voteit.VoteItCtrl;
63 
68 public class DirectoryContentIterator extends EntityDaoContentIterator<Contact, String> {
69 
70  private Set<DirectoryType> types;
71  private ExpressionSet syndications;
72  private List<String> contactIds;
73 
74  public DirectoryContentIterator(IConstructor constructor, Writer writer, IContact contact, boolean mail, String contextPath) {
75  super(new ContactsPU(), constructor, writer, contact, mail, contextPath);
76  }
77 
78  public Set<DirectoryType> getTypes() {
79  return types;
80  }
81 
82  public void setTypes(Set<DirectoryType> types) {
83  this.types = types;
84  }
85 
86  public void setTypes(String types) {
87  String type[] = types.split("\\s*,\\s*");
88  Set<DirectoryType> set = new HashSet<>();
89  for(int i = 0; i < type.length; i++) {
90  if("typed".equals(type[i])) {
91  set.addAll(EnumSet.complementOf(EnumSet.of(DirectoryType.DIRECTORY_SINGLETONS)));
92  } else if("companies".equals(type[i])) {
94  } else if("centers".equals(type[i])) {
96  } else if("professionals".equals(type[i])) {
98  } else if("educators".equals(type[i])) {
100  } else if("students".equals(type[i])) {
102  } else if("singletons".equals(type[i])) {
104  }
105  }
106  setTypes(set);
107  }
108 
109  public void setSyndications(List<String> syndications) {
110  this.syndications = new ExpressionSet(syndications);
111  }
112 
113  public void setSyndications(String syndications) {
114  if(!Strings.isBlank(syndications)) {
115  this.syndications = new ExpressionSet(Strings.csvToList(syndications));
116  }
117  }
118 
119  public void setContactIds(List<String> contactIds) {
120  this.contactIds = contactIds;
121  }
122 
124  return canShowSkills() ? SkillCloud.getSkills(constructor, entityRoot(), isUserType()) : null;
125  }
126 
127  public SkillSet getEntitySkills(Object entity) {
128  return SkillTags.getSkills(entity);
129  }
130 
131  @Override
133  WhereClause wc = new WhereClause();
134  wc.addClause("select distinct contact from Contact contact");
135  wc.addClause("left outer join contact.connectors connector on connector.description = :trade");
136  wc.addClause("left outer join contact.businessRelations relation");
137  wc.addClause("left outer join relation.business business");
138  wc.addClause("left outer join business.connectors bconnector on bconnector.description = :trade");
139  wc.addNamedValue("trade", IUser.CONNECTOR_TRADE);
140  if(syndications != null && !syndications.isEmpty()) {
141  wc.addClause("left outer join contact.syndications syndication");
142  }
143  return Statistics.load(constructor, "ContactRanking", "HomonymsMatching", wc)
144  .allowMatching(isAllowMatching())
145  .allowRanking(isAllowRanking())
146  .doMatching(isDoMatching())
147  .setContact(getContact())
148  .setEntityFields("contact", "id")
149  .setDefaultSorting("contact.name")
150  .onCriteria(w -> addCriteria(w))
151  .getClause();
152  }
153 
154  @Override
156  WhereClause wc = new WhereClause();
157  wc.addClause("select count(distinct contact) from Contact contact");
158  wc.addClause("left outer join contact.connectors connector on connector.description = :trade");
159  wc.addClause("left outer join contact.businessRelations relation");
160  wc.addClause("left outer join relation.business business");
161  wc.addClause("left outer join business.connectors bconnector on bconnector.description = :trade");
162  wc.addNamedValue("trade", IUser.CONNECTOR_TRADE);
163  if(syndications != null && !syndications.isEmpty()) {
164  wc.addClause("left outer join contact.syndications syndication");
165  }
166  addCriteria(wc);
167  return wc;
168  }
169 
170  @Override
171  protected void renderSummary(ElephantMarker marker, Contact e, int page) {
172  if(e != null) {
173  marker.put("contact", e);
174  prepareValues(e, page);
175  }
177  }
178 
179  @Override
180  protected void renderItem(ElephantMarker marker, Contact e, int page) {
181  marker.put("contact", e);
182  prepareValues(e, page);
184  }
185 
186  @Override
187  protected String entityRoot() {
188  return "contact";
189  }
190 
191  @Override
192  protected Contact entity(String value) {
193  WhereClause wc = new WhereClause();
194  wc.addClause("select distinct contact from Contact contact");
195  wc.addClause("left outer join contact.connectors connector on connector.description = :trade");
196  wc.addClause("left outer join contact.businessRelations relation");
197  wc.addClause("left outer join relation.business business");
198  wc.addClause("left outer join business.connectors bconnector on bconnector.description = :trade");
199  wc.addNamedValue("trade", IUser.CONNECTOR_TRADE);
200  if(syndications != null && !syndications.isEmpty()) {
201  wc.addClause("left outer join contact.syndications syndication");
202  }
203  addCriteria(wc);
204  wc.addClause("and contact.id = :id");
205  wc.addNamedValue("id", value);
206  return (Contact) dao.getSingleResultOrNull(wc);
207  }
208 
209  private void addCriteria(WhereClause wc) {
210  wc.addClause("where contact.type <> :type");
211  wc.addClause("and (business is null or business.type <> :type)");
213  if(isSearchOption()) {
215  if(dhs != null) {
216  DaoSearchKey dsk = dhs.get("search-value");
217  if(dsk != null) {
218  dsk.applyToQuery(wc, Arrays.asList(new String[] {
219  "contact.name", "business.name", "connector.value", "bconnector.value" }), false);
220  }
221  }
222  }
223  if(types != null && !types.isEmpty()) {
224  String sep = "";
225  Date now = new Date();
226  wc.addClause("and (");
227  if(isSingleton()) {
228  FuzzyRelationTypes.isSingleton(wc, "", "contact", "relation");
229  } else if(isTyped()) {
230  FuzzyRelationTypes.isTyped(wc, "", "relation");
231  } else {
232  if(isJuridical()) {
233  FuzzyRelationTypes.isJuridical(wc, "", "contact");
234  } else {
235  if(isCompanies()) {
236  wc.addClause(sep + "contact.type = :ctype");
237  wc.addNamedValue("ctype", ContactType.CONTACT_COMPANY);
238  sep = "or ";
239  }
240  if(isCenters()) {
241  wc.addClause(sep + "contact.type = :ltype");
242  wc.addNamedValue("ltype", ContactType.CONTACT_LEARNINGCENTER);
243  sep = "or ";
244  }
245  }
246  if(isNatural()) {
247  wc.addClause(sep + "(");
248  FuzzyRelationTypes.isNatural(wc, "", "relation");
249  wc.addClause("and (relation.startDate is null or relation.startDate <= :now)");
250  wc.addClause("and (relation.endDate is null or relation.endDate >= :now))");
251  wc.addNamedValue("now", now);
252  sep = "or ";
253  } else {
254  if(isWorkers()) {
255  wc.addClause(sep + "(");
256  FuzzyRelationTypes.isWorker(wc, "", "relation");
257  wc.addClause("and (relation.startDate is null or relation.startDate <= :now)");
258  wc.addClause("and (relation.endDate is null or relation.endDate >= :now))");
259  wc.addNamedValue("now", now);
260  sep = "or ";
261  } else {
262  if(isProfessionals()) {
263  wc.addClause(sep + "(");
264  FuzzyRelationTypes.isProfessional(wc, "", "relation");
265  wc.addClause("and (relation.startDate is null or relation.startDate <= :now)");
266  wc.addClause("and (relation.endDate is null or relation.endDate >= :now))");
267  wc.addNamedValue("now", now);
268  sep = "or ";
269  }
270  if(isEducators()) {
271  wc.addClause(sep + "(");
272  FuzzyRelationTypes.isEducator(wc, "", "relation");
273  wc.addClause("and (relation.startDate is null or relation.startDate <= :now)");
274  wc.addClause("and (relation.endDate is null or relation.endDate >= :now))");
275  wc.addNamedValue("now", now);
276  sep = "or ";
277  }
278  }
279  if(isStudents()) {
280  wc.addClause(sep + "(");
281  FuzzyRelationTypes.isStudent(wc, "", "relation");
282  wc.addClause("and (relation.startDate is null or relation.startDate <= :now)");
283  wc.addClause("and (relation.endDate is null or relation.endDate >= :now))");
284  wc.addNamedValue("now", now);
285  sep = "or ";
286  }
287  }
288  }
289  wc.addClause(")");
290  }
291  if(isOnlyStudents()) {
292  if(syndications == null) {
293  syndications = new ExpressionSet(loadNegativesFrom(ProfileContext.getNetworkingRoles()));
294  } else {
295  syndications.addAll(loadNegativesFrom(ProfileContext.getNetworkingRoles()));
296  }
297  syndications.add("!brightside_admin");
298  }
299  if(syndications != null && !syndications.isEmpty()) {
300  if(syndications.hasPositives()) {
301  wc.addIn("and", "syndication.name", syndications.getPositives());
302  }
303  if(syndications.hasNegatives()) {
304  wc.addClause("and not exists (select s from Syndication s");
305  wc.addIn("where", "s.name", syndications.getNegatives());
306  wc.addClause("and s.contact = contact)");
307  }
308  }
309  if(contactIds != null && !contactIds.isEmpty()) {
310  wc.addIn("and", "contact.id", contactIds);
311  }
312  if(SkillCloud.hasSelected(constructor, "contact", isUserType())) {
313  wc.addIn("and", "contact.id", SkillCloud.getIdentifiers(constructor, "contact", isUserType()));
314  }
315  }
316 
317  @Override
318  protected boolean isValid(Contact e) {
319  return super.isValid(e);
320  }
321 
322  private void prepareValues(final Contact e, int page) {
323  prepareControls(e, page);
324  marker.put("profile", e.getProfile());
325  }
326 
327  @Override
328  protected String title(Contact e) {
329  if(!Strings.isBlank(e.getName())) {
330  return e.getName();
331  }
332  return null;
333  }
334 
335  @Override
336  protected Collection<String> metas(Contact e) {
337  ArrayList<RepositoryFile> files = new ArrayList<>();
338  String path = getItemLink(e);
339  if(!SocialImageMap.hasImage(path)) {
342  files.addAll(repository.getRepositoryFiles("*_social.png,*_social.jpg"));
343  files.addAll(repository.getRepositoryFiles("*.png,*.jpg"));
344  }
345  SocialNet sn;
346  sn = new SocialNet(path, e.getName(), e.getName(), files);
347  return sn.getMetas();
348  }
349 
350  @Override
351  protected String getTemplateRoot() {
352  return isMail() ? "content/newsletter/sections/directory" : "directory";
353  }
354 
355  @Override
356  protected Object doVotesCtrl(Contact e) {
359  }
360 
361  @Override
362  protected Object doInterestCtrl(Contact e) {
365  }
366 
367  @Override
368  protected Object doCommentsCtrl(Contact e) {
371  }
372 
373  @Override
374  protected Object doAttachmentsCtrl(Contact e) {
377  }
378 
379  @Override
380  protected Object doFilesCtrl(Contact e) {
383  }
384 
385  @Override
386  protected Object doDescriptionsCtrl(Contact e) {
389  }
390 
391  @Override
392  protected Object doPollsCtrl(Contact e) {
395  }
396 
397  @Override
398  protected String getItemLink(Contact e) {
399  return doItemLink(e, e.getId(), true);
400  }
401 
402  @Override
403  protected String getReadAllLink() {
404  String path = getContextPath();
405  if(Strings.isBlank(path)) {
406  path = ElephantContext.getEntityWebContext("/directory");
407  }
408  if(Strings.isBlank(path)) {
409  return getRestrictedLink();
410  }
411  return path;
412  }
413 
414  @Override
415  protected String getRestrictedLink() {
416  return "/user/profile";
417  }
418 
419  /* Types */
420 
421  private boolean isTyped() {
422  return types.contains(DirectoryType.DIRECTORY_COMPANIES) &&
423  types.contains(DirectoryType.DIRECTORY_PROFESSIONALS) &&
424  types.contains(DirectoryType.DIRECTORY_CENTERS) &&
425  types.contains(DirectoryType.DIRECTORY_EDUCATORS) &&
426  types.contains(DirectoryType.DIRECTORY_STUDENTS);
427  }
428 
429  private boolean isJuridical() {
430  return types.contains(DirectoryType.DIRECTORY_COMPANIES) &&
431  types.contains(DirectoryType.DIRECTORY_CENTERS);
432  }
433 
434  private boolean isNatural() {
435  return types.contains(DirectoryType.DIRECTORY_PROFESSIONALS) &&
436  types.contains(DirectoryType.DIRECTORY_EDUCATORS) &&
437  types.contains(DirectoryType.DIRECTORY_STUDENTS);
438  }
439 
440  private boolean isCompanies() {
441  return types.contains(DirectoryType.DIRECTORY_COMPANIES);
442  }
443 
444  private boolean isCenters() {
445  return types.contains(DirectoryType.DIRECTORY_CENTERS);
446  }
447 
448  private boolean isWorkers() {
449  return types.contains(DirectoryType.DIRECTORY_PROFESSIONALS) &&
450  types.contains(DirectoryType.DIRECTORY_EDUCATORS);
451  }
452 
453  private boolean isProfessionals() {
454  return types.contains(DirectoryType.DIRECTORY_PROFESSIONALS);
455  }
456 
457  private boolean isEducators() {
458  return types.contains(DirectoryType.DIRECTORY_EDUCATORS);
459  }
460 
461  private boolean isStudents() {
462  return types.contains(DirectoryType.DIRECTORY_STUDENTS);
463  }
464 
465  private boolean isOnlyStudents() {
466  return EnumSet.of(DirectoryType.DIRECTORY_STUDENTS).equals(types);
467  }
468 
469  private boolean isSingleton() {
470  return types.contains(DirectoryType.DIRECTORY_SINGLETONS);
471  }
472 
473  private boolean canShowSkills() {
474  return isNatural() ^ isJuridical();
475  }
476 
477  private boolean isUserType() {
478  return types == null || isNatural();
479  }
480 
481  private List<String> loadNegativesFrom(String networkingRoles) {
482  return Strings.extractAll(networkingRoles, "\\@([a-zA-Z0-9]+):on")
483  .stream().map(s -> "!" + s).collect(Collectors.toList());
484  }
485 
486 }
void renderItem(ElephantMarker marker, Contact e, int page)
DirectoryContentIterator(IConstructor constructor, Writer writer, IContact contact, boolean mail, String contextPath)
void renderSummary(ElephantMarker marker, Contact e, int page)
static String getObjectPath(Object object)
Definition: ContactsPU.java:68
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)
static SkillSet getSkills(IConstructor constructor, String root, boolean user)
Definition: SkillCloud.java:36
static SkillSet getSkills(Object entity)
Definition: SkillTags.java:137
static final String CONNECTOR_TRADE
Definition: IUser.java:28
Object configureCtrl(Object ctrl, IContact contact)