Unverified Commit 48199e21 authored by Martin Lowe's avatar Martin Lowe 🇨🇦 Committed by GitHub
Browse files

Add external org API binding with properties (#83)

* Add external org API binding with properties

* Update Organization members API binding

Update to match new API format that will soon be live.

* Update external organizations endpoint for caching

* Update to organizations resource to split retrieval and add caching
parent 91f84f2e
/**
* Copyright (c) 2021 Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.react.api;
import java.util.Set;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.eclipsefoundation.react.api.model.Organization;
/**
* REST API binding for the external Foundation Organizations API. This endpoint
* allows for the retrieval of Eclipse Foundation members, and for filtering by
* page, working group ID, or ID of the organization.
*/
@Path("member")
@RegisterRestClient(configKey = "fdn-api")
public interface OrganizationAPI {
/**
* Retrieves a set of organizations from the external endpoing, allowing for
* simple pagination of the results and filtering by organizations participation
* within a working group.
*
* @param workingGroup optional string to filter organizations by working group
* participation, given the ID
* @param page the page of results ro retrieve
* @return the set of organizations for the given query parameters, or an empty
* set if none are found.
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
Set<Organization> organizations(@QueryParam("working_group") String workingGroup, @QueryParam("page") int page);
/**
* Retrieves a single organization by ID from the external endpoint.
*
* @param id the ID of the organization that should be retrieved.
* @return the organization data if it exists as an Eclipse Foundation member,
* or null if there is no member with the given ID.
*/
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
Organization organizationByID(@PathParam("id") String id);
}
/**
* Copyright (c) 2021 Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.react.api.model;
import java.util.HashSet;
import java.util.Set;
public class Organization {
private Integer id;
private String name;
private OrganizationMembershipLevel memberLevel;
private OrganizationDescription description;
private String website;
private OrganizationLogos logos;
private Set<WorkingGroupParticipationAgreement> wgpa;
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public OrganizationMembershipLevel getMemberLevel() {
return this.memberLevel;
}
public void setMemberLevel(OrganizationMembershipLevel memberLevel) {
this.memberLevel = memberLevel;
}
public OrganizationDescription getDescription() {
return this.description;
}
public void setDescription(OrganizationDescription description) {
this.description = description;
}
public String getWebsite() {
return this.website;
}
public void setWebsite(String website) {
this.website = website;
}
public OrganizationLogos getLogos() {
return this.logos;
}
public void setLogos(OrganizationLogos logos) {
this.logos = logos;
}
public Set<WorkingGroupParticipationAgreement> getWgpa() {
return new HashSet<>(this.wgpa);
}
public void setWgpa(Set<WorkingGroupParticipationAgreement> wgpa) {
this.wgpa = new HashSet<>(wgpa);
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* Copyright (c) 2021 Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.react.api.model;
import javax.json.bind.annotation.JsonbProperty;
public class OrganizationDescription {
@JsonbProperty("short")
private String shortDesc;
private String full;
public String getShortDesc() {
return this.shortDesc;
}
public void setShortDesc(String shortDesc) {
this.shortDesc = shortDesc;
}
public String getFull() {
return this.full;
}
public void setFull(String full) {
this.full = full;
}
}
/**
* Copyright (c) 2021 Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.react.api.model;
import javax.json.bind.annotation.JsonbProperty;
public class OrganizationLogos {
@JsonbProperty("small")
private String compressedLogoUrl;
@JsonbProperty("full")
private String fullResolutionLogoUrl;
public String getCompressedLogoUrl() {
return this.compressedLogoUrl;
}
public void setCompressedLogoUrl(String compressedLogoUrl) {
this.compressedLogoUrl = compressedLogoUrl;
}
public String getFullResolutionLogoUrl() {
return this.fullResolutionLogoUrl;
}
public void setFullResolutionLogoUrl(String fullResolutionLogoUrl) {
this.fullResolutionLogoUrl = fullResolutionLogoUrl;
}
}
/**
* Copyright (c) 2021 Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.react.api.model;
public class OrganizationMembershipLevel {
private String level;
private String description;
public String getLevel() {
return this.level;
}
public void setLevel(String level) {
this.level = level;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
}
/**
* Copyright (c) 2021 Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.react.api.model;
public class WorkingGroupParticipationAgreement {
private String documentID;
private String level;
private String description;
private String workingGroup;
public WorkingGroupParticipationAgreement() {
}
public String getDocumentID() {
return this.documentID;
}
public void setDocumentID(String documentID) {
this.documentID = documentID;
}
public String getLevel() {
return this.level;
}
public void setLevel(String level) {
this.level = level;
}
public String getWorkingGroup() {
return this.workingGroup;
}
public void setWorkingGroup(String workingGroup) {
this.workingGroup = workingGroup;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
}
\ No newline at end of file
......@@ -35,6 +35,8 @@ public abstract class AbstractRESTResource {
PersistenceDao dao;
@Inject
FilterService filters;
@Inject
CachingService cache;
@Inject
RequestWrapper wrap;
......
/**
* Copyright (c) 2021 Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.react.request;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipsefoundation.react.api.model.Organization;
import org.eclipsefoundation.react.service.OrganizationsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Allows for external organizations data to be retrieved and displayed. This
* endpoint is unencrypted as all data displayed is publicly available
* information.
*/
@Path("organizations")
@Produces(MediaType.APPLICATION_JSON)
public class OrganizationResource extends AbstractRESTResource {
public static final Logger LOGGER = LoggerFactory.getLogger(OrganizationResource.class);
@Inject
OrganizationsService orgAPI;
@GET
public Response get() {
List<Organization> orgs = orgAPI.get();
if (orgs.isEmpty()) {
return Response.noContent().build();
}
return Response.ok(new ArrayList<>(orgs)).build();
}
@GET
@Path("{orgID}")
public Response get(@PathParam("orgID") String organizationID) {
Organization org = orgAPI.getByID(organizationID);
if (org == null) {
return Response.noContent().build();
}
return Response.ok(org).build();
}
}
/**
* Copyright (c) 2021 Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.react.service;
import java.util.List;
import org.eclipsefoundation.react.api.model.Organization;
public interface OrganizationsService {
public List<Organization> get();
public Organization getByID(String id);
}
/**
* Copyright (c) 2021 Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.react.service.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.eclipsefoundation.core.service.CachingService;
import org.eclipsefoundation.react.api.OrganizationAPI;
import org.eclipsefoundation.react.api.model.Organization;
import org.eclipsefoundation.react.service.OrganizationsService;
import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.quarkus.runtime.Startup;
/**
* Builds a list of working group definitions from an embedded list of working
* group definitions. This is an interim solution to accelerate this project and
* should be replaced with a call to the foundation API to retrieve this data.
*
* @author Martin Lowe
*/
@Startup
@ApplicationScoped
public class DefaultOrganizationsService implements OrganizationsService {
public static final Logger LOGGER = LoggerFactory.getLogger(DefaultOrganizationsService.class);
@RestClient
@Inject
OrganizationAPI orgAPI;
@Inject
CachingService cache;
@PostConstruct
void init() throws IOException {
LOGGER.info("Starting init of cached organizations");
Optional<List<Organization>> orgs = cache.get("all", new MultivaluedMapImpl<>(), Organization.class, () -> getAll(null));
if (orgs.isEmpty()) {
throw new RuntimeException("Could not load organizations");
}
}
@Override
public List<Organization> get() {
Optional<List<Organization>> orgs = cache.get("all", new MultivaluedMapImpl<>(), Organization.class, () -> getAll(null));
if (orgs.isEmpty()) {
return Collections.emptyList();
}
return new ArrayList<>(orgs.get());
}
@Override
public Organization getByID(String id) {
return orgAPI.organizationByID(id);
}
private List<Organization> getAll(String workingGroup) {
String actualWG = workingGroup == null ? "" : workingGroup;
List<Organization> orgs = new LinkedList<>();
Set<Organization> tmp = Collections.emptySet();
int count = 1;
do {
tmp = orgAPI.organizations(actualWG, count);
orgs.addAll(tmp);
count++;
} while(!tmp.isEmpty() && tmp != null);
return orgs;
}
}
......@@ -2,7 +2,7 @@ quarkus.log.level=INFO
quarkus.http.port=8080
## EXTERNAL API CLIENT CONFIG
fdn-api/mp-rest/url=https://api.eclipse.org/foundation
fdn-api/mp-rest/url=https://api.eclipse.org/public
fdn-api/mp-rest/scope=javax.inject.Singleton
## Required for wg interim solution, remove when moved to external API
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment