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