1   package hudsonfog.voc.system;
2   
3   import com.fogx.webdav.DavResource;
4   import com.fogx.webdav.DavClass;
5   import com.fogx.webdav.DavBean;
6   import com.fogx.webdav.DavProperty;
7   import static com.fogx.webdav.DavProperty.*;
8   import com.fogx.webdav.packages.DavBeanPackage;
9   import com.fogx.webdav.util.DavResourceSupport;
10  import com.fogx.webdav.util.UrlUtil;
11  import java.util.Date;
12  import java.util.Map;
13  import java.util.HashMap;
14  import java.util.List;
15  import java.util.Collections;
16  import java.util.Arrays;
17  
18  import hudsonfog.voc.model.company.*;
19  import hudsonfog.voc.system.primitiveTypes.*;
20  import hudsonfog.voc.system.fog.*;
21  import hudsonfog.voc.system.parse.*;
22  import hudsonfog.voc.system.security.*;
23  import hudsonfog.voc.model.top.*;
24  import hudsonfog.voc.system.XMLSchema.*;
25  
26  import hudsonfog.voc.system.fog.*;
27  
28  
29  public abstract class parse {
30  
31    @DavClass._avoidIndexing
32    public static class EntryError {
33           @_subPropertyOf("partOf")
34      @k@s public Entry                         entry;
35        @k public Integer                       seq;
36           @_maxSize(200)
37           public String                        message;
38        @r public Boolean                       fatal;
39    }
40  
41    @DavClass._avoidIndexing
42    public static class ImportItem extends hudsonfog.voc.system.fog.Entry {
43      @k@s public dateTime                      entered;
44        @k public Integer                       timeEntered;
45           @_backLink("entry")
46           public ImportItemError[]             errors; //* errors automatically detected by the system when processing this ImportItem
47           public Contact                       contact; //* Contact that initiated this Entry
48           @_backLink("partOf")
49           public ExternalFile[]                attachments; //* files that arrived with this Entry
50    }
51  
52    @DavClass._avoidIndexing
53    public static class ImportItemError extends EntryError {
54      @k@s public ImportItem                    entry;
55      @k@s public Integer                       seq;
56    }
57  
58    /***************************** Messages *******************************/
59    public static interface FolderItem {
60           @_alwaysReturnToClient // this is needed so that client app can build a tree
61           public Folder                        folder = null; // parent folder for this item
62           @_alwaysReturnToClient // needed to build a tree
63           @_delegatedAccessControl
64           public Folder                        rootFolder = null; // top folder in the tree
65    }
66  
67    public static interface Folder extends FolderItem {
68           @_backLink("folder")
69           public FolderItem[]                  folderItems = null;
70           @_subPropertyOf("folder")
71        @s public Folder                        parentFolder = null;
72    }
73  
74    public static interface GenericMessage extends Submission, FolderItem {
75           @_containerMember
76           @_notifyContainer(false) // no avoid extra proppatches when status of message is changing it is important to notify 'to' for calculating unreadCount in contact's inbox
77           @_subPropertyOf("submittedBy")
78        @s public Contact                       sender = null;
79           @_containerMember
80           @_subPropertyOf("rootFolder")
81        @c public GenericMessageAccount         to = null;
82        @c public GenericMessageFolder          folder = null;
83           @_subPropertyOf("dateSubmitted")
84        @s public ComplexDate                   dateReceived = null;
85        @s public String                        subject = null;
86           @_maxSize(10000)
87           @_subPropertyOf("description")
88        @s public String                        body = null;
89           @_icon("icons/Priority.gif")
90           @_colorCoding("'Normal' icons/priority_normal.gif; 'High' icons/priority_major.gif; 'Critical' icons/priority_critical.gif; 'Lowest' icons/priority_trivial.gif; 'Low' icons/priority_minor.gif")
91           public Priority                      priority = null;
92           @_allowEditInList
93           @_icon("icons/markedAsRead.gif")
94           @_colorCoding("'False' icons/status-message-unread.gif; 'True' icons/status-message-read.gif;")
95           public Boolean                       markedAsRead = null; //* marks that the message was read by the recipient
96           @_allowEditInList
97           @_icon("icons/flag.gif")
98           @_colorCoding("'False' icons/status-message-read.gif; 'True' icons/flag-red.gif;")
99           public Boolean                       flagForFollowUp = null; //* important messages can be flagged by recipient
100   }
101 
102   public static interface Submission {
103          @_readOnly
104          @_icon("icons/openedBy.gif")
105          @_allowPermissions("MKRESOURCE, PROPPATCH, PUT")
106          @_delegatedAccessControl
107          @_onCreate
108          public Contact                       submittedBy = writeJS("submittedBy ? submittedBy : getRequest().getHeader('hudsonfog.bulk-operations') ? submittedBy : getContact()");
109          @_dateFormat("~MMM-dd, yyyy HH:mm")
110          @_readOnly
111          @_icon("icons/dateReceived.gif")
112          @_onCreate
113          public ComplexDate                   dateSubmitted = writeJS("dateSubmitted == null ? new Date().getTime() : dateSubmitted"); //* when this message entered the system
114          @_maxSize(200)
115          @_resourceLink
116          public String                        subject = null;
117          @_maxSize(10000)
118          @_icon("icons/description.gif")
119          @_displayInline
120          public String                        description = null;
121   }
122 
123   public static enum FlagStatus {
124     Red, Orange, Yellow, Green, Blue, Purple, Completed;
125   }
126 
127   public static interface GenericMessageFolder extends Folder {
128          @_maxSize(200)
129          public String                        folderName = null;
130          public GenericMessageAccount         messageAccount = null;
131          @_backLink("folder")
132          @_subPropertyOf("folderItems")
133       @s public GenericMessage[]              messages = null;
134       @s public GenericMessageFolder          parentFolder = null;
135          @_dateFormat("~MMM-dd, yyyy HH:mm")
136          @_readOnly
137          @_icon("icons/dateReceived.gif")
138          @_onCreate
139          public ComplexDate                   dateCreated = writeJS("(dateCreated == null) ? (getSession() == null ? null : new Date().getTime()) : dateCreated"); //* when this folder was created
140          @_maxSize(1000)
141          public String                        notes = null;
142   }
143 
144   /**
145  * FileSystem is a resource that has files associated with it.
146  * Its attachmentsUrl property specifies location of the files.
147  */
148   public static interface FileSystem extends Folder {
149          @_maxSize(250)
150          @_readOnly
151          @_mustImplement // this property must be implemented in implementors
152          @_avoidDisplaying
153          @_avoidIndexing
154          public String                        attachmentsUrl = null;
155          @_largeIcon("icons/Attachment-large.gif")
156          @_icon("icons/Attachment.gif")
157          @_mustImplement
158          @_notSearchable
159          @_avoidDisplayingInControlPanel
160          @_backLink("forResource")
161          public ExternalFile[]                attachments = null;
162          @_icon("icons/size.gif")
163          @_makeTotal
164          @_readOnly // if loading from data file and file has value for this property - do not calculate
165          public fileSize                      sizeOfAttachments = writeJS("getThisChange().attachments ? attachments.SUM('size') : sizeOfAttachments"); //* total size of attachments
166          @_readOnly
167          public Integer                       attachmentsCount = writeJS("getThisChange().attachments ? attachments.COUNT() : attachmentsCount"); //* total number of attachments
168   }
169 
170   /* GenericMessageAccount is a (INBOX) folder too */
171   public static interface GenericMessageAccount extends GenericMessageFolder {
172          @_maxSize(100)
173          public String                        accountName = null;
174          public ExternalOrganization          organization = null; // organization of the owner of this account
175          @_backLink("messageAccount")
176          public GenericMessageFolder[]        customFolders = null;
177   }
178 
179   @DavClass._largeIcon("icons/classes/Inbox-large.gif")
180   @DavClass._viewCols("subject, associatedWith, sender, date, priority, attachments, sizeOfAttachments, markedAsRead, flagForFollowUp")
181   @DavClass._icon("icons/classes/Inbox.gif")
182   public static class Message implements GenericMessage, FileSystem {
183          @_displayNameElm
184     @k@c public String                        subject;
185       @c public GenericMessageAccount         to;
186          @_readOnly
187       @c public GenericMessageFolder          folder;
188          @_sortAscending(false)
189          @_cloneOf("dateReceived")
190     @k@c public ComplexDate                   date;
191       @c public String                        body;
192       @c public Priority                      priority;
193          @_readOnly
194       @c public Contact                       sender;
195          @_backLink("forResource")
196       @c public ExternalFile[]                attachments;
197       @c public fileSize                      sizeOfAttachments; //* total size of attachments
198       @c public Boolean                       markedAsRead; //* marks that the message was read by the recipient
199       @c public Boolean                       flagForFollowUp; //* important messages can be flagged by recipient
200          @_largeIcon("icons/Status-large.gif")
201          @_icon("icons/Status.gif")
202          @_readOnly
203          @_colorCoding("'Replied' icons/status-message-replied.gif; 'Forwarded' icons/status-message-forwarded.gif;")
204          public MessageStatus                 status;
205          @_readOnly
206          public DavResource                   associatedWith;
207          @_cloneOf("attachmentsUrl")
208       @c public String                        url;
209   }
210 
211   public static enum MessageStatus {
212     Replied, Forwarded;
213   }
214 
215   @DavClass._label("Message")
216   @DavClass._largeIcon("icons/classes/Inbox-large.gif")
217   @DavClass._viewCols("subject, associatedWith, sender, dateReceived, priority, sizeOfAttachments, attachments, markedAsRead, flagForFollowUp")
218   @DavClass._icon("icons/classes/Inbox.gif")
219   public static class IncomingMessage extends Message {
220          @_displayNameElm
221     @k@s public String                        subject;
222          @_sortAscending(false)
223          @_subPropertyOf("date")
224     @k@s public ComplexDate                   dateReceived;
225          @_readOnly
226          @_backLink("forResource")
227       @s public ExternalFile[]                attachments;
228   }
229 
230   /**
231  * Message that is not sent yet. Could be draft or may be connection is not available.
232  */
233   @DavClass._label("Message")
234   @DavClass._viewCols("subject, associatedWith, to, dateSent, priority, sizeOfAttachments, attachments, markedAsRead, flagForFollowUp")
235   @DavClass._largeIcon("icons/classes/Inbox-large.gif")
236   @DavClass._icon("icons/classes/Inbox.gif")
237   public static class OutgoingMessage extends Message {
238          @_displayNameElm
239     @k@s public String                        subject;
240          @_sortAscending(false)
241          @_subPropertyOf("date")
242     @k@s public ComplexDate                   dateSent;
243   }
244 
245   @DavClass._largeIcon("icons/classes/MessageFolder-large.gif")
246   @DavClass._icon("icons/classes/MessageFolder.gif")
247   public static class MessageFolder implements GenericMessageFolder {
248          @_displayNameElm
249          @_cloneOf("messageAccount")
250     @k@c public GenericMessageAccount         belongsTo;
251       @k public Integer                       seq;
252          @_displayNameElm
253       @c public String                        folderName;
254       @c public ComplexDate                   dateCreated; //* when this folder was created
255       @c public String                        notes;
256          @_backLink("folder")
257       @c public Message[]                     messages;
258   }
259 
260   @DavClass._avoidIndexing
261   public static class EmailMessage extends ImportItem implements GenericMessage {
262       @k public MailAccount                   mailAccount;
263       @c public MailFolder                    folder;
264          @_sortAscending(false)
265          @_subPropertyOf("entered")
266     @k@s public dateTime                      dateReceived;
267          @_subPropertyOf("timeEntered")
268     @k@s public Integer                       timeReceived;
269          public Long                          dateSent;
270          @_maxSize(100)
271          public String                        fromAddress;
272          @_maxSize(1000)
273          public String                        to;
274          @_maxSize(200)
275          public String                        validEmailAddress;
276          @_maxSize(1000)
277          public String                        cc;
278          @_cloneOf("subject")
279       @c public String                        subjectText;
280          @_cloneOf("priority")
281       @c public Priority                      mailPriority;
282          public Boolean                       messageCompleted;
283          @_backLink("partOf")
284       @s public ExternalFile[]                attachments;
285   }
286 
287   public static class MailFolder implements GenericMessageFolder {
288     @k@c public String                        folderName;
289          @_cloneOf("messageAccount")
290     @k@c public MailAccount                   mailAccount;
291          @_backLink("folder")
292       @c public Message[]                     messages;
293   }
294 
295   /**
296  * MailAccount defines a receiving point for Emailable resources
297  * or for resources imported from email attachments, like EDI.
298  */
299   public static class MailAccount implements GenericMessageAccount {
300     @k@c public String                        accountName; //* Unique name for this account.
301          @_backLink("mailAccount")
302       @c public MailFolder[]                  customFolders; //* Folders where inbox messages might be moved
303     /**
304     * When importing Email attachments - specifies the configuration that
305     * will govern the importing and transformation process.
306     */
307          public DocumentTable                 aliasTo;
308     /*
309     * Addresses where warnings and errors will be sent (in addition to sending them to the sender)
310     * Use ';' as a delimeter, e.g: steve@toy.com; lucy@work.com
311     */
312          @_maxSize(500)
313          public String                        supportEmails;
314          @_maxSize(500)
315          public String                        additionalSupportEmails; //* same as supportEmails, but email is sent as CC
316     /*
317     * By default 'from' in incoming email is matched with Contact.email or ContactEmail.
318     * If this proeprty is true - any sender willbe accepted.
319     * Consider using -skipSenderValidation class property.
320     * This might let you avoid creating a MailAccount resource altogether.
321     */
322          public Boolean                       skipSenderValidation;
323          @_maxSize(500)
324          public String                        authorizedDomains; //* Works like skipSenderValidation, but for specific Domains, like "mail.com; host.com"
325     /*
326     * By default all emails are sent to backup account (see mail.conf).
327     * If true - emails on this account will not be backed up.
328     */
329          public Boolean                       skipBackup;
330          public Boolean                       pickupOnly; //* If true - email attachments will be saved, but not imported.
331          public Boolean                       overwriteExistingFile; //* If true - email attachment will overwrite the existing file, if name clashes.
332     /*
333     * Normally warnings and errors in incoming emails will be sent to the sender.
334     * But in case sender is a robot, this is undesirable and may even cause an email loop,
335     * since sender robot may reply: "what did you say, I did not understand" - adn so forth.
336     */
337          public Boolean                       doNotSendToSender;
338     /**
339     * Watchdog properties - for emails that must come on a regular basis.
340     * this will be redesigned soon since a generic more powerful Watchdog
341     * is being developed.
342     */
343          public Boolean                       leaveMessagesOnServer;
344          public Integer                       firstDelayAlert;
345          public Integer                       secondDelayAlert;
346          @_maxSize(500)
347          public String                        escalationSupportEmails;
348          @_maxSize(500)
349          public String                        escalationAddSuppEmails;
350          public ExternalFile                  alertTemplate;
351          public Boolean                       delayAlertTest;
352          @_maxSize(200)
353          public String                        delayAlertTestEmails;
354          public DavClass                      emailableClass;
355   }
356 
357   public static class MailDelayAlert {
358       @k public MailAccount                   account;
359       @k public Long                          created;
360          public Integer                       delay;
361   }
362 
363   public static class EmailMessageAddress {
364       @k public EmailMessage                  emailMessage;
365       @k public Integer                       seq;
366          @_maxSize(100)
367       @r public String                        address;
368   }
369 
370   public static class ToAddress extends EmailMessageAddress {
371     @k@s public EmailMessage                  emailMessage;
372     @k@s public Integer                       seq;
373   }
374 
375   public static class CcAddress extends EmailMessageAddress {
376     @k@s public EmailMessage                  emailMessage;
377     @k@s public Integer                       seq;
378   }
379 
380   public static enum MailPriorityType {
381     Lowest, Low, Normal, High, Highest;
382   }
383 
384   /**
385  * ExternalFile resource is created for every file in a file system (uploaded, read from email, or otherwise imported into the system).
386  * Some Resource implementing FileSystem interface always serves as a Container resource for ExternalFile(s).
387  * (all the security rules, cascading delete rule apply to a Container resource)
388  */
389   @DavClass._viewCols("name, size")
390   @DavClass._largeIcon("icons/classes/File-large.gif")
391   @DavClass._icon("icons/classes/File.gif")
392   public static class ExternalFile implements FolderItem {
393          @_maxSize(250)
394          @_propertyEditor("ExternalFilePropertyEditor")
395       @k public String                        url;
396          @_makeTotal
397          @_icon("icons/size.gif")
398          @_readOnly
399          public fileSize                      size; // HACK - must change to long
400          @_resourceLink
401          @_readOnly
402          @_displayNameElm
403          public String                        name = writeJS("name ? name : getFileName()");
404          @_maxSize(50)
405          @_sortAscending
406          @_readOnly
407          public String                        mimeType;
408          @_containerMember
409          @_delegatedAccessControl
410          @_cloneOf("rootFolder")
411          @_forwardLink("http://www.hudsonfog.com/voc/system/parse/FileSystem/attachments")
412          @_readOnly
413          @_notifyContainer
414       @c public FileSystem                    forResource;
415          @_readOnly
416          @_allowRoles("admin")
417          public User                          user;
418          @_readOnly
419          public Contact                       owner = writeJS("owner ? owner : user ? user.contact : getContact()");
420          @_readOnly
421          public dateTime                      lastModified = writeJS("lastModified ? lastModified : new Date().getTime()");
422   }
423 
424   /*
425 class ExternalFileError extends EntryError {
426   -avoidIndexing : true;
427   #ExternalFile             entry :: entry;
428   #int                      seq :: seq;
429 }
430 */
431   @DavClass._avoidIndexing
432   @DavClass._largeIcon("icons/classes/Txt-large.gif")
433   @DavClass._icon("icons/classes/Txt.gif")
434   public static class TxtFile extends ExternalFile {
435          @_subPropertyOf("url")
436     @k@s public String                        txtFile;
437          public Long                          date;
438       @s public String                        name;
439          public String                        filename;
440          public DocumentTable                 docTable;
441   }
442 
443   @DavClass._largeIcon("icons/classes/Comment-large.gif")
444   @DavClass._icon("icons/classes/Comment.gif")
445   public static class ChatHistoryFile extends ExternalFile {
446          @_propertyEditor("ExternalFilePropertyEditor")
447     @k@s public String                        url;
448   }
449 
450   /**
451  * Entry that is created for each imported file (file processed by ETL).
452  * (a separate entry is created for each sheet in MS Excel file)
453  */
454   @DavClass._avoidIndexing
455   @DavClass._viewCols("file, sheetNumber, entered, completed, errors")
456   public static class FileEntry extends hudsonfog.voc.system.fog.Entry {
457          @_displayNameElm
458       @k public ExternalFile                  file;
459       @k public Integer                       sheetNumber;
460          @_readOnly
461          public DocumentTable                 docTable;
462          @_readOnly
463          @_backLink("entry")
464          public FileEntryError[]              errors;
465          @_dateFormat("~MMM-dd, yyyy HH:mm")
466          @_readOnly
467          public dateTime                      created; //* when processing for this Entry was completed
468   }
469 
470   @DavClass._avoidIndexing
471   public static class BackupFile extends hudsonfog.voc.system.fog.Entry {
472          @_displayNameElm
473       @k public ExternalFile                  backupFile;
474   }
475 
476   @DavClass._avoidIndexing
477   public static class ExcelLocation {
478       @k public FileEntry                     sheet;
479       @k public Integer                       column;
480       @k public Integer                       row;
481          @_maxSize(20)
482          @_displayNameElm
483       @r public String                        name;
484   }
485 
486   @DavClass._avoidIndexing
487   public static class FileEntryError extends EntryError {
488     @k@s public FileEntry                     entry;
489     @k@s public Integer                       seq;
490          public Integer                       sheetNumber;
491          public DavResource                   errorResource;
492          @_displayNameElm
493          public ExcelLocation                 location;
494          public DavResource                   duplicateOf;
495          public Boolean                       transformationError;
496   }
497 
498   @DavClass._avoidIndexing
499   public static class TransformationEntry extends hudsonfog.voc.system.fog.Entry implements TransformationJob {
500     @k@c public String                        code;
501       @c public DavClass                      items;
502       @c public String                        transformations;
503          @_backLink("entry")
504          public EntryError[]                  errors;
505   }
506 
507   @DavClass._viewCols("code, description, entries, doNotProcess, forTesting")
508   @DavClass._avoidEditing
509   public static class DocumentTable implements TransformationJob {
510          @_displayNameElm
511     @k@c public String                        code;
512          @_maxSize(1000)
513       @r public String                        description;
514          @_allowRoles("admin")
515       @c public String                        transformations;
516          @_allowRoles("admin")
517       @c public DavClass                      items;
518          @_notSearchable
519          @_backLink("submittedFor")
520          public Submit[]                      submits; //* each document [re]processing is recorded
521          @_notSearchable
522          @_backLink("docTable")
523          public FileEntry[]                   entries; //* Each Entry resource corresponds to a Document part (e.g. Excel Sheet)
524          @_allowRoles("admin")
525          public Boolean                       isDavServlet;
526          public Boolean                       doNotProcess; //* suspended - not processed at this time
527          public Boolean                       forTesting; //* this document is used for testing purposes only
528          @_allowRoles("admin")
529          public Boolean                       doNotCheckForDuplicates;
530          @_allowRoles("admin")
531          public Boolean                       trackModificationHistory; //* Enable Modification tracking. By default it is disabled for all bulk operations.
532          @_allowRoles("admin")
533          public DavClass                      displayAfterUpload; //* when uploaded via UI - specifies the class of resources to display right after upload. If false (default)- will instead show uploaded file in file list.
534   }
535 
536   public static interface TransformationJob {
537          @_maxSize(100)
538       @k public String                        code = null;
539          @_maxSize(1000)
540          public String                        transformations = null;
541          public DavClass                      items = null;
542   }
543 
544   public static class Submit extends hudsonfog.voc.system.fog.Action {
545       @k public Integer                       seq;
546       @k public DocumentTable                 submittedFor;
547          public ExternalFile                  file;
548   }
549 
550   public static class Replacement extends Submit {
551     @k@s public Integer                       seq;
552     @k@s public DocumentTable                 submittedFor;
553          public ExternalFile                  forFile;
554   }
555 
556   @DavClass._largeIcon("icons/classes/AssignedItem-large.gif")
557   @DavClass._icon("icons/classes/AssignedItem.gif")
558   public static interface WorkItem {
559          @_autoSubscribeContact
560          @_icon("icons/classes/AssignedItem.gif")
561          @_allowPermissions("MKRESOURCE, PROPPATCH, PUT")
562          public Contact                       assignedTo = null;
563          @_maxSize(100)
564          @_largeIcon("icons/Status-large.gif")
565          @_icon("icons/Status.gif")
566          public String                        status = null;
567   }
568 
569   public static enum Priority {
570     Lowest, Low, Normal, High, Critical;
571   }
572 }
573