diff --git a/changelog.html b/changelog.html
index 3d24eb0a7..659be7ee0 100644
--- a/changelog.html
+++ b/changelog.html
@@ -47,6 +47,8 @@
1.9.0 (tbd)
- [#130] - Add endpoint to create a new MUC service
+ - [#129] - Add endpoint(s) to invite users to a chatroom
+ - [#128] - Modify endpoints to add 'send invitations to affiliated users' as optional functionality
- [#127] - Add endpoint that allows for more than one MUC room to be created with one request
- [#33] - Add 'allowPM' to representation of MUC room.
- [#15] - Fix group-based affiliations with MUC rooms.
diff --git a/readme.md b/readme.md
index 25a478ca5..724dbf784 100644
--- a/readme.md
+++ b/readme.md
@@ -804,9 +804,10 @@ Endpoint to create a new chat room.
### Possible parameters
-| Parameter | Parameter Type | Description | Default value |
-|-------------|-----------------|-------------------------------------|---------------|
-| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| Parameter | Parameter Type | Description | Default value |
+|-----------------|-----------------|-------------------------------------------------|---------------|
+| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| sendInvitations | @QueryParam | Whether to send invitations to affiliated users | false |
### XML Examples
@@ -1035,9 +1036,10 @@ Endpoint to create multiple new chat rooms at once.
```
### Possible parameters
-| Parameter | Parameter Type | Description | Default value |
-|-------------|-----------------|-------------------------------------|---------------|
-| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| Parameter | Parameter Type | Description | Default value |
+|-----------------|-----------------|-------------------------------------------------------|---------------|
+| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| sendInvitations | @QueryParam | Whether to send invitations to newly affiliated users | false |
### XML Examples
@@ -1125,10 +1127,11 @@ Endpoint to update a chat room.
### Possible parameters
-| Parameter | Parameter Type | Description | Default value |
-|-------------|-----------------|------------------------------------|---------------|
-| roomname | @Path | Exact room name | |
-| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| Parameter | Parameter Type | Description | Default value |
+|-----------------|----------------|-------------------------------------------------------|---------------|
+| roomname | @Path | Exact room name | |
+| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| sendInvitations | @QueryParam | Whether to send invitations to newly affiliated users | false |
### Examples
>**Header:** Authorization: Basic YWRtaW46MTIzNDU=
@@ -1178,9 +1181,9 @@ Endpoint to update a chat room.
```
-## Invite user to a chat Room
+## Invite user or user group to a chat Room
-Endpoint to invite a user to a room.
+Endpoint to invite a user or a user group to a room.
> **Header:** Authorization: Basic YWRtaW46MTIzNDU=
>
> **Header:** Content-Type: application/xml
@@ -1198,10 +1201,40 @@ Endpoint to invite a user to a room.
**Return value:** HTTP status 200 (OK)
### Possible parameters
-| Parameter | Parameter Type | Description | Default value |
-|-----------|-----------------|------------------------------------|---------------|
-| roomname | @Path | Exact room name | |
-| name | @Path | The local username or the user JID | |
+| Parameter | Parameter Type | Description | Default value |
+|-----------|-----------------|---------------------------------------------------------------|---------------|
+| roomname | @Path | Exact room name | |
+| name | @Path | The local username or group name or the user JID or group JID | |
+
+## Invite multiple users and/or user groups to a chat Room
+
+Endpoint to invite multiple users and/or user groups to a room. Works both with JIDs and (user/group) names.
+> **Header:** Authorization: Basic YWRtaW46MTIzNDU=
+>
+> **Header:** Content-Type: application/xml
+>
+> **POST** http://localhost:9090/plugins/restapi/v1/chatrooms/{roomName}/invite
+
+**Payload Example:**
+
+```xml
+
+
+ Hello, come to this room, it is nice
+
+ jane@example.org
+ ADNMQP8=@example.org/695c6ae413c00446733d926ccadefd8b
+ john
+ SomeGroupName
+
+
+```
+**Return value:** HTTP status 200 (OK)
+
+### Possible parameters
+| Parameter | Parameter Type | Description | Default value |
+|-----------|-----------------|---------------------------------------------------------------|---------------|
+| roomname | @Path | Exact room name | |
## Get all users with a particular affiliation in a chat room
Retrieves a list of JIDs for all users with the specified affiliation in a multi-user chat room.
@@ -1246,12 +1279,13 @@ Endpoint to add a new user with affiliation to a room.
### Possible parameters
-| Parameter | Parameter Type | Description | Default value |
-|-------------|-----------------|--------------------------------------------------------------------------------------------|---------------|
-| roomname | @Path | Exact room name | |
-| name | @Path | The local username or the user JID | |
-| affiliation | @Path | Available affiliations:
**owners**
**admins**
**members**
**outcasts** | |
-| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| Parameter | Parameter Type | Description | Default value |
+|-----------------|-----------------|--------------------------------------------------------------------------------------------|---------------|
+| roomname | @Path | Exact room name | |
+| name | @Path | The local username or the user JID | |
+| affiliation | @Path | Available affiliations:
**owners**
**admins**
**members**
**outcasts** | |
+| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| sendInvitations | @QueryParam | Whether to send invitation to the newly affiliated user | false |
### Examples
>**Header:** Authorization: Basic YWRtaW46MTIzNDU=
@@ -1264,7 +1298,7 @@ Endpoint to add a new user with affiliation to a room.
>
>**POST** http://example.org:9090/plugins/restapi/v1/chatrooms/global/admins/testUser
>
->**POST** http://example.org:9090/plugins/restapi/v1/chatrooms/global/members/testUser
+>**POST** http://example.org:9090/plugins/restapi/v1/chatrooms/global/members/testUser?sendInvitations=true
>
>**POST** http://example.org:9090/plugins/restapi/v1/chatrooms/global/outcasts/testUser
>
@@ -1280,11 +1314,12 @@ Endpoint to replace all users with a particular affiliation in a multi-user chat
### Possible parameters
-| Parameter | Parameter Type | Description | Default value |
-|-------------|-----------------|--------------------------------------------------------------------------------------------|---------------|
-| roomname | @Path | Exact room name | |
-| affiliation | @Path | Available affiliations:
**owners**
**admins**
**members**
**outcasts** | |
-| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| Parameter | Parameter Type | Description | Default value |
+|-----------------|-----------------|--------------------------------------------------------------------------------------------|---------------|
+| roomname | @Path | Exact room name | |
+| affiliation | @Path | Available affiliations:
**owners**
**admins**
**members**
**outcasts** | |
+| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| sendInvitations | @QueryParam | Whether to send invitation to newly affiliated users | false |
### Examples
>**Header:** Authorization: Basic YWRtaW46MTIzNDU=
@@ -1312,11 +1347,12 @@ Endpoint to add multiple users with an affiliation to a multi-user chat room. No
### Possible parameters
-| Parameter | Parameter Type | Description | Default value |
-|--------------|-----------------|-------------------------------------------------------------------------------------|---------------|
-| roomname | @Path | Exact room name | |
-| affiliation | @Path | Available affiliation:
**owners**
**admins**
**members**
**outcasts** | |
-| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| Parameter | Parameter Type | Description | Default value |
+|-----------------|-----------------|-------------------------------------------------------------------------------------------|---------------|
+| roomname | @Path | Exact room name | |
+| affiliation | @Path | Available affiliation:
**owners**
**admins**
**members**
**outcasts** | |
+| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| sendInvitations | @QueryParam | Whether to send invitations to newly affiliated users | false |
### Examples
>**Header:** Authorization: Basic YWRtaW46MTIzNDU=
@@ -1344,12 +1380,13 @@ Endpoint to add a new group with affiliation to a room.
### Possible parameters
-| Parameter | Parameter Type | Description | Default value |
-|-------------|----------------|--------------------------------------------------------------------------------------------|---------------|
-| roomname | @Path | Exact room name | |
-| name | @Path | The group name | |
-| affiliation | @Path | Available affiliations:
**owners**
**admins**
**members**
**outcasts** | |
-| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| Parameter | Parameter Type | Description | Default value |
+|-----------------|----------------|--------------------------------------------------------------------------------------------|---------------|
+| roomname | @Path | Exact room name | |
+| name | @Path | The group name | |
+| affiliation | @Path | Available affiliations:
**owners**
**admins**
**members**
**outcasts** | |
+| servicename | @QueryParam | The name of the Group Chat Service | conference |
+| sendInvitations | @QueryParam | Whether to send invitations to the users in the newly affiliated groups | false |
### Examples
>**Header:** Authorization: Basic YWRtaW46MTIzNDU=
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 683e362c7..008d89e50 100644
--- a/src/java/org/jivesoftware/openfire/plugin/rest/controller/MUCRoomController.java
+++ b/src/java/org/jivesoftware/openfire/plugin/rest/controller/MUCRoomController.java
@@ -41,6 +41,7 @@
import javax.ws.rs.core.Response;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
+import java.util.function.BiFunction;
import java.util.stream.Collectors;
/**
@@ -200,17 +201,15 @@ public void deleteChatRoom(String roomName, String serviceName) throws ServiceEx
/**
* Creates the chat room.
*
- * @param serviceName
- * the service name
- * @param mucRoomEntity
- * the MUC room entity
- * @throws ServiceException
- * the service exception
+ * @param serviceName the service name
+ * @param mucRoomEntity the MUC room entity
+ * @param sendInvitations whether to send invitations to affiliated users
+ * @throws ServiceException the service exception
*/
- public void createChatRoom(String serviceName, MUCRoomEntity mucRoomEntity) throws ServiceException {
+ public void createChatRoom(String serviceName, MUCRoomEntity mucRoomEntity, boolean sendInvitations) throws ServiceException {
log("Create a chat room: " + mucRoomEntity.getRoomName());
try {
- createRoom(mucRoomEntity, serviceName);
+ createRoom(mucRoomEntity, serviceName, sendInvitations);
} catch (NotAllowedException | ForbiddenException e) {
throw new ServiceException("Could not create the channel", mucRoomEntity.getRoomName(),
ExceptionType.NOT_ALLOWED, Response.Status.FORBIDDEN, e);
@@ -230,12 +229,14 @@ public void createChatRoom(String serviceName, MUCRoomEntity mucRoomEntity) thro
* the service name
* @param mucRoomEntities
* the chat rooms to create
+ * @param sendInvitations
+ * whether to send invitations to affiliated users
* @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 {
+ public RoomCreationResultEntities createMultipleChatRooms(String serviceName, MUCRoomEntities mucRoomEntities, boolean sendInvitations) throws ServiceException {
List roomsToCreate = mucRoomEntities.getMucRooms();
log("Create " + roomsToCreate.size() + " chat rooms");
List results = new ArrayList<>();
@@ -243,7 +244,7 @@ public RoomCreationResultEntities createMultipleChatRooms(String serviceName, MU
RoomCreationResultEntity result = new RoomCreationResultEntity();
result.setRoomName(roomToCreate.getRoomName());
try {
- createRoom(roomToCreate, serviceName);
+ createRoom(roomToCreate, serviceName, sendInvitations);
result.setResultType(RoomCreationResultEntity.RoomCreationResultType.Success);
result.setMessage("Room was successfully created");
} catch (AlreadyExistsException e) {
@@ -267,10 +268,12 @@ public RoomCreationResultEntities createMultipleChatRooms(String serviceName, MU
* the service name
* @param mucRoomEntity
* the MUC room entity
+ * @param sendInvitations
+ * whether to send invitations to affiliated users
* @throws ServiceException
* the service exception
*/
- public void updateChatRoom(String roomName, String serviceName, MUCRoomEntity mucRoomEntity)
+ public void updateChatRoom(String roomName, String serviceName, MUCRoomEntity mucRoomEntity, boolean sendInvitations)
throws ServiceException {
log("Update a chat room: " + mucRoomEntity.getRoomName());
try {
@@ -280,7 +283,7 @@ public void updateChatRoom(String roomName, String serviceName, MUCRoomEntity mu
"Could not update the channel. The room name is different to the entity room name.", roomName,
ExceptionType.ILLEGAL_ARGUMENT_EXCEPTION, Response.Status.BAD_REQUEST);
}
- createRoom(mucRoomEntity, serviceName);
+ createRoom(mucRoomEntity, serviceName, sendInvitations);
} catch (NotAllowedException | ForbiddenException e) {
throw new ServiceException("Could not update the channel", roomName, ExceptionType.NOT_ALLOWED, Response.Status.FORBIDDEN, e);
} catch (ConflictException e) {
@@ -295,9 +298,11 @@ public void updateChatRoom(String roomName, String serviceName, MUCRoomEntity mu
* Creates the room.
*
* @param mucRoomEntity
- * the MUC room entity
+ * the MUC room entity
* @param serviceName
- * the service name
+ * the service name
+ * @param sendInvitations
+ * whether to send invitations to affiliated users
* @throws NotAllowedException
* the not allowed exception
* @throws ForbiddenException
@@ -307,7 +312,7 @@ public void updateChatRoom(String roomName, String serviceName, MUCRoomEntity mu
* @throws AlreadyExistsException
* the already exists exception
*/
- private void createRoom(MUCRoomEntity mucRoomEntity, String serviceName) throws NotAllowedException,
+ private void createRoom(MUCRoomEntity mucRoomEntity, String serviceName, boolean sendInvitations) throws NotAllowedException,
ForbiddenException, ConflictException, AlreadyExistsException, ServiceException
{
log("Create a chat room: " + mucRoomEntity.getRoomName());
@@ -355,9 +360,11 @@ private void createRoom(MUCRoomEntity mucRoomEntity, String serviceName) throws
} else {
room.setRolesToBroadcastPresence(new ArrayList<>());
}
+
// Set all roles
+ Collection allUsersWithNewAffiliations = null;
if (!equalToAffiliations(room, mucRoomEntity)) {
- setRoles(room, mucRoomEntity);
+ allUsersWithNewAffiliations = setRoles(room, mucRoomEntity);
}
// Set creation date
@@ -383,6 +390,10 @@ private void createRoom(MUCRoomEntity mucRoomEntity, String serviceName) throws
}
MUCServiceController.getService(serviceName).syncChatRoom(room);
+
+ if (sendInvitations && allUsersWithNewAffiliations != null) {
+ sendInvitationsFromRoom(room, null, allUsersWithNewAffiliations, null, true);
+ }
}
private boolean equalToAffiliations(MUCRoom room, MUCRoomEntity mucRoomEntity) {
@@ -510,28 +521,208 @@ public MUCRoomMessageEntities getRoomHistory(String roomName, String serviceName
}
/**
- * Invites the user to the MUC room.
+ * Invites the user(s) or group(s) to the MUC room. This method differs from the other 'sendInvitations' methods in
+ * that no checks are performed. This really just sends the invitation stanza(s).
*
* @param serviceName
* the service name
* @param roomName
* the room name
- * @param jid
- * the jid to invite
+ * @param mucInvitationEntity
+ * the invitation entity containing invitation reason and jids to invite
* @throws ServiceException
* the service exception
*/
- public void inviteUser(String serviceName, String roomName, String jid, MUCInvitationEntity mucInvitationEntity)
+ public void inviteUsersAndOrGroups(String serviceName, String roomName, MUCInvitationEntity mucInvitationEntity)
throws ServiceException {
MUCRoom room = getRoom(serviceName, roomName);
- try {
- room.sendInvitation(UserUtils.checkAndGetJID(jid), mucInvitationEntity.getReason(), room.getRole(), null);
- } catch (ForbiddenException | CannotBeInvitedException e) {
- throw new ServiceException("Could not invite user", jid, ExceptionType.NOT_ALLOWED, Response.Status.FORBIDDEN, e);
+ // First determine where to send all the invitations
+ Set targetJIDs = new HashSet<>();
+ for (String jidString : mucInvitationEntity.getJidsToInvite()) {
+ JID jid = UserUtils.checkAndGetJID(jidString);
+ // Is it a group? Then unpack and send to every single group member.
+ Group g = UserUtils.getGroupIfIsGroup(jid);
+ if (g != null) {
+ targetJIDs.addAll(g.getAll());
+ } else {
+ targetJIDs.add(jid);
+ }
+ }
+
+ // And now send
+ for (JID jid : targetJIDs) {
+ try {
+ room.sendInvitation(jid, mucInvitationEntity.getReason(), room.getRole(), null);
+ } catch (ForbiddenException | CannotBeInvitedException e) {
+ throw new ServiceException("Could not invite user", jid.toString(), ExceptionType.NOT_ALLOWED, Response.Status.FORBIDDEN, e);
+ }
}
}
+ /**
+ * Sends invitations "from the room" to a single user that is affiliated to the room.
+ *
+ * @see #sendInvitationsFromRoom(MUCRoom, EnumSet, Collection, String, boolean)
+ *
+ * @param room
+ * The room
+ * @param affiliations
+ * The set of affiliations for which to send invitations, with a default of admin+owner+member when left
+ * unspecified (null)
+ * @param limitToThisUserOrGroup
+ * The user or group for which to send invitations
+ * @param reason
+ * The reason to include in the invitation, with a sensible default when left unspecified (null)
+ * @param performAffiliationCheck
+ * Whether to validate if the user or group is actually affiliated to the room in the correct way
+ * @throws ForbiddenException
+ * The forbidden exception
+ */
+ private void sendInvitationsToSingleJID(
+ MUCRoom room,
+ EnumSet affiliations,
+ JID limitToThisUserOrGroup,
+ String reason,
+ boolean performAffiliationCheck
+ ) throws ForbiddenException {
+ Set setOfOneJID = new HashSet<>();
+ setOfOneJID.add(limitToThisUserOrGroup);
+ sendInvitationsFromRoom(room, affiliations, setOfOneJID, reason, performAffiliationCheck);
+ }
+
+ /**
+ * Sends invitations "from the room" to users that are affiliated to the room. The target audience can be limited to
+ * a specific set of JIDs through the #limitToTheseUsers parameter. If this parameter is left null, invitations are
+ * sent to all users with the specified affiliations.
+ *
+ * Before sending any invitation, this method checks whether the invitation recipient is actually affiliated to the
+ * room in the way that the invitation expresses.
+ *
+ * @param room
+ * The room
+ * @param affiliations
+ * The set of affiliations for which to send invitations, with a default of admin+owner+member when left
+ * unspecified (null)
+ * @param limitToTheseUsers
+ * The collection of users for which to send invitations, with a default of "all" affiliated users when
+ * left unspecified (null)
+ * @param reason
+ * The reason to include in the invitation, with a sensible default when left unspecified (null)
+ * @param performAffiliationCheck
+ * Whether to validate if the user or group is actually affiliated to the room in the correct way
+ * @throws ForbiddenException
+ * The forbidden exception
+ */
+ private void sendInvitationsFromRoom(
+ MUCRoom room,
+ EnumSet affiliations,
+ Collection limitToTheseUsers,
+ String reason,
+ boolean performAffiliationCheck
+ ) throws ForbiddenException {
+
+ if (affiliations == null) {
+ affiliations = EnumSet.of(MUCRole.Affiliation.admin, MUCRole.Affiliation.member, MUCRole.Affiliation.owner);
+ }
+ MUCRole roomRole = MUCRole.createRoomRole(room);
+
+ if (affiliations.contains(MUCRole.Affiliation.admin)) {
+ Collection sendHere = limitToTheseUsers == null ? room.getAdmins() : limitToTheseUsers;
+ for (JID roomAdmin : sendHere) {
+ sendSingleInvitationFromRoom(
+ roomAdmin,
+ room,
+ roomRole,
+ MUCRole.Affiliation.admin,
+ reason == null ? "You are admin of room " + room.getName() : reason,
+ performAffiliationCheck ? (r, j) -> r.getAdmins().contains(j) : null
+ );
+ }
+ }
+ if (affiliations.contains(MUCRole.Affiliation.owner)) {
+ Collection sendHere = limitToTheseUsers == null ? room.getOwners() : limitToTheseUsers;
+ for (JID roomOwner : sendHere) {
+ sendSingleInvitationFromRoom(
+ roomOwner,
+ room,
+ roomRole,
+ MUCRole.Affiliation.owner,
+ reason == null ? "You are owner of room " + room.getName() : reason,
+ performAffiliationCheck ? (r, j) -> r.getOwners().contains(j) : null
+ );
+ }
+ }
+ if (affiliations.contains(MUCRole.Affiliation.member)) {
+ Collection sendHere = limitToTheseUsers == null ? room.getMembers() : limitToTheseUsers;
+ for (JID roomMember : sendHere) {
+ sendSingleInvitationFromRoom(
+ roomMember,
+ room,
+ roomRole,
+ MUCRole.Affiliation.member,
+ reason == null ? "You are member of room " + room.getName() : reason,
+ performAffiliationCheck ? (r, j) -> r.getMembers().contains(j) : null
+ );
+ }
+ }
+ }
+
+ /**
+ * Sends an invitation for a specific affiliation to a single JID, (optionally) performing a check if that JID is
+ * actually affiliated to the room that way.
+ *
+ * @param sendHere
+ * The JID to send the invitation to
+ * @param room
+ * The room
+ * @param roomRole
+ * Role of the room (added for optimisation, to prevent the MUCRole.createRoomRole(room) from being called
+ * many times)
+ * @param affiliation
+ * The affiliation for which the jid is invited
+ * @param invitationReason
+ * The reason to include in the invitation message
+ * @param validation
+ * Function to apply to the room and the jid to check whether the jid is actually affiliated in the correct
+ * way (or null if no validation is required)
+ * @throws ForbiddenException
+ * The forbidden exception
+ */
+ private void sendSingleInvitationFromRoom(
+ JID sendHere,
+ MUCRoom room,
+ MUCRole roomRole,
+ MUCRole.Affiliation affiliation,
+ String invitationReason,
+ BiFunction validation
+ ) throws ForbiddenException {
+ boolean jidIsGroup = false;
+
+ if (validation != null && !validation.apply(room, sendHere)) {
+ log("User or group " + sendHere + " can not be invited to be " + affiliation + " of room " + room.getName() + " because it is not affiliated that way");
+ } else {
+ // First handle group behavior
+ Group g = UserUtils.getGroupIfIsGroup(sendHere);
+ if (g != null) {
+ jidIsGroup = true;
+ // This is a group jid, so we need to send the invitation to every single group member
+ for (JID singleGroupMemberJID : g.getAll()) {
+ // Skip affiliation check, because it has already been done for the group, and the single user may not
+ // actually be known to be affiliated on its own merits
+ sendSingleInvitationFromRoom(singleGroupMemberJID, room, roomRole, affiliation, invitationReason, null);
+ }
+ }
+
+ if (!jidIsGroup) {
+ try {
+ room.sendInvitation(sendHere, invitationReason, roomRole, null);
+ } catch (CannotBeInvitedException e) {
+ log("User " + sendHere + " can not be invited to be " + affiliation + " of room " + room.getName());
+ }
+ }
+ }
+ }
/**
* Convert to MUC room entity.
@@ -606,6 +797,8 @@ public MUCRoomEntity convertToMUCRoomEntity(MUCRoom room, boolean expand) {
* the room
* @param mucRoomEntity
* the muc room entity
+ * @return
+ * all users for which a role was added
* @throws ForbiddenException
* the forbidden exception
* @throws NotAllowedException
@@ -613,8 +806,10 @@ public MUCRoomEntity convertToMUCRoomEntity(MUCRoom room, boolean expand) {
* @throws ConflictException
* the conflict exception
*/
- private void setRoles(MUCRoom room, MUCRoomEntity mucRoomEntity) throws ForbiddenException, NotAllowedException,
+ private Collection setRoles(MUCRoom room, MUCRoomEntity mucRoomEntity) throws ForbiddenException, NotAllowedException,
ConflictException {
+ Collection allNewAffiliations = new ArrayList<>();
+
List roles = new ArrayList<>();
Collection existingOwners = new ArrayList<>();
@@ -630,7 +825,6 @@ private void setRoles(MUCRoom room, MUCRoomEntity mucRoomEntity) throws Forbidde
// Don't delete the same owners
owners.removeAll(existingOwners);
- room.addOwners(MUCRoomUtils.convertStringsToJIDs(mucRoomEntity.getOwners()), room.getRole());
// Collect all roles to reset
roles.addAll(owners);
@@ -642,20 +836,37 @@ private void setRoles(MUCRoom room, MUCRoomEntity mucRoomEntity) throws Forbidde
room.addNone(jid, room.getRole());
}
- room.addOwners(MUCRoomUtils.convertStringsToJIDs(mucRoomEntity.getOwners()), room.getRole());
+ // Owners
+ List ownersToAdd = MUCRoomUtils.convertStringsToJIDs(mucRoomEntity.getOwners());
+ allNewAffiliations.addAll(ownersToAdd);
+ room.addOwners(ownersToAdd, room.getRole());
+
+ // Admins
if (mucRoomEntity.getAdmins() != null) {
- room.addAdmins(MUCRoomUtils.convertStringsToJIDs(mucRoomEntity.getAdmins()), room.getRole());
+ List newAdmins = MUCRoomUtils.convertStringsToJIDs(mucRoomEntity.getAdmins());
+ newAdmins.removeAll(room.getAdmins());
+ allNewAffiliations.addAll(newAdmins);
+ room.addAdmins(newAdmins, room.getRole());
}
+
+ // Members
if (mucRoomEntity.getMembers() != null) {
- for (String memberJid : mucRoomEntity.getMembers()) {
- room.addMember(new JID(memberJid), null, room.getRole());
+ List newMembers = MUCRoomUtils.convertStringsToJIDs(mucRoomEntity.getMembers());
+ newMembers.removeAll(room.getMembers());
+ allNewAffiliations.addAll(newMembers);
+ for (JID memberJid : newMembers) {
+ room.addMember(memberJid, null, room.getRole());
}
}
+
+ // Outcasts
if (mucRoomEntity.getOutcasts() != null) {
for (String outcastJid : mucRoomEntity.getOutcasts()) {
room.addOutcast(new JID(outcastJid), null, room.getRole());
}
}
+
+ return allNewAffiliations;
}
/**
@@ -667,18 +878,29 @@ private void setRoles(MUCRoom room, MUCRoomEntity mucRoomEntity) throws Forbidde
* the room name
* @param jid
* the jid
+ * @param sendInvitation
+ * whether to send an invitation to the newly affiliated user
* @throws ServiceException
* the service exception
*/
- public void addAdmin(String serviceName, String roomName, String jid) throws ServiceException {
+ public void addAdmin(String serviceName, String roomName, String jid, boolean sendInvitation) throws ServiceException {
MUCRoom room = getRoom(serviceName, roomName);
+ JID userOrGroupJID = UserUtils.checkAndGetJID(jid);
try {
- room.addAdmin(UserUtils.checkAndGetJID(jid), room.getRole());
+ room.addAdmin(userOrGroupJID, room.getRole());
} catch (ForbiddenException e) {
throw new ServiceException("Could not add admin", jid, ExceptionType.NOT_ALLOWED, Response.Status.FORBIDDEN, e);
} catch (ConflictException e) {
throw new ServiceException("Could not add admin", jid, ExceptionType.NOT_ALLOWED, Response.Status.CONFLICT, e);
}
+
+ if (sendInvitation) {
+ try {
+ sendInvitationsToSingleJID(room, EnumSet.of(MUCRole.Affiliation.admin), userOrGroupJID, null, true);
+ } catch (ForbiddenException e) {
+ throw new ServiceException("Could not invite admin", jid, ExceptionType.NOT_ALLOWED, Response.Status.FORBIDDEN, e);
+ }
+ }
}
/**
@@ -690,16 +912,27 @@ public void addAdmin(String serviceName, String roomName, String jid) throws Ser
* the room name
* @param jid
* the jid
+ * @param sendInvitation
+ * whether to send an invitation to the newly affiliated user
* @throws ServiceException
* the service exception
*/
- public void addOwner(String serviceName, String roomName, String jid) throws ServiceException {
+ public void addOwner(String serviceName, String roomName, String jid, boolean sendInvitation) throws ServiceException {
MUCRoom room = getRoom(serviceName, roomName);
+ JID userOrGroupJID = UserUtils.checkAndGetJID(jid);
try {
- room.addOwner(UserUtils.checkAndGetJID(jid), room.getRole());
+ room.addOwner(userOrGroupJID, room.getRole());
} catch (ForbiddenException e) {
throw new ServiceException("Could not add owner", jid, ExceptionType.NOT_ALLOWED, Response.Status.FORBIDDEN, e);
}
+
+ if (sendInvitation) {
+ try {
+ sendInvitationsToSingleJID(room, EnumSet.of(MUCRole.Affiliation.owner), userOrGroupJID, null, true);
+ } catch (ForbiddenException e) {
+ throw new ServiceException("Could not invite owner", jid, ExceptionType.NOT_ALLOWED, Response.Status.FORBIDDEN, e);
+ }
+ }
}
/**
@@ -711,16 +944,27 @@ public void addOwner(String serviceName, String roomName, String jid) throws Ser
* the room name
* @param jid
* the jid
+ * @param sendInvitation
+ * whether to send an invitation to the newly affiliated user
* @throws ServiceException
* the service exception
*/
- public void addMember(String serviceName, String roomName, String jid) throws ServiceException {
+ public void addMember(String serviceName, String roomName, String jid, boolean sendInvitation) throws ServiceException {
MUCRoom room = getRoom(serviceName, roomName);
+ JID userOrGroupJID = UserUtils.checkAndGetJID(jid);
try {
- room.addMember(UserUtils.checkAndGetJID(jid), null, room.getRole());
+ room.addMember(userOrGroupJID, null, room.getRole());
} catch (ForbiddenException | ConflictException e) {
throw new ServiceException("Could not add member", jid, ExceptionType.NOT_ALLOWED, Response.Status.FORBIDDEN, e);
}
+
+ if (sendInvitation) {
+ try {
+ sendInvitationsToSingleJID(room, EnumSet.of(MUCRole.Affiliation.member), userOrGroupJID, null, true);
+ } catch (ForbiddenException e) {
+ throw new ServiceException("Could not invite member", jid, ExceptionType.NOT_ALLOWED, Response.Status.FORBIDDEN, e);
+ }
+ }
}
/**
@@ -792,9 +1036,11 @@ public Collection getByAffiliation(@Nonnull final String serviceName, @Nonn
* the affiliation for which to replace all users
* @param jids
* the new list of affiliated users
+ * @param sendInvitations
+ * whether to send invitations to newly affiliated users
* @throws ServiceException On any issue looking up the room or changing its affiliated users.
*/
- public void replaceAffiliatedUsers(@Nonnull final String serviceName, @Nonnull final String roomName, @Nonnull final MUCRole.Affiliation affiliation, @Nonnull final Collection jids) throws ServiceException
+ public void replaceAffiliatedUsers(@Nonnull final String serviceName, @Nonnull final String roomName, @Nonnull final MUCRole.Affiliation affiliation, @Nonnull final Collection jids, boolean sendInvitations) throws ServiceException
{
final Collection replacements = new HashSet<>();
@@ -853,6 +1099,14 @@ public void replaceAffiliatedUsers(@Nonnull final String serviceName, @Nonnull f
} catch (ConflictException e) {
throw new ServiceException("Could not apply modification to list of " + affiliation, roomName, ExceptionType.NOT_ALLOWED, Response.Status.CONFLICT, e);
}
+
+ try {
+ if (sendInvitations) {
+ sendInvitationsFromRoom(room, EnumSet.of(affiliation), toAdd, null, true);
+ }
+ } catch (ForbiddenException e) {
+ throw new ServiceException("Can not send invitation to newly affiliated " + affiliation + " users or groups", roomName, ExceptionType.NOT_ALLOWED, Response.Status.FORBIDDEN, e);
+ }
}
/**
@@ -867,9 +1121,11 @@ public void replaceAffiliatedUsers(@Nonnull final String serviceName, @Nonnull f
* the affiliation for which to add users
* @param jids
* the list of additional affiliated users
+ * @param sendInvitations
+ * whether to send invitations to newly affiliated users
* @throws ServiceException On any issue looking up the room or changing its affiliated users.
*/
- public void addAffiliatedUsers(@Nonnull final String serviceName, @Nonnull final String roomName, @Nonnull final MUCRole.Affiliation affiliation, @Nonnull final Collection jids) throws ServiceException
+ public void addAffiliatedUsers(@Nonnull final String serviceName, @Nonnull final String roomName, @Nonnull final MUCRole.Affiliation affiliation, @Nonnull final Collection jids, boolean sendInvitations) throws ServiceException
{
final Collection additions = new HashSet<>();
@@ -919,6 +1175,14 @@ public void addAffiliatedUsers(@Nonnull final String serviceName, @Nonnull final
} catch (ConflictException e) {
throw new ServiceException("Could not apply modification to list of " + affiliation, roomName, ExceptionType.NOT_ALLOWED, Response.Status.CONFLICT, e);
}
+
+ try {
+ if (sendInvitations) {
+ sendInvitationsFromRoom(room, EnumSet.of(affiliation), toAdd, null, true);
+ }
+ } catch (ForbiddenException e) {
+ throw new ServiceException("Can not send invitation to newly affiliated " + affiliation + " users or groups", roomName, ExceptionType.NOT_ALLOWED, Response.Status.FORBIDDEN, e);
+ }
}
/**
diff --git a/src/java/org/jivesoftware/openfire/plugin/rest/entity/MUCInvitationEntity.java b/src/java/org/jivesoftware/openfire/plugin/rest/entity/MUCInvitationEntity.java
index 623226131..81cb4f4dd 100644
--- a/src/java/org/jivesoftware/openfire/plugin/rest/entity/MUCInvitationEntity.java
+++ b/src/java/org/jivesoftware/openfire/plugin/rest/entity/MUCInvitationEntity.java
@@ -16,18 +16,27 @@
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 java.util.ArrayList;
+import java.util.List;
@XmlRootElement(name = "mucInvitation")
public class MUCInvitationEntity {
String reason;
+ private List jidsToInvite;
+
public MUCInvitationEntity() {
}
@XmlElement
+ @Schema(description = "The reason that will be included in the invitation message(s)", example = "Come join this cool room please!")
public String getReason() {
return reason;
}
@@ -36,4 +45,18 @@ public void setReason(String reason) {
this.reason = reason;
}
+ @XmlElementWrapper(name = "jidsToInvite")
+ @XmlElement(name = "jid")
+ @JsonProperty(value = "jidsToInvite")
+ @Schema(description = "The JIDs and/or names of the users and groups to invite into the room", example = "jane@example.org")
+ public List getJidsToInvite() {
+ if (jidsToInvite == null) {
+ jidsToInvite = new ArrayList<>();
+ }
+ return jidsToInvite;
+ }
+
+ public void setJidsToInvite(List jidsToInvite) {
+ this.jidsToInvite = jidsToInvite;
+ }
}
diff --git a/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomAdminsService.java b/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomAdminsService.java
index 1e5b7517b..40d6ea542 100644
--- a/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomAdminsService.java
+++ b/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomAdminsService.java
@@ -26,7 +26,6 @@
import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.openfire.plugin.rest.controller.MUCRoomController;
import org.jivesoftware.openfire.plugin.rest.entity.AdminEntities;
-import org.jivesoftware.openfire.plugin.rest.entity.OwnerEntities;
import org.jivesoftware.openfire.plugin.rest.exceptions.ErrorResponse;
import org.jivesoftware.openfire.plugin.rest.exceptions.ServiceException;
import org.xmpp.packet.JID;
@@ -79,10 +78,11 @@ public Response getAdmins(
public Response replaceMUCRoomAdmins(
@Parameter(description = "The name of the MUC service that the MUC room is part of.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
@Parameter(description = "The name of the MUC room of which admins are to be replaced.", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ @Parameter(description = "Whether to send invitations to newly affiliated admin users.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations,
@RequestBody(description = "The new list of room admins.", required = true) AdminEntities adminEntities)
throws ServiceException
{
- MUCRoomController.getInstance().replaceAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.admin, adminEntities.getAdmins());
+ MUCRoomController.getInstance().replaceAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.admin, adminEntities.getAdmins(), sendInvitations);
return Response.status(Status.CREATED).build();
}
@@ -102,10 +102,11 @@ public Response replaceMUCRoomAdmins(
public Response addMUCRoomAdmins(
@Parameter(description = "The name of the MUC service that the MUC room is part of.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
@Parameter(description = "The name of the MUC room to which admins are to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ @Parameter(description = "Whether to send invitations to newly affiliated admin users.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations,
@RequestBody(description = "The list of room admins to add to the room.", required = true) AdminEntities adminEntities)
throws ServiceException
{
- MUCRoomController.getInstance().addAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.admin, adminEntities.getAdmins());
+ MUCRoomController.getInstance().addAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.admin, adminEntities.getAdmins(), sendInvitations);
return Response.status(Status.CREATED).build();
}
@@ -123,10 +124,11 @@ public Response addMUCRoomAdmins(
public Response addMUCRoomAdmin(
@Parameter(description = "The name of the MUC service that the MUC room is part of.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
@Parameter(description = "The (bare) JID of the entity that is to be added as an admin.", example = "john@example.org", required = true) @PathParam("jid") String jid,
- @Parameter(description = "The name of the MUC room to which an administrator is to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName)
+ @Parameter(description = "The name of the MUC room to which an administrator is to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ @Parameter(description = "Whether to send an invitation to the new admin user.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations)
throws ServiceException
{
- MUCRoomController.getInstance().addAdmin(serviceName, roomName, jid);
+ MUCRoomController.getInstance().addAdmin(serviceName, roomName, jid, sendInvitations);
return Response.status(Status.CREATED).build();
}
@@ -144,10 +146,11 @@ public Response addMUCRoomAdmin(
public Response addMUCRoomAdminGroup(
@Parameter(description = "The name of the MUC service that the MUC room is part of.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
@Parameter(description = "The name of the user group from which all members will be administrators of the room.", example = "Operators", required = true) @PathParam("groupname") String groupname,
- @Parameter(description = "The name of the MUC room to which administrators are to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName)
+ @Parameter(description = "The name of the MUC room to which administrators are to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ @Parameter(description = "Whether to send invitations to new admin users.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations)
throws ServiceException
{
- MUCRoomController.getInstance().addAdmin(serviceName, roomName, groupname);
+ MUCRoomController.getInstance().addAdmin(serviceName, roomName, groupname, sendInvitations);
return Response.status(Status.CREATED).build();
}
diff --git a/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomMembersService.java b/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomMembersService.java
index 2f1809ea6..60289dd0a 100644
--- a/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomMembersService.java
+++ b/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomMembersService.java
@@ -79,10 +79,11 @@ public Response getMembers(
public Response replaceMUCRoomMembers(
@Parameter(description = "The name of the MUC service that the MUC room is part of.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
@Parameter(description = "The name of the MUC room of which members are to be replaced.", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ @Parameter(description = "Whether to send invitations to newly affiliated users.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations,
@RequestBody(description = "The new list of room members.", required = true) MemberEntities memberEntities)
throws ServiceException
{
- MUCRoomController.getInstance().replaceAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.member, memberEntities.getMembers());
+ MUCRoomController.getInstance().replaceAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.member, memberEntities.getMembers(), sendInvitations);
return Response.status(Status.CREATED).build();
}
@@ -102,10 +103,11 @@ public Response replaceMUCRoomMembers(
public Response addMUCRoomMembers(
@Parameter(description = "The name of the MUC service that the MUC room is part of.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
@Parameter(description = "The name of the MUC room to which members are to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ @Parameter(description = "Whether to send invitations to newly affiliated users.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations,
@RequestBody(description = "The list of room members to add to the room.", required = true) MemberEntities memberEntities)
throws ServiceException
{
- MUCRoomController.getInstance().addAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.member, memberEntities.getMembers());
+ MUCRoomController.getInstance().addAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.member, memberEntities.getMembers(), sendInvitations);
return Response.status(Status.CREATED).build();
}
@@ -123,10 +125,11 @@ public Response addMUCRoomMembers(
public Response addMUCRoomMember(
@Parameter(description = "The name of the MUC service that the MUC room is part of.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
@Parameter(description = "The (bare) JID of the entity that is to be a registered member.", example = "john@example.org", required = true) @PathParam("jid") String jid,
- @Parameter(description = "The name of the MUC room to which a member is to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName)
+ @Parameter(description = "The name of the MUC room to which a member is to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ @Parameter(description = "Whether to send invitation to the newly affiliated user.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations)
throws ServiceException
{
- MUCRoomController.getInstance().addMember(serviceName, roomName, jid);
+ MUCRoomController.getInstance().addMember(serviceName, roomName, jid, sendInvitations);
return Response.status(Status.CREATED).build();
}
@@ -144,10 +147,11 @@ public Response addMUCRoomMember(
public Response addMUCRoomMemberGroup(
@Parameter(description = "The name of the MUC service that the MUC room is part of.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
@Parameter(description = "The name of the user group from which all members will be registered members of the room.", example = "Operators", required = true) @PathParam("groupname") String groupname,
- @Parameter(description = "The name of the MUC room to which members are to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName)
+ @Parameter(description = "The name of the MUC room to which members are to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ @Parameter(description = "Whether to send invitations to newly affiliated users.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations)
throws ServiceException
{
- MUCRoomController.getInstance().addMember(serviceName, roomName, groupname);
+ MUCRoomController.getInstance().addMember(serviceName, roomName, groupname, sendInvitations);
return Response.status(Status.CREATED).build();
}
diff --git a/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomOutcastsService.java b/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomOutcastsService.java
index 8434873df..ca7c166ae 100644
--- a/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomOutcastsService.java
+++ b/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomOutcastsService.java
@@ -82,7 +82,7 @@ public Response replaceMUCRoomOutcasts(
@RequestBody(description = "The new list of room outcasts.", required = true) OutcastEntities outcastEntities)
throws ServiceException
{
- MUCRoomController.getInstance().replaceAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.outcast, outcastEntities.getOutcasts());
+ MUCRoomController.getInstance().replaceAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.outcast, outcastEntities.getOutcasts(), false);
return Response.status(Status.CREATED).build();
}
@@ -105,7 +105,7 @@ public Response addMUCRoomOutcasts(
@RequestBody(description = "The list of room outcasts to add to the room.", required = true) OutcastEntities outcastEntities)
throws ServiceException
{
- MUCRoomController.getInstance().addAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.outcast, outcastEntities.getOutcasts());
+ MUCRoomController.getInstance().addAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.outcast, outcastEntities.getOutcasts(), false);
return Response.status(Status.CREATED).build();
}
diff --git a/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomOwnersService.java b/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomOwnersService.java
index 09dc40ef4..baf81dde6 100644
--- a/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomOwnersService.java
+++ b/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomOwnersService.java
@@ -78,10 +78,11 @@ public Response getOwners(
public Response replaceMUCRoomOwners(
@Parameter(description = "The name of the MUC service that the MUC room is part of.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
@Parameter(description = "The name of the MUC room of which owners are to be replaced.", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ @Parameter(description = "Whether to send invitations to newly affiliated users.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations,
@RequestBody(description = "The new list of room owners.", required = true) OwnerEntities ownerEntities)
throws ServiceException
{
- MUCRoomController.getInstance().replaceAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.owner, ownerEntities.getOwners());
+ MUCRoomController.getInstance().replaceAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.owner, ownerEntities.getOwners(), sendInvitations);
return Response.status(Status.CREATED).build();
}
@@ -101,10 +102,11 @@ public Response replaceMUCRoomOwners(
public Response addMUCRoomOwners(
@Parameter(description = "The name of the MUC service that the MUC room is part of.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
@Parameter(description = "The name of the MUC room to which owners are to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ @Parameter(description = "Whether to send invitations to new owners.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations,
@RequestBody(description = "The list of room owners to add to the room.", required = true) OwnerEntities ownerEntities)
throws ServiceException
{
- MUCRoomController.getInstance().addAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.owner, ownerEntities.getOwners());
+ MUCRoomController.getInstance().addAffiliatedUsers(serviceName, roomName, MUCRole.Affiliation.owner, ownerEntities.getOwners(), sendInvitations);
return Response.status(Status.CREATED).build();
}
@@ -122,10 +124,11 @@ public Response addMUCRoomOwners(
public Response addMUCRoomOwner(
@Parameter(description = "The name of the MUC service that the MUC room is part of.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
@Parameter(description = "The (bare) JID of the entity that is to be added as an owner.", example = "john@example.org", required = true) @PathParam("jid") String jid,
- @Parameter(description = "The name of the MUC room to which an owner is to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName)
+ @Parameter(description = "The name of the MUC room to which an owner is to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ @Parameter(description = "Whether to send invitation to new owner.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations)
throws ServiceException
{
- MUCRoomController.getInstance().addOwner(serviceName, roomName, jid);
+ MUCRoomController.getInstance().addOwner(serviceName, roomName, jid, sendInvitations);
return Response.status(Status.CREATED).build();
}
@@ -143,10 +146,11 @@ public Response addMUCRoomOwner(
public Response addMUCRoomOwnerGroup(
@Parameter(description = "The name of the MUC service that the MUC room is part of.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
@Parameter(description = "The name of the user group from which all members will be owners of the room.", example = "Operators", required = true) @PathParam("groupname") String groupname,
- @Parameter(description = "The name of the MUC room to which owners are to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName)
+ @Parameter(description = "The name of the MUC room to which owners are to be added.", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ @Parameter(description = "Whether to send invitations to new owners.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations)
throws ServiceException
{
- MUCRoomController.getInstance().addOwner(serviceName, roomName, groupname);
+ MUCRoomController.getInstance().addOwner(serviceName, roomName, groupname, sendInvitations);
return Response.status(Status.CREATED).build();
}
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 1f63d42f7..44bd24b3f 100644
--- a/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomService.java
+++ b/src/java/org/jivesoftware/openfire/plugin/rest/service/MUCRoomService.java
@@ -111,10 +111,11 @@ public Response deleteMUCRoom(
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response createMUCRoom(
@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,
+ @Parameter(description = "Whether to send invitations to affiliated users.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations,
@RequestBody(description = "The MUC room that needs to be created.", required = true) MUCRoomEntity mucRoomEntity)
throws ServiceException
{
- MUCRoomController.getInstance().createChatRoom(serviceName, mucRoomEntity);
+ MUCRoomController.getInstance().createChatRoom(serviceName, mucRoomEntity, sendInvitations);
return Response.status(Status.CREATED).build();
}
@@ -132,10 +133,11 @@ public Response createMUCRoom(
@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,
+ @Parameter(description = "Whether to send invitations to newly affiliated users.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations,
@RequestBody(description = "The MUC rooms that need to be created.", required = true) MUCRoomEntities mucRoomEntities)
throws ServiceException
{
- return MUCRoomController.getInstance().createMultipleChatRooms(serviceName, mucRoomEntities);
+ return MUCRoomController.getInstance().createMultipleChatRooms(serviceName, mucRoomEntities, sendInvitations);
}
@PUT
@@ -154,10 +156,11 @@ public RoomCreationResultEntities createMUCRooms(
public Response updateMUCRoom(
@Parameter(description = "The name of the chat room that needs to be updated", example = "lobby", required = true) @PathParam("roomName") String roomName,
@Parameter(description = "The name of the MUC service in which to update a chat room.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
+ @Parameter(description = "Whether to send invitations to newly affiliated users.", example = "true", required = false) @DefaultValue("false") @QueryParam("sendInvitations") boolean sendInvitations,
@RequestBody(description = "The new MUC room definition that needs to overwrite the old definition.", required = true) MUCRoomEntity mucRoomEntity)
throws ServiceException
{
- MUCRoomController.getInstance().updateChatRoom(roomName, serviceName, mucRoomEntity);
+ MUCRoomController.getInstance().updateChatRoom(roomName, serviceName, mucRoomEntity, sendInvitations);
return Response.status(Status.OK).build();
}
@@ -220,8 +223,8 @@ public MUCRoomMessageEntities getMUCRoomHistory(
@POST
@Path("/{roomName}/invite/{jid}")
- @Operation( summary = "Invite user",
- description = "Invites a user to join a specific multi-user chat room.",
+ @Operation( summary = "Invite user or group",
+ description = "Invites a user or group to join a specific multi-user chat room.",
responses = {
@ApiResponse(responseCode = "200", description = "Invitation sent"),
@ApiResponse(responseCode = "401", description = "Web service authentication failed.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@@ -230,14 +233,39 @@ public MUCRoomMessageEntities getMUCRoomHistory(
@ApiResponse(responseCode = "500", description = "Unexpected, generic error condition.", content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
- public Response inviteUserToMUCRoom(
- @Parameter(description = "The name of the chat room in which to invite a user", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ public Response inviteUserOrGroupToMUCRoom(
+ @Parameter(description = "The name of the chat room in which to invite a user or group", example = "lobby", required = true) @PathParam("roomName") String roomName,
@Parameter(description = "The JID of the entity to invite into the room", example = "john@example.org", required = true) @PathParam("jid") String jid,
@Parameter(description = "The name of the chat room's MUC service.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
- @RequestBody(description = "The invitation message to send.", required = true) MUCInvitationEntity mucInvitationEntity)
+ @RequestBody(description = "The invitation message to send and whom to send it to.", required = true) MUCInvitationEntity mucInvitationEntity)
throws ServiceException
{
- MUCRoomController.getInstance().inviteUser(serviceName, roomName, jid, mucInvitationEntity);
+ if (!mucInvitationEntity.getJidsToInvite().contains(jid)) {
+ mucInvitationEntity.getJidsToInvite().add(jid);
+ }
+ MUCRoomController.getInstance().inviteUsersAndOrGroups(serviceName, roomName, mucInvitationEntity);
+ return Response.status(Status.OK).build();
+ }
+
+ @POST
+ @Path("/{roomName}/invite")
+ @Operation( summary = "Invite a collection of users and/or groups",
+ description = "Invites a collection of users and/or groups to join a specific multi-user chat room.",
+ responses = {
+ @ApiResponse(responseCode = "200", description = "Invitation sent"),
+ @ApiResponse(responseCode = "401", description = "Web service authentication failed.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
+ @ApiResponse(responseCode = "403", description = "Not allowed to invite a user or group to this room.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
+ @ApiResponse(responseCode = "404", description = "The chat room (or its service) can not be found 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})
+ public Response inviteUsersAndOrGroupsToMUCRoom(
+ @Parameter(description = "The name of the chat room in which to invite a user or group", example = "lobby", required = true) @PathParam("roomName") String roomName,
+ @Parameter(description = "The name of the chat room's MUC service.", example = "conference", required = false) @DefaultValue("conference") @QueryParam("servicename") String serviceName,
+ @RequestBody(description = "The invitation message to send and whom to send it to.", required = true) MUCInvitationEntity mucInvitationEntity)
+ throws ServiceException
+ {
+ MUCRoomController.getInstance().inviteUsersAndOrGroups(serviceName, roomName, mucInvitationEntity);
return Response.status(Status.OK).build();
}
diff --git a/src/java/org/jivesoftware/openfire/plugin/rest/utils/UserUtils.java b/src/java/org/jivesoftware/openfire/plugin/rest/utils/UserUtils.java
index 42d8f44dc..e233f4c58 100644
--- a/src/java/org/jivesoftware/openfire/plugin/rest/utils/UserUtils.java
+++ b/src/java/org/jivesoftware/openfire/plugin/rest/utils/UserUtils.java
@@ -52,7 +52,7 @@ private UserUtils() {
* @return the list
*/
public static List convertUsersToUserEntities(Collection users, String userSearch) {
- List result = new ArrayList();
+ List result = new ArrayList<>();
for (User user : users) {
if (userSearch != null) {
@@ -76,7 +76,7 @@ public static List convertUsersToUserEntities(Collection users
public static UserEntity convertUserToUserEntity(User user) {
UserEntity userEntity = new UserEntity(user.getUsername(), user.getName(), user.getEmail());
- List userProperties = new ArrayList();
+ List userProperties = new ArrayList<>();
for (Entry property : user.getProperties().entrySet()) {
userProperties.add(new UserProperty(property.getKey(), property.getValue()));
}
@@ -89,7 +89,6 @@ public static UserEntity convertUserToUserEntity(User user) {
* Checks if is valid sub type.
*
* @param subType the sub type
- * @return true, if is valid sub type
* @throws UserAlreadyExistsException the user already exists exception
*/
public static void checkSubType(int subType) throws UserAlreadyExistsException {
@@ -126,10 +125,7 @@ public static boolean isValidBareJid(String jid) {
final int index = jid.indexOf('@');
if (index == -1) {
return false;
- } else if (jid.indexOf('@', index + 1) != -1) {
- return false;
- }
- return true;
+ } else return jid.indexOf('@', index + 1) == -1;
}
/**
* Checks if this group exists.
@@ -139,10 +135,27 @@ public static boolean isValidBareJid(String jid) {
*/
public static boolean isValidGroupName(String groupname) {
try {
- Group g = GroupManager.getInstance().getGroup(groupname);
+ GroupManager.getInstance().getGroup(groupname);
} catch(GroupNotFoundException e) {
return false;
}
return true;
}
+
+ /**
+ * Checks if the JID represents a group, and returns the group if it does.
+ * @param maybeAGroupJIDOrAGroupName
+ * A JID that may or may not be a group JID or even just a group name
+ * @return
+ * The group represented by the JID, or null if the JID does not represent a group
+ */
+ public static Group getGroupIfIsGroup(JID maybeAGroupJIDOrAGroupName) {
+ try {
+ return GroupManager.getInstance().getGroup(maybeAGroupJIDOrAGroupName);
+ } catch (GroupNotFoundException e) {
+ // Just return null
+ }
+
+ return null;
+ }
}