Skip to content

Commit bfd12fa

Browse files
Farcasuttrrenty
andauthored
Allow multiple assignees for tasks #184 (#222)
* Allow multiple assignees for tasks #184 * Updated the task manager class to allow multiple assignees * Updated the java code allow the creation of a task macro with multiple assignees and made sure that the relation between them is kept * Added a new test * Allow multiple assignees for tasks #184 * Updated the task manager class to allow multiple assignees * Updated the java code allow the creation of a task macro with multiple assignees and made sure that the relation between them is kept * Added a new test * Allow multiple assignees for tasks #184 * Added the public code back and marked it as deprecated. * Forgotten merge files * Fix build --------- Co-authored-by: Teodor Caras <[email protected]>
1 parent b81c252 commit bfd12fa

File tree

14 files changed

+193
-53
lines changed

14 files changed

+193
-53
lines changed

application-task-api/src/main/java/com/xwiki/task/model/Task.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package com.xwiki.task.model;
2121

2222
import java.util.Date;
23+
import java.util.List;
2324

2425
import org.xwiki.model.reference.DocumentReference;
2526
import org.xwiki.stability.Unstable;
@@ -138,8 +139,11 @@ public class Task
138139

139140
private DocumentReference reporter;
140141

142+
@Deprecated(since = "3.7.2")
141143
private DocumentReference assignee;
142144

145+
private List<DocumentReference> assignees;
146+
143147
private Date createDate;
144148

145149
private Date startDate;
@@ -239,6 +243,7 @@ public void setReporter(DocumentReference reporter)
239243
/**
240244
* @return a list of references to the users that are assigned to this task.
241245
*/
246+
@Deprecated(since = "3.7.2")
242247
public DocumentReference getAssignee()
243248
{
244249
return assignee;
@@ -247,11 +252,28 @@ public DocumentReference getAssignee()
247252
/**
248253
* @param assignee a list of references to the users that are assigned to this task.
249254
*/
255+
@Deprecated(since = "3.7.2")
250256
public void setAssignee(DocumentReference assignee)
251257
{
252258
this.assignee = assignee;
253259
}
254260

261+
/**
262+
* @return a list of references to the users that are assigned to this task.
263+
*/
264+
public List<DocumentReference> getAssignees()
265+
{
266+
return assignees;
267+
}
268+
269+
/**
270+
* @param assignees a list of references to the users that are assigned to this task.
271+
*/
272+
public void setAssignees(List<DocumentReference> assignees)
273+
{
274+
this.assignees = assignees;
275+
}
276+
255277
/**
256278
* @return the timestamp for the creation of the task.
257279
*/

application-task-default/src/main/java/com/xwiki/task/internal/DefaultTaskManager.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
*/
2020
package com.xwiki.task.internal;
2121

22+
import java.util.Arrays;
2223
import java.util.Collections;
2324
import java.util.List;
25+
import java.util.stream.Collectors;
2426

2527
import javax.inject.Inject;
2628
import javax.inject.Named;
@@ -171,8 +173,10 @@ private Task getTaskFromXObject(BaseObject obj)
171173
task.setName(obj.getStringValue(Task.NAME));
172174
task.setNumber(obj.getIntValue(Task.NUMBER));
173175
task.setOwner(resolver.resolve(obj.getLargeStringValue(Task.OWNER), obj.getDocumentReference()));
174-
String assignee = obj.getLargeStringValue(Task.ASSIGNEE);
175-
task.setAssignee(assignee.isEmpty() ? null : resolver.resolve(assignee));
176+
String assignees = obj.getLargeStringValue(Task.ASSIGNEE);
177+
task.setAssignees(assignees.isEmpty() ? null
178+
: Arrays.stream(assignees.split(",")).map(user -> resolver.resolve(user))
179+
.collect(Collectors.toList()));
176180
task.setStatus(obj.getStringValue(Task.STATUS));
177181
task.setReporter(resolver.resolve(obj.getLargeStringValue(Task.REPORTER)));
178182
task.setDuedate(obj.getDateValue(Task.DUE_DATE));

application-task-default/src/main/java/com/xwiki/task/internal/TaskBlockProcessor.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,14 @@ public Block createTaskLinkBlock(String reference, int taskNumber, ResourceType
106106
* Generate the content of a Task macro as a list of blocks. This list can be rendered in different syntaxes i.e.
107107
* xwiki/2.1.
108108
*
109-
* @param assignee the string that will be used to generate a mention macro.
109+
* @param assignees the list of strings that will be used to generate a mention macros.
110110
* @param duedate the date that will be formatted and used to generate a date macro.
111111
* @param text the message of the task that will precede the assignee and due date.
112112
* @param storageFormat the format desired for the date.
113113
* @return a list of blocks that represent the content of a macro.
114114
* @throws TaskException if the text parameter failed to be parsed.
115115
*/
116-
public List<Block> generateTaskContentBlocks(String assignee, Date duedate, String text,
116+
public List<Block> generateTaskContentBlocks(List<String> assignees, Date duedate, String text,
117117
SimpleDateFormat storageFormat) throws TaskException
118118
{
119119
XDOM newTaskContentXDOM = null;
@@ -129,13 +129,13 @@ public List<Block> generateTaskContentBlocks(String assignee, Date duedate, Stri
129129
Block deadline = newTaskContentXDOM.getFirstBlock(new MacroBlockMatcher(DATE), Block.Axes.DESCENDANT_OR_SELF);
130130

131131
boolean changed = false;
132-
changed |= handleMentions(mentions, newTaskContentXDOM, assignee);
132+
changed |= handleMentions(mentions, newTaskContentXDOM, assignees);
133133

134134
changed |= handleDeadline(deadline, newTaskContentXDOM, duedate, storageFormat);
135135
return newTaskContentXDOM.getChildren();
136136
}
137137

138-
private boolean handleMentions(List<Block> mentions, XDOM newTaskContentXDOM, String assignees)
138+
private boolean handleMentions(List<Block> mentions, XDOM newTaskContentXDOM, List<String> assignees)
139139
{
140140
if (mentions.isEmpty() && assignees == null) {
141141
// Nothing changed.
@@ -149,9 +149,8 @@ private boolean handleMentions(List<Block> mentions, XDOM newTaskContentXDOM, St
149149
return true;
150150
}
151151

152-
String[] splitAssignees = assignees.split(",");
153152
if (mentions.stream().map(block -> block.getParameter(REFERENCE)).collect(Collectors.toList())
154-
.equals(Arrays.asList(splitAssignees)))
153+
.equals(assignees))
155154
{
156155
// If the mentions and assignees are equal, nothing changed.
157156
return false;
@@ -160,20 +159,20 @@ private boolean handleMentions(List<Block> mentions, XDOM newTaskContentXDOM, St
160159
int i = 0;
161160
for (Block mention : mentions) {
162161
// Replace the existing mentions with the updated values coming from the task obj.
163-
if (i >= splitAssignees.length) {
162+
if (i >= assignees.size()) {
164163
// If there are more mentions than assignees coming from the task obj, it means that they were removed.
165164
mention.getParent().removeBlock(mention);
166165
continue;
167166
}
168-
mention.setParameter(REFERENCE, splitAssignees[i++]);
167+
mention.setParameter(REFERENCE, assignees.get(i++));
169168
}
170169
// If there are more assignees than mentions, we need to create the said mentions.
171-
for (int j = i; j < splitAssignees.length; j++) {
170+
for (int j = i; j < assignees.size(); j++) {
172171
Map<String, String> mentionParams = new HashMap<>();
173172
mentionParams.put("style", "FULL_NAME");
174-
mentionParams.put(REFERENCE, splitAssignees[j]);
173+
mentionParams.put(REFERENCE, assignees.get(j));
175174
mentionParams.put("anchor",
176-
splitAssignees[j].replace('.', '-') + '-' + RandomStringUtils.random(5, true, false));
175+
assignees.get(j).replace('.', '-') + '-' + RandomStringUtils.random(5, true, false));
177176
MacroBlock mentionBlock = new MacroBlock(MENTION, mentionParams, true);
178177
newTaskContentXDOM.addChild(mentionBlock);
179178
}

application-task-default/src/main/java/com/xwiki/task/internal/TaskMacroUpdateEventListener.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,10 @@ private void populateObjectWithMacroParams(XWikiContext context, Task task, Base
281281

282282
object.set(Task.CREATE_DATE, task.getCreateDate(), context);
283283

284-
object.set(Task.ASSIGNEE, serializer.serialize(task.getAssignee()), context);
284+
String assignees =
285+
task.getAssignees().stream().map(user -> serializer.serialize(user))
286+
.collect(Collectors.joining(","));
287+
object.set(Task.ASSIGNEE, assignees, context);
285288

286289
object.set(Task.DUE_DATE, task.getDueDate(), context);
287290

application-task-default/src/main/java/com/xwiki/task/internal/TaskXDOMProcessor.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
import java.text.ParseException;
2323
import java.text.SimpleDateFormat;
2424
import java.util.ArrayList;
25+
import java.util.Collections;
2526
import java.util.Date;
2627
import java.util.List;
2728
import java.util.Map;
29+
import java.util.stream.Collectors;
2830

2931
import javax.inject.Inject;
3032
import javax.inject.Singleton;
@@ -203,7 +205,7 @@ private Task initTask(Syntax syntax, DocumentReference contentSource, MacroBlock
203205
XDOM macroContent = macroUtils.getMacroContentXDOM(macro, syntax);
204206
task.setName(macroUtils.renderMacroContent(macroContent.getChildren(), Syntax.PLAIN_1_0));
205207
task.setDescription(macro.getContent());
206-
task.setAssignee(extractAssignedUser(macroContent));
208+
task.setAssignees(extractAssignedUser(macroContent));
207209

208210
Date deadline = extractDeadlineDate(macroContent);
209211

@@ -231,7 +233,8 @@ private boolean maybeUpdateTaskMacroCall(DocumentReference documentReference, Ba
231233
(Syntax) content.getMetaData().getMetaData().getOrDefault(MetaData.SYNTAX, Syntax.XWIKI_2_1);
232234

233235
List<Block> newTaskContentBlocks =
234-
taskBlockProcessor.generateTaskContentBlocks(taskObject.getLargeStringValue(Task.ASSIGNEE),
236+
taskBlockProcessor.generateTaskContentBlocks(
237+
List.of(taskObject.getLargeStringValue(Task.ASSIGNEE).split(",")),
235238
taskObject.getDateValue(Task.DUE_DATE), taskObject.getLargeStringValue(Task.DESCRIPTION),
236239
storageFormat);
237240

@@ -306,14 +309,16 @@ private void extractBasicProperties(Map<String, String> macroParams, Task task)
306309
}
307310
}
308311

309-
private DocumentReference extractAssignedUser(XDOM taskContent)
312+
private List<DocumentReference> extractAssignedUser(XDOM taskContent)
310313
{
311-
MacroBlock macro = taskContent.getFirstBlock(new MacroBlockMatcher(MENTION_MACRO_ID), Block.Axes.DESCENDANT);
314+
List<MacroBlock> macros = taskContent.getBlocks(new MacroBlockMatcher(MENTION_MACRO_ID), Block.Axes.DESCENDANT);
312315

313-
if (macro == null) {
314-
return null;
316+
if (macros == null) {
317+
return Collections.emptyList();
315318
}
316-
return resolver.resolve(macro.getParameters().get(Task.REFERENCE));
319+
320+
return macros.stream().map(macroBlock -> resolver.resolve(macroBlock.getParameters().get(Task.REFERENCE)))
321+
.collect(Collectors.toList());
317322
}
318323

319324
private Date extractDeadlineDate(XDOM taskContent)

application-task-default/src/main/java/com/xwiki/task/internal/macro/TasksMacro.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.HashMap;
2626
import java.util.List;
2727
import java.util.Map;
28+
import java.util.stream.Collectors;
2829

2930
import javax.inject.Inject;
3031
import javax.inject.Named;
@@ -153,7 +154,8 @@ private String getMacroContent(Task task, SimpleDateFormat storageFormat,
153154

154155
{
155156
taskContent = macroUtils.renderMacroContent(blockProcessor.generateTaskContentBlocks(
156-
task.getAssignee() != null ? serializer.serialize(task.getAssignee()) : null, task.getDueDate(),
157+
task.getAssignees() != null ? task.getAssignees().stream().map(
158+
user -> serializer.serialize(user)).collect(Collectors.toList()) : null, task.getDueDate(),
157159
task.getName(), storageFormat), context.getSyntax());
158160
}
159161
return taskContent;

application-task-default/src/test/java/com/xwiki/task/TaskMacroUpdateEventListenerTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.ArrayList;
2424
import java.util.Collections;
2525
import java.util.Date;
26+
import java.util.List;
2627

2728
import javax.inject.Named;
2829

@@ -51,7 +52,6 @@
5152
import com.xpn.xwiki.XWiki;
5253
import com.xpn.xwiki.XWikiContext;
5354
import com.xpn.xwiki.XWikiException;
54-
import com.xpn.xwiki.doc.DocumentRevisionProvider;
5555
import com.xpn.xwiki.doc.XWikiDocument;
5656
import com.xpn.xwiki.objects.BaseObject;
5757
import com.xpn.xwiki.objects.ObjectDiff;
@@ -188,7 +188,7 @@ void setup() throws XWikiException
188188
task_1.setReference(taskPage_1);
189189
task_1.setReporter(adminRef);
190190
task_1.setDuedate(date1);
191-
task_1.setAssignee(adminRef);
191+
task_1.setAssignees(List.of(adminRef));
192192
task_1.setName(TASK_NAME);
193193
task_1.setCompleteDate(date1);
194194
task_1.setStatus(Task.STATUS_DONE);
@@ -199,7 +199,7 @@ void setup() throws XWikiException
199199
task.setReference(taskPage);
200200
task.setReporter(adminRef);
201201
task.setDuedate(date1);
202-
task.setAssignee(adminRef);
202+
task.setAssignees(List.of(adminRef));
203203
task.setName(TASK_NAME);
204204
task.setCompleteDate(date1);
205205
task.setStatus(Task.STATUS_DONE);

application-task-default/src/test/java/com/xwiki/task/TaskXDOMProcessorTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ void updateTaskMacroCall() throws TaskException, ComponentLookupException
204204
when(this.taskObject.getDateValue(Task.CREATE_DATE)).thenReturn(DEFAULT_TASK_DATE);
205205
when(this.taskObject.getIntValue(Task.NUMBER)).thenReturn(1);
206206

207-
when(this.taskBlockProcessor.generateTaskContentBlocks(eq(adminReference.toString()), eq(DEFAULT_TASK_DATE),
207+
when(this.taskBlockProcessor.generateTaskContentBlocks(eq(List.of(adminReference.toString())),
208+
eq(DEFAULT_TASK_DATE),
208209
eq(TASK1_ID), any(SimpleDateFormat.class))).thenReturn(Collections.emptyList());
209210
when(this.macroUtils.renderMacroContent(Collections.emptyList(), Syntax.XWIKI_2_1)).thenReturn(
210211
"TaskContent");
@@ -219,7 +220,8 @@ void updateTaskMacroCall() throws TaskException, ComponentLookupException
219220
verify(this.taskMacro1).setParameter(Task.STATUS, Task.STATUS_DONE);
220221
verify(this.taskMacro1).setParameter(Task.CREATE_DATE, DEFAULT_TASK_DATE_STRING);
221222
verify(this.taskMacro1).setParameter(Task.REPORTER, this.adminReference.toString());
222-
verify(this.taskBlockProcessor).generateTaskContentBlocks(eq(adminReference.toString()), eq(DEFAULT_TASK_DATE),
223+
verify(this.taskBlockProcessor).generateTaskContentBlocks(eq(List.of(adminReference.toString())),
224+
eq(DEFAULT_TASK_DATE),
223225
eq(TASK1_ID), any(SimpleDateFormat.class));
224226
verify(this.macroUtils).renderMacroContent(Collections.emptyList(), Syntax.XWIKI_2_1);
225227
}
Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,55 @@
11
.runTransformations
22
.#-----------------------------------------------------
33
.input|xwiki/2.0
4-
.# Task macro test without displaying the id.
4+
.# Task macro test with multiple users inside
55
.#-----------------------------------------------------
6-
{{task reference="Sandbox.Task" status="Done" idDisplayed="FALSE" }}
7-
Important task with the following deadline: {{date value="2021/09/07 00:00"/}}
6+
{{task reference="Sandbox.Task" createDate="2025-04-28" reporter="XWiki.superadmin" status="InProgress" completeDate=""}}
7+
{{mention reference="XWiki.Admin" anchor="XWiki-Admin-SdPsS" style="FULL_NAME"/}}{{mention reference="XWiki.testest" anchor="XWiki-testest-ZiyFB" style="FULL_NAME"/}}
88
{{/task}}
99
.#-----------------------------------------------------
1010
.expect|event/1.0
1111
.#-----------------------------------------------------
1212
beginDocument
13-
beginMacroMarkerStandalone [task] [reference=Sandbox.Task|status=Done|idDisplayed=FALSE] [Important task with the following deadline: {{date value="2021/09/07 00:00"/}}]
13+
beginMacroMarkerStandalone [task] [reference=Sandbox.Task|createDate=2025-04-28|reporter=XWiki.superadmin|status=InProgress|completeDate=] [ {{mention reference="XWiki.Admin" anchor="XWiki-Admin-SdPsS" style="FULL_NAME"/}}{{mention reference="XWiki.testest" anchor="XWiki-testest-ZiyFB" style="FULL_NAME"/}}]
1414
beginGroup [[class]=[task-macro]]
1515
beginGroup [[class]=[task-info]]
1616
beginFormat [NONE]
17-
onRawText [<input type="checkbox" data-taskId="Sandbox.Task" data-rawid="Sandbox.Task" checked class="task-status">] [html/5.0]
17+
onRawText [<input type="checkbox" data-taskId="Sandbox.Task" data-rawid="Sandbox.Task" class="task-status">] [html/5.0]
1818
endFormat [NONE]
19+
beginLink [Typed = [true] Type = [doc] Reference = [Sandbox.Task]] [false]
20+
onSpecialSymbol [#]
21+
onWord [1]
22+
endLink [Typed = [true] Type = [doc] Reference = [Sandbox.Task]] [false]
1923
endGroup [[class]=[task-info]]
2024
beginGroup [[class]=[task-content]]
2125
beginMetaData [[non-generated-content]=[java.util.List<org.xwiki.rendering.block.Block>]]
2226
beginParagraph
23-
onWord [Important]
2427
onSpace
25-
onWord [task]
2628
onSpace
27-
onWord [with]
2829
onSpace
29-
onWord [the]
30-
onSpace
31-
onWord [following]
32-
onSpace
33-
onWord [deadline]
34-
onSpecialSymbol [:]
35-
onSpace
36-
beginMacroMarkerInline [date] [value=2021/09/07 00:00]
37-
beginFormat [NONE] [[class]=[xwiki-date]]
38-
onWord [2021/09/07 00:00]
39-
endFormat [NONE] [[class]=[xwiki-date]]
40-
endMacroMarkerInline [date] [value=2021/09/07 00:00]
30+
beginMacroMarkerInline [mention] [reference=XWiki.Admin|anchor=XWiki-Admin-SdPsS|style=FULL_NAME]
31+
beginFormat [NONE] [[class]=[xwikirenderingerror]]
32+
onWord [Unknown macro: mention. Click on this message for details.]
33+
endFormat [NONE] [[class]=[xwikirenderingerror]]
34+
beginFormat [NONE] [[class]=[xwikirenderingerrordescription hidden]]
35+
onVerbatim [The [mention] macro is not in the list of registered macros. Verify the spelling or contact your administrator.] [true]
36+
endFormat [NONE] [[class]=[xwikirenderingerrordescription hidden]]
37+
endMacroMarkerInline [mention] [reference=XWiki.Admin|anchor=XWiki-Admin-SdPsS|style=FULL_NAME]
38+
beginMacroMarkerInline [mention] [reference=XWiki.testest|anchor=XWiki-testest-ZiyFB|style=FULL_NAME]
39+
beginFormat [NONE] [[class]=[xwikirenderingerror]]
40+
onWord [Unknown macro: mention. Click on this message for details.]
41+
endFormat [NONE] [[class]=[xwikirenderingerror]]
42+
beginFormat [NONE] [[class]=[xwikirenderingerrordescription hidden]]
43+
onVerbatim [The [mention] macro is not in the list of registered macros. Verify the spelling or contact your administrator.] [true]
44+
endFormat [NONE] [[class]=[xwikirenderingerrordescription hidden]]
45+
endMacroMarkerInline [mention] [reference=XWiki.testest|anchor=XWiki-testest-ZiyFB|style=FULL_NAME]
4146
endParagraph
4247
endMetaData [[non-generated-content]=[java.util.List<org.xwiki.rendering.block.Block>]]
4348
endGroup [[class]=[task-content]]
4449
endGroup [[class]=[task-macro]]
45-
endMacroMarkerStandalone [task] [reference=Sandbox.Task|status=Done|idDisplayed=FALSE] [Important task with the following deadline: {{date value="2021/09/07 00:00"/}}]
50+
endMacroMarkerStandalone [task] [reference=Sandbox.Task|createDate=2025-04-28|reporter=XWiki.superadmin|status=InProgress|completeDate=] [ {{mention reference="XWiki.Admin" anchor="XWiki-Admin-SdPsS" style="FULL_NAME"/}}{{mention reference="XWiki.testest" anchor="XWiki-testest-ZiyFB" style="FULL_NAME"/}}]
4651
endDocument
4752
.#-----------------------------------------------------
4853
.expect|xhtml/1.0
4954
.#-----------------------------------------------------
50-
<div class="task-macro"><div class="task-info"><input type="checkbox" data-taskId="Sandbox.Task" data-rawid="Sandbox.Task" checked class="task-status"></div><div class="task-content"><p>Important task with the following deadline: <span class="xwiki-date">2021/09/07 00:00</span></p></div></div>
55+
<div class="task-macro"><div class="task-info"><input type="checkbox" data-taskId="Sandbox.Task" data-rawid="Sandbox.Task" class="task-status"><span class="wikiinternallink"><a href="Sandbox.Task">#1</a></span></div><div class="task-content"><p>&nbsp;&nbsp;&nbsp;<span class="xwikirenderingerror">Unknown macro: mention. Click on this message for details.</span><span class="xwikirenderingerrordescription hidden"><tt class="wikimodel-verbatim">The [mention] macro is not in the list of registered macros. Verify the spelling or contact your administrator.</tt></span><span class="xwikirenderingerror">Unknown macro: mention. Click on this message for details.</span><span class="xwikirenderingerrordescription hidden"><tt class="wikimodel-verbatim">The [mention] macro is not in the list of registered macros. Verify the spelling or contact your administrator.</tt></span></p></div></div>

0 commit comments

Comments
 (0)