BrightSide Workbench Full Report + Source Code
ContactsVM.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.model;
20 
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.EnumSet;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Set;
27 import java.util.stream.Collectors;
28 import org.turro.action.Plugins;
29 import org.turro.command.Context;
30 import org.turro.contacts.Contact;
31 import org.turro.contacts.ContactType;
32 import org.turro.contacts.content.DirectoryType;
33 import org.turro.contacts.db.ContactsPU;
34 import org.turro.contacts.form.ContactWrapper;
35 import org.turro.contacts.relation.FuzzyRelationTypes;
36 import org.turro.contacts.social.SocialGroupListbox;
37 import org.turro.contacts.social.SocialGroupValue;
38 import org.turro.contacts.util.ContactList;
39 import org.turro.contacts.zul.contact.ContactTypeListbox;
40 import org.turro.contacts.zul.menu.ContactMenu;
41 import org.turro.elephant.context.Application;
42 import org.turro.elephant.db.WhereClause;
43 import org.turro.elephant.util.Components;
44 import org.turro.elephant.zkoss.ModalWindow;
45 import org.turro.entities.IElephantEntity;
46 import org.turro.i18n.I_;
47 import org.turro.jpa.Dao;
48 import org.turro.menu.ElephantMenu;
49 import org.turro.plugin.IPlugin;
50 import org.turro.security.SecItem;
51 import org.turro.security.Secs;
52 import org.turro.security.SecurityGroups;
53 import org.turro.security.SocialGroups;
54 import org.turro.skills.tags.SkillItem;
55 import org.turro.skills.tags.SkillTags;
56 import org.turro.tags.TagItem;
57 import org.turro.tags.Tags;
58 import org.turro.zkoss.dialog.DialogField;
59 import org.turro.zkoss.dialog.Dialogs;
60 import org.turro.zul.frame.Framework;
61 import org.zkoss.bind.BindUtils;
62 import org.zkoss.bind.annotation.BindingParam;
63 import org.zkoss.bind.annotation.Command;
64 import org.zkoss.bind.annotation.NotifyChange;
65 import org.zkoss.zk.ui.Component;
66 import org.zkoss.zul.Button;
67 import org.zkoss.zul.ListModel;
68 import org.zkoss.zul.ListModelSet;
69 import org.zkoss.zul.Row;
70 
75 public class ContactsVM {
76 
77  private final boolean allContacts;
78  private final ModelSearch search;
79 
80  private Set<DirectoryType> typeSet;
81  private Set<SecItem> secSet;
82  private Set<TagItem> tagSet;
83  private Set<SkillItem> skillSet;
84  private String searchValue;
85  private boolean doNotLoad;
86  private ContactItem selected;
87  private ContactModel model;
88 
89  public ContactsVM() {
90  this.search = new ModelSearch();
91  this.typeSet = new HashSet<>(EnumSet.allOf(DirectoryType.class));
92  this.secSet = new HashSet<>();
93  this.tagSet = new HashSet<>();
94  this.skillSet = new HashSet<>();
95  this.allContacts = Application.getApplication().isInRole("contact:all");
96 
97  // Migration
98  Secs.removeSyndication(getDao(), "directory");
99  Tags.removeTags("contact", List.of("directory"));
100  Tags.removeTags("contact", List.of("student"));
101  Tags.removeTags("contact", SecurityGroups.getAll().stream()
102  .map(sg -> sg.getTags()).flatMap(Set::stream).collect(Collectors.toList()));
103  }
104 
105  @NotifyChange("model")
106  @Command
107  public void sec(@BindingParam("selected") Set<SecItem> selected ) {
108  secSet = new HashSet<>(selected);
109  }
110 
111  @NotifyChange("model")
112  @Command
113  public void tag(@BindingParam("selected") Set<TagItem> selected ) {
114  tagSet = new HashSet<>(selected);
115  }
116 
117  @NotifyChange("model")
118  @Command
119  public void skill(@BindingParam("selected") Set<SkillItem> selected ) {
120  skillSet = new HashSet<>(selected);
121  }
122 
123  @Command
124  public void edit(@BindingParam("item") ContactItem item) {
126  }
127 
128  @Command
129  public void organigram(@BindingParam("item") ContactItem item) {
131  }
132 
133  @Command
134  public void vcard(@BindingParam("item") ContactItem item) {
135  ElephantMenu.showEntityModal(item.getContact().getId(), "contactId", "/contact/vcard.zul", null);
136  }
137 
138  @Command
139  public void qrcode(@BindingParam("item") ContactItem item) {
140  ElephantMenu.showEntityModal(item.getContact().getId(), "contactId", "/contact/qrcode.zul", null);
141  }
142 
143  @Command
144  public void participations(@BindingParam("item") ContactItem item) {
146  }
147 
148  @Command
149  public void subscriptions(@BindingParam("item") ContactItem item) {
151  }
152 
153  @Command
154  public void delete(@BindingParam("item") ContactItem item, @BindingParam("ctrl") Component ctrl) {
155  ElephantMenu.showEntityModal(item.getContact().getId(), "contactId", "/contact/delContact.zul", new org.turro.command.Command() {
156  @Override
157  public Object execute(Context context) {
158  ModalWindow mw = (ModalWindow) context.get("win");
159  if(mw.getResult() == 1) {
160  new ContactWrapper(item.getContact()).delete();
161  Row row = Components.from(ctrl).parent(Row.class);
162  if(row != null) row.detach();
163  }
164  return true;
165  }
166  });
167  }
168 
169  @NotifyChange("model")
170  @Command
171  public void select(@BindingParam("item") IElephantEntity item) {
172  selected = new ContactItem(getDao(), item.getStringId(), true);
173  }
174 
175  @Command
176  public void add() {
177  ContactMenu.showContact((String) null);
178  }
179 
180  @NotifyChange("model")
181  @Command
182  public void selectall() {
183  if(model != null) {
184  model.selectAll();
185  doNotLoad = true;
186  }
187  }
188 
189  @NotifyChange("model")
190  @Command
191  public void deselectall() {
192  if(model != null) {
193  model.deselectAll();
194  doNotLoad = true;
195  }
196  }
197 
198  @NotifyChange("model")
199  @Command
200  public void togglesel() {
201  if(model != null) {
202  model.toggleSelection();
203  doNotLoad = true;
204  }
205  }
206 
207  @Command
208  public void export() {
209  Button export = (Button) Plugins.loadImplementation(IPlugin.class, "vcard");
210  if(export != null) {
211  ((IPlugin) export).setData("export", contactsFromModel());
212  }
213  }
214 
215  @Command
216  public void copy() {
217  Framework.getClipboard().put("bbf_clip_contact", contactsFromModel());
218  }
219 
220  @Command
221  public void copyrel() {
222  Framework.getClipboard().put("bbf_clip_contact", relationsFromModel());
223  }
224 
225  @Command
226  public void addtosc() {
227  if(model != null && !model.getSelected().isEmpty()) {
228  Dialogs.title(I_.get("Add to social group"))
229  .width("400px")
230  .height("500px")
231  .addField(DialogField.field("Social group").onEditor(() -> {
232  SocialGroupListbox sglb = new SocialGroupListbox();
233  sglb.setMultiple(true);
234  sglb.setCheckmark(true);
235  sglb.setRows(11);
236  sglb.loadSocialGroups(true);
237  return sglb;
238  }))
239  .onOk((dialogs) -> {
240  Collection<SocialGroupValue> sgs = dialogs.<SocialGroupListbox>getEditor("Social group").getObjectValues();
241  if(!sgs.isEmpty()) {
242  List<Contact> selection = model.getSelected().stream().map(ci -> ci.getContact()).collect(Collectors.toList());
244  selection,
245  sgs.stream().map(sgv -> sgv.getKey()).collect(Collectors.toSet()),
246  getDao());
247  SocialGroups.checkInheritance(selection, getDao());
248  BindUtils.postNotifyChange(null, null, ContactsVM.this, "model");
249  }
250  })
251  .emptyCancel()
252  .show();
253  }
254  }
255 
256  @Command
257  public void delfromsc() {
258  if(model != null && !model.getSelected().isEmpty()) {
259  Dialogs.title(I_.get("Remove from social group"))
260  .width("400px")
261  .height("500px")
262  .addField(DialogField.field("Social group").onEditor(() -> {
263  SocialGroupListbox sglb = new SocialGroupListbox();
264  sglb.setMultiple(true);
265  sglb.setCheckmark(true);
266  sglb.setRows(11);
267  sglb.loadSocialGroups(true);
268  return sglb;
269  }))
270  .onOk((dialogs) -> {
271  Collection<SocialGroupValue> sgs = dialogs.<SocialGroupListbox>getEditor("Social group").getObjectValues();
272  if(!sgs.isEmpty()) {
273  List<Contact> selection = model.getSelected().stream().map(ci -> ci.getContact()).collect(Collectors.toList());
275  selection,
276  sgs.stream().map(sgv -> sgv.getKey()).collect(Collectors.toSet()),
277  getDao());
278  SocialGroups.checkInheritance(selection, getDao());
279  BindUtils.postNotifyChange(null, null, ContactsVM.this, "model");
280  }
281  })
282  .emptyCancel()
283  .show();
284  }
285  }
286 
287  @Command
288  public void resyndicate() {
289  if(model != null && !model.getSelected().isEmpty()) {
290  List<Contact> selection = model.getSelected().stream().map(ci -> ci.getContact()).collect(Collectors.toList());
292  selection,
293  getDao());
294  SocialGroups.checkInheritance(selection, getDao());
295  BindUtils.postNotifyChange(null, null, ContactsVM.this, "model");
296  }
297  }
298 
299  @Command
300  public void settype() {
301  if(model != null && !model.getSelected().isEmpty()) {
302  Dialogs.title(I_.get("Set type"))
303  .width("400px")
304  .height("300px")
305  .addField(DialogField.field("Type").onEditor(() -> {
306  ContactTypeListbox ctl = new ContactTypeListbox();
307  ctl.setSelectFirst(false);
308  ctl.setCheckmark(true);
309  ctl.setRows(4);
310  return ctl;
311  }))
312  .onOk((dialogs) -> {
313  ContactType type = dialogs.<ContactTypeListbox>getEditor("Type").getObjectValue();
314  if(type != null) {
315  List<Contact> contacts = model.getSelected().stream().map(ci -> ci.getContact())
316  .collect(Collectors.toList());
317  contacts.forEach(contact -> contact.setType(type));
318  getDao().saveCollection(contacts);
319  BindUtils.postNotifyChange(null, null, ContactsVM.this, "model");
320  }
321  })
322  .emptyCancel()
323  .show();
324  }
325  }
326 
327  @Command
328  public void activate() {
329  if(model != null && !model.getSelected().isEmpty()) {
330  List<Contact> contacts = model.getSelected().stream().map(ci -> ci.getContact())
331  .collect(Collectors.toList());
332  contacts.forEach(contact -> contact.setDeactivated(false));
333  getDao().saveCollection(contacts);
334  BindUtils.postNotifyChange(null, null, ContactsVM.this, "model");
335  }
336  }
337 
338  @Command
339  public void deactivate() {
340  if(model != null && !model.getSelected().isEmpty()) {
341  List<Contact> contacts = model.getSelected().stream().map(ci -> ci.getContact())
342  .collect(Collectors.toList());
343  contacts.forEach(contact -> contact.setDeactivated(true));
344  getDao().saveCollection(contacts);
345  BindUtils.postNotifyChange(null, null, ContactsVM.this, "model");
346  }
347  }
348 
349  @NotifyChange("model")
350  @Command("update")
351  public void update() {}
352 
353  public Set<DirectoryType> getTypeSet() {
354  return typeSet;
355  }
356 
357  public void setTypeSet(Set<DirectoryType> typeSet) {
358  this.typeSet = typeSet;
359  }
360 
361  public String getSearchValue() {
362  return searchValue;
363  }
364 
365  public void setSearchValue(String searchValue) {
366  this.searchValue = searchValue;
367  }
368 
369  public boolean isUseConnector() {
370  return search.isUseConnector();
371  }
372 
373  public void setUseConnector(boolean useConnector) {
374  search.setUseConnector(useConnector);
375  }
376 
377  public boolean isUseAddress() {
378  return search.isUseAddress();
379  }
380 
381  public void setUseAddress(boolean useAddress) {
382  search.setUseAddress(useAddress);
383  }
384 
385  public boolean isUseComment() {
386  return search.isUseComment();
387  }
388 
389  public void setUseComment(boolean useComment) {
390  search.setUseComment(useComment);
391  }
392 
394  if(doNotLoad) {
395  doNotLoad = false;
396  return model;
397  }
398  model = null;
399  if(selected != null) {
400  model = new ContactModel(getDao(), selected);
401  selected = null;
402  } else {
403  if(typeSet.isEmpty()) return new ContactModel(getDao(), Collections.EMPTY_LIST);
404  WhereClause wc = new WhereClause();
405  wc.addClause("select distinct contact.id from Contact contact");
406  wc.addClause("left outer join contact.businessRelations relation");
407  wc.addClause("left outer join contact.connectors connector");
408  wc.addClause("left outer join contact.addresses address");
409  wc.addClause("left outer join contact.syndications syndication");
410  wc.addClause("left outer join contact.comments comment");
411  search.apply("where", searchValue, wc, secSet.isEmpty() && tagSet.isEmpty() && skillSet.isEmpty());
412  if(!typeSet.equals(EnumSet.allOf(DirectoryType.class))) {
413  wc.addClause("and (");
414  String sep = "";
415  if(typeSet.contains(DirectoryType.DIRECTORY_COMPANIES)) {
416  wc.addClause(sep + "contact.type = :typeb");
418  sep = "or ";
419  }
420  if(typeSet.contains(DirectoryType.DIRECTORY_CENTERS)) {
421  wc.addClause(sep + "contact.type = :typec");
423  sep = "or ";
424  }
425  if(typeSet.contains(DirectoryType.DIRECTORY_PROFESSIONALS)) {
426  FuzzyRelationTypes.isProfessional(wc, sep, "relation");
427  sep = "or ";
428  }
429  if(typeSet.contains(DirectoryType.DIRECTORY_EDUCATORS)) {
430  FuzzyRelationTypes.isEducator(wc, sep, "relation");
431  sep = "or ";
432  }
433  if(typeSet.contains(DirectoryType.DIRECTORY_STUDENTS)) {
434  FuzzyRelationTypes.isStudent(wc, sep, "relation");
435  sep = "or ";
436  }
437  if(typeSet.contains(DirectoryType.DIRECTORY_SINGLETONS)) {
438  FuzzyRelationTypes.isSingleton(wc, sep, "contact", "relation");
439  sep = "or ";
440  }
441  wc.addClause(")");
442  }
443  if(secSet != null && !secSet.isEmpty()) {
444  List<String> ids = Secs.getIdentifiers(getDao(), secSet);
445  if(ids == null || ids.isEmpty()) {
446  wc.addClause("and 1=2");
447  } else {
448  wc.addIn("and", "contact.id", ids);
449  }
450  }
451  if(tagSet != null && !tagSet.isEmpty()) {
452  List<String> ids = Tags.getIdentifiers("contact", tagSet);
453  if(ids == null || ids.isEmpty()) {
454  wc.addClause("and 1=2");
455  } else {
456  wc.addIn("and", "contact.id", ids);
457  }
458  }
459  if(skillSet != null && !skillSet.isEmpty()) {
460  List<String> ids = SkillTags.getIdentifiers("contact", skillSet);
461  if(ids == null || ids.isEmpty()) {
462  wc.addClause("and 1=2");
463  } else {
464  wc.addIn("and", "contact.id", ids);
465  }
466  }
467  if(!allContacts) {
468  wc.addIn("and", "syndication.name",
469  SocialGroups.allowedSocialGroups().stream().map(sg -> sg.getId()).collect(Collectors.toList()));
470  }
471  wc.addClause("order by contact.name");
472  model = new ContactModel(getDao(), getDao().getResultList(wc));
473  }
474  return model;
475  }
476 
477  public ListModel getTypeModel() {
478  return new ListModelSet(DirectoryType.values());
479  }
480 
481  private List contactsFromModel() {
482  ContactList list = new ContactList();
483  if(model != null) {
484  for(ContactItem mi : model.getSelected()) {
485  list.add(mi.getContact());
486  }
487  }
488  return list;
489  }
490 
491  private List relationsFromModel() {
492  ContactList list = new ContactList();
493  if(model != null) {
494  for(ContactItem mi : model.getSelected()) {
495  list.addAll(mi.getContact().getCoworkers(mi.getContact()));
496  }
497  }
498  return list;
499  }
500 
501  /* Dao */
502 
503  private Dao _dao;
504 
505  private Dao getDao() {
506  if(_dao == null) {
507  _dao = new ContactsPU();
508  }
509  return _dao;
510  }
511 
512 }
static< T > T loadImplementation(Class< T > jclass)
Definition: Plugins.java:57
static String getObjectPath(Object object)
Definition: ContactsPU.java:68
void qrcode(@BindingParam("item") ContactItem item)
void edit(@BindingParam("item") ContactItem item)
void setSearchValue(String searchValue)
void vcard(@BindingParam("item") ContactItem item)
void organigram(@BindingParam("item") ContactItem item)
void skill(@BindingParam("selected") Set< SkillItem > selected)
void sec(@BindingParam("selected") Set< SecItem > selected)
void setUseComment(boolean useComment)
void setUseAddress(boolean useAddress)
Set< DirectoryType > getTypeSet()
void select(@BindingParam("item") IElephantEntity item)
void subscriptions(@BindingParam("item") ContactItem item)
void setTypeSet(Set< DirectoryType > typeSet)
void tag(@BindingParam("selected") Set< TagItem > selected)
void participations(@BindingParam("item") ContactItem item)
void setUseConnector(boolean useConnector)
void setUseComment(boolean useComment)
void setUseConnector(boolean useConnector)
void apply(String operator, String value, WhereClause wc, boolean stopIfEmpty)
void setUseAddress(boolean useAddress)
static boolean isStudent(BusinessRelation relation)
static boolean isEducator(BusinessRelation relation)
static void isSingleton(WhereClause wc, String separator, String contactField, String relationField)
static boolean isProfessional(BusinessRelation relation)
static void showOrganigram(Contact contact)
static void showSubscriptions(Contact contact)
static void showContact(Contact contact)
static void showParticipations(String entityPath)
void addIn(String operator, String field, List values)
void addNamedValue(String name, Object value)
static String get(String msg)
Definition: I_.java:41
static void showEntityModal(Object id, String attribute, String include, Command command)
static void removeSyndication(Dao dao, String syndication)
Definition: Secs.java:102
static List< String > getIdentifiers(Dao dao, Set< SecItem > sets)
Definition: Secs.java:85
static Collection< SecurityGroup > getAll()
static Collection< SecurityGroup > allowedSocialGroups()
static void unsyndicate(List< Contact > contacts, Set< String > socialGroupIds, Dao dao)
static void resyndicate(List< Contact > contacts, Dao dao)
static void checkInheritance(List< Contact > contacts, Dao dao)
static void syndicate(List< Contact > contacts, Set< String > socialGroupIds, Dao dao)
static List< String > getIdentifiers(String root, Set< SkillItem > set)
Definition: SkillTags.java:100
static List< String > getIdentifiers(String root, Set< TagItem > set)
Definition: Tags.java:234
static void removeTags(Object entity)
Definition: Tags.java:366
static DialogField field(String label)
Dialogs width(String width)
Definition: Dialogs.java:70
Dialogs height(String height)
Definition: Dialogs.java:75
Dialogs onOk(Consumer< Dialogs > onOk)
Definition: Dialogs.java:85
static Dialogs title(String title)
Definition: Dialogs.java:161
Dialogs addField(DialogField field)
Definition: Dialogs.java:110
static FrameClipboard getClipboard()
Definition: Framework.java:220