Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions changelog.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ <h1>
REST API Plugin Changelog
</h1>

<p><b>1.11.1</b> (tbd)</p>
<p><b>1.12.0</b> (tbd)</p>
<ul>
<li>[<a href='https://github.com/igniterealtime/openfire-restAPI-plugin/issues/203'>#203</a>] - Reduce log level verbosity for some errors.</li>
<li>Now requires Openfire 5.0.0 or later</li>
<li>[<a href='https://github.com/igniterealtime/openfire-restAPI-plugin/issues/7'>#7</a>] - Add endpoints that can get, set and delete user vCards.</li>
<li>[<a href='https://github.com/igniterealtime/openfire-restAPI-plugin/issues/200'>#200</a>] - Fix compatibility issue with Openfire 4.9.0.</li>
<li>[<a href='https://github.com/igniterealtime/openfire-restAPI-plugin/issues/203'>#203</a>] - Reduce log level verbosity for some errors.</li>
<li>[<a href='https://github.com/igniterealtime/openfire-restAPI-plugin/issues/208'>#208</a>] - Fix compatibility issue with Openfire 5.0.0, update jersey to 2.45 and swagger to 2.2.31.</li>
</ul>

Expand Down
2 changes: 1 addition & 1 deletion plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<description>Allows administration over a RESTful API.</description>
<author>Roman Soldatow</author>
<version>${project.version}</version>
<date>2024-11-17</date>
<date>2025-07-04</date>
<minServerVersion>5.0.0</minServerVersion>
<adminconsole>
<tab id="tab-server">
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</parent>
<groupId>org.igniterealtime.openfire.plugins</groupId>
<artifactId>restAPI</artifactId>
<version>1.11.1-SNAPSHOT</version>
<version>1.12.0-SNAPSHOT</version>
<name>REST API Plugin</name>
<description>Allows administration over a RESTful API.</description>
<licenses>
Expand Down
700 changes: 368 additions & 332 deletions readme.html

Large diffs are not rendered by default.

142 changes: 142 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,148 @@ Endpoint to update a roster entry
</rosterItem>
```

## Retrieve user's vcard
Endpoint to get the vCard of a particular user
> **GET** /users/{username}/vcard

**Payload:** none

**Return value:** vCard XML data

### Possible parameters

| Parameter | Parameter Type | Description | Default value |
|-----------|-----------------|----------------|---------------|
| username | @Path | Exact username | |

### Examples
>**Header:** Authorization: Basic YWRtaW46MTIzNDU=
>
>**GET** http://example.org:9090/plugins/restapi/v1/users/testuser/vcard

## Add or update user's vCard
Endpoint to add or replace a vCard of a particular user.
> **PUT** /users/{username}/vcard

**Payload:** vCard XML data

**Return value:** HTTP status 200 (Created)

### Possible parameters


| Parameter | Parameter Type | Description | Default value |
|-----------|-----------------|----------------|---------------|
| username | @Path | Exact username | |

### Examples
>**Header:** Authorization: Basic YWRtaW46MTIzNDU=
>
>**Header:** Content-Type application/xml
>
>**POST** http://example.org:9090/plugins/restapi/v1/users/testuser/vcard

**Payload:**
```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<vCard xmlns="vcard-temp">
<N>
<FAMILY>Doe</FAMILY>
<GIVEN>Janice</GIVEN>
<MIDDLE>Francis</MIDDLE>
</N>
<ORG>
<ORGNAME/>
<ORGUNIT/>
</ORG>
<NICKNAME>Jane</NICKNAME>
<FN>Janice Francis Doe</FN>
<TITLE/>
<URL/>
<EMAIL>
<HOME/>
<INTERNET/>
<PREF/>
<USERID>j.doe@example.org</USERID>
</EMAIL>
<TEL>
<WORK/>
<VOICE/>
<NUMBER/>
</TEL>
<TEL>
<WORK/>
<PAGER/>
<NUMBER/>
</TEL>
<TEL>
<WORK/>
<FAX/>
<NUMBER/>
</TEL>
<TEL>
<WORK/>
<CELL/>
<NUMBER/>
</TEL>
<TEL>
<HOME/>
<VOICE/>
<NUMBER/>
</TEL>
<TEL>
<HOME/>
<PAGER/>
<NUMBER/>
</TEL>
<TEL>
<HOME/>
<FAX/>
<NUMBER/>
</TEL>
<TEL>
<HOME/>
<CELL/>
<NUMBER/>
</TEL>
<ADR>
<WORK/>
<LOCALITY/>
<CTRY/>
<STREET/>
<PCODE/>
<REGION/>
</ADR>
<ADR>
<HOME/>
<LOCALITY/>
<CTRY/>
<STREET/>
<PCODE/>
<REGION/>
</ADR>
</vCard>
```

## Delete user's vcard
Endpoint to remove the vCard of a particular user
> **DELETE** /users/{username}/vcard

**Payload:** none

**Return value:** none

### Possible parameters

| Parameter | Parameter Type | Description | Default value |
|-----------|-----------------|----------------|---------------|
| username | @Path | Exact username | |

### Examples
>**Header:** Authorization: Basic YWRtaW46MTIzNDU=
>
>**DELETE** http://example.org:9090/plugins/restapi/v1/users/testuser/vcard

# Chat room related REST Endpoints

## Retrieve all chat services
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

package org.jivesoftware.openfire.plugin.rest.controller;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.SharedGroupException;
import org.jivesoftware.openfire.XMPPServer;
Expand All @@ -37,6 +41,7 @@
import org.jivesoftware.openfire.user.UserAlreadyExistsException;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.openfire.vcard.VCardManager;
import org.jivesoftware.util.JiveGlobals;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -69,6 +74,8 @@ public class UserServiceController {
/** The lock out manager. */
private final LockOutManager lockOutManager;

private final VCardManager vcardManager;

/**
* Gets the single instance of UserServiceController.
*
Expand Down Expand Up @@ -98,6 +105,7 @@ private UserServiceController() {
userManager = server.getUserManager();
rosterManager = server.getRosterManager();
lockOutManager = server.getLockOutManager();
vcardManager = server.getVCardManager();
}

public static void log(String logMessage) {
Expand Down Expand Up @@ -611,4 +619,82 @@ private Roster getUserRoster(String username) throws ServiceException {
Response.Status.NOT_FOUND, e);
}
}

/**
* Retrieves a vCard for a user.
*
* @param username The username for which to return a vcard
* @return A vCard (or null)
*/
public Element getUserVCard(String username) throws ServiceException
{
log("Get user vCard for user: " + username);
if (username.contains("@")) {
final JID jid = new JID(username);
if (jid.getDomain().equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
username = jid.getNode();
} else {
// Implementing this would require us to iterate over all groups, which is a performance nightmare.
throw new ServiceException("This service cannot be used for non-local users.", username, ExceptionType.USER_NOT_FOUND_EXCEPTION, Response.Status.INTERNAL_SERVER_ERROR);
}
}

return vcardManager.getVCard(username);
}

/**
* Adds or updates a vCard for a user.
*
* @param username The username for which to return a vcard
* @param data The raw XML vCard data
*/
public void setUserVCard(String username, String data) throws ServiceException
{
log("Set user vCard for user: " + username);
if (username.contains("@")) {
final JID jid = new JID(username);
if (jid.getDomain().equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
username = jid.getNode();
} else {
// Implementing this would require us to iterate over all groups, which is a performance nightmare.
throw new ServiceException("This service cannot be used for non-local users.", username, ExceptionType.USER_NOT_FOUND_EXCEPTION, Response.Status.INTERNAL_SERVER_ERROR);
}
}

try {
final Document document = DocumentHelper.parseText(data);
vcardManager.setVCard(username, document.getRootElement());
} catch (DocumentException e) {
throw new ServiceException("Could not parse the provided data as a vCard", username, ExceptionType.ILLEGAL_ARGUMENT_EXCEPTION, Response.Status.BAD_REQUEST);
} catch (UnsupportedOperationException e) {
throw new ServiceException("Cannot update vCards in the system, as the vCard system is configured to be read-only.", username, ExceptionType.ILLEGAL_ARGUMENT_EXCEPTION, Response.Status.CONFLICT);
} catch (Exception e) {
throw new ServiceException("Unexpected problem while trying to update vCard.", username, ExceptionType.ILLEGAL_ARGUMENT_EXCEPTION, Response.Status.INTERNAL_SERVER_ERROR);
}
}

/**
* Removes a vCard for a user.
*
* @param username The username for which to return a vcard
*/
public void deleteUserVCard(String username) throws ServiceException
{
log("Get user vCard for user: " + username);
if (username.contains("@")) {
final JID jid = new JID(username);
if (jid.getDomain().equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
username = jid.getNode();
} else {
// Implementing this would require us to iterate over all groups, which is a performance nightmare.
throw new ServiceException("This service cannot be used for non-local users.", username, ExceptionType.USER_NOT_FOUND_EXCEPTION, Response.Status.INTERNAL_SERVER_ERROR);
}
}

try {
vcardManager.deleteVCard(username);
} catch (UnsupportedOperationException e) {
throw new ServiceException("Cannot update vCards in the system, as the vCard system is configured to be read-only.", username, ExceptionType.ILLEGAL_ARGUMENT_EXCEPTION, Response.Status.CONFLICT);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ public JerseyWrapper(@Context ServletConfig servletConfig) {
UserLockoutService.class,
UserRosterService.class,
UserService.class,
UserServiceLegacy.class
UserServiceLegacy.class,
UserVCardService.class
);

// Exception mapper
Expand Down
Loading