001/*
002 *  Copyright 2020 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.workspaces.tasks.jcr;
017
018import java.time.LocalDate;
019import java.time.ZonedDateTime;
020import java.util.Arrays;
021import java.util.List;
022import java.util.Set;
023import java.util.stream.Collectors;
024
025import javax.jcr.Node;
026import javax.jcr.RepositoryException;
027
028import org.ametys.cms.data.Binary;
029import org.ametys.cms.data.holder.ModifiableIndexableDataHolder;
030import org.ametys.cms.data.holder.impl.DefaultModifiableModelAwareDataHolder;
031import org.ametys.cms.repository.comment.Comment;
032import org.ametys.core.user.UserIdentity;
033import org.ametys.plugins.repository.AmetysRepositoryException;
034import org.ametys.plugins.repository.data.holder.ModifiableModelLessDataHolder;
035import org.ametys.plugins.repository.data.holder.group.ModifiableModelAwareRepeater;
036import org.ametys.plugins.repository.data.holder.group.ModifiableModelAwareRepeaterEntry;
037import org.ametys.plugins.repository.data.holder.impl.DefaultModifiableModelLessDataHolder;
038import org.ametys.plugins.repository.data.repositorydata.ModifiableRepositoryData;
039import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData;
040import org.ametys.plugins.repository.jcr.DefaultAmetysObject;
041import org.ametys.plugins.repository.tag.TaggableAmetysObjectHelper;
042import org.ametys.plugins.workspaces.tasks.Task;
043
044/**
045 * JCR implementation of a task
046 */
047public class JCRTask extends DefaultAmetysObject<JCRTaskFactory> implements Task
048{
049    /** Attribute Taskid */
050    public static final String ATTRIBUTE_TASK_ID = "id";
051    /** Attribute Taskid */
052    public static final String ATTRIBUTE_TASKSLISTID = "tasksListId";
053    /** Attribute Taskid */
054    public static final String ATTRIBUTE_TASKSLISTPOSITION = "tasksListPosition";
055    /** Attribute Label */
056    public static final String ATTRIBUTE_LABEL = "label";
057    /** Attribute Description */
058    public static final String ATTRIBUTE_DESCRIPTION = "description";
059    /** Attribute Startdate */
060    public static final String ATTRIBUTE_STARTDATE = "startDate";
061    /** Attribute DueDate */
062    public static final String ATTRIBUTE_DUEDATE = "dueDate";
063    /** Attribute IsClosed */
064    public static final String ATTRIBUTE_ISCLOSED = "isClosed";
065    /** Attribute CloseDate */
066    public static final String ATTRIBUTE_CLOSEDATE = "closeDate";
067    /** Attribute CloseAuthor */
068    public static final String ATTRIBUTE_CLOSEAUTHOR = "closeAuthor";
069    /** Attribute Author */
070    public static final String ATTRIBUTE_AUTHOR = "author";
071    /** Attribute Assignments */
072    public static final String ATTRIBUTE_ASSIGNMENTS = "assignments";
073    /** Attribute Creationdate */
074    public static final String ATTRIBUTE_CREATIONDATE = "creationDate";
075    /** Attribute Lastmodified */
076    public static final String ATTRIBUTE_LASTMODIFIED = "lastModified";
077    /** Attribute Attachments */
078    public static final String ATTRIBUTE_ATTACHMENTS = "attachments";
079    /** Attribute CheckList */
080    public static final String ATTRIBUTE_CHECKLIST = "checkList";
081    /** Attribute Label for checkList */
082    public static final String ATTRIBUTE_CHECKLIST_LABEL = "label";
083    /** Attribute IsChecked for checkList */
084    public static final String ATTRIBUTE_CHECKLIST_ISCHECKED = "isChecked";
085    /** Attribute Tags */
086    public static final String ATTRIBUTE_TAGS = "tags";
087    
088    /**
089     * Default constructor for the JCRTask
090     * @param node The task node
091     * @param parentPath The parent path
092     * @param factory The factory
093     */
094    public JCRTask(Node node, String parentPath, JCRTaskFactory factory)
095    {
096        super(node, parentPath, factory);
097    }
098
099    public String getTaskListId()
100    {
101        return getValue(ATTRIBUTE_TASKSLISTID);
102    }
103    
104    public void setTasksListId(String taskListId)
105    {
106        setValue(ATTRIBUTE_TASKSLISTID, taskListId);
107    }
108    
109    public Long getPosition()
110    {
111        return getValue(ATTRIBUTE_TASKSLISTPOSITION);
112    }
113    
114    public void setPosition(Long position)
115    {
116        setValue(ATTRIBUTE_TASKSLISTPOSITION, position);
117    }
118
119    public String getLabel()
120    {
121        return getValue(ATTRIBUTE_LABEL);
122    }
123
124    public void setLabel(String label)
125    {
126        setValue(ATTRIBUTE_LABEL, label);
127    }
128    
129    public String getDescription()
130    {
131        return getValue(ATTRIBUTE_DESCRIPTION);
132    }
133
134    public void setDescription(String description)
135    {
136        setValue(ATTRIBUTE_DESCRIPTION, description);
137    }
138    
139    public LocalDate getStartDate()
140    {
141        return getValue(ATTRIBUTE_STARTDATE);
142    }
143    
144    public void setStartDate(LocalDate startDate)
145    {
146        setValue(ATTRIBUTE_STARTDATE, startDate);
147    }
148
149    public LocalDate getDueDate()
150    {
151        return getValue(ATTRIBUTE_DUEDATE);
152    }
153
154    public void setDueDate(LocalDate dueDate)
155    {
156        setValue(ATTRIBUTE_DUEDATE, dueDate);
157    }
158    
159    public boolean isClosed()
160    {
161        return getValue(ATTRIBUTE_ISCLOSED, false, false);
162    }
163    
164    public void close(boolean isClosed)
165    {
166        setValue(ATTRIBUTE_ISCLOSED, isClosed);
167    }
168    
169    public UserIdentity getCloseAuthor()
170    {
171        return getValue(ATTRIBUTE_CLOSEAUTHOR);
172    }
173    
174    public void setCloseAuthor(UserIdentity author)
175    {
176        setValue(ATTRIBUTE_CLOSEAUTHOR, author);
177    }
178
179    public LocalDate getCloseDate()
180    {
181        return getValue(ATTRIBUTE_CLOSEDATE);
182    }
183    
184    public void setCloseDate(LocalDate closedDate)
185    {
186        setValue(ATTRIBUTE_CLOSEDATE, closedDate);
187    }
188    
189    public UserIdentity getAuthor()
190    {
191        return getValue(ATTRIBUTE_AUTHOR);
192    }
193    
194    public void setAuthor(UserIdentity author)
195    {
196        setValue(ATTRIBUTE_AUTHOR, author);
197    }
198    
199    public List<UserIdentity> getAssignments()
200    {
201        UserIdentity[] users = getValue(ATTRIBUTE_ASSIGNMENTS, false, new UserIdentity[0]);
202        return Arrays.asList(users);
203    }
204    
205    public void setAssignments(List<UserIdentity> assignments)
206    {
207        setValue(ATTRIBUTE_ASSIGNMENTS, assignments.toArray(new UserIdentity[assignments.size()]));
208    }
209
210    public ZonedDateTime getCreationDate()
211    {
212        return getValue(ATTRIBUTE_CREATIONDATE);
213    }
214    
215    public void setCreationDate(ZonedDateTime creationDate)
216    {
217        setValue(ATTRIBUTE_CREATIONDATE, creationDate);
218    }
219    
220    public ZonedDateTime getLastModified()
221    {
222        return getValue(ATTRIBUTE_LASTMODIFIED);
223    }
224    
225    public void setLastModified(ZonedDateTime lastModifiedDate)
226    {
227        setValue(ATTRIBUTE_LASTMODIFIED, lastModifiedDate);
228    }
229    
230    public List<Binary> getAttachments()
231    {
232        Binary[] attachements = getValue(ATTRIBUTE_ATTACHMENTS, false, new Binary[0]);
233        return Arrays.asList(attachements);
234    }
235    
236    public void setAttachments(List<Binary> attachments)
237    {
238        setValue(ATTRIBUTE_ATTACHMENTS, attachments.toArray(new Binary[attachments.size()]));
239    }
240
241    public void tag(String tag) throws AmetysRepositoryException
242    {
243        TaggableAmetysObjectHelper.tag(this, tag);
244    }
245
246    public void untag(String tag) throws AmetysRepositoryException
247    {
248        TaggableAmetysObjectHelper.untag(this, tag);
249    }
250
251    public Set<String> getTags() throws AmetysRepositoryException
252    {
253        return TaggableAmetysObjectHelper.getTags(this);
254    }
255
256    public List<CheckItem> getCheckList()
257    {
258        ModifiableModelAwareRepeater repeater = getRepeater(ATTRIBUTE_CHECKLIST, true);
259        return repeater.getEntries()
260                    .stream()
261                    .map(e -> new CheckItem(e.getValue(ATTRIBUTE_CHECKLIST_LABEL), e.getValue(ATTRIBUTE_CHECKLIST_ISCHECKED, false, false)))
262                    .collect(Collectors.toList());
263    }
264
265    public void setCheckListItem(List<CheckItem> checkItems)
266    {
267        ModifiableModelAwareRepeater repeater = getRepeater(ATTRIBUTE_CHECKLIST, true);
268        for (ModifiableModelAwareRepeaterEntry entry : repeater.getEntries())
269        {
270            repeater.removeEntry(entry.getPosition());
271        }
272        
273        for (CheckItem checkItem : checkItems)
274        {
275            ModifiableModelAwareRepeaterEntry entry = repeater.addEntry();
276            
277            entry.setValue(ATTRIBUTE_CHECKLIST_LABEL, checkItem.getLabel());
278            entry.setValue(ATTRIBUTE_CHECKLIST_ISCHECKED, checkItem.isChecked());
279        }
280    }
281    
282    private ModifiableModelLessDataHolder _getCommentsDataHolder()
283    {
284        try
285        {
286            Node baseNode = getBaseNode();
287            if (!baseNode.hasNode("ametys:comments"))
288            {
289                baseNode.addNode("ametys:comments", "ametys:compositeMetadata");
290            }
291            Node commentsNode = baseNode.getNode("ametys:comments");
292            
293            // FIXME WORKSPACES-1614: there is a double level of comments nodes
294            if (!commentsNode.hasNode("ametys:comments"))
295            {
296                commentsNode.addNode("ametys:comments", "ametys:compositeMetadata");
297            }
298            Node secondLevelCommentsNode = commentsNode.getNode("ametys:comments");
299            
300            baseNode.getSession().save();
301            
302            ModifiableRepositoryData repositoryData = new JCRRepositoryData(secondLevelCommentsNode);
303            return new DefaultModifiableModelLessDataHolder(_getFactory().getUnversionedDataTypeExtensionPoint(), repositoryData);
304        }
305        catch (RepositoryException e)
306        {
307            throw new AmetysRepositoryException(e);
308        }
309    }
310    
311    public Comment createComment()
312    {
313        
314        return new Comment(_getCommentsDataHolder());
315    }
316    
317    public Comment createComment(String commentId, ZonedDateTime creationDate)
318    {
319        return new Comment(_getCommentsDataHolder(), commentId, creationDate);
320    }
321    
322    public Comment getComment(String commentId) throws AmetysRepositoryException
323    {
324        return Comment.getComment(_getCommentsDataHolder(), commentId);
325    }
326    
327    public List<Comment> getComments(boolean includeNotValidatedComments, boolean includeValidatedComments) throws AmetysRepositoryException
328    {
329        return Comment.getComments(_getCommentsDataHolder(), includeNotValidatedComments, includeValidatedComments);
330    }
331
332    public ModifiableIndexableDataHolder getDataHolder()
333    {
334        ModifiableRepositoryData repositoryData = new JCRRepositoryData(getNode());
335        return new DefaultModifiableModelAwareDataHolder(repositoryData, _getFactory().getTaskModel());
336    }
337}