diff --git a/spec/openapi.yaml b/spec/openapi.yaml index b577120b2f5a688fe5db4ee37baa3414d2d00cf6..423399b8a8d3d584396620b713dbf101da3fdfd6 100644 --- a/spec/openapi.yaml +++ b/spec/openapi.yaml @@ -174,7 +174,32 @@ paths: $ref: "#/components/schemas/Error" 500: description: Error while retrieving data - + /organization/{id}: + parameters: + - name: id + in: path + description: The ID of the organization to retrieve working groups for + required: true + schema: + type: integer + get: + summary: Working Group by Organization ID + description: Returns working groups that the target organization is a member of + responses: + 200: + description: Success + content: + application/json: + schema: + $ref: "#/components/schemas/WorkingGroups" + 404: + description: Not Found + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + 500: + description: Error while retrieving data components: securitySchemes: openId: diff --git a/src/main/java/org/eclipsefoundation/wg/api/MembershipAPI.java b/src/main/java/org/eclipsefoundation/wg/api/MembershipAPI.java index d58e7ee37df1f384c3a0045cbd0370cd1c608dc8..e0ad726ff703e39afad09420281b885adf23b5f8 100644 --- a/src/main/java/org/eclipsefoundation/wg/api/MembershipAPI.java +++ b/src/main/java/org/eclipsefoundation/wg/api/MembershipAPI.java @@ -39,6 +39,6 @@ public interface MembershipAPI { */ @GET @Compressed - @Path("organizations/slim") + @Path("organizations") RestResponse<List<MemberOrganization>> getWGMemberOrgs(@BeanParam BaseAPIParameters baseParams); } diff --git a/src/main/java/org/eclipsefoundation/wg/models/MemberOrganization.java b/src/main/java/org/eclipsefoundation/wg/models/MemberOrganization.java index c69b71f716247a76623896b8be79e51f38c8e3fc..61e7080a1b83428c89f7b22e8a117c0dd4a551b2 100644 --- a/src/main/java/org/eclipsefoundation/wg/models/MemberOrganization.java +++ b/src/main/java/org/eclipsefoundation/wg/models/MemberOrganization.java @@ -9,12 +9,17 @@ **********************************************************************/ package org.eclipsefoundation.wg.models; +import java.util.List; import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonProperty.Access; + /** * Entity representing a working group member organization. */ -public record MemberOrganization(String name, Integer organizationId, MemberOrganizationLogos logos) { +public record MemberOrganization(String name, @JsonProperty(value = "organization_id") Integer organizationId, MemberOrganizationLogos logos, + @JsonProperty(access = Access.WRITE_ONLY) List<WorkingGroupParticipationAgreement> wgpas) { public MemberOrganization { Objects.requireNonNull(name); @@ -27,4 +32,11 @@ public record MemberOrganization(String name, Integer organizationId, MemberOrga public record MemberOrganizationLogos(String print, String web) { } + + /** + * Entity representing a member organization's WGPAs on file. + */ + public record WorkingGroupParticipationAgreement(String documentId, String description, String level, String workingGroup) { + + } } diff --git a/src/main/java/org/eclipsefoundation/wg/resource/WorkingGroupsResource.java b/src/main/java/org/eclipsefoundation/wg/resource/WorkingGroupsResource.java index a6892a05541ec014f721ac8da89309432a6b4816..1662970fb45556c88e65e31f1a7b88dc1477e247 100644 --- a/src/main/java/org/eclipsefoundation/wg/resource/WorkingGroupsResource.java +++ b/src/main/java/org/eclipsefoundation/wg/resource/WorkingGroupsResource.java @@ -65,6 +65,13 @@ public class WorkingGroupsResource { return RestResponse.ok(new ArrayList<>(wgService.get(status, parentOrganization))); } + @GET + @Path("organization/{organizationId}") + public RestResponse<List<WorkingGroup>> getWorkingGroupsForOrganization(@RestPath String organizationId) { + // return the results as a response + return RestResponse.ok(new ArrayList<>(wgService.getByOrganizationId(organizationId))); + } + @GET @Path("{alias}") public RestResponse<WorkingGroup> getWorkingGroup(@RestPath String alias) { diff --git a/src/main/java/org/eclipsefoundation/wg/services/WorkingGroupsService.java b/src/main/java/org/eclipsefoundation/wg/services/WorkingGroupsService.java index 46681a2478731360b55e8d63c458931ee12c1131..cf4a422e520d9bfcc5ccb97a2d419346aeffd446 100644 --- a/src/main/java/org/eclipsefoundation/wg/services/WorkingGroupsService.java +++ b/src/main/java/org/eclipsefoundation/wg/services/WorkingGroupsService.java @@ -35,6 +35,14 @@ public interface WorkingGroupsService { */ public Set<WorkingGroup> get(List<String> projectStatus, List<String> parentOrganization); + /** + * Returns a set of working groups, filtering to only those that the target organization is a member of. + * + * @param organizationId the organization to retrieve working groups for + * @return set of working groups for the matching organization ID + */ + public Set<WorkingGroup> getByOrganizationId(String organizationId); + /** * Returns a working group based on the given alias. * diff --git a/src/main/java/org/eclipsefoundation/wg/services/impl/DefaultWorkingGroupsService.java b/src/main/java/org/eclipsefoundation/wg/services/impl/DefaultWorkingGroupsService.java index d7f1ab580f80ab238ee32f955ab5376c94401fa8..2bd520907e7ea680c93ed21dd7ab5974928b4e49 100644 --- a/src/main/java/org/eclipsefoundation/wg/services/impl/DefaultWorkingGroupsService.java +++ b/src/main/java/org/eclipsefoundation/wg/services/impl/DefaultWorkingGroupsService.java @@ -20,6 +20,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -47,11 +48,14 @@ import org.eclipsefoundation.wg.services.WorkingGroupsService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.cronutils.utils.StringUtils; import com.fasterxml.jackson.databind.ObjectMapper; import io.quarkus.runtime.Startup; import jakarta.annotation.PostConstruct; import jakarta.enterprise.context.ApplicationScoped; +import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.ServerErrorException; import jakarta.ws.rs.core.MultivaluedHashMap; import jakarta.ws.rs.core.Response.Status; @@ -123,6 +127,20 @@ public class DefaultWorkingGroupsService implements WorkingGroupsService { return workingGroups.get(alias); } + @Override + public Set<WorkingGroup> getByOrganizationId(String organizationId) { + if (!StringUtils.isNumeric(organizationId)) { + throw new BadRequestException("Organization ID should be a valid number"); + } + Optional<MemberOrganization> org = getOrganizationById(Integer.parseInt(organizationId)); + if (org.isEmpty()) { + throw new NotFoundException("Could not find an org with the given id: " + TransformationHelper.formatLog(organizationId)); + } + + // map the WGPA aliases to the actual working groups, dropping non matching null values + return org.get().wgpas().stream().map(wgpa -> getByAlias(wgpa.workingGroup())).filter(Objects::nonNull).collect(Collectors.toSet()); + } + @Override public Map<String, List<String>> getWGPADocumentIDs() { return workingGroups.values().stream().collect(Collectors.toMap(WorkingGroup::alias, WorkingGroupsHelper::extractWGPADocumentIDs)); @@ -215,7 +233,7 @@ public class DefaultWorkingGroupsService implements WorkingGroupsService { String orgName = contact.organization().name1(); Integer orgId = contact.organization().organizationID(); MemberOrganizationLogos logos = getOrgLogosById(contact.organization().organizationID()); - return new CommitteeMember(name, username, new MemberOrganization(orgName, orgId, logos)); + return new CommitteeMember(name, username, new MemberOrganization(orgName, orgId, logos, Collections.emptyList())); } /** @@ -225,20 +243,9 @@ public class DefaultWorkingGroupsService implements WorkingGroupsService { * @return A MemberOrganizationLogos entity or null. */ private MemberOrganizationLogos getOrgLogosById(int orgId) { - List<MemberOrganization> memberOrgs = cacheManager - .getList(ParameterizedCacheKeyBuilder - .builder() - .id("all") - .clazz(MemberOrganization.class) - .params(new MultivaluedHashMap<>()) - .build()); - // Return null logos object if none found - return memberOrgs - .stream() - .filter(m -> m.organizationId() == orgId) - .findFirst() - .orElse(new MemberOrganization("", orgId, new MemberOrganizationLogos(null, null))) + return getOrganizationById(orgId) + .orElse(new MemberOrganization("", orgId, new MemberOrganizationLogos(null, null), Collections.emptyList())) .logos(); } @@ -287,4 +294,14 @@ public class DefaultWorkingGroupsService implements WorkingGroupsService { return orgContacts.get(); } + private Optional<MemberOrganization> getOrganizationById(int organizationId) { + List<MemberOrganization> memberOrgs = cacheManager + .getList(ParameterizedCacheKeyBuilder + .builder() + .id("all") + .clazz(MemberOrganization.class) + .params(new MultivaluedHashMap<>()) + .build()); + return memberOrgs.stream().filter(m -> m.organizationId() == organizationId).findFirst(); + } } diff --git a/src/test/java/org/eclipsefoundation/wg/resource/WorkingGroupsResourceTest.java b/src/test/java/org/eclipsefoundation/wg/resource/WorkingGroupsResourceTest.java index ccab3981de420c0181e35ab005aa9f2421a98b9e..6b969048690ac9fc91f3fed7772f2bfc5a84cfcc 100644 --- a/src/test/java/org/eclipsefoundation/wg/resource/WorkingGroupsResourceTest.java +++ b/src/test/java/org/eclipsefoundation/wg/resource/WorkingGroupsResourceTest.java @@ -26,6 +26,8 @@ class WorkingGroupsResourceTest { public static final String WG_STATUS_URL = WGS_BASE_URL + "?status={param}"; public static final String WG_STATUSES_URL = WGS_BASE_URL + "?status={param1}&status={param2}"; + + public static final String WG_BY_ORGANIZATION_URL = WGS_BASE_URL + "/organization/{id}"; public static final String WG_BASE_URL = WGS_BASE_URL + "/{alias}"; @@ -54,6 +56,17 @@ class WorkingGroupsResourceTest { public static final EndpointTestCase GET_BY_ALIAS_404 = TestCaseHelper .buildNotFoundCase(WG_BASE_URL, new String[] { "invalid-Group" }, SchemaNamespaceHelper.ERROR_SCHEMA_PATH); + + /* + * GET_BY_ORGANIZATION + */ + public static final EndpointTestCase GET_BY_ORGANIZATION_SUCCESS = TestCaseHelper + .buildSuccessCase(WG_BY_ORGANIZATION_URL, new String[] { "11" }, SchemaNamespaceHelper.WORKING_GROUPS_SCHEMA_PATH); + + public static final EndpointTestCase GET_BY_ORGANIZATION_404 = TestCaseHelper + .buildNotFoundCase(WG_BY_ORGANIZATION_URL, new String[] { "12345" }, SchemaNamespaceHelper.ERROR_SCHEMA_PATH); + public static final EndpointTestCase GET_BY_ORGANIZATION_BAD_REQUEST = TestCaseHelper + .buildBadRequestCase(WG_BY_ORGANIZATION_URL, new String[] { "ibm" }, SchemaNamespaceHelper.ERROR_SCHEMA_PATH); /* * GET_RESOURCES @@ -176,6 +189,43 @@ class WorkingGroupsResourceTest { void getByAlias_failure_invalidName_validateSchema() { EndpointTestBuilder.from(GET_BY_ALIAS_404).run(); } + + /* + * GET_BY_ORGANIZATION + */ + @Test + void getWorkingGroupsForOrganization_success() { + EndpointTestBuilder.from(GET_BY_ORGANIZATION_SUCCESS).run(); + } + + @Test + void getWorkingGroupsForOrganization_success_validResponseFormat() { + EndpointTestBuilder.from(GET_BY_ORGANIZATION_SUCCESS).andCheckFormat().run(); + } + + @Test + void getWorkingGroupsForOrganization_success_matchingSpec() { + EndpointTestBuilder.from(GET_BY_ORGANIZATION_SUCCESS).andCheckSchema().run(); + } + + @Test + void getWorkingGroupsForOrganization_failure_noMatchingOrg() { + EndpointTestBuilder.from(GET_BY_ORGANIZATION_404).run(); + } + + @Test + void getWorkingGroupsForOrganization_failure_noMatchingOrg_validateSchema() { + EndpointTestBuilder.from(GET_BY_ORGANIZATION_404).andCheckSchema().run(); + } + @Test + void getWorkingGroupsForOrganization_failure_invalidName() { + EndpointTestBuilder.from(GET_BY_ORGANIZATION_BAD_REQUEST).run(); + } + + @Test + void getWorkingGroupsForOrganization_failure_invalidName_validateSchema() { + EndpointTestBuilder.from(GET_BY_ORGANIZATION_BAD_REQUEST).andCheckSchema().run(); + } /* * GET_RESOURCES diff --git a/src/test/java/org/eclipsefoundation/wg/test/api/MockMembershipAPI.java b/src/test/java/org/eclipsefoundation/wg/test/api/MockMembershipAPI.java index 8a8cc50d00bf57f562352e3cca3019d2e047249f..abbe5c95cbeb5ecec9fe7565c06c69aa8d4c495f 100644 --- a/src/test/java/org/eclipsefoundation/wg/test/api/MockMembershipAPI.java +++ b/src/test/java/org/eclipsefoundation/wg/test/api/MockMembershipAPI.java @@ -13,6 +13,7 @@ package org.eclipsefoundation.wg.test.api; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.eclipse.microprofile.rest.client.inject.RestClient; @@ -37,14 +38,17 @@ public class MockMembershipAPI implements MembershipAPI { this.memberOrgs = new ArrayList<>(); this.memberOrgs .addAll(Arrays - .asList(new MemberOrganization("org", 11, new MemberOrganizationLogos("url", "url")), - new MemberOrganization("fake company", 22, new MemberOrganizationLogos("url", "url")), - new MemberOrganization("real company", 33, new MemberOrganizationLogos("url", "url")), - new MemberOrganization("other org", 44, new MemberOrganizationLogos("url", "url")), - new MemberOrganization("fake inc", 55, new MemberOrganizationLogos("url", "url")), - new MemberOrganization("org name", 66, new MemberOrganizationLogos("url", "url")), - new MemberOrganization("org inc", 77, new MemberOrganizationLogos("url", "url")), - new MemberOrganization("company foundation", 88, new MemberOrganizationLogos("url", "url")))); + .asList(new MemberOrganization("org", 11, new MemberOrganizationLogos("url", "url"), Collections.emptyList()), + new MemberOrganization("fake company", 22, new MemberOrganizationLogos("url", "url"), + Collections.emptyList()), + new MemberOrganization("real company", 33, new MemberOrganizationLogos("url", "url"), + Collections.emptyList()), + new MemberOrganization("other org", 44, new MemberOrganizationLogos("url", "url"), Collections.emptyList()), + new MemberOrganization("fake inc", 55, new MemberOrganizationLogos("url", "url"), Collections.emptyList()), + new MemberOrganization("org name", 66, new MemberOrganizationLogos("url", "url"), Collections.emptyList()), + new MemberOrganization("org inc", 77, new MemberOrganizationLogos("url", "url"), Collections.emptyList()), + new MemberOrganization("company foundation", 88, new MemberOrganizationLogos("url", "url"), + Collections.emptyList()))); } @Override