diff options
| author | Jesse Morgan <jesse@jesterpm.net> | 2018-07-21 22:42:50 -0700 | 
|---|---|---|
| committer | Jesse Morgan <jesse@jesterpm.net> | 2018-07-21 22:42:50 -0700 | 
| commit | fafa1140f3e8eedcb0f00b25c7891093df5fbf43 (patch) | |
| tree | 5a0dea7fdc11176115283bbd56ff2137130afc7b /src/main/java/com | |
Initial commit of groups search lambdas
Diffstat (limited to 'src/main/java/com')
9 files changed, 866 insertions, 0 deletions
| diff --git a/src/main/java/com/p4square/groupsindexer/GroupsSearch.java b/src/main/java/com/p4square/groupsindexer/GroupsSearch.java new file mode 100644 index 0000000..2cbc7e5 --- /dev/null +++ b/src/main/java/com/p4square/groupsindexer/GroupsSearch.java @@ -0,0 +1,144 @@ +package com.p4square.groupsindexer; + +import com.amazonaws.auth.AWS4Signer; +import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; +import com.amazonaws.http.AWSRequestSigningApacheInterceptor; +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.p4square.groupsindexer.model.ErrorResponse; +import com.p4square.groupsindexer.model.GroupSearchDocument; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequestInterceptor; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.builder.SearchSourceBuilder; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * GroupsSearch is an API Gateway Proxy Lambda which executes a search and returns the results. + * + * Required (custom) environment variables: + * + * <ul> + *  <li>ES_URL</li> + *  <li>IMAGE_URL_PREFIX</li> + * </ul> + */ +public class GroupsSearch implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> { + +    private static final AWSCredentialsProvider credentialsProvider = new DefaultAWSCredentialsProviderChain(); + +    private static final Logger LOG = LogManager.getLogger(GroupsSearch.class); +    private static final ObjectMapper MAPPER = new ObjectMapper(); + +    private final RestHighLevelClient esClient; +    private final String imageUrlPrefix; + +    public GroupsSearch() throws Exception { +        // Prefix to prepend to image urls. +        imageUrlPrefix = System.getenv("IMAGE_URL_PREFIX"); + +        // Setup ElasticSearch client +        final String ES_URL = System.getenv("ES_URL"); +        AWS4Signer signer = new AWS4Signer(); +        signer.setServiceName("es"); +        signer.setRegionName(System.getenv("AWS_DEFAULT_REGION")); +        HttpRequestInterceptor interceptor = new AWSRequestSigningApacheInterceptor(signer.getServiceName(), signer, credentialsProvider); + +        esClient = new RestHighLevelClient(RestClient +                .builder(HttpHost.create(ES_URL)) +                .setHttpClientConfigCallback(hacb -> hacb.addInterceptorLast(interceptor))); +    } + +    @Override +    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent event, Context context) { +        final APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent(); + +        try { +            final Map<String, String> params = event.getQueryStringParameters(); +            if (params == null) { +                response.setStatusCode(400); +                response.setBody(MAPPER.writeValueAsString(new ErrorResponse("Request must contain a query."))); +                return response; +            } + +            final BoolQueryBuilder query = QueryBuilders.boolQuery(); + +            if (params.containsKey("q")) { +                query.must(QueryBuilders.simpleQueryStringQuery(params.get("q"))); +            } + +            if (params.containsKey("groupTypeId")) { +                query.filter(QueryBuilders.termQuery("groupType.id", params.get("groupTypeId"))); +            } + +            if (params.containsKey("campusId")) { +                query.filter(QueryBuilders.termQuery("campus.id", params.get("campusId"))); +            } + +            if (params.containsKey("meetingDayId")) { +                query.filter(QueryBuilders.termQuery("meetingDay.id", params.get("meetingDayId"))); +            } + +            if (params.containsKey("childcare")) { +                query.filter(QueryBuilders.termQuery("childcare", Boolean.parseBoolean(params.get("childcare")))); +            } + +            params.entrySet() +                    .stream() +                    .filter(entry -> entry.getKey().startsWith("udf_")) +                    .map(entry -> QueryBuilders.termQuery("udf." + entry.getKey() + ".id", entry.getValue())) +                    .forEach(query::filter); + +            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); +            searchSourceBuilder.query(query); +            searchSourceBuilder.size(20); + +            SearchRequest searchRequest = new SearchRequest("groups"); +            searchRequest.types("group"); +            searchRequest.source(searchSourceBuilder); + +            SearchResponse searchResponse = esClient.search(searchRequest); + +            List<GroupSearchDocument> docs = new ArrayList<>(); +            for (final SearchHit hit : searchResponse.getHits().getHits()) { +                GroupSearchDocument doc = MAPPER.readValue(hit.getSourceAsString(), GroupSearchDocument.class); +                // Sanitize the output +                doc.setLeaderEmail(null); +                if (doc.getImageUrl() != null) { +                    doc.setImageUrl(imageUrlPrefix + "/" + doc.getImageUrl()); +                } +                docs.add(doc); +            } + +            response.setStatusCode(200); +            response.setBody(MAPPER.writeValueAsString(docs)); + +        } catch (Exception e) { +            LOG.error(e.getMessage()); +            response.setStatusCode(500); +            try { +                response.setBody(MAPPER.writeValueAsString(new ErrorResponse(e.getMessage()))); +            } catch (JsonProcessingException _) { +                // Unexpected. +            } +        } + +        return response; +    } +} diff --git a/src/main/java/com/p4square/groupsindexer/SearchFields.java b/src/main/java/com/p4square/groupsindexer/SearchFields.java new file mode 100644 index 0000000..8c21449 --- /dev/null +++ b/src/main/java/com/p4square/groupsindexer/SearchFields.java @@ -0,0 +1,153 @@ +package com.p4square.groupsindexer; + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.p4square.ccbapi.CCBAPI; +import com.p4square.ccbapi.CCBAPIClient; +import com.p4square.ccbapi.model.*; +import com.p4square.groupsindexer.model.ErrorResponse; +import com.p4square.groupsindexer.model.SearchField; +import com.p4square.groupsindexer.model.StringPair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.net.URI; +import java.util.*; +import java.util.stream.Collectors; + +/** + * SearchFields is an API Gateway Proxy which returns the searchable dropdown fields and their choices. + * + * Required (custom) environment variables: + * <ul> + *  <li>CCBAPIURL</li> + *  <li>CCBAPIUser</li> + *  <li>CCBAPIPassword</li> + * </ul> + * + */ +public class SearchFields implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> { + +    private static final long REFRESH_INTERVAL_MS = 15 * 60 * 1000; + +    private static final Logger LOG = LogManager.getLogger(GroupsSearch.class); +    private static final ObjectMapper MAPPER = new ObjectMapper(); + +    private final CCBAPI ccbClient; + +    private List<SearchField> cachedFields; +    private long lastRefresh; + +    public SearchFields() throws Exception { +        // Setup CCB Client +        final String CCBAPIURL = System.getenv("CCBAPIURL"); +        final String CCBAPIUser = System.getenv("CCBAPIUser"); +        final String CCBAPIPassword = System.getenv("CCBAPIPassword"); +        ccbClient = new CCBAPIClient(new URI(CCBAPIURL), CCBAPIUser, CCBAPIPassword); +    } + +    @Override +    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent event, Context context) { +        final APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent(); +        try { +            final List<SearchField> fields = getFields(); +            if (fields == null) { +                response.setStatusCode(500); +                response.setBody(MAPPER.writeValueAsString(new ErrorResponse("Unable to get search fields."))); +                return response; +            } + +            response.setStatusCode(200); +            response.setBody(MAPPER.writeValueAsString(fields)); + +        } catch (Exception e) { +            LOG.error(e.getMessage()); +            response.setStatusCode(500); +            try { +                response.setBody(MAPPER.writeValueAsString(new ErrorResponse(e.getMessage()))); +            } catch (JsonProcessingException _) { +                // Unexpected. +            } +        } + +        return response; +    } + +    private synchronized List<SearchField> getFields() { +        if (System.currentTimeMillis() - lastRefresh < REFRESH_INTERVAL_MS) { +            LOG.debug("Using cached CCB fields"); +            return cachedFields; +        } + +        try { +            LOG.info("Fetching fields from CCB"); + +            cachedFields = new ArrayList<>(); +            final GetCustomFieldLabelsResponse labels = ccbClient.getCustomFieldLabels(); + +            cachedFields.add(new SearchField("groupTypeId", "Group Type", getValues(LookupTableType.GROUP_TYPE))); +            // TODO fields.add(new SearchField("campusId", "Campus", ...)); +            cachedFields.add(new SearchField("meetingDayId", "Day", getValues(LookupTableType.MEET_DAY))); + + +            for (final CustomField field : labels.getCustomFields()) { +                final LookupTableType type = getTypeFromString(field.getName()); +                if (type != null) { +                    cachedFields.add(new SearchField(getSearchFieldIdForType(type), field.getLabel(), getValues(type))); +                } +            } + +            cachedFields.add(new SearchField("childcare", "Childcare", +                    Arrays.asList(StringPair.of("true", "Yes"), StringPair.of("false", "No")))); + +            lastRefresh = System.currentTimeMillis(); +            return cachedFields; + +        } catch (Exception e) { +            LOG.error(e.getMessage()); +            return null; +        } +    } + +    private LookupTableType getTypeFromString(String name) { +        switch (name) { +            case "udf_grp_pulldown_1": +                return LookupTableType.UDF_GRP_PULLDOWN_1; +            case "udf_grp_pulldown_2": +                return LookupTableType.UDF_GRP_PULLDOWN_2; +            case "udf_grp_pulldown_3": +                return LookupTableType.UDF_GRP_PULLDOWN_3; +            default: +                return null; +        } +    } + +    private String getSearchFieldIdForType(LookupTableType type) { +        switch (type) { +            case UDF_GRP_PULLDOWN_1: +                return "udf_1"; +            case UDF_GRP_PULLDOWN_2: +                return "udf_2"; +            case UDF_GRP_PULLDOWN_3: +                return "udf_3"; +            default: +                throw new IllegalArgumentException(); +        } +    } + +    private List<StringPair> getValues(LookupTableType type) throws IOException { +        final GetLookupTableRequest lookupTableRequest = new GetLookupTableRequest().withType(type); +        final GetLookupTableResponse lookupTable = ccbClient.getLookupTable(lookupTableRequest); + +        return lookupTable.getItems() +                .stream() +                .map(entry -> StringPair.of(String.valueOf(entry.getId()), entry.getName())) +                .collect(Collectors.toList()); +    } + +} diff --git a/src/main/java/com/p4square/groupsindexer/UpdateIndexes.java b/src/main/java/com/p4square/groupsindexer/UpdateIndexes.java new file mode 100644 index 0000000..e4937e1 --- /dev/null +++ b/src/main/java/com/p4square/groupsindexer/UpdateIndexes.java @@ -0,0 +1,150 @@ +package com.p4square.groupsindexer; + +import com.amazonaws.auth.AWS4Signer; +import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; +import com.amazonaws.http.AWSRequestSigningApacheInterceptor; +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.amazonaws.services.lambda.runtime.events.ScheduledEvent; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.p4square.ccbapi.CCBAPI; +import com.p4square.ccbapi.CCBAPIClient; +import com.p4square.ccbapi.model.*; +import com.p4square.groupsindexer.model.GroupSearchDocument; +import com.p4square.groupsindexer.model.GroupSearchDocumentAdapter; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequestInterceptor; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.elasticsearch.action.bulk.BulkRequest; +import org.elasticsearch.action.bulk.BulkResponse; +import org.elasticsearch.client.Requests; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.common.xcontent.XContentType; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; + +/** + * UpdateIndexes is a scheduled lambda which populates the groups search index. + * + * Required (custom) environment variables: + * <ul> + *  <li>CCBAPIURL</li> + *  <li>CCBAPIUser</li> + *  <li>CCBAPIPassword</li> + *  <li>ES_URL</li> + *  <li>IMAGE_BUCKET</li> + * </ul> + * + */ +public class UpdateIndexes implements RequestHandler<ScheduledEvent, String> { + +    private static final AWSCredentialsProvider credentialsProvider = new DefaultAWSCredentialsProviderChain(); + +    private static final Logger LOG = LogManager.getLogger(UpdateIndexes.class); +    private static final GroupSearchDocumentAdapter ADAPTER = new GroupSearchDocumentAdapter(); +    private static final ObjectMapper MAPPER = new ObjectMapper(); + +    private final String imageBucket; + +    private final CCBAPI ccbClient; +    private final RestHighLevelClient esClient; +    private final AmazonS3 s3Client; + +    public UpdateIndexes() throws Exception { +        // Setup CCB Client +        final String CCBAPIURL = System.getenv("CCBAPIURL"); +        final String CCBAPIUser = System.getenv("CCBAPIUser"); +        final String CCBAPIPassword = System.getenv("CCBAPIPassword"); +        ccbClient = new CCBAPIClient(new URI(CCBAPIURL), CCBAPIUser, CCBAPIPassword); + +        // Setup ElasticSearch client +        final String ES_URL = System.getenv("ES_URL"); +        AWS4Signer signer = new AWS4Signer(); +        signer.setServiceName("es"); +        signer.setRegionName(System.getenv("AWS_DEFAULT_REGION")); +        HttpRequestInterceptor interceptor = new AWSRequestSigningApacheInterceptor(signer.getServiceName(), signer, credentialsProvider); + +        esClient = new RestHighLevelClient(RestClient +                        .builder(HttpHost.create(ES_URL)) +                        .setHttpClientConfigCallback(hacb -> hacb.addInterceptorLast(interceptor))); + +        // Setup S3 Client +        imageBucket = System.getenv("IMAGE_BUCKET"); +        s3Client = AmazonS3ClientBuilder.defaultClient(); +    } + +    @Override +    public String handleRequest(ScheduledEvent s3Event, Context context) { +        try { +            GetGroupProfilesResponse response = ccbClient.getGroupProfiles( +                    new GetGroupProfilesRequest() +                            .withIncludeImageUrl(true) +                            .withIncludeParticipants(false)); + +            final BulkRequest indexRequest = new BulkRequest(); + +            for (GroupProfile profile : response.getGroups()) { +                if (!profile.isActive() || +                        !profile.isPublicSearchListed() || +                        profile.getInteractionType() != InteractionType.MEMBERS_INTERACT) { +                    LOG.info("Skipping inactive/unlisted group " + profile.getName()); +                    continue; +                } + +                // Transform GroupProfile to Search Document. +                final GroupSearchDocument document = ADAPTER.apply(profile); + +                // Save GroupProfile image. +                document.setImageUrl(null); +                if (profile.getImageUrl() != null && !profile.getImageUrl().isEmpty()) { +                    final String imageKey = "group-images/group-" + profile.getId(); +                    InputStream in = null; +                    try { +                        final URL imageUrl = new URL(profile.getImageUrl()); +                        in = imageUrl.openStream(); +                        s3Client.putObject(imageBucket, imageKey, in, null); +                        document.setImageUrl(imageKey); +                    } catch (Exception e) { +                        LOG.error("Failed to upload image for group " + profile.getId(), e); +                    } finally { +                        if (in != null) { +                            try { +                                in.close(); +                            } catch (IOException e) { +                                // Ignore +                            } +                        } +                    } +                } + +                // Add request to batch. +                indexRequest.add(Requests +                        .indexRequest("groups") +                        .type("group") +                        .id(String.valueOf(document.getId())) +                        .source(MAPPER.writeValueAsString(document), XContentType.JSON)); +            } + +            BulkResponse esResponse = esClient.bulk(indexRequest); + +            if (esResponse.hasFailures()) { +                throw new RuntimeException(esResponse.buildFailureMessage()); +            } + +            LOG.info("Updated search index. Found " + response.getGroups().size() + " groups."); +            return "ok"; + +        } catch (IOException e) { +            LOG.error("Unexpected Exception: " + e.getMessage(), e); +            throw new RuntimeException(e); +        } +    } +} diff --git a/src/main/java/com/p4square/groupsindexer/model/ErrorResponse.java b/src/main/java/com/p4square/groupsindexer/model/ErrorResponse.java new file mode 100644 index 0000000..186bd27 --- /dev/null +++ b/src/main/java/com/p4square/groupsindexer/model/ErrorResponse.java @@ -0,0 +1,22 @@ +package com.p4square.groupsindexer.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ErrorResponse { +    @JsonProperty("error") +    private String error; + +    public ErrorResponse() {} + +    public ErrorResponse(String error) { +        this.error = error; +    } + +    public String getError() { +        return error; +    } + +    public void setError(String error) { +        this.error = error; +    } +} diff --git a/src/main/java/com/p4square/groupsindexer/model/GroupSearchDocument.java b/src/main/java/com/p4square/groupsindexer/model/GroupSearchDocument.java new file mode 100644 index 0000000..e336cb8 --- /dev/null +++ b/src/main/java/com/p4square/groupsindexer/model/GroupSearchDocument.java @@ -0,0 +1,232 @@ +package com.p4square.groupsindexer.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.HashMap; +import java.util.Map; + +/** + * A group description in ElasticSearch. + */ +public class GroupSearchDocument { + +    @JsonProperty("id") +    private int id; + +    @JsonProperty("name") +    private String name; + +    @JsonProperty("description") +    private String description; + +    @JsonProperty("image-url") +    private String imageUrl; + +    @JsonProperty("leader-id") +    private int leaderId; + +    @JsonProperty("leader-name") +    private String leaderName; + +    @JsonProperty("leader-email") +    private String leaderEmail; + +    @JsonProperty("member-count") +    private int currentMembers; + +    @JsonProperty("group-capacity") +    private Integer groupCapacity; + +    @JsonProperty("childcare") +    private boolean childcareProvided; + +    @JsonProperty("listed") +    private boolean listed; + +    @JsonProperty("public") +    private boolean publicSearchListed; + +    @JsonProperty("active") +    private boolean active; + +    @JsonProperty("udf") +    private Map<String, Reference> customFields; + +    private Reference campus; +    private Reference groupType; +    private Reference department; +    private Reference area; +    private Reference meetingDay; +    private Reference meetingTime; + +    public GroupSearchDocument() { +        customFields = new HashMap<>(); +    } + +    public int getId() { +        return id; +    } + +    public void setId(int id) { +        this.id = id; +    } + +    public String getName() { +        return name; +    } + +    public void setName(String name) { +        this.name = name; +    } + +    public String getDescription() { +        return description; +    } + +    public void setDescription(String description) { +        this.description = description; +    } + +    public int getLeaderId() { +        return leaderId; +    } + +    public void setLeaderId(int leaderId) { +        this.leaderId = leaderId; +    } + +    public String getLeaderName() { +        return leaderName; +    } + +    public void setLeaderName(String leaderName) { +        this.leaderName = leaderName; +    } + +    public String getLeaderEmail() { +        return leaderEmail; +    } + +    public void setLeaderEmail(String leaderEmail) { +        this.leaderEmail = leaderEmail; +    } + +    public String getImageUrl() { +        return imageUrl; +    } + +    public void setImageUrl(String imageUrl) { +        this.imageUrl = imageUrl; +    } + +    public int getCurrentMembers() { +        return currentMembers; +    } + +    public void setCurrentMembers(int currentMembers) { +        this.currentMembers = currentMembers; +    } + +    public Integer getGroupCapacity() { +        return this.groupCapacity; +    } + +    @JsonIgnore +    public boolean isGroupCapacityUnlimited() { +        return this.groupCapacity == null; +    } + +    public void setGroupCapacity(Integer groupCapacity) { +        this.groupCapacity = groupCapacity; +    } + +    public boolean isChildcareProvided() { +        return childcareProvided; +    } + +    public void setChildcareProvided(boolean childcareProvided) { +        this.childcareProvided = childcareProvided; +    } + +    public boolean isListed() { +        return listed; +    } + +    public void setListed(boolean listed) { +        this.listed = listed; +    } + +    public boolean isPublicSearchListed() { +        return publicSearchListed; +    } + +    public void setPublicSearchListed(boolean publicSearchListed) { +        this.publicSearchListed = publicSearchListed; +    } + +    public boolean isActive() { +        return active; +    } + +    public void setActive(boolean active) { +        this.active = active; +    } + +    public Reference getCampus() { +        return campus; +    } + +    public void setCampus(Reference campus) { +        this.campus = campus; +    } + +    public Reference getGroupType() { +        return groupType; +    } + +    public void setGroupType(Reference groupType) { +        this.groupType = groupType; +    } + +    public Reference getDepartment() { +        return department; +    } + +    public void setDepartment(Reference department) { +        this.department = department; +    } + +    public Reference getArea() { +        return area; +    } + +    public void setArea(Reference area) { +        this.area = area; +    } + +    public Reference getMeetingDay() { +        return meetingDay; +    } + +    public void setMeetingDay(Reference meetingDay) { +        this.meetingDay = meetingDay; +    } + +    public Reference getMeetingTime() { +        return meetingTime; +    } + +    public void setMeetingTime(Reference meetingTime) { +        this.meetingTime = meetingTime; +    } + +    public Map<String, Reference> getCustomFields() { +        return customFields; +    } + +    public void setCustomFields(Map<String, Reference> customFields) { +        this.customFields = customFields; +    } + +}
\ No newline at end of file diff --git a/src/main/java/com/p4square/groupsindexer/model/GroupSearchDocumentAdapter.java b/src/main/java/com/p4square/groupsindexer/model/GroupSearchDocumentAdapter.java new file mode 100644 index 0000000..ebe852d --- /dev/null +++ b/src/main/java/com/p4square/groupsindexer/model/GroupSearchDocumentAdapter.java @@ -0,0 +1,53 @@ +package com.p4square.groupsindexer.model; + +import com.p4square.ccbapi.model.CustomPulldownFieldValue; +import com.p4square.ccbapi.model.GroupProfile; + +import java.util.function.Function; + +/** + * GroupSearchDocumentAdapter is a function which converts a CCB {@link GroupProfile} to a {@link GroupSearchDocument}. + */ +public class GroupSearchDocumentAdapter implements Function<GroupProfile, GroupSearchDocument> { +    @Override +    public GroupSearchDocument apply(GroupProfile groupProfile) { +        final GroupSearchDocument doc = new GroupSearchDocument(); + +        doc.setId(groupProfile.getId()); +        doc.setName(groupProfile.getName()); +        doc.setDescription(groupProfile.getDescription()); +        doc.setImageUrl(groupProfile.getImageUrl()); +        doc.setLeaderId(groupProfile.getMainLeader().getId()); +        doc.setLeaderName(groupProfile.getMainLeader().getFullName()); +        doc.setLeaderEmail(groupProfile.getMainLeader().getEmail()); +        doc.setCurrentMembers(groupProfile.getCurrentMembers()); +        doc.setGroupCapacity(groupProfile.getGroupCapacity()); +        doc.setChildcareProvided(groupProfile.isChildcareProvided()); +        doc.setListed(groupProfile.isListed()); +        doc.setPublicSearchListed(groupProfile.isPublicSearchListed()); +        doc.setActive(groupProfile.isActive()); +        doc.setCampus(adaptReference(groupProfile.getCampus())); +        doc.setGroupType(adaptReference(groupProfile.getGroupType())); +        doc.setDepartment(adaptReference(groupProfile.getDepartment())); +        doc.setArea(adaptReference(groupProfile.getArea())); +        doc.setMeetingDay(adaptReference(groupProfile.getMeetingDay())); +        doc.setMeetingTime(adaptReference(groupProfile.getMeetingTime())); + +        for (final CustomPulldownFieldValue field : groupProfile.getCustomPulldownFields()) { +            final Reference ref = new Reference(); +            ref.setId(String.valueOf(field.getSelection().getId())); +            ref.setLabel(field.getSelection().getLabel()); +            doc.getCustomFields().put(field.getName(), ref); +        } + + +        return doc; +    } + +    private Reference adaptReference(com.p4square.ccbapi.model.Reference r) { +        final Reference ref = new Reference(); +        ref.setId(String.valueOf(r.getId())); +        ref.setLabel(r.getName()); +        return ref; +    } +} diff --git a/src/main/java/com/p4square/groupsindexer/model/Reference.java b/src/main/java/com/p4square/groupsindexer/model/Reference.java new file mode 100644 index 0000000..84dcc15 --- /dev/null +++ b/src/main/java/com/p4square/groupsindexer/model/Reference.java @@ -0,0 +1,28 @@ +package com.p4square.groupsindexer.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Reference { + +    @JsonProperty("id") +    private String id; + +    @JsonProperty("label") +    private String label; + +    public String getId() { +        return id; +    } + +    public void setId(String id) { +        this.id = id; +    } + +    public String getLabel() { +        return label; +    } + +    public void setLabel(String label) { +        this.label = label; +    } +} diff --git a/src/main/java/com/p4square/groupsindexer/model/SearchField.java b/src/main/java/com/p4square/groupsindexer/model/SearchField.java new file mode 100644 index 0000000..454b082 --- /dev/null +++ b/src/main/java/com/p4square/groupsindexer/model/SearchField.java @@ -0,0 +1,52 @@ +package com.p4square.groupsindexer.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +/** + * SearchField describes a pulldown field and its options. + */ +public class SearchField { + +    @JsonProperty("id") +    private String id; + +    @JsonProperty("label") +    private String label; + +    @JsonProperty("values") +    private List<StringPair> values; + +    public SearchField() { } + +    public SearchField(String id, String label, List<StringPair> values) { +        this.id = id; +        this.label = label; +        this.values = values; +    } + +    public String getId() { +        return id; +    } + +    public void setId(String id) { +        this.id = id; +    } + +    public String getLabel() { +        return label; +    } + +    public void setLabel(String label) { +        this.label = label; +    } + +    public List<StringPair> getValues() { +        return values; +    } + +    public void setValues(List<StringPair> values) { +        this.values = values; +    } +} diff --git a/src/main/java/com/p4square/groupsindexer/model/StringPair.java b/src/main/java/com/p4square/groupsindexer/model/StringPair.java new file mode 100644 index 0000000..a16040a --- /dev/null +++ b/src/main/java/com/p4square/groupsindexer/model/StringPair.java @@ -0,0 +1,32 @@ +package com.p4square.groupsindexer.model; + +/** + * A key/value pair of Strings. + */ +public class StringPair { +    private String key; +    private String value; + +    public static StringPair of(String key, String value) { +        final StringPair pair = new StringPair(); +        pair.setKey(key); +        pair.setValue(value); +        return pair; +    } + +    public String getKey() { +        return key; +    } + +    public void setKey(String key) { +        this.key = key; +    } + +    public String getValue() { +        return value; +    } + +    public void setValue(String value) { +        this.value = value; +    } +} | 
