Skip to content

Commit

Permalink
Meetings API (#434)
Browse files Browse the repository at this point in the history
* Added MeetingsClient stub

* Added api-eu base URI

* Added endpoints & types

* Added _links

* Added missing fields for room

* Format createdAt & expiresAt

* Added validation to MeetingRoom

* Added documentation for top-level methods

* Validate theme colour

* Some fixes to ser/des properties

* Added test stub utilities

* Added test for getRoom

* Comprehensive MeetingRoomTest

* Hide UrlContainer nesting from user

* Bumped sample expiration year

* Param validation in MeetingsClient

* Use UUID in MeetingsClient methods

* GetRooms client test

* expireAfterUse validation

* Fixed UpdateApplicationRequest

* Use ListX for plural endpoints

* App & recording ID now UUIDs

* Rename to match conventions

* Added simplified listRooms call

* Added Recordings test

* Test listLogoUploadUrls

* Use Instant instead of ZonedDateTime

* More tests

* More tests & edge case coverage

* UpdateRoom/UpdateTheme tests

* Use enum for UISettings.Language

* Added ThemeTest

* Fixed updateTheme & added uploadLogo

* Added uploadLogo method & wrapper

* Updated MeetingRoom.expiresAt builder

* Updated BugRepro

* Fixed failing test

* Various fixes & improvements

* 100% coverage

* Removed /beta from URLs

* Added MeetingsResponseException

* Made SelfReferencing final

* Added webhook

* Improved VonageApiResponseException coverage

* Hydrate MeetingRoom on creation response

* Hydrate Theme

* Recurse through ListRooms response

* Added throws to MeetingsClient doc

* Clarified thread safety FAQ

* More fixes

* Renamed setThemeLogo
  • Loading branch information
SMadani authored Jun 28, 2023
1 parent 66ab674 commit 212cb3e
Show file tree
Hide file tree
Showing 94 changed files with 7,895 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle
- name: Publish with gradle
- name: Publish with Gradle
env:
signingKey: ${{secrets.SIGNING_KEY}}
signingPassword: ${{secrets.SIGNING_PASSWORD}}
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
src/test/java/com/vonage/client/BugRepro.java
*.groovy
.classpath
.gradle
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

# [7.6.0] - 2023-06-29
- Added Proactive Connect API implementation
- Added Meetings API implementation
- Updated Subaccounts name & secret validation logic

# [7.5.0] - 2023-06-14
Expand Down
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ to your project's classpath.
* There are also **many useful code samples** in our [nexmo-community/nexmo-java-quickstart](https://github.com/nexmo-community/nexmo-java-quickstart) repository.

### Customize the Base URI
By default, the client will use https://api.nexmo.com, https://rest.nexmo.com, and https://sns.nexmo.com as base URIs for the various endpoints. To customize these you can instantiate `VonageClient` with an `HttpConfig` object.
By default, the client will use https://api.nexmo.com, https://rest.nexmo.com, https://sns.nexmo.com and https://api-eu.vonage.com as base URIs for the various endpoints. To customize these you can instantiate `VonageClient` with an `HttpConfig` object.

`HttpConfig.Builder` has been created to assist in building this object. Usage is as follows:

Expand All @@ -97,6 +97,7 @@ HttpConfig httpConfig = HttpConfig.builder()
.apiBaseUri("https://api.example.com")
.restBaseUri("https://rest.example.com")
.snsBaseUri("https://sns.example.com")
.apiEuBaseUri("https://api-eu.example.com")
.build();

VonageClient client = VonageClient.builder()
Expand Down Expand Up @@ -524,8 +525,11 @@ Our [Voice API](https://developer.vonage.com/voice/voice-api/overview) can conne

## Frequently Asked Questions

Q: Does this SDK support thread safety?
A: No, it currently does not.
Q: What is your policy on thread safety?

A: The current architecture of the SDK means that only one thread should use the client at a time.
If you would like to use the SDK in a multithreaded environment, create a separate instance of
`VonageClient` for each thread.

Q: Does this SDK support asynchronous request / response processing?
A: Currently no, but it is on the roadmap.
Expand All @@ -544,6 +548,7 @@ The following is a list of Vonage APIs and whether the Java SDK provides support
| Dispatch | Beta ||
| External Accounts | Developer Preview ||
| Media | Beta ||
| Meetings | General Availability ||
| Messages | General Availability ||
| Number Insight | General Availability ||
| Number Management | General Availability ||
Expand Down
5 changes: 3 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies {

implementation 'commons-codec:commons-codec:1.15'
implementation 'org.apache.httpcomponents:httpclient:4.5.14'
implementation 'org.apache.httpcomponents:httpmime:4.5.14'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.2'
implementation 'io.openapitools.jackson.dataformat:jackson-dataformat-hal:1.0.9'
Expand All @@ -36,8 +37,8 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito:mockito-inline:4.11.0'
testImplementation 'org.hamcrest:hamcrest-all:1.3'
testImplementation 'org.springframework:spring-test:5.3.27'
testImplementation 'org.springframework:spring-web:5.3.27'
testImplementation 'org.springframework:spring-test:5.3.28'
testImplementation 'org.springframework:spring-web:5.3.28'
testImplementation 'jakarta.servlet:jakarta.servlet-api:4.0.4'
}

Expand Down
35 changes: 32 additions & 3 deletions src/main/java/com/vonage/client/VonageApiResponseException.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Objects;

/**
Expand All @@ -38,8 +39,24 @@
public abstract class VonageApiResponseException extends VonageClientException {
protected URI type;
protected String title, detail, instance;
protected List<?> errors;
@JsonIgnore protected int statusCode;

protected VonageApiResponseException() {
}

protected VonageApiResponseException(String message) {
super(message);
}

protected VonageApiResponseException(String message, Throwable cause) {
super(message, cause);
}

protected VonageApiResponseException(Throwable cause) {
super(cause);
}

/**
* Link to the <a href=https://developer.vonage.com/en/api-errors>API error type</a>.
*
Expand Down Expand Up @@ -80,6 +97,18 @@ public String getInstance() {
return instance;
}

/**
* Additional description of problems encountered with the request.
* This is typically only applicable to 400 or 409 error codes.
*
* @return The list of errors returned from the server (could be a Map or String),
* or {@code null} if none / not applicable.
*/
@JsonProperty("errors")
public List<?> getErrors() {
return errors;
}

/**
* The API response status code, usually 4xx or 500.
*
Expand Down Expand Up @@ -145,9 +174,9 @@ public String toJson() {
protected static <E extends VonageApiResponseException> E fromJson(Class<E> clazz, String json) {
if (json == null || json.length() < 2) {
try {
return clazz.newInstance();
return clazz.getConstructor().newInstance();
}
catch (InstantiationException | IllegalAccessException ex) {
catch (Exception ex) {
throw new VonageUnexpectedException(ex);
}
}
Expand All @@ -156,7 +185,7 @@ protected static <E extends VonageApiResponseException> E fromJson(Class<E> claz
return mapper.readValue(json, clazz);
}
catch (IOException ex) {
throw new VonageUnexpectedException("Failed to produce "+clazz.getSimpleName()+" from json.", ex);
throw new VonageResponseParseException("Failed to produce "+clazz.getSimpleName()+" from json.", ex);
}
}

Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/vonage/client/VonageClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.vonage.client.auth.hashutils.HashUtil;
import com.vonage.client.conversion.ConversionClient;
import com.vonage.client.insight.InsightClient;
import com.vonage.client.meetings.MeetingsClient;
import com.vonage.client.messages.MessagesClient;
import com.vonage.client.numbers.NumbersClient;
import com.vonage.client.proactiveconnect.ProactiveConnectClient;
Expand Down Expand Up @@ -62,6 +63,7 @@ public class VonageClient {
private final Verify2Client verify2;
private final SubaccountsClient subaccounts;
private final ProactiveConnectClient proactiveConnect;
private final MeetingsClient meetings;

private VonageClient(Builder builder) {
httpWrapper = new HttpWrapper(builder.httpConfig, builder.authCollection);
Expand All @@ -81,6 +83,7 @@ private VonageClient(Builder builder) {
verify2 = new Verify2Client(httpWrapper);
subaccounts = new SubaccountsClient(httpWrapper);
proactiveConnect = new ProactiveConnectClient(httpWrapper);
meetings = new MeetingsClient(httpWrapper);
}

public AccountClient getAccountClient() {
Expand Down Expand Up @@ -147,6 +150,15 @@ public ProactiveConnectClient getProactiveConnectClient() {
return proactiveConnect;
}

/**
*
* @return The Meetings client.
* @since 7.6.0
*/
public MeetingsClient getMeetingsClient() {
return meetings;
}

/**
*
* @return The Verify v2 client.
Expand Down
78 changes: 78 additions & 0 deletions src/main/java/com/vonage/client/meetings/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2023 Vonage
*
* 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 com.vonage.client.meetings;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.vonage.client.VonageResponseParseException;
import java.io.IOException;
import java.util.UUID;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Application {
private String accountId;
private UUID applicationId, defaultThemeId;

protected Application() {
}

/**
* ID of the application.
*
* @return The application ID.
*/
@JsonProperty("application_id")
public UUID getApplicationId() {
return applicationId;
}

/**
* ID of the account application.
*
* @return The account ID.
*/
@JsonProperty("account_id")
public String getAccountId() {
return accountId;
}

/**
* ID of the default theme.
*
* @return The application default theme ID.
*/
@JsonProperty("default_theme_id")
public UUID getDefaultThemeId() {
return defaultThemeId;
}

/**
* Creates an instance of this class from a JSON payload.
*
* @param json The JSON string to parse.
* @return An instance of this class with the fields populated, if present.
*/
public static Application fromJson(String json) {
try {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(json, Application.class);
}
catch (IOException ex) {
throw new VonageResponseParseException("Failed to produce Application from json.", ex);
}
}
}
Loading

0 comments on commit 212cb3e

Please sign in to comment.