Skip to content
Snippets Groups Projects
Commit 5ee445a3 authored by Zachary Sabourin's avatar Zachary Sabourin
Browse files

feat: Improve code quality + upgrade to SDK 1.0.0 and Quarkus 3.8.3

parent 044be38e
No related branches found
No related tags found
1 merge request!25feat: Improve code quality + upgrade to SDK 1.0.0 and Quarkus 3.8.3
Showing
with 297 additions and 419 deletions
......@@ -23,7 +23,7 @@ services:
depends_on:
- foundationdb
foundationdb:
image: eclipsefdn/foundationdb-api:production-a25f588-21
image: eclipsefdn/foundationdb-api:production-529fdf7-37
ports:
- '10112:8095'
environment:
......
......@@ -7,6 +7,7 @@
<groupId>org.eclipsefoundation</groupId>
<artifactId>eclipse-openvsx-api</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<compiler-plugin.version>3.11.0</compiler-plugin.version>
<maven.compiler.source>17</maven.compiler.source>
......@@ -15,11 +16,11 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.2.11.Final</quarkus.platform.version>
<quarkus.platform.version>3.8.3</quarkus.platform.version>
<surefire-plugin.version>3.1.2</surefire-plugin.version>
<auto-value.version>1.10.4</auto-value.version>
<hibernate.version>5.5.6.Final</hibernate.version>
<eclipse-api-version>0.9.5</eclipse-api-version>
<eclipse-api-version>1.0.0</eclipse-api-version>
<org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
<fdndb-api-version>1.0.6</fdndb-api-version>
<sonar.sources>src/main</sonar.sources>
......@@ -34,6 +35,7 @@
<sonar.projectKey>eclipse-openvsx-api</sonar.projectKey>
<sonar.projectName>Open VSX API</sonar.projectName>
</properties>
<repositories>
<repository>
<id>eclipsefdn</id>
......@@ -46,6 +48,7 @@
</snapshots>
</repository>
</repositories>
<dependencyManagement>
<dependencies>
<dependency>
......@@ -57,8 +60,8 @@
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependencies>
<dependency>
<groupId>org.eclipsefoundation</groupId>
<artifactId>quarkus-core</artifactId>
......@@ -87,13 +90,6 @@
<artifactId>quarkus-oidc-client</artifactId>
</dependency>
<!-- Annotation preprocessors - reduce all of the boiler plate -->
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value-annotations</artifactId>
<version>${auto-value.version}</version>
</dependency>
<!-- Testing dependencies only -->
<dependency>
<groupId>org.eclipsefoundation</groupId>
......@@ -111,8 +107,8 @@
<artifactId>quarkus-jacoco</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
......@@ -130,20 +126,7 @@
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>
com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<version>${auto-value.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
......@@ -159,6 +142,7 @@
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
......
......@@ -202,6 +202,42 @@ components:
type: array
items:
$ref: "#/components/schemas/EfUser"
example:
- uid: "606609"
name: zacharysabourin
mail: zachary.sabourin@eclipse-foundation.org
picture: https://secure.gravatar.com/avatar/fbbbb03860062596a5cf11105dcc7d47.jpg?d=mm&s=185&r=G
eca:
signed: true
can_contribute_spec_project: true
is_committer: true
first_name: Zachary
last_name: Sabourin
github_handle: zacharysabourin
twitter_handle: sometwitteruser
publisher_agreements:
"open-vsx":
version: "1"
org: Eclipse Foundation
org_id: null
job_title: Web Developer
website: https://google.com
country:
code: CA
name: Canada
bio: This is my bio. Hello!
interests:
- MTG
- Warhammer
- Bass guitar
working_groups_interests:
- adoptium
- oniro
eca_url: https://api.eclipse.org/account/profile/zacharysabourin/eca
projects_url: https://api.eclipse.org/account/profile/zacharysabourin/projects
gerrit_url: https://api.eclipse.org/account/profile/zacharysabourin/gerrit
mailinglist_url: https://api.eclipse.org/account/profile/zacharysabourin/mailing-list
mpc_favorites_url: https://api.eclipse.org/marketplace/favorites?name=zacharysabourin
EfUser:
type: object
......@@ -346,10 +382,10 @@ components:
working_groups_interests:
- adoptium
- oniro
eca_url: https://api.eclipse.org/sandbox/account/profile/zacharysabourin/eca
projects_url: https://api.eclipse.org/sandbox/account/profile/zacharysabourin/projects
gerrit_url: https://api.eclipse.org/sandbox/account/profile/zacharysabourin/gerrit
mailinglist_url: https://api.eclipse.org/sandbox/account/profile/zacharysabourin/mailing-list
eca_url: https://api.eclipse.org/account/profile/zacharysabourin/eca
projects_url: https://api.eclipse.org/account/profile/zacharysabourin/projects
gerrit_url: https://api.eclipse.org/account/profile/zacharysabourin/gerrit
mailinglist_url: https://api.eclipse.org/account/profile/zacharysabourin/mailing-list
mpc_favorites_url: https://api.eclipse.org/marketplace/favorites?name=zacharysabourin
Eca:
......
......@@ -13,6 +13,12 @@ package org.eclipsefoundation.openvsx.api;
import java.util.List;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.eclipsefoundation.foundationdb.client.model.PeopleData;
import org.eclipsefoundation.foundationdb.client.model.PeopleDocumentData;
import org.eclipsefoundation.openvsx.api.models.ModLogHeaders;
import io.quarkus.oidc.client.filter.OidcClientFilter;
import jakarta.annotation.security.RolesAllowed;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.BeanParam;
......@@ -25,13 +31,6 @@ import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.eclipsefoundation.foundationdb.client.model.PeopleData;
import org.eclipsefoundation.foundationdb.client.model.PeopleDocumentData;
import org.eclipsefoundation.openvsx.api.models.ModLogHeaders;
import io.quarkus.oidc.client.filter.OidcClientFilter;
/**
* Fdndb-api binding for People resources.
*/
......@@ -43,8 +42,7 @@ import io.quarkus.oidc.client.filter.OidcClientFilter;
public interface PeopleAPI {
/**
* Create a person record into foundationDB. Only status code is used to
* validate success of the operation.
* Create a person record into foundationDB. Only status code is used to validate success of the operation.
*
* @param src The person to create
* @return A Response containing the persisted person.
......@@ -65,32 +63,30 @@ public interface PeopleAPI {
PeopleData getPerson(@PathParam("personID") String personId);
/**
* Fetches a list of all PeopleDocument entities tied to a given user filtered
* by documentID.
* Fetches a list of all PeopleDocument entities tied to a given user filtered by documentID.
*
* @param personId The given ef username
* @param personId The given ef username
* @param documentId The desired document id
* @return A List of PeopleDocumentData entities if they exist
*/
@GET
@Path("{personID}/documents")
@RolesAllowed("fdb_read_people_documents")
List<PeopleDocumentData> getPeopleDocument(@PathParam("personID") String personId,
@QueryParam("documentID") String documentId);
List<PeopleDocumentData> getPeopleDocument(@PathParam("personID") String personId, @QueryParam("documentID") String documentId,
@QueryParam("include_bytes") boolean includeBytes);
/**
* Persists a PeopleDocumentData entity in foundationDb. Can be used to create
* new documents or update existing ones. Passes the required ModLog headers to
* allow automatic ModLogEvent tracking.
* Persists a PeopleDocumentData entity in foundationDb. Can be used to create new documents or update existing ones. Passes the
* required ModLog headers to allow automatic ModLogEvent tracking.
*
* @param modLog The required ModLog headers
* @param modLog The required ModLog headers
* @param personId The person signing the document
* @param src The signed document(s).
* @param src The signed document(s).
* @return A List of PeopleDocumentData entites if the operation was successful
*/
@PUT
@Path("{personID}/documents")
@RolesAllowed("fdb_write_people_documents")
List<PeopleDocumentData> persistPeopleDocument(@BeanParam ModLogHeaders modLog,
@PathParam("personID") String personId, PeopleDocumentData src);
List<PeopleDocumentData> persistPeopleDocument(@BeanParam ModLogHeaders modLog, @PathParam("personID") String personId,
PeopleDocumentData src);
}
......@@ -13,6 +13,10 @@ package org.eclipsefoundation.openvsx.api;
import java.util.List;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.eclipsefoundation.foundationdb.client.model.SysModLogData;
import io.quarkus.oidc.client.filter.OidcClientFilter;
import jakarta.annotation.security.RolesAllowed;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.PUT;
......@@ -20,11 +24,6 @@ import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.eclipsefoundation.foundationdb.client.model.SysModLogData;
import io.quarkus.oidc.client.filter.OidcClientFilter;
/**
* Fdndb-api binding for System resources.
*/
......@@ -36,8 +35,7 @@ import io.quarkus.oidc.client.filter.OidcClientFilter;
public interface SysAPI {
/**
* Persists SysModLogData entities in foundationDB. Returns a list of
* created/updated results if the operation was successful.
* Persists SysModLogData entities in foundationDB. Returns a list of created/updated results if the operation was successful.
*
* @param src The new/updated ModLog
* @return A List or new/updated SysModLogData entities on success.
......
......@@ -11,60 +11,88 @@
**********************************************************************/
package org.eclipsefoundation.openvsx.api.models;
import jakarta.annotation.Nullable;
import jakarta.ws.rs.HeaderParam;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.auto.value.AutoValue;
@AutoValue
@JsonDeserialize(builder = AutoValue_ModLogHeaders.Builder.class)
public abstract class ModLogHeaders {
/**
* Model used to capture X-ModLog-* header params.
*/
public class ModLogHeaders {
@HeaderParam("X-ModLog-Key-1")
public abstract String getModLogKey1();
@Nullable
private String key1;
@HeaderParam("X-ModLog-Key-2")
public abstract String getModLogKey2();
private String key2;
@HeaderParam("X-ModLog-table")
public abstract String getModLogTable();
private String table;
@HeaderParam("X-ModLog-Person")
public abstract String getModLogPerson();
@Nullable
private String person;
@HeaderParam("X-ModLog-Action")
public abstract String getModLogAction();
@Nullable
private String action;
@HeaderParam("X-ModLog-Time")
public abstract String getModLogTime();
private String time;
public ModLogHeaders() {
this.key1 = "api.eclipse.org";
this.table = "openvsx/publisher_agreement";
}
public ModLogHeaders(String key2, String person, String action) {
this("api.eclipse.org", key2, "openvsx/publisher_agreement", person, action, null);
}
public ModLogHeaders(String key1, String key2, String table, String person, String action, String time) {
this.key1 = key1;
this.key2 = key2;
this.table = table;
this.person = person;
this.action = action;
this.time = time;
}
public static Builder builder() {
return new AutoValue_ModLogHeaders.Builder()
.setModLogTable("openvsx/publisher_agreement")
.setModLogKey1("api.eclipse.org");
public String getKey1() {
return key1;
}
@AutoValue.Builder
@JsonPOJOBuilder(withPrefix = "set")
public abstract static class Builder {
public void setKey1(String key1) {
this.key1 = key1;
}
public abstract Builder setModLogKey1(String key);
public String getKey2() {
return key2;
}
public abstract Builder setModLogKey2(String key);
public void setKey2(String key2) {
this.key2 = key2;
}
public abstract Builder setModLogTable(String table);
public String getTable() {
return table;
}
public abstract Builder setModLogPerson(String person);
public void setTable(String table) {
this.table = table;
}
public abstract Builder setModLogAction(String action);
public String getPerson() {
return person;
}
public abstract Builder setModLogTime(String time);
public void setPerson(String person) {
this.person = person;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getTime() {
return time;
}
public abstract ModLogHeaders build();
public void setTime(String time) {
this.time = time;
}
}
\ No newline at end of file
}
......@@ -21,7 +21,7 @@ import io.smallrye.config.WithDefault;
*/
@ConfigMapping(prefix = "eclipse.openvsx.publisher-agreement")
public interface PublisherAgreementConfig {
String docId();
@WithDefault("1")
......
......@@ -11,30 +11,9 @@
**********************************************************************/
package org.eclipsefoundation.openvsx.models;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.auto.value.AutoValue;
/**
* Model used to capture incoming publisher agreement signing requests.
*/
public record AgreementSigningRequest(String version, String githubHandle) {
@AutoValue
@JsonDeserialize(builder = AutoValue_AgreementSigningRequest.Builder.class)
public abstract class AgreementSigningRequest {
public abstract String getVersion();
public abstract String getGithubHandle();
public static Builder builder() {
return new AutoValue_AgreementSigningRequest.Builder();
}
@AutoValue.Builder
@JsonPOJOBuilder(withPrefix = "set")
public abstract static class Builder {
public abstract Builder setVersion(String version);
public abstract Builder setGithubHandle(String handle);
public abstract AgreementSigningRequest build();
}
}
......@@ -11,49 +11,19 @@
**********************************************************************/
package org.eclipsefoundation.openvsx.models;
import jakarta.annotation.Nullable;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.auto.value.AutoValue;
@AutoValue
@JsonDeserialize(builder = AutoValue_DocumentBody.Builder.class)
public abstract class DocumentBody {
public abstract String getVersion();
public abstract String getGithubHandle();
public abstract String getUsername();
public abstract String getFirstName();
public abstract String getLastName();
@Nullable
public abstract String getMail();
public static Builder builder() {
return new AutoValue_DocumentBody.Builder();
}
@AutoValue.Builder
@JsonPOJOBuilder(withPrefix = "set")
public abstract static class Builder {
public abstract Builder setVersion(String version);
public abstract Builder setGithubHandle(String handle);
public abstract Builder setUsername(String name);
public abstract Builder setFirstName(String name);
public abstract Builder setLastName(String name);
public abstract Builder setMail(String mail);
public abstract DocumentBody build();
import java.util.Objects;
/**
* Model used to represent the publisher agreement document. Gets serialized to a String then inserted into the DB as a Blob.
* Every field except mail is required to be non-null.
*/
public record DocumentBody(String version, String githubHandle, String username, String firstName, String lastName, String mail) {
public DocumentBody {
Objects.requireNonNull(version);
Objects.requireNonNull(githubHandle);
Objects.requireNonNull(username);
Objects.requireNonNull(firstName);
Objects.requireNonNull(lastName);
}
}
......@@ -11,73 +11,35 @@
**********************************************************************/
package org.eclipsefoundation.openvsx.models;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.auto.value.AutoValue;
@AutoValue
@JsonDeserialize(builder = AutoValue_PublisherAgreementData.Builder.class)
public abstract class PublisherAgreementData {
@JsonProperty("PersonID")
public abstract String getPersonID();
@JsonProperty("DocumentID")
public abstract String getDocumentID();
@JsonProperty("Version")
public abstract String getVersion();
@JsonProperty("EffectiveDate")
public abstract String getEffectiveDate();
@JsonProperty("ReceivedDate")
public abstract String getReceivedDate();
import java.util.Objects;
@JsonProperty("ScannedDocumentBLOB")
public abstract String getScannedDocumentBlob();
@JsonProperty("ScannedDocumentMime")
public abstract String getScannedDocumentMime();
@JsonProperty("ScannedDocumentBytes")
public abstract String getScannedDocumentBytes();
@JsonProperty("ScannedDocumentFileName")
public abstract String getScannedDocumentFileName();
@JsonProperty("Comments")
public abstract String getComments();
public static Builder builder() {
return new AutoValue_PublisherAgreementData.Builder();
}
@AutoValue.Builder
@JsonPOJOBuilder(withPrefix = "set")
public abstract static class Builder {
public abstract Builder setPersonID(String id);
public abstract Builder setDocumentID(String id);
public abstract Builder setVersion(String version);
public abstract Builder setEffectiveDate(String date);
public abstract Builder setReceivedDate(String date);
public abstract Builder setScannedDocumentBlob(String blob);
public abstract Builder setScannedDocumentMime(String mime);
public abstract Builder setScannedDocumentBytes(String bytes);
public abstract Builder setScannedDocumentFileName(String name);
public abstract Builder setComments(String commetns);
import com.fasterxml.jackson.annotation.JsonProperty;
public abstract PublisherAgreementData build();
/**
* Model used to capture outbound PA data for a user. All fields are required to be non-null.
*/
public record PublisherAgreementData(
@JsonProperty("PersonID") String personId,
@JsonProperty("DocumentID") String documentId,
@JsonProperty("Version") String version,
@JsonProperty("EffectiveDate") String effectiveDate,
@JsonProperty("ReceivedDate") String receivedDate,
@JsonProperty("ScannedDocumentBLOB") String scannedDocumentBlob,
@JsonProperty("ScannedDocumentMime") String scannedDocumentMime,
@JsonProperty("ScannedDocumentBytes") String scannedDocumentBytes,
@JsonProperty("ScannedDocumentFileName") String scannedDocumentFiledName,
@JsonProperty("Comments") String comments) {
public PublisherAgreementData {
Objects.requireNonNull(personId);
Objects.requireNonNull(documentId);
Objects.requireNonNull(version);
Objects.requireNonNull(effectiveDate);
Objects.requireNonNull(receivedDate);
Objects.requireNonNull(scannedDocumentBlob);
Objects.requireNonNull(scannedDocumentMime);
Objects.requireNonNull(scannedDocumentBytes);
Objects.requireNonNull(scannedDocumentFiledName);
Objects.requireNonNull(comments);
}
}
......@@ -11,19 +11,17 @@
**********************************************************************/
package org.eclipsefoundation.openvsx.models;
import org.eclipsefoundation.efservices.api.models.EfUser;
import org.eclipsefoundation.utils.exception.FinalForbiddenException;
import jakarta.enterprise.context.RequestScoped;
import jakarta.servlet.http.HttpServletRequest;
import org.eclipsefoundation.core.exception.FinalForbiddenException;
import org.eclipsefoundation.efservices.api.models.EfUser;
/**
* A RequestScoped bean that wraps the EfUser value set in the request
* chain. This bean is used to access profile information about the
* user associated with the current token. To set this data, a user search must
* be performed using the 'uid' from the current oauth token info. To access
* this data, a EfUser object must be set as the 'current_profile' property in
* the HttpServletRequest bound to the current request chain.
* A RequestScoped bean that wraps the EfUser value set in the request chain. This bean is used to access profile information about the user
* associated with the current token. To set this data, a user search must be performed using the 'uid' from the current oauth token info.
* To access this data, a EfUser object must be set as the 'current_profile' property in the HttpServletRequest bound to the current request
* chain.
*/
@RequestScoped
public class RequestUserProfileWrapper {
......
......@@ -14,25 +14,25 @@ package org.eclipsefoundation.openvsx.request;
import java.io.IOException;
import java.util.Optional;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.ext.Provider;
import org.eclipsefoundation.core.config.OAuth2SecurityConfig;
import org.eclipsefoundation.core.exception.FinalForbiddenException;
import org.eclipsefoundation.efservices.api.models.DrupalOAuthData;
import org.eclipsefoundation.efservices.api.models.EfUser;
import org.eclipsefoundation.efservices.api.models.UserSearchParams;
import org.eclipsefoundation.efservices.helpers.DrupalAuthHelper;
import org.eclipsefoundation.efservices.services.AccountService;
import org.eclipsefoundation.efservices.services.DrupalOAuthService;
import org.eclipsefoundation.efservices.services.ProfileService;
import org.eclipsefoundation.http.config.OAuth2SecurityConfig;
import org.eclipsefoundation.openvsx.models.RequestUserProfileWrapper;
import org.eclipsefoundation.utils.exception.FinalForbiddenException;
import org.jboss.resteasy.util.HttpHeaderNames;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.ext.Provider;
@Provider
public class OAuthFilter implements ContainerRequestFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(OAuthFilter.class);
......@@ -43,19 +43,17 @@ public class OAuthFilter implements ContainerRequestFilter {
@Inject
DrupalOAuthService oauthService;
@Inject
AccountService accountService;
ProfileService profileService;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (Boolean.TRUE.equals(config.get().filter().enabled())) {
// Strip token from Auth header
String token = DrupalAuthHelper
.stripBearerToken(requestContext.getHeaderString(HttpHeaderNames.AUTHORIZATION));
String token = DrupalAuthHelper.stripBearerToken(requestContext.getHeaderString(HttpHeaderNames.AUTHORIZATION));
DrupalOAuthData tokenStatus = oauthService
.validateTokenStatus(token, config.get().filter().validScopes(),
config.get().filter().validClientIds());
.validateTokenStatus(token, config.get().filter().validScopes(), config.get().filter().validClientIds());
// The incoming token must have a user associated with it.
if (tokenStatus == null || tokenStatus.getUserId() == null) {
......@@ -63,12 +61,11 @@ public class OAuthFilter implements ContainerRequestFilter {
}
// There is no openid scope incoming. User search needed for user data
Optional<EfUser> currentUserProfile = accountService
Optional<EfUser> currentUserProfile = profileService
.performUserSearch(UserSearchParams.builder().setUid(tokenStatus.getUserId()).build());
if (currentUserProfile.isEmpty()) {
LOGGER.warn("Cannot find profile for user {}", tokenStatus.getUserId());
throw new FinalForbiddenException(
String.format("Cannot find profile for user %s", tokenStatus.getUserId()));
throw new FinalForbiddenException(String.format("Cannot find profile for user %s", tokenStatus.getUserId()));
}
// Set profile data into context
......
......@@ -13,13 +13,13 @@ package org.eclipsefoundation.openvsx.resources;
import java.util.Arrays;
import org.eclipsefoundation.openvsx.models.RequestUserProfileWrapper;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import org.eclipsefoundation.openvsx.models.RequestUserProfileWrapper;
@Path("profile")
public class ProfileResource {
......
......@@ -13,6 +13,18 @@ package org.eclipsefoundation.openvsx.resources;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.eclipsefoundation.efservices.api.models.EfUser;
import org.eclipsefoundation.foundationdb.client.model.PeopleDocumentData;
import org.eclipsefoundation.http.model.WebError;
import org.eclipsefoundation.openvsx.config.PublisherAgreementConfig;
import org.eclipsefoundation.openvsx.models.AgreementSigningRequest;
import org.eclipsefoundation.openvsx.models.PublisherAgreementData;
import org.eclipsefoundation.openvsx.models.RequestUserProfileWrapper;
import org.eclipsefoundation.openvsx.services.FoundationOperationService;
import org.eclipsefoundation.openvsx.services.PublisherAgreementService;
import org.eclipsefoundation.utils.exception.FinalForbiddenException;
import jakarta.inject.Inject;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.DELETE;
......@@ -25,18 +37,6 @@ import jakarta.ws.rs.ServerErrorException;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import org.apache.commons.lang3.StringUtils;
import org.eclipsefoundation.core.exception.FinalForbiddenException;
import org.eclipsefoundation.core.model.Error;
import org.eclipsefoundation.efservices.api.models.EfUser;
import org.eclipsefoundation.foundationdb.client.model.PeopleDocumentData;
import org.eclipsefoundation.openvsx.config.PublisherAgreementConfig;
import org.eclipsefoundation.openvsx.models.AgreementSigningRequest;
import org.eclipsefoundation.openvsx.models.PublisherAgreementData;
import org.eclipsefoundation.openvsx.models.RequestUserProfileWrapper;
import org.eclipsefoundation.openvsx.services.FoundationOperationService;
import org.eclipsefoundation.openvsx.services.PublisherAgreementService;
@Path("publisher_agreement")
public class PublisherAgreementResource {
......@@ -80,14 +80,13 @@ public class PublisherAgreementResource {
// Conflict if already signed agreement that isn't expired
if (agreementService.getPublisherAgreementByUsername(user.getName()).isPresent()) {
return new Error(Status.CONFLICT,
"The request could not be completed due to a conflict with the current state of the resource.")
.asResponse();
return new WebError(Status.CONFLICT,
"The request could not be completed due to a conflict with the current state of the resource.").asResponse();
}
// Create user in fdndb if they don't exist
if (!foundationService.createDbUserIfNotFound(user)) {
throw new ServerErrorException("Internal Server Error", 500);
throw new ServerErrorException("Internal Server Error", Status.INTERNAL_SERVER_ERROR);
}
// Attempt to persist the agreement data. Returning the result
......@@ -127,43 +126,38 @@ public class PublisherAgreementResource {
String currentUser = userProfile.getCurrentUserProfile().getName();
Optional<PeopleDocumentData> updateResult = agreementService.revokePublisherAgreement(fetchResult.get(),
currentUser);
Optional<PeopleDocumentData> updateResult = agreementService.revokePublisherAgreement(fetchResult.get(), currentUser);
if (updateResult.isEmpty()) {
throw new ServerErrorException("Internal Server Error", 500);
throw new ServerErrorException("Internal Server Error", Status.INTERNAL_SERVER_ERROR);
}
return Response.noContent().build();
}
/**
* Validates the incoming signing request by ensuring the fields are in valid
* states, and that the user in the URL is the same as the one bound to the
* token.
* Validates the incoming signing request by ensuring the fields are in valid states, and that the user in the URL is the same as the
* one bound to the token.
*
* @param request The incoming singing request
*/
private void validateSigningRequest(AgreementSigningRequest request) {
if (!StringUtils.isNumeric(request.getVersion())
|| Double.parseDouble(request.getVersion()) != config.docVersion()) {
if (!StringUtils.isNumeric(request.version()) || Double.parseDouble(request.version()) != config.docVersion()) {
throw new BadRequestException("The version of the agreement is missing or invalid");
}
if (StringUtils.isBlank(request.getGithubHandle())) {
if (StringUtils.isBlank(request.githubHandle())) {
throw new BadRequestException("The github_handle is missing or invalid");
}
// Ensure GH handle from current user same as in request body.
if (!StringUtils.equalsIgnoreCase(userProfile.getCurrentUserProfile().getGithubHandle(),
request.getGithubHandle())) {
if (!StringUtils.equalsIgnoreCase(userProfile.getCurrentUserProfile().getGithubHandle(), request.githubHandle())) {
throw new BadRequestException("The github_handle does not match our records.");
}
}
/**
* Checks whether the token user is in the listed allowed users or if the token
* user is the same as the user in the request URL. Throws a
* FinalForbiddenException if the user can't access this resource
* Checks whether the token user is in the listed allowed users or if the token user is the same as the user in the request URL. Throws
* a FinalForbiddenException if the user can't access this resource
*
* @param urlUsername The username in the request URL
* @return True if current user can access endpoint
......@@ -171,8 +165,7 @@ public class PublisherAgreementResource {
void checkIfAdminOrSelf(String urlUsername) {
// Reject request if current user is not in URL and they aren't an admin
if (!urlUsername.equalsIgnoreCase(userProfile.getCurrentUserProfile().getName())
&& config.adminUsers().stream().noneMatch(
email -> email.equalsIgnoreCase(userProfile.getCurrentUserProfile().getMail()))) {
&& config.adminUsers().stream().noneMatch(email -> email.equalsIgnoreCase(userProfile.getCurrentUserProfile().getMail()))) {
throw new FinalForbiddenException(String.format("Access denied to resources for: %s", urlUsername));
}
}
......
......@@ -19,14 +19,12 @@ import org.eclipsefoundation.foundationdb.client.model.SysModLogData;
import org.eclipsefoundation.openvsx.api.models.ModLogHeaders;
/**
* Defines the service for performing specific CRUD operations on
* FoundationDb-API.
* Defines the service for performing specific CRUD operations on FoundationDb-API.
*/
public interface FoundationOperationService {
/**
* Given the username, retrieves the most recent openvsx publisher
* agreement for the given user.
* Given the username, retrieves the most recent openvsx publisher agreement for the given user.
*
* @param username The desired user's EF username.
* @return An Optional containing a PeopleDocumentData entity if it exists.
......@@ -34,32 +32,29 @@ public interface FoundationOperationService {
Optional<PeopleDocumentData> fetchMostRecentDocument(String username);
/**
* Sends a PeopleDocumentData object to the fdndb-api to be created/updated.
* Sets a set of ModLog headers to enable auto-event logging at request-time.
* Sends a PeopleDocumentData object to the fdndb-api to be created/updated. Sets a set of ModLog headers to enable auto-event logging
* at request-time.
*
* @param headers The request ModLog headers
* @param headers The request ModLog headers
* @param toInsert the document to insert
* @return An Optional containing the updated document if it exists.
*/
Optional<PeopleDocumentData> persistDocumentWithModLog(ModLogHeaders headers, PeopleDocumentData toInsert);
/**
* Creates a SysModLogData entity using the desired values and sends it to
* fdndb-api.
* Creates a SysModLogData entity using the desired values and sends it to fdndb-api.
*
* @param pk1 The given pk1
* @param pk1 The given pk1
* @param personId The person logging the event
* @return An optional containing a SysModLogData entity if it exists
*/
Optional<SysModLogData> insertErrorSysModLog(String pk1, String personId);
/**
* Checks if the given user exists in fdndb. Creates a new record if they can't
* be found.
* Checks if the given user exists in fdndb. Creates a new record if they can't be found.
*
* @param user The current user to add.
* @return True if success. False if there was an error performing the
* operation.
* @return True if success. False if there was an error performing the operation.
*/
boolean createDbUserIfNotFound(EfUser user);
}
......@@ -18,14 +18,12 @@ import org.eclipsefoundation.foundationdb.client.model.PeopleDocumentData;
import org.eclipsefoundation.openvsx.models.PublisherAgreementData;
/**
* Defines the service for fetching, creating and revoking openvsx publisher
* agreements.
* Defines the service for fetching, creating and revoking openvsx publisher agreements.
*/
public interface PublisherAgreementService {
/**
* Given the username, retrieves the most recent valid openvsx publisher
* agreement for the given user.
* Given the username, retrieves the most recent valid openvsx publisher agreement for the given user.
*
* @param username The desired user's EF username.
* @return An Optional containing a PublisherAgreementData entity if it exists.
......@@ -33,22 +31,19 @@ public interface PublisherAgreementService {
public Optional<PublisherAgreementData> getPublisherAgreementByUsername(String username);
/**
* Creates a publisher agreement for the given user using the request
* body containing the user GH handle and document version. Inserts a modLog
* event on fail or pass. Returns an empty Optional if it encounters an error.
* Creates a publisher agreement for the given user using the request body containing the user GH handle and document version. Inserts a
* modLog event on fail or pass. Returns an empty Optional if it encounters an error.
*
* @param user The current logged in user
* @return An Optional containing the created PublisherAgreementData entity if
* it exists
* @return An Optional containing the created PublisherAgreementData entity if it exists
*/
public Optional<PublisherAgreementData> createPublisherAgreement(EfUser user);
/**
* Expires a Publisher agreement and updates it in the foundationdb. Inserts a
* modLog event on fail or pass. Returns an empty Optional if it encounters an
* error.
* Expires a Publisher agreement and updates it in the foundationdb. Inserts a modLog event on fail or pass. Returns an empty Optional
* if it encounters an error.
*
* @param document The current signed publisher agreement
* @param document The current signed publisher agreement
* @param currentUser The user bound to the token
* @return An Optional containing the updated PeopleDocumentData if it exists
*/
......
......@@ -15,17 +15,13 @@ import java.time.ZonedDateTime;
import java.util.List;
import java.util.Optional;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.eclipsefoundation.core.model.RequestWrapper;
import org.eclipsefoundation.core.service.CachingService;
import org.eclipsefoundation.caching.service.CachingService;
import org.eclipsefoundation.efservices.api.models.EfUser;
import org.eclipsefoundation.foundationdb.client.model.PeopleData;
import org.eclipsefoundation.foundationdb.client.model.PeopleDocumentData;
import org.eclipsefoundation.foundationdb.client.model.SysModLogData;
import org.eclipsefoundation.http.helper.IPParser;
import org.eclipsefoundation.openvsx.api.PeopleAPI;
import org.eclipsefoundation.openvsx.api.SysAPI;
import org.eclipsefoundation.openvsx.api.models.ModLogHeaders;
......@@ -36,6 +32,10 @@ import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.core.Response.Status;
@ApplicationScoped
public class DefaultFoundationOperationService implements FoundationOperationService {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultFoundationOperationService.class);
......@@ -43,34 +43,29 @@ public class DefaultFoundationOperationService implements FoundationOperationSer
@Inject
PublisherAgreementConfig config;
@Inject
@RestClient
PeopleAPI peopleAPI;
@Inject
@RestClient
SysAPI sysAPI;
@Inject
CachingService cache;
@Inject
RequestWrapper wrap;
IPParser ipParser;
@Override
public Optional<PeopleDocumentData> fetchMostRecentDocument(String username) {
try {
LOGGER.debug("Fetching most recent publisher agreement for user: {}", username);
List<PeopleDocumentData> results = peopleAPI.getPeopleDocument(username, config.docId());
List<PeopleDocumentData> results = peopleAPI.getPeopleDocument(username, config.docId(), true);
if (results == null || results.isEmpty()) {
LOGGER.warn("Unable to find agreement for user with name: {}", username);
return Optional.empty();
}
// Sort by date. Most recent first
return results
.stream()
.sorted((pDoc1, pDoc2) -> pDoc2.getEffectiveDate().compareTo(pDoc1.getEffectiveDate()))
.findFirst();
return results.stream().sorted((pDoc1, pDoc2) -> pDoc2.getEffectiveDate().compareTo(pDoc1.getEffectiveDate())).findFirst();
} catch (Exception e) {
LOGGER.error("Error while fetching publisher agreement for user: {}", username, e);
......@@ -99,7 +94,7 @@ public class DefaultFoundationOperationService implements FoundationOperationSer
.builder()
.setLogTable("openvsx/publisher_agreement")
.setPK1(pk1)
.setPK2(getBestMatchingIP())
.setPK2(ipParser.getBestMatchingIP())
.setLogAction(OpenvsxModLogActions.SQL_ERROR)
.setPersonId(personId)
.setModDateTime(ZonedDateTime.now())
......@@ -144,7 +139,7 @@ public class DefaultFoundationOperationService implements FoundationOperationSer
.build();
// Insert new person record
return peopleAPI.persistPersonEntity(person).getStatus() == 200;
return peopleAPI.persistPersonEntity(person).getStatus() == Status.OK.getStatusCode();
} catch (Exception e) {
LOGGER.error("Error inserting user: {}", user.getName(), e);
......@@ -162,37 +157,11 @@ public class DefaultFoundationOperationService implements FoundationOperationSer
private Optional<PeopleData> fetchFoundationUser(String personId) {
try {
LOGGER.debug("Fetching user: {}", personId);
return cache
.get(personId, new MultivaluedMapImpl<>(), PeopleData.class, () -> peopleAPI.getPerson(personId))
.getData();
return cache.get(personId, new MultivaluedMapImpl<>(), PeopleData.class, () -> peopleAPI.getPerson(personId)).getData();
} catch (Exception e) {
LOGGER.error("Error searching for user: {}", personId, e);
insertErrorSysModLog("fetchFoundationUser", personId);
return Optional.empty();
}
}
/**
* Retrieves the best IP for the current request, using the x-real-ip and x-forwarded-for headers to pull the
* information from the current request.
*
* @return the best matching IP for current request, or localhost if none can be found
*/
private String getBestMatchingIP() {
LOGGER.debug("Looking up best IP address");
// use real IP, followed by forwarded for to get the requests IP
String initialIp = wrap.getHeader("X-Real-Ip");
if (StringUtils.isBlank(initialIp)) {
String[] forwardedIps = StringUtils.split(wrap.getHeader("X-Forwarded-For"), ",\\s*");
if (forwardedIps != null && forwardedIps.length > 1) {
initialIp = forwardedIps[1];
}
}
// default to localhost if we can't find request information
if (StringUtils.isBlank(initialIp)) {
initialIp = "0.0.0.0";
}
return initialIp;
}
}
......@@ -19,11 +19,7 @@ import java.util.Date;
import java.util.List;
import java.util.Optional;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.apache.commons.lang3.ArrayUtils;
import org.eclipsefoundation.core.helper.DateTimeHelper;
import org.eclipsefoundation.efservices.api.models.EfUser;
import org.eclipsefoundation.foundationdb.client.model.PeopleDocumentData;
import org.eclipsefoundation.openvsx.api.models.ModLogHeaders;
......@@ -33,11 +29,15 @@ import org.eclipsefoundation.openvsx.models.PublisherAgreementData;
import org.eclipsefoundation.openvsx.namespace.OpenvsxModLogActions;
import org.eclipsefoundation.openvsx.services.FoundationOperationService;
import org.eclipsefoundation.openvsx.services.PublisherAgreementService;
import org.eclipsefoundation.utils.helper.DateTimeHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
public class DefaultPublisherAgreementService implements PublisherAgreementService {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultPublisherAgreementService.class);
......@@ -63,29 +63,20 @@ public class DefaultPublisherAgreementService implements PublisherAgreementServi
try {
LOGGER.debug("Creating publisher agreement for user: {}", user.getName());
ModLogHeaders headers = ModLogHeaders.builder()
.setModLogKey2(user.getName())
.setModLogAction(OpenvsxModLogActions.AGREEMENT_SIGNED)
.setModLogPerson(user.getName()).build();
ModLogHeaders headers = new ModLogHeaders(user.getName(), user.getName(), OpenvsxModLogActions.AGREEMENT_SIGNED);
LOGGER.debug("Encoding publisher agreement document for user: {}", user.getName());
// Create document from user data + request info. Then encode it
String jsonDoc = objectMapper.writeValueAsString(DocumentBody.builder()
.setVersion(String.valueOf(config.docVersion()))
.setGithubHandle(user.getGithubHandle())
.setUsername(user.getName())
.setFirstName(user.getFirstName())
.setLastName(user.getLastName())
.setMail(user.getMail())
.build());
Optional<PeopleDocumentData> creationResult = foundationService.persistDocumentWithModLog(headers,
createDocumentSigningRequest(jsonDoc, user.getName()));
String jsonDoc = objectMapper
.writeValueAsString(new DocumentBody(String.valueOf(config.docVersion()), user.getGithubHandle(), user.getName(),
user.getFirstName(), user.getLastName(), user.getMail()));
Optional<PeopleDocumentData> creationResult = foundationService
.persistDocumentWithModLog(headers, createDocumentSigningRequest(jsonDoc, user.getName()));
// Convert to PublisherAgreementData if persistence successful
return creationResult.isEmpty() ? Optional.empty()
: Optional.of(buildPublisherAgreement(creationResult.get(), false));
return creationResult.isEmpty() ? Optional.empty() : Optional.of(buildPublisherAgreement(creationResult.get(), false));
} catch (Exception e) {
LOGGER.error("Error while creating publisher agreement", e);
......@@ -100,7 +91,8 @@ public class DefaultPublisherAgreementService implements PublisherAgreementServi
LOGGER.debug("{} is revoking publisher agreement for user: {}", currentUser, document.getPersonID());
// Update the doc with an expiry date
PeopleDocumentData updated = PeopleDocumentData.builder()
PeopleDocumentData updated = PeopleDocumentData
.builder()
.setPersonID(document.getPersonID())
.setDocumentID(document.getDocumentID())
.setVersion(document.getVersion())
......@@ -114,10 +106,7 @@ public class DefaultPublisherAgreementService implements PublisherAgreementServi
.setExpirationDate(new Date())
.build();
ModLogHeaders headers = ModLogHeaders.builder()
.setModLogKey2(document.getPersonID())
.setModLogAction(OpenvsxModLogActions.AGREEMENT_REVOKED)
.setModLogPerson(currentUser).build();
ModLogHeaders headers = new ModLogHeaders(document.getPersonID(), currentUser, OpenvsxModLogActions.AGREEMENT_REVOKED);
return foundationService.persistDocumentWithModLog(headers, updated);
......@@ -135,8 +124,7 @@ public class DefaultPublisherAgreementService implements PublisherAgreementServi
* @return True if expired/invalid, false otherwise
*/
private boolean isdocumentExpired(PeopleDocumentData document) {
boolean isExpired = document.getExpirationDate() != null
&& document.getExpirationDate().before(Date.from(Instant.now()));
boolean isExpired = document.getExpirationDate() != null && document.getExpirationDate().before(Date.from(Instant.now()));
if (isExpired) {
LOGGER.warn("Most recent document is expired");
}
......@@ -144,11 +132,10 @@ public class DefaultPublisherAgreementService implements PublisherAgreementServi
}
/**
* Creates an OpenVSX publisher agreement document signing request using the
* given user. Builds and encodes the current Publisher Agreement from the
* necessary fields.
* Creates an OpenVSX publisher agreement document signing request using the given user. Builds and encodes the current Publisher
* Agreement from the necessary fields.
*
* @param jsonDoc The encoded Document as a Json String
* @param jsonDoc The encoded Document as a Json String
* @param username The user signing the agreement
* @return The constructed PeopleDocumentData object.
*/
......@@ -160,7 +147,8 @@ public class DefaultPublisherAgreementService implements PublisherAgreementServi
// Set date to UTC timezone when creating
Date now = Date.from(DateTimeHelper.now().toInstant());
return PeopleDocumentData.builder()
return PeopleDocumentData
.builder()
.setPersonID(username)
.setDocumentID(config.docId())
.setVersion(config.docVersion())
......@@ -175,11 +163,10 @@ public class DefaultPublisherAgreementService implements PublisherAgreementServi
}
/**
* Builds a PublisherAgreementData object using the given PeopleDocumentData
* entity. Has a flag to offset the received date by one day to compensate for
* the modification made by fdndb-api.
* Builds a PublisherAgreementData object using the given PeopleDocumentData entity. Has a flag to offset the received date by one day
* to compensate for the modification made by fdndb-api.
*
* @param document The given PeopleDocumentData entity
* @param document The given PeopleDocumentData entity
* @param adjustTime A Flag to increment the received date by a day
* @return A populated PublisherAgreementData object
*/
......@@ -187,8 +174,7 @@ public class DefaultPublisherAgreementService implements PublisherAgreementServi
// Conversion of List<Byte> to byte[] to allow conversion to string
byte[] blob = document.getScannedDocumentBLOB() == null ? new byte[0]
: ArrayUtils.toPrimitive(
document.getScannedDocumentBLOB().toArray(new Byte[document.getScannedDocumentBLOB().size()]));
: ArrayUtils.toPrimitive(document.getScannedDocumentBLOB().toArray(new Byte[document.getScannedDocumentBLOB().size()]));
SimpleDateFormat effectiveDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat receivedDateFormat = new SimpleDateFormat("yyyy-MM-dd");
......@@ -198,24 +184,14 @@ public class DefaultPublisherAgreementService implements PublisherAgreementServi
// The 'received_date' column is only a 'date' type and gets rewinded a day when
// adjusted for UTC time by fdndb-api. Flag should onlybe set on fetch requests
if (adjustTime) {
ZonedDateTime adjustedTime = ZonedDateTime.parse(DateTimeHelper.toRFC3339(document.getReceivedDate()))
.plusDays(1);
ZonedDateTime adjustedTime = ZonedDateTime.parse(DateTimeHelper.toRFC3339(document.getReceivedDate())).plusDays(1);
receivedDate = receivedDateFormat.format(Date.from(adjustedTime.toInstant()));
} else {
receivedDate = receivedDateFormat.format(document.getReceivedDate());
}
return PublisherAgreementData.builder()
.setPersonID(document.getPersonID())
.setDocumentID(document.getDocumentID())
.setVersion(Integer.toString((int) document.getVersion()))
.setEffectiveDate(effectiveDateFormat.format(document.getEffectiveDate()))
.setReceivedDate(receivedDate)
.setScannedDocumentBlob(new String(blob))
.setScannedDocumentMime(document.getScannedDocumentMime())
.setScannedDocumentBytes(Integer.toString(blob.length))
.setScannedDocumentFileName(document.getScannedDocumentFileName())
.setComments(document.getComments())
.build();
return new PublisherAgreementData(document.getPersonID(), document.getDocumentID(), Integer.toString((int) document.getVersion()),
effectiveDateFormat.format(document.getEffectiveDate()), receivedDate, new String(blob), document.getScannedDocumentMime(),
Integer.toString(blob.length), document.getScannedDocumentFileName(), document.getComments());
}
}
......@@ -7,3 +7,7 @@ fdndb-api/mp-rest/url=http://foundationdb:8095
%dev.fdndb-api/mp-rest/url=http://localhost:10112
eclipse.security.oauth2.filter.enabled=true
quarkus.log.file.enable=false
quarkus.micrometer.enabled=true
\ No newline at end of file
......@@ -28,11 +28,9 @@ class ProfileResourceTest {
public static final Optional<Map<String, Object>> userCreds = Optional.of(Map.of("Authorization", "Bearer token2"));
public static final Optional<Map<String, Object>> noUserCreds = Optional
.of(Map.of("Authorization", "Bearer token6"));
public static final Optional<Map<String, Object>> noUserCreds = Optional.of(Map.of("Authorization", "Bearer token6"));
public static final Optional<Map<String, Object>> invalidCreds = Optional
.of(Map.of("Authorization", "Bearer token1"));
public static final Optional<Map<String, Object>> invalidCreds = Optional.of(Map.of("Authorization", "Bearer token1"));
public static final EndpointTestCase GET_CURRENT_SUCCESS = TestCaseHelper
.prepareTestCase(BASE_URL, new String[] {}, SchemaNamespaceHelper.EF_USERS_SCHEMA_PATH)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment