提交 938a9ae4 编写于 作者: F Frederik Heremans

Added creation/deletion of group membership

上级 d28eb6c8
......@@ -60,6 +60,7 @@ import org.activiti.rest.api.history.HistoricProcessInstanceResponse;
import org.activiti.rest.api.history.HistoricTaskInstanceResponse;
import org.activiti.rest.api.history.HistoricVariableInstanceResponse;
import org.activiti.rest.api.identity.GroupResponse;
import org.activiti.rest.api.identity.MembershipResponse;
import org.activiti.rest.api.identity.UserInfoResponse;
import org.activiti.rest.api.identity.UserResponse;
import org.activiti.rest.api.legacy.identity.LegacyRestIdentityLink;
......@@ -582,6 +583,13 @@ public class RestResponseFactory {
return response;
}
public MembershipResponse createMembershipResponse(SecuredResource securedResource, String userId, String groupId) {
MembershipResponse response = new MembershipResponse();
response.setGroupId(groupId);
response.setUserId(userId);
response.setUrl(securedResource.createFullResourceUrl(RestUrls.URL_GROUP_MEMBERSHIP, groupId, userId));
return response;
}
/**
* Called once when the converters need to be initialized. Override of custom conversion
......
......@@ -63,6 +63,7 @@ public final class RestUrls {
public static final String SEGMENT_GROUPS = "groups";
public static final String SEGMENT_PICTURE = "picture";
public static final String SEGMENT_INFO = "info";
public static final String SEGMENT_MEMBERS = "members";
/**
* URL template for the deployment collection: <i>repository/deployments</i>
......@@ -378,6 +379,16 @@ public final class RestUrls {
*/
public static final String[] URL_GROUP = {SEGMENT_IDENTITY_RESOURCES, SEGMENT_GROUPS, "{0}"};
/**
* URL template for the membership-collection of a group: <i>identity/groups/{0:groupId}/members</i>
*/
public static final String[] URL_GROUP_MEMBERSHIP_COLLECTION = {SEGMENT_IDENTITY_RESOURCES, SEGMENT_GROUPS, "{0}", SEGMENT_MEMBERS};
/**
* URL template for the membership-collection of a single group membership: <i>identity/groups/{0:groupId}/members/{1:userId}</i>
*/
public static final String[] URL_GROUP_MEMBERSHIP = {SEGMENT_IDENTITY_RESOURCES, SEGMENT_GROUPS, "{0}", SEGMENT_MEMBERS, "{1}"};
/**
* Creates an url based on the passed fragments and replaces any placeholders with the given arguments. The
* placeholders are folowing the {@link MessageFormat} convention
......
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.activiti.rest.api.identity;
import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.identity.Group;
import org.activiti.rest.api.ActivitiUtil;
import org.activiti.rest.application.ActivitiRestServicesApplication;
import org.restlet.data.Status;
import org.restlet.resource.Post;
import org.restlet.resource.ResourceException;
/**
* @author Frederik Heremans
*/
public class GroupMembershipCollectionResource extends BaseGroupResource {
@Post
public MembershipResponse createMembership(MembershipRequest memberShip) {
Group group = getGroupFromRequest();
if(memberShip.getUserId() == null) {
throw new ActivitiIllegalArgumentException("UserId cannot be null.");
}
// Check if user is member of group since API doesn't return typed exception
if(ActivitiUtil.getIdentityService().createUserQuery()
.memberOfGroup(group.getId())
.userId(memberShip.getUserId())
.count() > 0) {
throw new ResourceException(Status.CLIENT_ERROR_CONFLICT.getCode(), "User '" + memberShip.getUserId() +
"' is already part of group '" + group.getId() + "'.", null, null);
}
ActivitiUtil.getIdentityService().createMembership(memberShip.getUserId(), group.getId());
setStatus(Status.SUCCESS_CREATED);
return getApplication(ActivitiRestServicesApplication.class).getRestResponseFactory()
.createMembershipResponse(this, memberShip.getUserId(), group.getId());
}
}
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.activiti.rest.api.identity;
import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.identity.Group;
import org.activiti.rest.api.ActivitiUtil;
import org.restlet.data.Status;
import org.restlet.resource.Delete;
import org.restlet.resource.ResourceException;
/**
* @author Frederik Heremans
*/
public class GroupMembershipResource extends BaseGroupResource {
@Delete
public void deleteMembership() {
Group group = getGroupFromRequest();
String userId = getAttribute("userId");
if(userId == null) {
throw new ActivitiIllegalArgumentException("UserId cannot be null.");
}
// Check if user is not a member of group since API doesn't return typed exception
if(ActivitiUtil.getIdentityService().createUserQuery()
.memberOfGroup(group.getId())
.userId(userId)
.count() != 1) {
throw new ResourceException(Status.CLIENT_ERROR_NOT_FOUND.getCode(), "User '" + userId +
"' is not part of group '" + group.getId() + "'.", null, null);
}
ActivitiUtil.getIdentityService().deleteMembership(userId, group.getId());
setStatus(Status.SUCCESS_NO_CONTENT);
}
}
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.activiti.rest.api.identity;
/**
* @author Frederik Heremans
*/
public class MembershipRequest {
protected String userId;
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserId() {
return userId;
}
}
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.activiti.rest.api.identity;
/**
* @author Frederik Heremans
*/
public class MembershipResponse extends MembershipRequest {
protected String url;
protected String groupId;
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getGroupId() {
return groupId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
......@@ -16,6 +16,8 @@ import org.activiti.rest.api.history.HistoricTaskInstanceResource;
import org.activiti.rest.api.history.HistoricVariableInstanceCollectionResource;
import org.activiti.rest.api.history.HistoricVariableInstanceQueryResource;
import org.activiti.rest.api.identity.GroupCollectionResource;
import org.activiti.rest.api.identity.GroupMembershipCollectionResource;
import org.activiti.rest.api.identity.GroupMembershipResource;
import org.activiti.rest.api.identity.GroupResource;
import org.activiti.rest.api.identity.UserCollectionResource;
import org.activiti.rest.api.identity.UserInfoCollectionResource;
......@@ -179,6 +181,8 @@ public class RestServicesInit {
router.attach("/identity/users/{userId}/info", UserInfoCollectionResource.class);
router.attach("/identity/groups", GroupCollectionResource.class);
router.attach("/identity/groups/{groupId}", GroupResource.class);
router.attach("/identity/groups/{groupId}/members", GroupMembershipCollectionResource.class);
router.attach("/identity/groups/{groupId}/members/{userId}", GroupMembershipResource.class);
router.attach("/query/tasks", TaskQueryResource.class);
......
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.activiti.rest.api.identity;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.rest.BaseRestTestCase;
import org.activiti.rest.api.RestUrls;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ObjectNode;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;
import org.restlet.resource.ResourceException;
/**
* @author Frederik Heremans
*/
public class GroupMembershipResourceTest extends BaseRestTestCase {
public void testCreatemembership() throws Exception {
try {
Group testGroup = identityService.newGroup("testgroup");
testGroup.setName("Test group");
testGroup.setType("Test type");
identityService.saveGroup(testGroup);
User testUser = identityService.newUser("testuser");
identityService.saveUser(testUser);
ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_GROUP_MEMBERSHIP_COLLECTION, "testgroup"));
ObjectNode requestNode = objectMapper.createObjectNode();
requestNode.put("userId", "testuser");
Representation response = client.post(requestNode);
assertEquals(Status.SUCCESS_CREATED, client.getResponse().getStatus());
JsonNode responseNode = objectMapper.readTree(response.getStream());
assertNotNull(responseNode);
assertEquals("testuser", responseNode.get("userId").getTextValue());
assertEquals("testgroup", responseNode.get("groupId").getTextValue());
assertTrue(responseNode.get("url").getTextValue().endsWith(RestUrls.createRelativeResourceUrl(
RestUrls.URL_GROUP_MEMBERSHIP, testGroup.getId(), testUser.getId())));
Group createdGroup = identityService.createGroupQuery().groupId("testgroup").singleResult();
assertNotNull(createdGroup);
assertEquals("Test group", createdGroup.getName());
assertEquals("Test type", createdGroup.getType());
assertNotNull(identityService.createUserQuery().memberOfGroup("testgroup").singleResult());
assertEquals("testuser", identityService.createUserQuery().memberOfGroup("testgroup").singleResult().getId());
} finally {
try {
identityService.deleteGroup("testgroup");
} catch(Throwable ignore) {
// Ignore, since the group may not have been created in the test
// or already deleted
}
try {
identityService.deleteUser("testuser");
} catch(Throwable ignore) {
// Ignore, since the group may not have been created in the test
// or already deleted
}
}
}
public void testCreateMembershipAlreadyExisting() throws Exception {
try {
Group testGroup = identityService.newGroup("testgroup");
testGroup.setName("Test group");
testGroup.setType("Test type");
identityService.saveGroup(testGroup);
User testUser = identityService.newUser("testuser");
identityService.saveUser(testUser);
identityService.createMembership("testuser", "testgroup");
ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_GROUP_MEMBERSHIP_COLLECTION, "testgroup"));
ObjectNode requestNode = objectMapper.createObjectNode();
requestNode.put("userId", "testuser");
try {
client.post(requestNode);
fail("Exception expected");
} catch(ResourceException expected) {
assertEquals(Status.CLIENT_ERROR_CONFLICT, expected.getStatus());
assertEquals("User 'testuser' is already part of group 'testgroup'.", expected.getStatus().getDescription());
}
} finally {
try {
identityService.deleteGroup("testgroup");
} catch(Throwable ignore) {
// Ignore, since the group may not have been created in the test
// or already deleted
}
try {
identityService.deleteUser("testuser");
} catch(Throwable ignore) {
// Ignore, since the group may not have been created in the test
// or already deleted
}
}
}
public void testDeleteMembership() throws Exception {
try {
Group testGroup = identityService.newGroup("testgroup");
testGroup.setName("Test group");
testGroup.setType("Test type");
identityService.saveGroup(testGroup);
User testUser = identityService.newUser("testuser");
identityService.saveUser(testUser);
identityService.createMembership("testuser", "testgroup");
ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(
RestUrls.URL_GROUP_MEMBERSHIP, "testgroup", "testuser"));
Representation response = client.delete();
assertEquals(Status.SUCCESS_NO_CONTENT, client.getResponse().getStatus());
assertEquals(0, response.getSize());
// Check if membership is actually deleted
assertNull(identityService.createUserQuery().memberOfGroup("testgroup").singleResult());
} finally {
try {
identityService.deleteGroup("testgroup");
} catch(Throwable ignore) {
// Ignore, since the group may not have been created in the test
// or already deleted
}
try {
identityService.deleteUser("testuser");
} catch(Throwable ignore) {
// Ignore, since the group may not have been created in the test
// or already deleted
}
}
}
/**
* Test delete membership that is no member in the group.
*/
public void testDeleteMembershipNoMember() throws Exception {
try {
Group testGroup = identityService.newGroup("testgroup");
testGroup.setName("Test group");
testGroup.setType("Test type");
identityService.saveGroup(testGroup);
User testUser = identityService.newUser("testuser");
identityService.saveUser(testUser);
ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(
RestUrls.URL_GROUP_MEMBERSHIP, "testgroup", "testuser"));
try {
client.delete();
fail("Exception expected");
} catch(ResourceException expected) {
assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
assertEquals("User 'testuser' is not part of group 'testgroup'.", expected.getStatus().getDescription());
}
} finally {
try {
identityService.deleteGroup("testgroup");
} catch(Throwable ignore) {
// Ignore, since the group may not have been created in the test
// or already deleted
}
try {
identityService.deleteUser("testuser");
} catch(Throwable ignore) {
// Ignore, since the group may not have been created in the test
// or already deleted
}
}
}
/**
* Test deleting member from an unexisting group.
*/
public void testDeleteMemberfromUnexistingGroup() throws Exception {
ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(
RestUrls.URL_GROUP_MEMBERSHIP, "unexisting", "kermit"));
try {
client.delete();
fail("Exception expected");
} catch(ResourceException expected) {
assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
assertEquals("Could not find a group with id 'unexisting'.", expected.getStatus().getDescription());
}
}
/**
* Test adding member to an unexisting group.
*/
public void testAddMemberToUnexistingGroup() throws Exception {
ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_GROUP_MEMBERSHIP_COLLECTION, "unexisting"));
try {
client.post(objectMapper.createObjectNode());
fail("Exception expected");
} catch(ResourceException expected) {
assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
assertEquals("Could not find a group with id 'unexisting'.", expected.getStatus().getDescription());
}
}
/**
* Test adding member to a group, without specifying userId
*/
public void testAddMemberNoUserId() throws Exception {
ClientResource client = getAuthenticatedClient(RestUrls.createRelativeResourceUrl(RestUrls.URL_GROUP_MEMBERSHIP_COLLECTION, "admin"));
try {
client.post(objectMapper.createObjectNode());
fail("Exception expected");
} catch(ResourceException expected) {
assertEquals(Status.CLIENT_ERROR_BAD_REQUEST, expected.getStatus());
assertEquals("UserId cannot be null.", expected.getStatus().getDescription());
}
}
}
......@@ -5479,6 +5479,153 @@ Only the attachment name is required to create a new attachment.
</table>
</para>
</section>
<section>
<title>Get members in a group</title>
<para>There is no GET allowed on <literal>identity/groups/members</literal>. Use the <literal>identity/users?memberOfGroup=sales</literal> URL to get all users that are part of a particular group.</para>
</section>
<section>
<title>Add a member to a group</title>
<para>
<programlisting>POST identity/groups/{groupId}/members</programlisting>
</para>
<para>
<table>
<title>URL parameters</title>
<tgroup cols='3'>
<thead>
<row>
<entry>Parameter</entry>
<entry>Required</entry>
<entry>Value</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>groupId</entry>
<entry>Yes</entry>
<entry>String</entry>
<entry>The id of the group to add a member to.</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para>
<emphasis role="bold">Body JSON:</emphasis>
<programlisting>
{
"userId":"kermit"
}</programlisting>
</para>
<para>
<table>
<title>Response codes</title>
<tgroup cols='2'>
<thead>
<row>
<entry>Response code</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>201</entry>
<entry>Indicates the group was found and the member has been added.</entry>
</row>
<row>
<entry>404</entry>
<entry>Indicates the userId was not included in the request body.</entry>
</row>
<row>
<entry>404</entry>
<entry>Indicates the requested group was not found.</entry>
</row>
<row>
<entry>409</entry>
<entry>Indicates the requested user is already a member of the group.</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para>
<emphasis role="bold">Response Body:</emphasis>
<programlisting>
{
"userId":"kermit",
"groupId":"sales",
"url":"http://localhost:8182/identity/groups/sales/members/kermit"
}</programlisting>
</para>
</section>
<section>
<title>Delete a member from a group</title>
<para>
<programlisting>DELETE identity/groups/{groupId}/members/{userId}</programlisting>
</para>
<para>
<table>
<title>URL parameters</title>
<tgroup cols='3'>
<thead>
<row>
<entry>Parameter</entry>
<entry>Required</entry>
<entry>Value</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>groupId</entry>
<entry>Yes</entry>
<entry>String</entry>
<entry>The id of the group to remove a member from.</entry>
</row>
<row>
<entry>userId</entry>
<entry>Yes</entry>
<entry>String</entry>
<entry>The id of the user to remove.</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para>
<table>
<title>Response codes</title>
<tgroup cols='2'>
<thead>
<row>
<entry>Response code</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>204</entry>
<entry>Indicates the group was found and the member has been deleted. The response body is left empty intentionally.</entry>
</row>
<row>
<entry>404</entry>
<entry>Indicates the requested group was not found or that the user is not a member of the group. The status description contains additional information about the error.</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para>
<emphasis role="bold">Response Body:</emphasis>
<programlisting>
{
"userId":"kermit",
"groupId":"sales",
"url":"http://localhost:8182/identity/groups/sales/members/kermit"
}</programlisting>
</para>
</section>
</section>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册