From 869a056a29aac2a817adb0b2ce02b1bbe1d07a89 Mon Sep 17 00:00:00 2001 From: Frank Becker Date: Sat, 21 Feb 2015 15:31:52 +0100 Subject: 414360: add support for Task update Change-Id: I4374580bfe58dafe735c95820c434f8d7100bb85 Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=414360 --- .../rest/core/tests/BugzillaRestClientTest.java | 107 ++++++++--- .../rest/test/support/BugzillaRestHarness.java | 65 +++++++ .../core/BugzillaRestAuthenticatedPutRequest.java | 103 ++++++++++ .../bugzilla/rest/core/BugzillaRestClient.java | 8 +- .../rest/core/BugzillaRestConfiguration.java | 17 +- .../rest/core/BugzillaRestPutUpdateTask.java | 214 +++++++++++++++++++++ .../rest/core/BugzillaRestTaskDataHandler.java | 3 +- .../bugzilla/rest/core/BugzillaRestTaskSchema.java | 30 ++- .../rest/core/response/data/PutUpdateEntry.java | 36 ++++ .../rest/core/response/data/PutUpdateResult.java | 24 +++ 10 files changed, 576 insertions(+), 31 deletions(-) create mode 100644 connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestAuthenticatedPutRequest.java create mode 100644 connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestPutUpdateTask.java create mode 100644 connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/response/data/PutUpdateEntry.java create mode 100644 connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/response/data/PutUpdateResult.java diff --git a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core.tests/src/org/eclipse/mylyn/internal/bugzilla/rest/core/tests/BugzillaRestClientTest.java b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core.tests/src/org/eclipse/mylyn/internal/bugzilla/rest/core/tests/BugzillaRestClientTest.java index 2344b658d..9c0ecb330 100644 --- a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core.tests/src/org/eclipse/mylyn/internal/bugzilla/rest/core/tests/BugzillaRestClientTest.java +++ b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core.tests/src/org/eclipse/mylyn/internal/bugzilla/rest/core/tests/BugzillaRestClientTest.java @@ -11,14 +11,17 @@ package org.eclipse.mylyn.internal.bugzilla.rest.core.tests; +import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -38,12 +41,13 @@ import org.eclipse.mylyn.internal.bugzilla.rest.core.BugzillaRestConfiguration; import org.eclipse.mylyn.internal.bugzilla.rest.core.BugzillaRestConnector; import org.eclipse.mylyn.internal.bugzilla.rest.core.BugzillaRestCreateTaskSchema; import org.eclipse.mylyn.internal.bugzilla.rest.core.BugzillaRestException; +import org.eclipse.mylyn.internal.bugzilla.rest.core.BugzillaRestTaskSchema; import org.eclipse.mylyn.internal.bugzilla.rest.core.BugzillaRestVersion; -import org.eclipse.mylyn.internal.bugzilla.rest.core.SingleTaskDataCollector; import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.Field; import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.LoginToken; import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.Parameters; import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.Product; +import org.eclipse.mylyn.internal.bugzilla.rest.test.support.BugzillaRestHarness; import org.eclipse.mylyn.internal.bugzilla.rest.test.support.BugzillaRestTestFixture; import org.eclipse.mylyn.internal.commons.core.operations.NullOperationMonitor; import org.eclipse.mylyn.internal.commons.repositories.core.InMemoryCredentialsStore; @@ -54,6 +58,7 @@ import org.eclipse.mylyn.tasks.core.TaskMapping; import org.eclipse.mylyn.tasks.core.TaskMapping; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler; +import org.eclipse.mylyn.tasks.core.data.TaskAttribute; import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper; import org.eclipse.mylyn.tasks.core.data.TaskData; import org.eclipse.mylyn.tasks.core.data.TaskMapper; @@ -80,13 +85,16 @@ public class BugzillaRestClientTest { private BugzillaRestConnector connector; + private BugzillaRestHarness harness; + public BugzillaRestClientTest(BugzillaRestTestFixture fixture) { this.actualFixture = fixture; } @Before public void setUp() { - connector = new BugzillaRestConnector(); + connector = actualFixture.connector(); + harness = actualFixture.createHarness(); } @Test @@ -254,8 +262,8 @@ public class BugzillaRestClientTest { taskDataHandler.initializeTaskData(actualFixture.repository(), taskData, taskMappingInit, null); taskData.getRoot().getAttribute("cf_dropdown").setValue("one"); try { - connector.getClient(actualFixture.repository()).postTaskData(taskData, null); - fail("BugzillaRestException expected, never reach this!"); + connector.getClient(actualFixture.repository()).postTaskData(taskData, null, null); + fail("never reach this!"); } catch (BugzillaRestException e) { String url = actualFixture.getRepositoryUrl(); assertEquals("You must select/enter a product. (status: Bad Request from " @@ -298,7 +306,7 @@ public class BugzillaRestClientTest { taskDataHandler.initializeTaskData(actualFixture.repository(), taskData, taskMappingInit, null); taskData.getRoot().getAttribute("cf_dropdown").setValue("one"); try { - connector.getClient(actualFixture.repository()).postTaskData(taskData, null); + connector.getClient(actualFixture.repository()).postTaskData(taskData, null, null); fail("never reach this!"); } catch (BugzillaRestException e) { String url = actualFixture.getRepositoryUrl(); @@ -344,7 +352,8 @@ public class BugzillaRestClientTest { taskData.getRoot() .getAttribute(BugzillaRestCreateTaskSchema.getDefault().TARGET_MILESTONE.getKey()) .setValue("M2"); - RepositoryResponse reposonse = connector.getClient(actualFixture.repository()).postTaskData(taskData, null); + RepositoryResponse reposonse = connector.getClient(actualFixture.repository()).postTaskData(taskData, null, + null); assertEquals(ResponseKind.TASK_CREATED, reposonse.getReposonseKind()); } @@ -393,7 +402,7 @@ public class BugzillaRestClientTest { connector.getTaskMapping(taskDataSubmit).merge(mapper1); RepositoryResponse reposonse = connector.getClient(actualFixture.repository()).postTaskData(taskDataSubmit, - null); + null, null); assertEquals(ResponseKind.TASK_CREATED, reposonse.getReposonseKind()); } @@ -425,31 +434,25 @@ public class BugzillaRestClientTest { return "R1"; } }; - AbstractTaskDataHandler taskDataHandler = connector.getTaskDataHandler(); - TaskAttributeMapper mapper = taskDataHandler.getAttributeMapper(actualFixture.repository()); - TaskData taskData = new TaskData(mapper, actualFixture.repository().getConnectorKind(), - actualFixture.repository().getRepositoryUrl(), ""); - taskDataHandler.initializeTaskData(actualFixture.repository(), taskData, taskMappingInit, null); + TaskData taskData = harness.createTaskData(taskMappingInit, null, null); + taskData.getRoot().getAttribute("cf_dropdown").setValue("one"); taskData.getRoot() .getAttribute(BugzillaRestCreateTaskSchema.getDefault().TARGET_MILESTONE.getKey()) .setValue("M2"); - RepositoryResponse reposonse = connector.getClient(actualFixture.repository()).postTaskData(taskData, null); - assertEquals(ResponseKind.TASK_CREATED, reposonse.getReposonseKind()); - String taskId = reposonse.getTaskId(); - Set taskIds = new HashSet(); - taskIds.add(taskId); - SingleTaskDataCollector singleTaskDataCollector = new SingleTaskDataCollector(); - connector.getClient(actualFixture.repository()).getTaskData(taskIds, actualFixture.repository(), - singleTaskDataCollector, null); - TaskData taskDataGet = singleTaskDataCollector.getTaskData(); - assertNotNull(taskDataGet); - assertNotNull(taskDataGet.getRoot()); + String taskId = harness.submitNewTask(taskData); + TaskData taskDataGet = harness.getTaskFromServer(taskId); // actual we read no comments and so we also can not get the description taskData.getRoot().removeAttribute("task.common.description"); taskDataGet.getRoot().removeAttribute("task.common.description"); + // resolution is only for new tasks readonly + taskData.getRoot() + .getAttribute(BugzillaRestTaskSchema.getDefault().RESOLUTION.getKey()) + .getMetaData() + .setReadOnly(false); + // attributes we know that they can not be equal taskData.getRoot().removeAttribute("task.common.status"); taskDataGet.getRoot().removeAttribute("task.common.status"); @@ -471,9 +474,65 @@ public class BugzillaRestClientTest { taskDataGet.getRoot().removeAttribute("task.common.operation-RESOLVED"); taskDataGet.getRoot().removeAttribute("resolutionInput"); taskDataGet.getRoot().removeAttribute("task.common.operation-duplicate"); - taskDataGet.getRoot().removeAttribute("dup_id"); + taskDataGet.getRoot().removeAttribute("dupe_of"); assertEquals(taskData.getRoot().toString(), taskDataGet.getRoot().toString()); } + @Test + public void testUpdateTaskData() throws Exception { + String taskId = harness.getTaksId4TestProduct(); + TaskData taskDataGet = harness.getTaskFromServer(taskId); + + Set changed = new HashSet(); + + TaskAttribute attribute = taskDataGet.getRoot() + .getMappedAttribute(BugzillaRestCreateTaskSchema.getDefault().PRODUCT.getKey()); + attribute.setValue("Product with Spaces"); + changed.add(attribute); + attribute = taskDataGet.getRoot() + .getMappedAttribute(BugzillaRestCreateTaskSchema.getDefault().COMPONENT.getKey()); + attribute.setValue("Component 1"); + changed.add(attribute); + attribute = taskDataGet.getRoot() + .getMappedAttribute(BugzillaRestCreateTaskSchema.getDefault().VERSION.getKey()); + attribute.setValue("b"); + changed.add(attribute); + attribute = taskDataGet.getRoot() + .getMappedAttribute(BugzillaRestCreateTaskSchema.getDefault().TARGET_MILESTONE.getKey()); + attribute.setValue("M3.0"); + changed.add(attribute); + + attribute = taskDataGet.getRoot().getAttribute("cf_dropdown"); + attribute.setValue("two"); + changed.add(attribute); + attribute = taskDataGet.getRoot().getAttribute("cf_multiselect"); + attribute.setValues(Arrays.asList("Red", "Yellow")); + changed.add(attribute); + + //Act + RepositoryResponse reposonse = connector.getClient(actualFixture.repository()).postTaskData(taskDataGet, + changed, null); + + //Assert + TaskData taskDataUpdate = harness.getTaskFromServer(taskId); + + attribute = taskDataGet.getRoot() + .getMappedAttribute(BugzillaRestCreateTaskSchema.getDefault().PRODUCT.getKey()); + assertThat(attribute.getValue(), is("Product with Spaces")); + attribute = taskDataGet.getRoot() + .getMappedAttribute(BugzillaRestCreateTaskSchema.getDefault().COMPONENT.getKey()); + assertThat(attribute.getValue(), is("Component 1")); + attribute = taskDataGet.getRoot() + .getMappedAttribute(BugzillaRestCreateTaskSchema.getDefault().VERSION.getKey()); + assertThat(attribute.getValue(), is("b")); + attribute = taskDataGet.getRoot() + .getAttribute(BugzillaRestCreateTaskSchema.getDefault().TARGET_MILESTONE.getKey()); + assertThat(attribute.getValue(), is("M3.0")); + attribute = taskDataUpdate.getRoot().getAttribute("cf_dropdown"); + assertThat(attribute.getValue(), is("two")); + attribute = taskDataUpdate.getRoot().getAttribute("cf_multiselect"); + assertThat(attribute.getValues(), is(Arrays.asList("Red", "Yellow"))); + } + } diff --git a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core.tests/src/org/eclipse/mylyn/internal/bugzilla/rest/test/support/BugzillaRestHarness.java b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core.tests/src/org/eclipse/mylyn/internal/bugzilla/rest/test/support/BugzillaRestHarness.java index aaa5da856..0c018787b 100644 --- a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core.tests/src/org/eclipse/mylyn/internal/bugzilla/rest/test/support/BugzillaRestHarness.java +++ b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core.tests/src/org/eclipse/mylyn/internal/bugzilla/rest/test/support/BugzillaRestHarness.java @@ -11,13 +11,26 @@ package org.eclipse.mylyn.internal.bugzilla.rest.test.support; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import java.util.HashSet; +import java.util.Set; + import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.mylyn.internal.bugzilla.rest.core.BugzillaRestConnector; import org.eclipse.mylyn.internal.bugzilla.rest.core.BugzillaRestCore; +import org.eclipse.mylyn.internal.bugzilla.rest.core.BugzillaRestCreateTaskSchema; +import org.eclipse.mylyn.internal.bugzilla.rest.core.BugzillaRestException; +import org.eclipse.mylyn.internal.bugzilla.rest.core.SingleTaskDataCollector; 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.TaskMapping; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler; import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper; @@ -54,4 +67,56 @@ public class BugzillaRestHarness { return taskData; } + public String submitNewTask(TaskData taskData) throws BugzillaRestException, CoreException { + RepositoryResponse reposonse = connector().getClient(repository()).postTaskData(taskData, null, null); + assertThat(reposonse.getReposonseKind(), is(ResponseKind.TASK_CREATED)); + return reposonse.getTaskId(); + } + + public TaskData getTaskFromServer(String taskId) throws BugzillaRestException, CoreException { + Set taskIds = new HashSet(); + taskIds.add(taskId); + SingleTaskDataCollector singleTaskDataCollector = new SingleTaskDataCollector(); + connector().getClient(repository()).getTaskData(taskIds, repository(), singleTaskDataCollector, null); + TaskData taskDataGet = singleTaskDataCollector.getTaskData(); + assertNotNull(taskDataGet); + assertNotNull(taskDataGet.getRoot()); + return taskDataGet; + } + + public String getTaksId4TestProduct() throws BugzillaRestException, CoreException { + final TaskMapping taskMappingInit = new TaskMapping() { + @Override + public String getSummary() { + return "The Summary"; + } + + @Override + public String getDescription() { + return "The Description"; + } + + @Override + public String getProduct() { + return "ManualTest"; + } + + @Override + public String getComponent() { + return "ManualC1"; + } + + @Override + public String getVersion() { + return "R1"; + } + }; + TaskData taskData = createTaskData(taskMappingInit, null, null); + taskData.getRoot().getAttribute("cf_dropdown").setValue("one"); + taskData.getRoot() + .getAttribute(BugzillaRestCreateTaskSchema.getDefault().TARGET_MILESTONE.getKey()) + .setValue("M1"); + String taskId = submitNewTask(taskData); + return taskId; + } } diff --git a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestAuthenticatedPutRequest.java b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestAuthenticatedPutRequest.java new file mode 100644 index 000000000..df6ef3f55 --- /dev/null +++ b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestAuthenticatedPutRequest.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2015 Frank Becker 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: + * Frank Becker - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.bugzilla.rest.core; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.text.MessageFormat; + +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpRequestBase; +import org.eclipse.mylyn.commons.core.operations.IOperationMonitor; +import org.eclipse.mylyn.commons.repositories.core.auth.AuthenticationException; +import org.eclipse.mylyn.commons.repositories.core.auth.AuthenticationRequest; +import org.eclipse.mylyn.commons.repositories.core.auth.AuthenticationType; +import org.eclipse.mylyn.commons.repositories.core.auth.UserCredentials; +import org.eclipse.mylyn.commons.repositories.http.core.CommonHttpResponse; +import org.eclipse.mylyn.commons.repositories.http.core.HttpUtil; +import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.LoginToken; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +public abstract class BugzillaRestAuthenticatedPutRequest extends BugzillaRestRequest { + + public BugzillaRestAuthenticatedPutRequest(BugzillaRestHttpClient client) { + super(client); + // TODO Auto-generated constructor stub + } + + @Override + protected void authenticate(IOperationMonitor monitor) throws IOException { + UserCredentials credentials = getClient().getLocation().getCredentials(AuthenticationType.REPOSITORY); + if (credentials == null) { + throw new IllegalStateException("Authentication requested without valid credentials"); + } + HttpRequestBase request = new HttpGet(baseUrl() + + MessageFormat.format("/login?login={0}&password={1}", new Object[] { credentials.getUserName(), + credentials.getPassword() })); + request.setHeader(CONTENT_TYPE, TEXT_XML_CHARSET_UTF_8); + request.setHeader(ACCEPT, APPLICATION_JSON); + HttpResponse response = getClient().execute(request, monitor); + try { + if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { + getClient().setAuthenticated(false); + throw new AuthenticationException("Authentication failed", + new AuthenticationRequest>(getClient().getLocation(), + AuthenticationType.REPOSITORY)); + } else { + TypeToken type = new TypeToken() { + }; + InputStream is = response.getEntity().getContent(); + InputStreamReader in = new InputStreamReader(is); + LoginToken loginToken = new Gson().fromJson(in, type.getType()); + ((BugzillaRestHttpClient) getClient()).setLoginToken(loginToken); + getClient().setAuthenticated(true); + } + } finally { + HttpUtil.release(request, response, monitor); + } + } + + @Override + protected T execute(IOperationMonitor monitor) throws IOException, BugzillaRestException { + if (needsAuthentication() && ((BugzillaRestHttpClient) getClient()).getLoginToken() == null) { + authenticate(monitor); + } + HttpRequestBase request = createHttpRequestBase(); + CommonHttpResponse response = execute(request, monitor); + return processAndRelease(response, monitor); + } + + @Override + protected HttpRequestBase createHttpRequestBase() { + String bugUrl = getUrlSuffix(); + LoginToken token = ((BugzillaRestHttpClient) getClient()).getLoginToken(); + if (token != null && bugUrl.length() > 0) { + if (bugUrl.endsWith("?")) { //$NON-NLS-1$ + bugUrl += ("token=" + token.getToken()); //$NON-NLS-1$ + } else { + bugUrl += ("&token=" + token.getToken()); //$NON-NLS-1$ + } + } + + HttpPut request = new HttpPut(baseUrl() + bugUrl); + request.setHeader(CONTENT_TYPE, APPLICATION_JSON); + request.setHeader(ACCEPT, APPLICATION_JSON); + return request; + } + +} \ No newline at end of file diff --git a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestClient.java b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestClient.java index 9593445a6..1eb602ab2 100644 --- a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestClient.java +++ b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestClient.java @@ -29,11 +29,13 @@ import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.Named; import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.ParameterResponse; import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.Product; import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.ProductResponse; +import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.PutUpdateResult; import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.RestResponse; import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.VersionResponse; import org.eclipse.mylyn.tasks.core.RepositoryResponse; import org.eclipse.mylyn.tasks.core.RepositoryResponse.ResponseKind; import org.eclipse.mylyn.tasks.core.TaskRepository; +import org.eclipse.mylyn.tasks.core.data.TaskAttribute; import org.eclipse.mylyn.tasks.core.data.TaskData; import org.eclipse.mylyn.tasks.core.data.TaskDataCollector; @@ -116,12 +118,14 @@ public class BugzillaRestClient { }).run(monitor); } - public RepositoryResponse postTaskData(TaskData taskData, IOperationMonitor monitor) throws BugzillaRestException { + public RepositoryResponse postTaskData(TaskData taskData, Set oldAttributes, + IOperationMonitor monitor) throws BugzillaRestException { if (taskData.isNew()) { BugzillaRestIdResult result = new BugzillaRestPostNewTask(client, taskData).run(monitor); return new RepositoryResponse(ResponseKind.TASK_CREATED, result.getId()); } else { - throw new UnsupportedOperationException(); + PutUpdateResult result = new BugzillaRestPutUpdateTask(client, taskData, oldAttributes).run(monitor); + return new RepositoryResponse(ResponseKind.TASK_UPDATED, result.getBugs()[0].getId()); } } diff --git a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestConfiguration.java b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestConfiguration.java index 1572e3818..3dbf3bc8b 100644 --- a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestConfiguration.java +++ b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestConfiguration.java @@ -120,6 +120,7 @@ public class BugzillaRestConfiguration implements Serializable { for (String key : data.getRoot().getAttributes().keySet()) { if (key.equals(BugzillaRestTaskSchema.getDefault().ADD_SELF_CC.getKey()) || key.equals(BugzillaRestTaskSchema.getDefault().NEW_COMMENT.getKey()) + || key.equals(BugzillaRestTaskSchema.getDefault().DUPE_OF.getKey()) || key.equals(TaskAttribute.OPERATION)) { continue; } @@ -396,6 +397,11 @@ public class BugzillaRestConfiguration implements Serializable { } TaskAttribute attribute = bugReport.getRoot() .createAttribute(TaskAttribute.PREFIX_OPERATION + attributeStatusValue); + if (attributeStatusValue.equals("RESOLVED")) { + attribute.getMetaData().putValue(TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID, + BugzillaRestTaskSchema.getDefault().RESOLUTION.getKey()); + } + TaskOperation.applyTo(attribute, attributeStatusValue, attributeStatusValue); // set as default TaskOperation.applyTo(operationAttribute, attributeStatusValue, attributeStatusValue); @@ -425,8 +431,15 @@ public class BugzillaRestConfiguration implements Serializable { } attribute = bugReport.getRoot().createAttribute(TaskAttribute.PREFIX_OPERATION + "duplicate"); TaskOperation.applyTo(attribute, "duplicate", "Mark as Duplicate"); - TaskAttribute attrResolvedInput = attribute.getTaskData().getRoot().createAttribute("dup_id"); + TaskAttribute attrResolvedInput = attribute.getTaskData() + .getRoot() + .getAttribute(BugzillaRestTaskSchema.getDefault().DUPE_OF.getKey()); + if (attrResolvedInput == null) { + attrResolvedInput = attribute.getTaskData() + .getRoot() + .createAttribute(BugzillaRestTaskSchema.getDefault().DUPE_OF.getKey()); + } attrResolvedInput.getMetaData().setType(TaskAttribute.TYPE_TASK_DEPENDENCY); - attribute.getMetaData().putValue(TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID, "dup_id"); + attribute.getMetaData().putValue(TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID, attrResolvedInput.getId()); } } \ No newline at end of file diff --git a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestPutUpdateTask.java b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestPutUpdateTask.java new file mode 100644 index 000000000..ee919ff39 --- /dev/null +++ b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestPutUpdateTask.java @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright (c) 2015 Frank Becker 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: + * Frank Becker - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.bugzilla.rest.core; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.Set; + +import org.apache.http.NameValuePair; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.entity.StringEntity; +import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.LoginToken; +import org.eclipse.mylyn.internal.bugzilla.rest.core.response.data.PutUpdateResult; +import org.eclipse.mylyn.tasks.core.data.TaskAttribute; +import org.eclipse.mylyn.tasks.core.data.TaskData; + +import com.google.common.base.Function; +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +public class BugzillaRestPutUpdateTask extends BugzillaRestAuthenticatedPutRequest { + private final TaskData taskData; + + class OldAttributes { + private final Set oldAttributes; + + public OldAttributes(Set oldAttributes) { + super(); + this.oldAttributes = oldAttributes; + } + + } + + OldAttributes oldAttributes; + + ImmutableList legalUpdateAttributes = new ImmutableList.Builder() + .add(BugzillaRestTaskSchema.getDefault().PRODUCT.getKey()) + .add(BugzillaRestTaskSchema.getDefault().COMPONENT.getKey()) + .add(BugzillaRestTaskSchema.getDefault().SUMMARY.getKey()) + .add(BugzillaRestTaskSchema.getDefault().VERSION.getKey()) + .add(BugzillaRestTaskSchema.getDefault().DESCRIPTION.getKey()) + .add(BugzillaRestTaskSchema.getDefault().OS.getKey()) + .add(BugzillaRestTaskSchema.getDefault().PLATFORM.getKey()) + .add(BugzillaRestTaskSchema.getDefault().PRIORITY.getKey()) + .add(BugzillaRestTaskSchema.getDefault().SEVERITY.getKey()) + .add(BugzillaRestTaskSchema.getDefault().ALIAS.getKey()) + .add(BugzillaRestTaskSchema.getDefault().ASSIGNED_TO.getKey()) + .add(BugzillaRestTaskSchema.getDefault().QA_CONTACT.getKey()) + .add(TaskAttribute.OPERATION) + .add(BugzillaRestTaskSchema.getDefault().TARGET_MILESTONE.getKey()) + .add(BugzillaRestTaskSchema.getDefault().NEW_COMMENT.getKey()) + .add("resolutionInput") //$NON-NLS-1$ + .add(BugzillaRestTaskSchema.getDefault().RESOLUTION.getKey()) + .add(BugzillaRestTaskSchema.getDefault().DUPE_OF.getKey()) + .build(); + + class TaskAttributeTypeAdapter extends TypeAdapter { + LoginToken token; + + public TaskAttributeTypeAdapter(LoginToken token) { + super(); + this.token = token; + } + + private final Function function = new Function() { + + @Override + public String apply(String input) { + return BugzillaRestGsonUtil.convertString2GSonString(input); + } + }; + + @Override + public void write(JsonWriter out, OldAttributes oldValues) throws IOException { + out.beginObject(); + out.name("Bugzilla_token").value(token.getToken()); //$NON-NLS-1$ + for (TaskAttribute element : oldValues.oldAttributes) { + TaskAttribute taskAttribute = taskData.getRoot().getAttribute(element.getId()); + String id = taskAttribute.getId(); + String value = BugzillaRestGsonUtil.convertString2GSonString(taskAttribute.getValue()); + if ((legalUpdateAttributes.contains(id) || id.startsWith("cf_")) && value != null) { //$NON-NLS-1$ + id = BugzillaRestTaskSchema.getFieldNameFromAttributeName(id); + if (id.equals("status")) { //$NON-NLS-1$ + if (value != null && value.equals(TaskAttribute.PREFIX_OPERATION + "default")) { //$NON-NLS-1$ + continue; + } + if (value.equals("duplicate")) { //$NON-NLS-1$ + TaskAttribute res = element.getParentAttribute() + .getAttribute(BugzillaRestTaskSchema.getDefault().RESOLUTION.getKey()); + if (!oldAttributes.oldAttributes.contains(res)) { + out.name("resolution").value("DUPLICATE"); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + TaskAttribute res1 = taskData.getRoot() + .getAttribute(BugzillaRestTaskSchema.getDefault().RESOLUTION.getKey()); + res1.setValue("DUPLICATE"); //$NON-NLS-1$ + } + value = "RESOLVED"; //$NON-NLS-1$ + } + } + if (taskAttribute.getMetaData().getType() != null + && taskAttribute.getMetaData().getType().equals(TaskAttribute.TYPE_MULTI_SELECT)) { + Iterable taskIdsTemp = Iterables.transform(taskAttribute.getValues(), function); + Joiner joiner = Joiner.on(",").skipNulls(); //$NON-NLS-1$ + value = joiner.join(taskIdsTemp); + } + if (id.equals(BugzillaRestTaskSchema.getDefault().NEW_COMMENT.getKey())) { + out.name("comment").beginObject(); //$NON-NLS-1$ + out.name("body").value(value); //$NON-NLS-1$ + out.endObject(); + continue; + } + out.name(id).value(value); + if (id.equals("description")) { //$NON-NLS-1$ + TaskAttribute descriptionpri = taskAttribute + .getAttribute(BugzillaRestTaskSchema.getDefault().COMMENT_ISPRIVATE.getKey()); + Boolean descriptionprivalue = (descriptionpri != null) + ? (descriptionpri.getValue().equals("1")) //$NON-NLS-1$ + : false; + out.name("comment_is_private").value(Boolean.toString(descriptionprivalue)); //$NON-NLS-1$ + } + } + } + out.endObject(); + } + + @Override + public OldAttributes read(JsonReader in) throws IOException { + // TODO Auto-generated method stub + return null; + } + + } + + public BugzillaRestPutUpdateTask(BugzillaRestHttpClient client, TaskData taskData, + Set oldAttributes) { + super(client); + this.taskData = taskData; + this.oldAttributes = new OldAttributes(oldAttributes); + } + + @Override + protected String getUrlSuffix() { + return "/bug/" + taskData.getTaskId(); //$NON-NLS-1$ + } + + List requestParameters; + + @Override + protected HttpRequestBase createHttpRequestBase() { + String bugUrl = getUrlSuffix(); + LoginToken token = ((BugzillaRestHttpClient) getClient()).getLoginToken(); + + HttpPut request = new HttpPut(baseUrl() + bugUrl); + request.setHeader(CONTENT_TYPE, APPLICATION_JSON); + request.setHeader(ACCEPT, APPLICATION_JSON); + + try { + Gson gson = new GsonBuilder().registerTypeAdapter(OldAttributes.class, new TaskAttributeTypeAdapter(token)) + .create(); + StringEntity requestEntity = new StringEntity(gson.toJson(oldAttributes)); + request.setEntity(requestEntity); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return request; + } + + public static String convert(String str) { + str = str.replace("\"", "\\\"").replace("\n", "\\\n"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$ + StringBuffer ostr = new StringBuffer(); + for (int i = 0; i < str.length(); i++) { + char ch = str.charAt(i); + if ((ch >= 0x0020) && (ch <= 0x007e)) { + ostr.append(ch); + } else { + ostr.append("\\u"); //$NON-NLS-1$ + String hex = Integer.toHexString(str.charAt(i) & 0xFFFF); + for (int j = 0; j < 4 - hex.length(); j++) { + ostr.append("0"); //$NON-NLS-1$ + } + ostr.append(hex.toLowerCase()); + } + } + return (new String(ostr)); + } + + @Override + protected PutUpdateResult parseFromJson(InputStreamReader in) { + TypeToken type = new TypeToken() { + }; + return new Gson().fromJson(in, type.getType()); + } + +} \ No newline at end of file diff --git a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestTaskDataHandler.java b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestTaskDataHandler.java index 9454dc7d0..f25f0e81f 100644 --- a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestTaskDataHandler.java +++ b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestTaskDataHandler.java @@ -47,7 +47,7 @@ public class BugzillaRestTaskDataHandler extends AbstractTaskDataHandler { BugzillaRestClient client = connector.getClient(repository); try { IOperationMonitor progress = OperationUtil.convert(monitor, "post taskdata", 3); - return client.postTaskData(taskData, progress); + return client.postTaskData(taskData, oldAttributes, progress); } catch (BugzillaRestException e) { throw new CoreException(new Status(IStatus.ERROR, BugzillaRestCore.ID_PLUGIN, 2, "Error post taskdata.\n\n" + e.getMessage(), e)); @@ -119,5 +119,4 @@ public class BugzillaRestTaskDataHandler extends AbstractTaskDataHandler { monitor.done(); } } - } diff --git a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestTaskSchema.java b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestTaskSchema.java index 977611289..dd8241c60 100644 --- a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestTaskSchema.java +++ b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/BugzillaRestTaskSchema.java @@ -35,6 +35,24 @@ public class BugzillaRestTaskSchema extends AbstractTaskSchema { .put("op_sys", getDefault().OS.getKey()) .put("resolution", getDefault().RESOLUTION.getKey()) .put("version", getDefault().VERSION.getKey()) + .put("dup_id", getDefault().DUPE_OF.getKey()) + .build(); + + private static ImmutableMap attribute2FieldMapper = new ImmutableMap.Builder() + .put(getDefault().SUMMARY.getKey(), "summary") + .put(getDefault().DESCRIPTION.getKey(), "description") + .put(getDefault().OPERATION.getKey(), "status") + .put(getDefault().PRODUCT.getKey(), "product") + .put(getDefault().COMPONENT.getKey(), "component") + .put(getDefault().CC.getKey(), "cc") + .put(getDefault().SEVERITY.getKey(), "severity") + .put(getDefault().PRIORITY.getKey(), "priority") + .put(getDefault().ASSIGNED_TO.getKey(), "assigned_to") + .put(getDefault().OS.getKey(), "op_sys") + .put(getDefault().VERSION.getKey(), "version") + .put(getDefault().RESOLUTION.getKey(), "resolution") + .put(getDefault().getDefault().DUPE_OF.getKey(), "dup_id") + .put("resolutionInput", "resolution") .build(); public static String getAttributeNameFromFieldName(String fieldName) { @@ -45,6 +63,14 @@ public class BugzillaRestTaskSchema extends AbstractTaskSchema { return result; } + public static String getFieldNameFromAttributeName(String attributeName) { + String result = attribute2FieldMapper.get(attributeName); + if (result == null) { + result = attributeName; + } + return result; + } + public static BugzillaRestTaskSchema getDefault() { return instance; } @@ -96,12 +122,14 @@ public class BugzillaRestTaskSchema extends AbstractTaskSchema { public final Field TARGET_MILESTONE = createField("target_milestone", "Target milestone", TaskAttribute.TYPE_SINGLE_SELECT, null, PRODUCT.getKey(), Flag.ATTRIBUTE, Flag.REQUIRED); - public final Field RESOLUTION = inheritFrom(parent.RESOLUTION).create(); + public final Field RESOLUTION = inheritFrom(parent.RESOLUTION).removeFlags(Flag.READ_ONLY).create(); public final Field OPERATION = createField(TaskAttribute.OPERATION, "Operation", TaskAttribute.TYPE_OPERATION); public final Field NEW_COMMENT = inheritFrom(parent.NEW_COMMENT).create(); + public final Field DUPE_OF = createField("dupe_of", "Dup", TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID); + @Override public void initialize(TaskData taskData) { for (Field field : getFields()) { diff --git a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/response/data/PutUpdateEntry.java b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/response/data/PutUpdateEntry.java new file mode 100644 index 000000000..0c730d170 --- /dev/null +++ b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/response/data/PutUpdateEntry.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2015 Frank Becker 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: + * Frank Becker - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.bugzilla.rest.core.response.data; + +public class PutUpdateEntry { + private String last_change_time; + + private String id; + + private String[] alias; + + public PutUpdateEntry() { + } + + public String getLast_change_time() { + return last_change_time; + } + + public String getId() { + return id; + } + + public String[] getAlias() { + return alias; + } + +} diff --git a/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/response/data/PutUpdateResult.java b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/response/data/PutUpdateResult.java new file mode 100644 index 000000000..f98c4b49e --- /dev/null +++ b/connector-bugzilla-rest/org.eclipse.mylyn.bugzilla.rest.core/src/org/eclipse/mylyn/internal/bugzilla/rest/core/response/data/PutUpdateResult.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2015 Frank Becker 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: + * Frank Becker - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.bugzilla.rest.core.response.data; + +public class PutUpdateResult { + private PutUpdateEntry[] bugs; + + public PutUpdateEntry[] getBugs() { + return bugs; + } + + public PutUpdateResult() { + } + +} -- cgit v1.2.3