User Directory support in REST Backend
This commit is contained in:
@@ -91,9 +91,13 @@ Content-type: JSON UTF-8
|
||||
#### Request Body
|
||||
```
|
||||
{
|
||||
"by": "<search type>",
|
||||
"search_term": "doe"
|
||||
}
|
||||
```
|
||||
`by` can be:
|
||||
- `name`
|
||||
- `threepid`
|
||||
|
||||
#### Response Body:
|
||||
If users found:
|
||||
@@ -102,8 +106,8 @@ If users found:
|
||||
"limited": false,
|
||||
"results": [
|
||||
{
|
||||
"display_name": "John Doe",
|
||||
"avatar_url": "http://domain.tld/path/to/avatar.png",
|
||||
"display_name": "John Doe",
|
||||
"user_id": "UserIdLocalpart"
|
||||
},
|
||||
{
|
||||
|
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* mxisd - Matrix Identity Server Daemon
|
||||
* Copyright (C) 2017 Maxime Dor
|
||||
*
|
||||
* https://max.kamax.io/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.kamax.mxisd.backend.rest;
|
||||
|
||||
import io.kamax.matrix.MatrixID;
|
||||
import io.kamax.mxisd.config.MatrixConfig;
|
||||
import io.kamax.mxisd.config.rest.RestBackendConfig;
|
||||
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest;
|
||||
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
|
||||
import io.kamax.mxisd.directory.IDirectoryProvider;
|
||||
import io.kamax.mxisd.exception.InternalServerError;
|
||||
import io.kamax.mxisd.util.RestClientUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class RestDirectoryProvider extends RestProvider implements IDirectoryProvider {
|
||||
|
||||
private MatrixConfig mxCfg;
|
||||
|
||||
public RestDirectoryProvider(RestBackendConfig cfg, MatrixConfig mxCfg) {
|
||||
super(cfg);
|
||||
this.mxCfg = mxCfg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return cfg.isEnabled() && StringUtils.isNotBlank(cfg.getEndpoints().getDirectory());
|
||||
}
|
||||
|
||||
private UserDirectorySearchResult search(String by, String query) {
|
||||
UserDirectorySearchRequest request = new UserDirectorySearchRequest(query);
|
||||
request.setBy(by);
|
||||
try (CloseableHttpResponse httpResponse = client.execute(RestClientUtils.post(cfg.getEndpoints().getDirectory(), request))) {
|
||||
int status = httpResponse.getStatusLine().getStatusCode();
|
||||
if (status < 200 || status >= 300) {
|
||||
throw new InternalServerError("REST backend: Error: " + IOUtils.toString(httpResponse.getEntity().getContent(), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
UserDirectorySearchResult response = parser.parse(httpResponse, UserDirectorySearchResult.class);
|
||||
for (UserDirectorySearchResult.Result result : response.getResults()) {
|
||||
result.setUserId(new MatrixID(result.getUserId(), mxCfg.getDomain()).getId());
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (IOException e) {
|
||||
throw new InternalServerError("REST backend: I/O error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDirectorySearchResult searchByDisplayName(String query) {
|
||||
return search("name", query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDirectorySearchResult searchBy3pid(String query) {
|
||||
return search("threepid", query);
|
||||
}
|
||||
|
||||
}
|
@@ -22,12 +22,21 @@ package io.kamax.mxisd.controller.directory.v1.io;
|
||||
|
||||
public class UserDirectorySearchRequest {
|
||||
|
||||
private String by;
|
||||
private String searchTerm;
|
||||
|
||||
public UserDirectorySearchRequest(String searchTerm) {
|
||||
setSearchTerm(searchTerm);
|
||||
}
|
||||
|
||||
public String getBy() {
|
||||
return by;
|
||||
}
|
||||
|
||||
public void setBy(String by) {
|
||||
this.by = by;
|
||||
}
|
||||
|
||||
public String getSearchTerm() {
|
||||
return searchTerm;
|
||||
}
|
||||
|
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* mxisd - Matrix Identity Server Daemon
|
||||
* Copyright (C) 2017 Maxime Dor
|
||||
*
|
||||
* https://max.kamax.io/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.kamax.mxisd.backend.rest;
|
||||
|
||||
import com.github.tomakehurst.wiremock.junit.WireMockRule;
|
||||
import io.kamax.matrix.MatrixID;
|
||||
import io.kamax.mxisd.config.MatrixConfig;
|
||||
import io.kamax.mxisd.config.rest.RestBackendConfig;
|
||||
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class RestDirectoryProviderTest {
|
||||
|
||||
@Rule
|
||||
public WireMockRule wireMockRule = new WireMockRule(65000);
|
||||
|
||||
private RestDirectoryProvider p;
|
||||
|
||||
private String domain = "example.org";
|
||||
private String endpoint = "/directory/search";
|
||||
private String byNameSearch = "doe";
|
||||
private String byNameAvatar = "http://domain.tld/path/to/avatar.png";
|
||||
private String byNameDisplay = "John Doe";
|
||||
private String byNameId = "john.doe";
|
||||
private String byNameRequest = "{\"by\":\"name\",\"search_term\":\"" + byNameSearch + "\"}";
|
||||
private String byNameResponse = "{\"limited\":false,\"results\":[{\"avatar_url\":\"" + byNameAvatar +
|
||||
"\",\"display_name\":\"" + byNameDisplay + "\",\"user_id\":\"" + byNameId + "\"}]}";
|
||||
private String byNameEmptyResponse = "{\"limited\":false,\"results\":[]}";
|
||||
|
||||
private String byThreepidSearch = "jane";
|
||||
private String byThreepidAvatar = "http://domain.tld/path/to/avatar.png";
|
||||
private String byThreepidDisplay = "John Doe";
|
||||
private String byThreepidId = "john.doe";
|
||||
private String byThreepidRequest = "{\"by\":\"threepid\",\"search_term\":\"" + byThreepidSearch + "\"}";
|
||||
private String byThreepidResponse = "{\"limited\":false,\"results\":[{\"avatar_url\":\"" + byThreepidAvatar +
|
||||
"\",\"display_name\":\"" + byThreepidDisplay + "\",\"user_id\":\"" + byThreepidId + "\"}]}";
|
||||
private String byThreepidEmptyResponse = "{\"limited\":false,\"results\":[]}";
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
MatrixConfig mxCfg = new MatrixConfig();
|
||||
mxCfg.setDomain(domain);
|
||||
mxCfg.build();
|
||||
|
||||
RestBackendConfig cfg = new RestBackendConfig();
|
||||
cfg.setEnabled(true);
|
||||
cfg.setHost("http://localhost:65000");
|
||||
cfg.getEndpoints().setDirectory(endpoint);
|
||||
cfg.build();
|
||||
|
||||
p = new RestDirectoryProvider(cfg, mxCfg);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byNameFound() {
|
||||
stubFor(post(urlEqualTo(endpoint))
|
||||
.willReturn(aResponse()
|
||||
.withHeader("Content-Type", "application/json")
|
||||
.withBody(byNameResponse)
|
||||
)
|
||||
);
|
||||
|
||||
UserDirectorySearchResult result = p.searchByDisplayName(byNameSearch);
|
||||
assertTrue(!result.isLimited());
|
||||
assertTrue(result.getResults().size() == 1);
|
||||
UserDirectorySearchResult.Result entry = result.getResults().get(0);
|
||||
assertNotNull(entry);
|
||||
assertTrue(StringUtils.equals(byNameAvatar, entry.getAvatarUrl()));
|
||||
assertTrue(StringUtils.equals(byNameDisplay, entry.getDisplayName()));
|
||||
assertTrue(StringUtils.equals(new MatrixID(byNameId, domain).getId(), entry.getUserId()));
|
||||
|
||||
verify(postRequestedFor(urlMatching(endpoint))
|
||||
.withHeader("Content-Type", containing("application/json"))
|
||||
.withRequestBody(equalTo(byNameRequest))
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byNameNotFound() {
|
||||
stubFor(post(urlEqualTo(endpoint))
|
||||
.willReturn(aResponse()
|
||||
.withHeader("Content-Type", "application/json")
|
||||
.withBody(byNameEmptyResponse)
|
||||
)
|
||||
);
|
||||
|
||||
UserDirectorySearchResult result = p.searchByDisplayName(byNameSearch);
|
||||
assertTrue(!result.isLimited());
|
||||
assertTrue(result.getResults().isEmpty());
|
||||
|
||||
verify(postRequestedFor(urlMatching(endpoint))
|
||||
.withHeader("Content-Type", containing("application/json"))
|
||||
.withRequestBody(equalTo(byNameRequest))
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byThreepidFound() {
|
||||
stubFor(post(urlEqualTo(endpoint))
|
||||
.willReturn(aResponse()
|
||||
.withHeader("Content-Type", "application/json")
|
||||
.withBody(new String(byThreepidResponse.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8))
|
||||
)
|
||||
);
|
||||
|
||||
UserDirectorySearchResult result = p.searchBy3pid(byThreepidSearch);
|
||||
assertTrue(!result.isLimited());
|
||||
assertTrue(result.getResults().size() == 1);
|
||||
UserDirectorySearchResult.Result entry = result.getResults().get(0);
|
||||
assertNotNull(entry);
|
||||
assertTrue(StringUtils.equals(byThreepidAvatar, entry.getAvatarUrl()));
|
||||
assertTrue(StringUtils.equals(byThreepidDisplay, entry.getDisplayName()));
|
||||
assertTrue(StringUtils.equals(new MatrixID(byThreepidId, domain).getId(), entry.getUserId()));
|
||||
|
||||
verify(postRequestedFor(urlMatching(endpoint))
|
||||
.withHeader("Content-Type", containing("application/json"))
|
||||
.withRequestBody(equalTo(byThreepidRequest))
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byThreepidNotFound() {
|
||||
stubFor(post(urlEqualTo(endpoint))
|
||||
.willReturn(aResponse()
|
||||
.withHeader("Content-Type", "application/json")
|
||||
.withBody(byThreepidEmptyResponse)
|
||||
)
|
||||
);
|
||||
|
||||
UserDirectorySearchResult result = p.searchBy3pid(byThreepidSearch);
|
||||
assertTrue(!result.isLimited());
|
||||
assertTrue(result.getResults().isEmpty());
|
||||
|
||||
verify(postRequestedFor(urlMatching(endpoint))
|
||||
.withHeader("Content-Type", containing("application/json"))
|
||||
.withRequestBody(equalTo(byThreepidRequest))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@@ -53,7 +53,7 @@ public class RestThreePidProviderTest {
|
||||
cfg.setEnabled(true);
|
||||
cfg.setHost("http://localhost:65000");
|
||||
cfg.getEndpoints().getIdentity().setSingle(lookupSinglePath);
|
||||
cfg.getEndpoints().getIdentity().setBulk("/lookup/bulk");
|
||||
cfg.getEndpoints().getIdentity().setBulk(lookupBulkPath);
|
||||
cfg.build();
|
||||
|
||||
p = new RestThreePidProvider(cfg, mxCfg);
|
||||
|
Reference in New Issue
Block a user