/******************************************************************************* * 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 changedAttributes = updateTaskData(repository, taskData, ticket); // remove attributes that were not set, i.e. were not received from the server List attributes = new ArrayList(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 attributes = new ArrayList(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 updateTaskData(TaskRepository repository, TaskData data, TracTicket ticket) { Set changedAttributes = new HashSet(); 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 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 values = TracAttributeMapper.getRepositoryOptions(client, attr.getId()); if (values != null && values.size() > 0) { boolean setDefault = field == null || !field.isOptional(); for (Entry 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 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 taskData from ticket. // */ // 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 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 removeValues = TracRepositoryConnector.getAttributeValues(data, TracAttributeMapper.REMOVE_CC); List 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 attributes = new ArrayList(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 attributes = new ArrayList(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); } } }