blob: 29da4204e0ba622da32dc48eecddc9d0cd486b04 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2012 Steffen Pingel and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Steffen Pingel - initial API and implementation
* Benjamin Muskalla - bug 386920
*******************************************************************************/
package org.eclipse.mylyn.internal.trac.core;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.StringTokenizer;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.mylyn.commons.net.Policy;
import org.eclipse.mylyn.internal.trac.core.client.ITracClient;
import org.eclipse.mylyn.internal.trac.core.client.InvalidTicketException;
import org.eclipse.mylyn.internal.trac.core.model.TracAction;
import org.eclipse.mylyn.internal.trac.core.model.TracAttachment;
import org.eclipse.mylyn.internal.trac.core.model.TracComment;
import org.eclipse.mylyn.internal.trac.core.model.TracTicket;
import org.eclipse.mylyn.internal.trac.core.model.TracTicket.Key;
import org.eclipse.mylyn.internal.trac.core.model.TracTicketField;
import org.eclipse.mylyn.internal.trac.core.util.TracUtil;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.ITaskMapping;
import org.eclipse.mylyn.tasks.core.RepositoryResponse;
import org.eclipse.mylyn.tasks.core.RepositoryResponse.ResponseKind;
import org.eclipse.mylyn.tasks.core.RepositoryStatus;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler;
import org.eclipse.mylyn.tasks.core.data.TaskAttachmentMapper;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper;
import org.eclipse.mylyn.tasks.core.data.TaskAttributeMetaData;
import org.eclipse.mylyn.tasks.core.data.TaskCommentMapper;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.mylyn.tasks.core.data.TaskMapper;
import org.eclipse.mylyn.tasks.core.data.TaskOperation;
import org.eclipse.osgi.util.NLS;
/**
* @author Steffen Pingel
* @author Benjamin Muskalla
*/
public class TracTaskDataHandler extends AbstractTaskDataHandler {
private static final String TASK_TYPE_TASK = "task"; //$NON-NLS-1$
public static final String TASK_TYPE_STORY = "story"; //$NON-NLS-1$
private static final String TASK_DATA_VERSION = "2"; //$NON-NLS-1$
public static final String ATTRIBUTE_BLOCKED_BY = "blockedby"; //$NON-NLS-1$
public static final String ATTRIBUTE_BLOCKING = "blocking"; //$NON-NLS-1$
private static final String CC_DELIMETER = ", "; //$NON-NLS-1$
private static final String TRAC_KEY = "tracKey"; //$NON-NLS-1$
private final TracRepositoryConnector connector;
public TracTaskDataHandler(TracRepositoryConnector connector) {
this.connector = connector;
}
public TaskData getTaskData(TaskRepository repository, String taskId, IProgressMonitor monitor)
throws CoreException {
monitor = Policy.monitorFor(monitor);
try {
monitor.beginTask("Task Download", IProgressMonitor.UNKNOWN); //$NON-NLS-1$
return downloadTaskData(repository, TracRepositoryConnector.getTicketId(taskId), monitor);
} finally {
monitor.done();
}
}
public TaskData downloadTaskData(TaskRepository repository, int taskId, IProgressMonitor monitor)
throws CoreException {
ITracClient client = connector.getClientManager().getTracClient(repository);
TracTicket ticket;
try {
client.updateAttributes(monitor, false);
ticket = client.getTicket(taskId, monitor);
} catch (OperationCanceledException e) {
throw e;
} catch (Exception e) {
// TODO catch TracException
throw new CoreException(TracCorePlugin.toStatus(e, repository));
}
return createTaskDataFromTicket(client, repository, ticket, monitor);
}
public TaskData createTaskDataFromTicket(ITracClient client, TaskRepository repository, TracTicket ticket,
IProgressMonitor monitor) throws CoreException {
TaskData taskData = new TaskData(getAttributeMapper(repository), TracCorePlugin.CONNECTOR_KIND,
repository.getRepositoryUrl(), ticket.getId() + ""); //$NON-NLS-1$
taskData.setVersion(TASK_DATA_VERSION);
try {
if (!TracRepositoryConnector.hasRichEditor(repository)) {
createDefaultAttributes(taskData, client, true);
Set<TaskAttribute> changedAttributes = updateTaskData(repository, taskData, ticket);
// remove attributes that were not set, i.e. were not received from the server
List<TaskAttribute> attributes = new ArrayList<TaskAttribute>(taskData.getRoot()
.getAttributes()
.values());
for (TaskAttribute attribute : attributes) {
if (!changedAttributes.contains(attribute) && !TracAttributeMapper.isInternalAttribute(attribute)) {
taskData.getRoot().removeAttribute(attribute.getId());
}
}
taskData.setPartial(true);
} else {
createDefaultAttributes(taskData, client, true);
updateTaskData(repository, taskData, ticket);
}
removeEmptySingleSelectAttributes(taskData);
return taskData;
} catch (OperationCanceledException e) {
throw e;
} catch (Exception e) {
// TODO catch TracException
throw new CoreException(TracCorePlugin.toStatus(e, repository));
}
}
private void removeEmptySingleSelectAttributes(TaskData taskData) {
List<TaskAttribute> attributes = new ArrayList<TaskAttribute>(taskData.getRoot().getAttributes().values());
for (TaskAttribute attribute : attributes) {
if (TaskAttribute.TYPE_SINGLE_SELECT.equals(attribute.getMetaData().getType())
&& attribute.getValue().length() == 0 && attribute.getOptions().isEmpty()) {
taskData.getRoot().removeAttribute(attribute.getId());
}
}
}
public static Set<TaskAttribute> updateTaskData(TaskRepository repository, TaskData data, TracTicket ticket) {
Set<TaskAttribute> changedAttributes = new HashSet<TaskAttribute>();
Date lastChanged = ticket.getLastChanged();
if (lastChanged != null) {
TaskAttribute taskAttribute = data.getRoot().getAttribute(TracAttribute.CHANGE_TIME.getTracKey());
taskAttribute.setValue(TracUtil.toTracTime(lastChanged) + ""); //$NON-NLS-1$
changedAttributes.add(taskAttribute);
}
if (ticket.getCreated() != null) {
TaskAttribute taskAttribute = data.getRoot().getAttribute(TracAttribute.TIME.getTracKey());
taskAttribute.setValue(TracUtil.toTracTime(ticket.getCreated()) + ""); //$NON-NLS-1$
changedAttributes.add(taskAttribute);
}
Map<String, String> valueByKey = ticket.getValues();
for (String key : valueByKey.keySet()) {
TaskAttribute taskAttribute = data.getRoot().getAttribute(key);
if (taskAttribute != null) {
if (Key.CC.getKey().equals(key)) {
StringTokenizer t = new StringTokenizer(valueByKey.get(key), CC_DELIMETER);
while (t.hasMoreTokens()) {
taskAttribute.addValue(t.nextToken());
}
} else {
taskAttribute.setValue(valueByKey.get(key));
}
changedAttributes.add(taskAttribute);
} else {
// TODO log missing attribute?
}
}
TracComment[] comments = ticket.getComments();
if (comments != null) {
int count = 1;
for (int i = 0; i < comments.length; i++) {
if (!"comment".equals(comments[i].getField()) || "".equals(comments[i].getNewValue())) { //$NON-NLS-1$ //$NON-NLS-2$
continue;
}
TaskCommentMapper mapper = new TaskCommentMapper();
mapper.setAuthor(repository.createPerson(comments[i].getAuthor()));
mapper.setCreationDate(comments[i].getCreated());
mapper.setText(comments[i].getNewValue());
// TODO mapper.setUrl();
mapper.setNumber(count);
TaskAttribute attribute = data.getRoot().createAttribute(TaskAttribute.PREFIX_COMMENT + count);
mapper.applyTo(attribute);
count++;
}
}
TracAttachment[] attachments = ticket.getAttachments();
if (attachments != null) {
for (int i = 0; i < attachments.length; i++) {
TaskAttachmentMapper mapper = new TaskAttachmentMapper();
mapper.setAuthor(repository.createPerson(attachments[i].getAuthor()));
mapper.setDescription(attachments[i].getDescription());
mapper.setFileName(attachments[i].getFilename());
mapper.setLength((long) attachments[i].getSize());
if (attachments[i].getCreated() != null) {
if (lastChanged == null || attachments[i].getCreated().after(lastChanged)) {
lastChanged = attachments[i].getCreated();
}
mapper.setCreationDate(attachments[i].getCreated());
}
mapper.setUrl(repository.getRepositoryUrl() + ITracClient.TICKET_ATTACHMENT_URL + ticket.getId() + "/" //$NON-NLS-1$
+ TracUtil.encodeUrl(attachments[i].getFilename()));
mapper.setAttachmentId(i + ""); //$NON-NLS-1$
TaskAttribute attribute = data.getRoot().createAttribute(TaskAttribute.PREFIX_ATTACHMENT + (i + 1));
mapper.applyTo(attribute);
}
}
TracAction[] actions = ticket.getActions();
if (actions != null) {
// add actions and set first as default
for (TracAction action : actions) {
addOperation(repository, data, ticket, action, action == actions[0]);
}
}
return changedAttributes;
}
private static void addOperation(TaskRepository repository, TaskData data, TracTicket ticket, TracAction action,
boolean setAsDefault) {
String label = action.getLabel();
if (label == null) {
if ("leave".equals(action.getId())) { //$NON-NLS-1$
String status = ticket.getValue(Key.STATUS);
if (status != null) {
String resolution = ticket.getValue(Key.RESOLUTION);
if (resolution != null) {
label = NLS.bind(Messages.TracTaskDataHandler_Leave_as_Status_Resolution, status, resolution);
} else {
label = NLS.bind(Messages.TracTaskDataHandler_Leave_as_Status, status);
}
} else {
label = Messages.TracTaskDataHandler_Leave;
}
} else if ("accept".equals(action.getId())) { //$NON-NLS-1$
label = Messages.TracTaskDataHandler_Accept;
} else if ("resolve".equals(action.getId())) { //$NON-NLS-1$
label = Messages.TracTaskDataHandler_Resolve_as;
} else if ("reopen".equals(action.getId())) { //$NON-NLS-1$
label = Messages.TracTaskDataHandler_Reopen;
} else if ("reassign".equals(action.getId())) { //$NON-NLS-1$
// do not add reassign for Trac 0.10 since the assigned to field is editable
} else {
label = action.getId();
}
}
if (label != null) {
TaskAttribute attribute = data.getRoot().createAttribute(TaskAttribute.PREFIX_OPERATION + action.getId());
TaskOperation.applyTo(attribute, action.getId(), label);
if (!action.getFields().isEmpty()) {
// TODO support more than one field
TracTicketField field = action.getFields().get(0);
TaskAttribute fieldAttribute = createAttribute(data, field);
fieldAttribute.getMetaData().setKind(null);
attribute.getMetaData().putValue(TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID, fieldAttribute.getId());
} else if ("resolve".equals(action.getId())) { //$NON-NLS-1$
attribute.getMetaData().putValue(TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID,
TracAttribute.RESOLUTION.getTracKey());
}
if (setAsDefault) {
TaskAttribute operationAttribute = data.getRoot().createAttribute(TaskAttribute.OPERATION);
TaskOperation.applyTo(operationAttribute, action.getId(), label);
}
}
}
public static void createDefaultAttributes(TaskData data, ITracClient client, boolean existingTask) {
data.setVersion(TASK_DATA_VERSION);
createAttribute(data, client, TracAttribute.SUMMARY);
createAttribute(data, client, TracAttribute.DESCRIPTION);
if (existingTask) {
createAttribute(data, client, TracAttribute.TIME);
createAttribute(data, client, TracAttribute.CHANGE_TIME);
createAttribute(data, client, TracAttribute.STATUS);
TaskAttribute attribute = createAttribute(data, client, TracAttribute.RESOLUTION);
// reset default value to avoid "fixed" resolution on tasks created through web
attribute.setValue(""); //$NON-NLS-1$
// internal attributes
createAttribute(data, null, TracAttribute.TOKEN);
}
createAttribute(data, client, TracAttribute.COMPONENT);
createAttribute(data, client, TracAttribute.VERSION);
createAttribute(data, client, TracAttribute.PRIORITY);
createAttribute(data, client, TracAttribute.SEVERITY);
createAttribute(data, client, TracAttribute.MILESTONE);
createAttribute(data, client, TracAttribute.TYPE);
createAttribute(data, client, TracAttribute.KEYWORDS);
// custom fields
TracTicketField[] fields = client.getTicketFields();
if (fields != null) {
for (TracTicketField field : fields) {
if (field.isCustom()) {
createAttribute(data, field);
}
}
}
// people
createAttribute(data, client, TracAttribute.OWNER);
if (existingTask) {
createAttribute(data, client, TracAttribute.REPORTER);
}
createAttribute(data, client, TracAttribute.CC);
if (existingTask) {
data.getRoot()
.createAttribute(TracAttributeMapper.NEW_CC)
.getMetaData()
.setType(TaskAttribute.TYPE_SHORT_TEXT)
.setReadOnly(false);
data.getRoot().createAttribute(TracAttributeMapper.REMOVE_CC);
data.getRoot()
.createAttribute(TaskAttribute.COMMENT_NEW)
.getMetaData()
.setType(TaskAttribute.TYPE_LONG_RICH_TEXT)
.setReadOnly(false);
}
// operations
data.getRoot().createAttribute(TaskAttribute.OPERATION).getMetaData().setType(TaskAttribute.TYPE_OPERATION);
}
private static TaskAttribute createAttribute(TaskData data, TracTicketField field) {
TaskAttribute attr = data.getRoot().createAttribute(field.getName());
TaskAttributeMetaData metaData = attr.getMetaData();
metaData.defaults();
metaData.setLabel(field.getLabel() + ":"); //$NON-NLS-1$
metaData.setKind(TaskAttribute.KIND_DEFAULT);
metaData.setReadOnly(false);
metaData.putValue(TRAC_KEY, field.getName());
if (field.getType() == TracTicketField.Type.CHECKBOX) {
// attr.addOption("True", "1");
// attr.addOption("False", "0");
metaData.setType(TaskAttribute.TYPE_BOOLEAN);
attr.putOption("1", "1"); //$NON-NLS-1$ //$NON-NLS-2$
attr.putOption("0", "0"); //$NON-NLS-1$ //$NON-NLS-2$
if (field.getDefaultValue() != null) {
attr.setValue(field.getDefaultValue());
}
} else if (field.getType() == TracTicketField.Type.SELECT || field.getType() == TracTicketField.Type.RADIO) {
metaData.setType(TaskAttribute.TYPE_SINGLE_SELECT);
String[] values = field.getOptions();
if (values != null && values.length > 0) {
if (field.isOptional()) {
attr.putOption("", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
for (String value : values) {
attr.putOption(value, value);
}
if (field.getDefaultValue() != null) {
try {
int index = Integer.parseInt(field.getDefaultValue());
if (index > 0 && index < values.length) {
attr.setValue(values[index]);
}
} catch (NumberFormatException e) {
for (String value : values) {
if (field.getDefaultValue().equals(value.toString())) {
attr.setValue(value);
break;
}
}
}
}
}
} else if (field.getType() == TracTicketField.Type.TEXTAREA) {
metaData.setType(TaskAttribute.TYPE_LONG_TEXT);
if (field.getDefaultValue() != null) {
attr.setValue(field.getDefaultValue());
}
} else {
metaData.setType(TaskAttribute.TYPE_SHORT_TEXT);
if (field.getDefaultValue() != null) {
attr.setValue(field.getDefaultValue());
}
}
if (ATTRIBUTE_BLOCKED_BY.equals(field.getName()) || ATTRIBUTE_BLOCKING.equals(field.getName())) {
metaData.setType(TaskAttribute.TYPE_TASK_DEPENDENCY);
}
return attr;
}
public static TaskAttribute createAttribute(TaskData data, TracAttribute tracAttribute) {
return createAttribute(data, null, tracAttribute);
}
public static TaskAttribute createAttribute(TaskData data, ITracClient client, TracAttribute tracAttribute) {
TaskAttribute attr = data.getRoot().createAttribute(tracAttribute.getTracKey());
TaskAttributeMetaData metaData = attr.getMetaData();
metaData.setType(tracAttribute.getType());
metaData.setKind(tracAttribute.getKind());
metaData.setLabel(tracAttribute.toString());
metaData.setReadOnly(tracAttribute.isReadOnly());
metaData.putValue(TRAC_KEY, tracAttribute.getTracKey());
if (client != null) {
TracTicketField field = client.getTicketFieldByName(tracAttribute.getTracKey());
Map<String, String> values = TracAttributeMapper.getRepositoryOptions(client, attr.getId());
if (values != null && values.size() > 0) {
boolean setDefault = field == null || !field.isOptional();
for (Entry<String, String> value : values.entrySet()) {
attr.putOption(value.getKey(), value.getValue());
// set first value as default, may get overwritten below
if (setDefault) {
attr.setValue(value.getKey());
}
setDefault = false;
}
} else if (TaskAttribute.TYPE_SINGLE_SELECT.equals(tracAttribute.getType())) {
attr.getMetaData().setReadOnly(true);
}
if (field != null) {
String defaultValue = field.getDefaultValue();
if (defaultValue != null && defaultValue.length() > 0) {
attr.setValue(defaultValue);
}
}
}
return attr;
}
@Override
public RepositoryResponse postTaskData(TaskRepository repository, TaskData taskData,
Set<TaskAttribute> oldAttributes, IProgressMonitor monitor) throws CoreException {
try {
TracTicket ticket = TracTaskDataHandler.getTracTicket(repository, taskData);
ITracClient server = connector.getClientManager().getTracClient(repository);
if (taskData.isNew()) {
int id = server.createTicket(ticket, monitor);
return new RepositoryResponse(ResponseKind.TASK_CREATED, id + ""); //$NON-NLS-1$
} else {
String newComment = ""; //$NON-NLS-1$
TaskAttribute newCommentAttribute = taskData.getRoot().getMappedAttribute(TaskAttribute.COMMENT_NEW);
if (newCommentAttribute != null) {
newComment = newCommentAttribute.getValue();
}
server.updateTicket(ticket, newComment, monitor);
return new RepositoryResponse(ResponseKind.TASK_UPDATED, ticket.getId() + ""); //$NON-NLS-1$
}
} catch (OperationCanceledException e) {
throw e;
} catch (Exception e) {
// TODO catch TracException
throw new CoreException(TracCorePlugin.toStatus(e, repository));
}
}
@Override
public boolean initializeTaskData(TaskRepository repository, TaskData data, ITaskMapping initializationData,
IProgressMonitor monitor) throws CoreException {
monitor = Policy.monitorFor(monitor);
try {
ITracClient client = connector.getClientManager().getTracClient(repository);
client.updateAttributes(monitor, false);
createDefaultAttributes(data, client, false);
removeEmptySingleSelectAttributes(data);
return true;
} catch (OperationCanceledException e) {
throw e;
} catch (Exception e) {
// TODO catch TracException
throw new CoreException(TracCorePlugin.toStatus(e, repository));
}
}
@Override
public boolean initializeSubTaskData(TaskRepository repository, TaskData taskData, TaskData parentTaskData,
IProgressMonitor monitor) throws CoreException {
initializeTaskData(repository, taskData, null, monitor);
TaskAttribute blockingAttribute = taskData.getRoot().getMappedAttribute(ATTRIBUTE_BLOCKING);
if (blockingAttribute == null) {
throw new CoreException(new RepositoryStatus(repository, IStatus.ERROR, TracCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_REPOSITORY, "The repository does not support subtasks")); //$NON-NLS-1$
}
TaskMapper mapper = new TaskMapper(taskData);
mapper.merge(new TaskMapper(parentTaskData));
mapper.setDescription(""); //$NON-NLS-1$
mapper.setSummary(""); //$NON-NLS-1$
blockingAttribute.setValue(parentTaskData.getTaskId());
TaskAttribute blockedByAttribute = taskData.getRoot().getMappedAttribute(ATTRIBUTE_BLOCKED_BY);
if (blockedByAttribute != null) {
blockedByAttribute.clearValues();
}
// special handling for stories which should have tasks as subtasks
TaskAttribute typeAttribute = taskData.getRoot().getAttribute(TracAttribute.TYPE.getTracKey());
if (typeAttribute != null && TASK_TYPE_STORY.equals(typeAttribute.getValue())) {
if (typeAttribute.getOptions().containsKey(TASK_TYPE_TASK)) {
typeAttribute.setValue(TASK_TYPE_TASK);
}
}
return true;
}
@Override
public boolean canInitializeSubTaskData(TaskRepository taskRepository, ITask task) {
return Boolean.parseBoolean(task.getAttribute(TracRepositoryConnector.TASK_KEY_SUPPORTS_SUBTASKS));
}
// /**
// * Updates attributes of <code>taskData</code> from <code>ticket</code>.
// */
// public void updateTaskDataFromTicket(TaskData taskData, TracTicket ticket, ITracClient client) {
// DefaultTaskSchema schema = new DefaultTaskSchema(taskData);
// if (ticket.getValue(Key.SUMMARY) != null) {
// schema.setSummary(ticket.getValue(Key.SUMMARY));
// }
//
// if (TracRepositoryConnector.isCompleted(ticket.getValue(Key.STATUS))) {
// schema.setCompletionDate(ticket.getLastChanged());
// } else {
// schema.setCompletionDate(null);
// }
//
// String priority = ticket.getValue(Key.PRIORITY);
// TracPriority[] tracPriorities = client.getPriorities();
// schema.setPriority(TracRepositoryConnector.getTaskPriority(priority, tracPriorities));
//
// if (ticket.getValue(Key.TYPE) != null) {
// TaskKind taskKind = TracRepositoryConnector.TaskKind.fromType(ticket.getValue(Key.TYPE));
// schema.setTaskKind((taskKind != null) ? taskKind.toString() : ticket.getValue(Key.TYPE));
// }
//
// if (ticket.getCreated() != null) {
// schema.setCreationDate(ticket.getCreated());
// }
//
// if (ticket.getCustomValue(TracTaskDataHandler.ATTRIBUTE_BLOCKING) != null) {
// taskData.addAttribute(ATTRIBUTE_BLOCKED_BY, new TaskAttribute(ATTRIBUTE_BLOCKED_BY, "Blocked by", true));
// }
// }
@Override
public TaskAttributeMapper getAttributeMapper(TaskRepository repository) {
ITracClient client = connector.getClientManager().getTracClient(repository);
return new TracAttributeMapper(repository, client);
}
public boolean supportsSubtasks(TaskData taskData) {
return taskData.getRoot().getAttribute(ATTRIBUTE_BLOCKED_BY) != null;
}
public static TracTicket getTracTicket(TaskRepository repository, TaskData data) throws InvalidTicketException,
CoreException {
TracTicket ticket = (data.isNew()) ? new TracTicket() : new TracTicket(
TracRepositoryConnector.getTicketId(data.getTaskId()));
Collection<TaskAttribute> attributes = data.getRoot().getAttributes().values();
for (TaskAttribute attribute : attributes) {
if (TracAttributeMapper.isInternalAttribute(attribute)
|| TracAttribute.RESOLUTION.getTracKey().equals(attribute.getId())) {
// ignore internal attributes, resolution is set through operations
} else if (!attribute.getMetaData().isReadOnly() || Key.TOKEN.getKey().equals(attribute.getId())) {
ticket.putValue(attribute.getId(), attribute.getValue());
}
}
// set cc value
StringBuilder sb = new StringBuilder();
List<String> removeValues = TracRepositoryConnector.getAttributeValues(data, TracAttributeMapper.REMOVE_CC);
List<String> values = TracRepositoryConnector.getAttributeValues(data, TaskAttribute.USER_CC);
for (String user : values) {
if (!removeValues.contains(user)) {
if (sb.length() > 0) {
sb.append(","); //$NON-NLS-1$
}
sb.append(user);
}
}
if (TracRepositoryConnector.getAttributeValue(data, TracAttributeMapper.NEW_CC).length() > 0) {
if (sb.length() > 0) {
sb.append(","); //$NON-NLS-1$
}
sb.append(TracRepositoryConnector.getAttributeValue(data, TracAttributeMapper.NEW_CC));
}
if (Boolean.TRUE.equals(TracRepositoryConnector.getAttributeValue(data, TaskAttribute.ADD_SELF_CC))) {
if (sb.length() > 0) {
sb.append(","); //$NON-NLS-1$
}
sb.append(repository.getUserName());
}
ticket.putBuiltinValue(Key.CC, sb.toString());
ticket.putValue("owner", TracRepositoryConnector.getAttributeValue(data, TaskAttribute.USER_ASSIGNED)); //$NON-NLS-1$
TaskAttribute operationAttribute = data.getRoot().getMappedAttribute(TaskAttribute.OPERATION);
if (operationAttribute != null) {
TaskOperation operation = TaskOperation.createFrom(operationAttribute);
String action = operation.getOperationId();
if (!"leave".equals(action)) { //$NON-NLS-1$
if ("accept".equals(action)) { //$NON-NLS-1$
ticket.putValue("status", TracRepositoryConnector.TaskStatus.ASSIGNED.toStatusString()); //$NON-NLS-1$
} else if ("resolve".equals(action)) { //$NON-NLS-1$
ticket.putValue("status", TracRepositoryConnector.TaskStatus.CLOSED.toStatusString()); //$NON-NLS-1$
ticket.putValue("resolution", TracRepositoryConnector.getAttributeValue(data, //$NON-NLS-1$
TaskAttribute.RESOLUTION));
} else if ("reopen".equals(action)) { //$NON-NLS-1$
ticket.putValue("status", TracRepositoryConnector.TaskStatus.REOPENED.toStatusString()); //$NON-NLS-1$
ticket.putValue("resolution", ""); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("reassign".equals(action)) { //$NON-NLS-1$
ticket.putValue("status", TracRepositoryConnector.TaskStatus.NEW.toStatusString()); //$NON-NLS-1$
}
}
ticket.putValue("action", action); //$NON-NLS-1$
}
Date lastChanged = TracUtil.parseDate(TracRepositoryConnector.getAttributeValue(data,
TracAttribute.CHANGE_TIME.getTracKey()));
ticket.setLastChanged(lastChanged);
return ticket;
}
@Override
public void migrateTaskData(TaskRepository taskRepository, TaskData taskData) {
int version = 0;
if (taskData.getVersion() != null) {
try {
version = Integer.parseInt(taskData.getVersion());
} catch (NumberFormatException e) {
// ignore
}
}
if (version < 1) {
TaskAttribute root = taskData.getRoot();
List<TaskAttribute> attributes = new ArrayList<TaskAttribute>(root.getAttributes().values());
for (TaskAttribute attribute : attributes) {
if (TaskAttribute.TYPE_OPERATION.equals(attribute.getMetaData().getType())
&& "reassign".equals(attribute.getValue())) { //$NON-NLS-1$
root.removeAttribute(attribute.getId());
} else if (TaskAttribute.OPERATION.equals(attribute.getId())) {
attribute.getMetaData().setType(TaskAttribute.TYPE_OPERATION);
} else if (TracAttributeMapper.NEW_CC.equals(attribute.getId())) {
attribute.getMetaData().setType(TaskAttribute.TYPE_SHORT_TEXT).setReadOnly(false);
} else {
TracAttribute tracAttribute = TracAttribute.getByTracKey(attribute.getId());
if (tracAttribute != null) {
attribute.getMetaData().setType(tracAttribute.getType());
attribute.getMetaData().setKind(tracAttribute.getKind());
attribute.getMetaData().setReadOnly(tracAttribute.isReadOnly());
}
}
}
if (root.getAttribute(TracAttributeMapper.REMOVE_CC) == null) {
root.createAttribute(TracAttributeMapper.REMOVE_CC);
}
if (root.getAttribute(TaskAttribute.COMMENT_NEW) == null) {
root.createAttribute(TaskAttribute.COMMENT_NEW)
.getMetaData()
.setType(TaskAttribute.TYPE_LONG_RICH_TEXT)
.setReadOnly(false);
}
}
if (version < 2) {
List<TaskAttribute> attributes = new ArrayList<TaskAttribute>(taskData.getRoot().getAttributes().values());
for (TaskAttribute attribute : attributes) {
if (!TracAttributeMapper.isInternalAttribute(attribute)) {
TaskAttributeMetaData metaData = attribute.getMetaData();
metaData.putValue(TRAC_KEY, attribute.getId());
if (metaData.getType() == null) {
metaData.setType(TaskAttribute.TYPE_SHORT_TEXT);
}
}
}
taskData.setVersion(TASK_DATA_VERSION);
}
}
}