diff --git a/changelog.html b/changelog.html
index 4e25edc69..bf90312ac 100644
--- a/changelog.html
+++ b/changelog.html
@@ -44,6 +44,11 @@
REST API Plugin Changelog
+Next Release at some date
+
+ - [#127] - AAdd endpoint that allows for more than one MUC room to be created with one request
+
+
1.8.3 July 19, 2022
- [#124] - Update dependency-check-maven to 7.1.1
diff --git a/readme.md b/readme.md
index f6247223b..3b6d9e201 100644
--- a/readme.md
+++ b/readme.md
@@ -732,7 +732,7 @@ Endpoint to get the chat message history of a specified room.
| roomname | @Path | Exact room name | |
| servicename | @QueryParam | The name of the Group Chat Service | conference |
-## Create a chat room
+## Create a chat room
Endpoint to create a new chat room.
>**POST** /chatrooms
@@ -917,6 +917,116 @@ Endpoint to create a new chat room.
}
```
+
+
+
+
+
+
+## Create multiple chat room
+Endpoint to create multiple new chat rooms at once.
+>**POST** /chatrooms/bulk
+
+**Payload:** Chatrooms
+
+**Return value:** Result list, ordered by successes and failures
+```xml
+
+
+
+
+ room1
+ Success
+ Room was successfully created
+
+
+ room2
+ Success
+ Room was successfully created
+
+
+
+
+
+```
+
+```json
+{
+ "success": [
+ {
+ "roomName": "room1",
+ "resultType": "Success",
+ "message": "Room was successfully created"
+ },
+ {
+ "roomName": "room2",
+ "resultType": "Success",
+ "message": "Room was successfully created"
+ }
+ ],
+ "failure": [],
+ "other": []
+}
+```
+### Possible parameters
+
+| Parameter | Parameter Type | Description | Default value |
+|-------------|-----------------|-------------------------------------|---------------|
+| servicename | @QueryParam | The name of the Group Chat Service | conference |
+
+### XML Examples
+
+>**Header:** Authorization: Basic YWRtaW46MTIzNDU=
+>
+>**Header:** Content-Type: application/xml
+>
+>**POST** http://example.org:9090/plugins/restapi/v1/chatrooms/bulk
+
+**Payload Example:**
+```xml
+
+
+
+ room1
+ description1
+
+
+ room2
+ description1
+
+
+```
+
+For more examples, with more parameters, see the [create a chat room](#create-a-chat-room) endpoint.
+
+### JSON Examples
+
+>**Header:** Authorization: Basic YWRtaW46MTIzNDU=
+>
+>**Header:** Content-Type: application/json
+>
+>**POST** http://example.org:9090/plugins/restapi/v1/chatrooms
+
+**Payload Example 1 (required parameters):**
+```json
+{
+ "chatRooms": [
+ { "roomName": "room1", "description": "description1" },
+ { "roomName": "room2", "description": "description2" }
+ ]
+}
+```
+
+For more examples, with more parameters, see the [create a chat room](#create-a-chat-room) endpoint.
+
+
+
+
+
+
+
+
+
## Delete a chat room
Endpoint to delete a chat room.
>**DELETE** /chatrooms/{roomName}
diff --git a/src/java/org/jivesoftware/openfire/plugin/rest/controller/MUCRoomController.java b/src/java/org/jivesoftware/openfire/plugin/rest/controller/MUCRoomController.java
index 04e0dca61..378466f63 100644
--- a/src/java/org/jivesoftware/openfire/plugin/rest/controller/MUCRoomController.java
+++ b/src/java/org/jivesoftware/openfire/plugin/rest/controller/MUCRoomController.java
@@ -38,7 +38,6 @@
import org.xmpp.packet.Presence;
import javax.annotation.Nonnull;
-import javax.servlet.ServletException;
import javax.ws.rs.core.Response;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
@@ -258,6 +257,41 @@ public void createChatRoom(String serviceName, MUCRoomEntity mucRoomEntity) thro
}
}
+ /**
+ * Creates multiple chat rooms.
+ *
+ * @param serviceName
+ * the service name
+ * @param mucRoomEntities
+ * the chat rooms to create
+ * @return
+ * a report detailing which creates were successful and which weren't
+ * @throws ServiceException
+ * the service exception
+ */
+ public RoomCreationResultEntities createMultipleChatRooms(String serviceName, MUCRoomEntities mucRoomEntities) throws ServiceException {
+ List roomsToCreate = mucRoomEntities.getMucRooms();
+ log("Create " + roomsToCreate.size() + " chat rooms");
+ List results = new ArrayList<>();
+ for (MUCRoomEntity roomToCreate : roomsToCreate) {
+ RoomCreationResultEntity result = new RoomCreationResultEntity();
+ result.setRoomName(roomToCreate.getRoomName());
+ try {
+ createRoom(roomToCreate, serviceName);
+ result.setResultType(RoomCreationResultEntity.RoomCreationResultType.Success);
+ result.setMessage("Room was successfully created");
+ } catch (AlreadyExistsException e) {
+ result.setResultType(RoomCreationResultEntity.RoomCreationResultType.Success);
+ result.setMessage("Room already existed and therefore not created again");
+ } catch (NotAllowedException | ForbiddenException | ConflictException e) {
+ result.setResultType(RoomCreationResultEntity.RoomCreationResultType.Failure);
+ result.setMessage("Room creation failed due to " + e.getClass().getSimpleName() + ": " + e.getMessage());
+ }
+ results.add(result);
+ }
+ return new RoomCreationResultEntities(results);
+ }
+
/**
* Update chat room.
*
diff --git a/src/java/org/jivesoftware/openfire/plugin/rest/entity/RoomCreationResultEntities.java b/src/java/org/jivesoftware/openfire/plugin/rest/entity/RoomCreationResultEntities.java
new file mode 100644
index 000000000..db18e0662
--- /dev/null
+++ b/src/java/org/jivesoftware/openfire/plugin/rest/entity/RoomCreationResultEntities.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2022.
+ *
+ * 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.jivesoftware.openfire.plugin.rest.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import java.util.ArrayList;
+import java.util.List;
+
+@XmlRootElement(name = "results")
+@XmlType(propOrder = { "successResults", "failureResults", "otherResults" })
+public class RoomCreationResultEntities {
+ List successResults;
+ List failureResults;
+
+ // This last list is for if a new result type is defined, but no extra result list is added here - a "catch all"
+ List otherResults;
+
+ public RoomCreationResultEntities() {
+ this.successResults = new ArrayList<>();
+ this.failureResults = new ArrayList<>();
+ this.otherResults = new ArrayList<>();
+ }
+
+ public RoomCreationResultEntities(List results) {
+ this();
+ addResults(results);
+ }
+
+ public void addResults(List resultsToAdd) {
+ resultsToAdd.forEach(this::addResult);
+ }
+
+ public void addResult(RoomCreationResultEntity resultToAdd) {
+ switch (resultToAdd.getResultType()) {
+ case Success:
+ this.successResults.add(resultToAdd);
+ break;
+ case Failure:
+ this.failureResults.add(resultToAdd);
+ break;
+ default:
+ this.otherResults.add(resultToAdd);
+ }
+ }
+
+ @XmlElement(name = "result")
+ @XmlElementWrapper(name = "success")
+ @JsonProperty(value = "success")
+ @Schema(description = "All creation results of type success")
+ public List getSuccessResults() {
+ return successResults;
+ }
+
+ @XmlElement(name = "result")
+ @XmlElementWrapper(name = "failure")
+ @JsonProperty(value = "failure")
+ @Schema(description = "All creation results of type failure")
+ public List getFailureResults() {
+ return failureResults;
+ }
+
+ @XmlElement(name = "result")
+ @XmlElementWrapper(name = "other")
+ @JsonProperty(value = "other")
+ @Schema(description = "All creation results of a type other than success or failure")
+ public List getOtherResults() {
+ return otherResults;
+ }
+}
diff --git a/src/java/org/jivesoftware/openfire/plugin/rest/entity/RoomCreationResultEntity.java b/src/java/org/jivesoftware/openfire/plugin/rest/entity/RoomCreationResultEntity.java
new file mode 100644
index 000000000..a272475e9
--- /dev/null
+++ b/src/java/org/jivesoftware/openfire/plugin/rest/entity/RoomCreationResultEntity.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2022.
+ *
+ * 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.jivesoftware.openfire.plugin.rest.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+@XmlRootElement(name = "result")
+@XmlType(propOrder = { "roomName", "resultType", "message"})
+public class RoomCreationResultEntity {
+
+ public enum RoomCreationResultType {
+ Success, Failure
+ }
+
+ String roomName;
+ RoomCreationResultType resultType;
+ String message;
+
+ @XmlElement
+ @Schema(description = "The name of the room that was to be created", example = "open_chat")
+ public String getRoomName() {
+ return roomName;
+ }
+
+ public void setRoomName(String roomName) {
+ this.roomName = roomName;
+ }
+
+ @XmlElement
+ @Schema(description = "The result of creating the room", example = "Failure")
+ public RoomCreationResultType getResultType() {
+ return resultType;
+ }
+
+ public void setResultType(RoomCreationResultType resultType) {
+ this.resultType = resultType;
+ }
+
+ @XmlElement
+ @Schema(description = "A message describing the result", example = "Room already existed and therefore not created again")
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomService.java b/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomService.java
index c01c24f13..1f63d42f7 100644
--- a/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomService.java
+++ b/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomService.java
@@ -118,6 +118,26 @@ public Response createMUCRoom(
return Response.status(Status.CREATED).build();
}
+ @POST
+ @Path("/bulk")
+ @Operation( summary = "Create multiple chat rooms",
+ description = "Create a number of new multi-user chat rooms.",
+ responses = {
+ @ApiResponse(responseCode = "200", description = "Request has been processed. Results are reported in the response.", content = @Content(schema = @Schema(implementation = RoomCreationResultEntities.class))),
+ @ApiResponse(responseCode = "401", description = "Web service authentication failed.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
+ @ApiResponse(responseCode = "404", description = "MUC Service does not exist or is not accessible.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
+ @ApiResponse(responseCode = "500", description = "Unexpected, generic error condition.", content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
+ })
+ @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ public RoomCreationResultEntities createMUCRooms(
+ @Parameter(description = "The name of the MUC service in which to create a chat room.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
+ @RequestBody(description = "The MUC rooms that need to be created.", required = true) MUCRoomEntities mucRoomEntities)
+ throws ServiceException
+ {
+ return MUCRoomController.getInstance().createMultipleChatRooms(serviceName, mucRoomEntities);
+ }
+
@PUT
@Path("/{roomName}")
@Operation( summary = "Update chat room",