split from api

This commit is contained in:
Brian Long 2023-10-03 10:38:14 -04:00
commit 3d31a3866f
34 changed files with 1978 additions and 0 deletions

55
.gitignore vendored Normal file
View File

@ -0,0 +1,55 @@
# These are some examples of commonly ignored file patterns.
# You should customize this list as applicable to your project.
# Learn more about .gitignore:
# https://www.atlassian.com/git/tutorials/saving-changes/gitignore
# Node artifact files
node_modules/
dist/
# Eclipse files
.settings
.project
.classpath
# Compiled Java class files
*.class
# Compiled Python bytecode
*.py[cod]
# Log files
*.log
# Package files
*.jar
# Maven
target/
dist/
# JetBrains IDE
.idea/
# Unit test reports
TEST*.xml
# Generated by MacOS
.DS_Store
# Generated by Windows
Thumbs.db
# Applications
*.app
*.exe
*.war
# Large media files
*.mp4
*.tiff
*.avi
*.flv
*.mov
*.wmv

146
pom.xml Normal file
View File

@ -0,0 +1,146 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.poststats</groupId>
<artifactId>poststats-rs-api</artifactId>
<version>2.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.release>11</maven.compiler.release>
<maven.compiler.debug>true</maven.compiler.debug>
<maven.compiler.debuglevel>lines,vars,source</maven.compiler.debuglevel>
<formatter.excludes>**/*Api.java</formatter.excludes>
<swagger.version>2.2.8</swagger.version>
</properties>
<dependencies>
<dependency>
<groupId>com.poststats</groupId>
<artifactId>poststats-core</artifactId>
<version>2.0-SNAPSHOT</version>
</dependency>
<!-- adds JAX-RS support (REST services) -->
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<version>3.1.0</version>
</dependency>
<!-- adds Servlet support -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
</dependency>
<!-- adds CDI support -->
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>jakarta.transaction</groupId>
<artifactId>jakarta.transaction-api</artifactId>
<version>2.0.1</version>
</dependency>
<!-- adds EJB support -->
<dependency>
<groupId>jakarta.ejb</groupId>
<artifactId>jakarta.ejb-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- adds JavaTime support for JSON (de)serialization -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.13.4</version>
</dependency>
<!-- adds multi-part support -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-multipart-provider</artifactId>
<version>6.2.1.Final</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations-jakarta</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-meta</artifactId>
<version>6.4.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.20.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-maven-plugin-jakarta</artifactId>
<version>${swagger.version}</version>
<configuration>
<resourcePackages>
<resourcePackage>com.poststats.api</resourcePackage>
</resourcePackages>
<outputPath>${project.build.outputDirectory}/META-INF</outputPath>
<outputFileName>poststats-swagger</outputFileName>
<outputFormat>JSONANDYAML</outputFormat>
<prettyPrint>true</prettyPrint>
</configuration>
<executions>
<execution>
<id>swagger-generate</id>
<goals>
<goal>resolve</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>io.repaint.maven</groupId>
<artifactId>tiles-maven-plugin</artifactId>
<version>2.33</version>
<extensions>true</extensions>
<configuration>
<tiles>
<tile>com.poststats:source-format-tile:[1.0.0,1.1.0)</tile>
</tiles>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,25 @@
package com.poststats.rs.api;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.info.Contact;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import jakarta.ws.rs.Path;
/**
* @author brian.long@poststats.com
*/
@Path("/")
@OpenAPIDefinition(
info = @Info(
contact = @Contact(name = "Brian Long", email = "brian.long@poststats.com"),
title = "PostStats API",
description = "An API providing access to PostStats objects.",
version = "v1"
)
)
@SecurityScheme(name = "basic", type = SecuritySchemeType.HTTP, scheme = "BASIC")
public interface BaseApi {
}

View File

@ -0,0 +1,16 @@
package com.poststats.rs.api;
public class Constants {
public static final String V1_JSON = "application/vnd.poststats-v1+json";
public static final String ADMIN_ROLE = "admin";
public static final String AUTH_ROLE = "auth";
public static final String MANAGER_ROLE = "owner";
public static final String MANAGER_ROLE_PREFIX = MANAGER_ROLE
+ ":";
public static final String FACILITY_ROLE_PREFIX = "facility:";
public static final String PERSON_ID = "personId";
public static final String FACILITY_ID = "facilityId";
}

View File

@ -0,0 +1,78 @@
package com.poststats.rs.api;
import java.util.List;
import com.poststats.rs.api.model.Facility;
import com.poststats.rs.api.model.PagedCollection;
import com.poststats.rs.api.model.Pagination;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.Size;
import jakarta.ws.rs.BeanParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
/**
* @author brian.long@poststats.com
*/
@Path("/facilities")
@Tag(name = "Facility API")
@Produces({ MediaType.APPLICATION_JSON, Constants.V1_JSON })
@ApiResponse(responseCode = "200", description = "Success", content = {
@Content(mediaType = MediaType.APPLICATION_JSON),
@Content(mediaType = Constants.V1_JSON)
})
@ApiResponse(responseCode = "400", description = "A request parameter is not valid")
@ApiResponse(responseCode = "404", description = "No matching facilities were found")
public interface FacilitiesApi {
@GET
@Path("/byName")
@Operation(summary = "Searches for facilities by their name.", description = "Searches for facilities by their name, excluding prefix (e.g. The) and suffix (e.g. Golf Club), returning limited meta-data about each matched facility.")
@Tag(name = "Search API")
PagedCollection<List<Facility>> searchByName(
@Parameter(description = "A fragment or whole facility name; the prefix and suffix are not included", example = "Bushwood") @QueryParam("name") @NotNull @Size(min = 3) String name,
@BeanParam @Valid Pagination paging);
@GET
@Path("/byLocation/{country}")
@Operation(summary = "Searches for facilities by their location.", description = "Searches for facilities by their country, returning limited meta-data about each matched facility.")
@Tag(name = "Search API")
PagedCollection<List<Facility>> searchByJurisdiction(
@Parameter(description = "A country code", example = "US") @PathParam("country") @NotNull String country,
@BeanParam @Valid Pagination paging);
@GET
@Path("/byLocation/{country}/{state}")
@Operation(summary = "Searches for facilities by their location.", description = "Searches for facilities by their major jurisdiction (e.g. US States), returning limited meta-data about each matched facility.")
@Tag(name = "Search API")
PagedCollection<List<Facility>> searchByJurisdiction(
@Parameter(description = "A country code", example = "US") @PathParam("country") @NotNull String country,
@Parameter(description = "A State or high-level jurisdiction", example = "FL") @PathParam("state") @NotNull String state,
@BeanParam @Valid Pagination paging);
@GET
@Path("/byGeo")
@Operation(summary = "Searches for facilities by their location.", description = "Searches for facilities by their major jurisdiction (e.g. US States), returning limited meta-data about each matched facility.")
@Tag(name = "Search API")
PagedCollection<List<Facility>> searchByJurisdiction(
@Parameter(description = "A latitude in decimal degrees", example = "41.2390") @QueryParam("latitude") @NotNull @DecimalMin("-90.0") @DecimalMax("90.0") double latitude,
@Parameter(description = "A longitude in decimal degrees", example = "-81.34891") @QueryParam("longitude") @NotNull @DecimalMin("-180.0") @DecimalMax("180.0") double longitude,
@Parameter(name = "radius", description = "A search radius in miles", example = "15") @QueryParam("radius") @Positive @Max(100) Integer radiusInMiles,
@BeanParam @Valid Pagination paging);
}

View File

@ -0,0 +1,41 @@
package com.poststats.rs.api;
import com.poststats.rs.api.model.Facility;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.enterprise.context.RequestScoped;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
/**
* @author brian.long@poststats.com
*/
@RequestScoped
@Path("/facility/{facilityId}")
@Tag(name = "Facility API")
@Produces({MediaType.APPLICATION_JSON, Constants.V1_JSON})
@ApiResponse(responseCode = "200", description = "Success", content = {
@Content(mediaType = MediaType.APPLICATION_JSON),
@Content(mediaType = Constants.V1_JSON)
})
@ApiResponse(responseCode = "400", description = "A request parameter is not valid")
@ApiResponse(responseCode = "404", description = "No matching facility was found")
public interface FacilityApi {
@GET
@Operation(
summary = "Retrieves limited meta-data about a facility.",
description = "Retreives name, location, and other direct meta-data about the specified facility."
)
Facility get(@Parameter(description = "A unique identifier for a facility") @NotNull @Positive @PathParam("facilityId") int facilityId);
}

View File

@ -0,0 +1,66 @@
package com.poststats.rs.api;
import java.io.InputStream;
import java.math.BigInteger;
import org.apache.http.HttpHeaders;
import com.poststats.rs.api.model.Person;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
/**
* @author brian.long@poststats.com
*/
@Path("/person/{personId}")
@Tag(name = "Person API")
@Produces({MediaType.APPLICATION_JSON, Constants.V1_JSON})
@ApiResponse(responseCode = "200", description = "Success", content = {
@Content(mediaType = MediaType.APPLICATION_JSON),
@Content(mediaType = Constants.V1_JSON)
})
@ApiResponse(responseCode = "400", description = "A request parameter is not valid")
@ApiResponse(responseCode = "404", description = "No matching person was found")
public interface PersonApi {
@GET
@Produces(Constants.V1_JSON)
@Operation(
summary = "Retrieves limited meta-data about a person.",
description = "Retreives name, location, contact, and other direct meta-data about the specified registered person."
)
Person get(@Parameter(description = "A unique identifier for a person")
@NotNull @Positive @PathParam("personId") long personId);
@Path("/photo")
@POST
@Consumes({"image/png", "image/jpeg"})
@Produces(Constants.V1_JSON)
@Operation(
summary = "Stores a photo of a person.",
description = "Auto-crops, scales, and stores the specified profile photo and associates the photo to the specified person."
)
@RolesAllowed({Constants.ADMIN_ROLE, Constants.MANAGER_ROLE})
@SecurityRequirement(name = "basic")
BigInteger uploadProfilePhoto(@Parameter(description = "A unique identifier for a person")
@NotNull @Positive @PathParam("personId") long personId,
@Parameter(hidden = true) @HeaderParam(HttpHeaders.CONTENT_TYPE) String contentType,
@Parameter(description = "A file of the photo") @NotNull InputStream istream);
}

View File

@ -0,0 +1,109 @@
package com.poststats.rs.api;
import java.math.BigInteger;
import org.jboss.resteasy.annotations.cache.Cache;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
import com.poststats.rs.api.model.Photo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Encoding;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
import io.swagger.v3.oas.annotations.media.SchemaProperty;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
/**
* @author brian.long@poststats.com
*/
@Path("/photo")
@Tag(name = "Photo API")
@Produces({MediaType.APPLICATION_JSON, Constants.V1_JSON})
@ApiResponse(responseCode = "200", description = "Success", content = {
@Content(mediaType = MediaType.APPLICATION_JSON),
@Content(mediaType = Constants.V1_JSON)
})
@ApiResponse(responseCode = "400", description = "A request parameter is not valid")
@ApiResponse(responseCode = "404", description = "No matching photo was found")
public interface PhotoApi {
@GET
@Path("/{photoId}/metadata")
@Cache(isPrivate = true, maxAge = 60)
@Operation(
summary = "Retrieves limited meta-data about a photo.",
description = "Retreives type, size, and other direct meta-data about the specified photo."
)
Photo get(
@Parameter(description = "A unique identifier for a photo")
@PathParam("photoId") @NotNull @Positive BigInteger photoId);
@GET
@Path("/{photoId}")
@Produces({"image/png", "image/jpeg"})
@Cache(maxAge = 864000)
@Operation(summary = "Retrieves the binary stream of a photo.")
@ApiResponse(responseCode = "200", description = "Success")
Response getStream(
@Parameter(description = "A unique identifier for a photo")
@PathParam("photoId") @NotNull @Positive BigInteger photoId);
@GET
@Path("/{photoId}/thumbnail")
@Produces({"image/png", "image/jpeg"})
@Cache(maxAge = 864000)
@Operation(summary = "Retrieves the binary stream of the thumbnail of a photo.")
@ApiResponse(responseCode = "200", description = "Success")
Response getThumbnailStream(
@Parameter(description = "A unique identifier for a photo")
@PathParam("photoId") @NotNull @Positive BigInteger photoId);
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Operation(
summary = "Stores a photo and associates it to any other object.",
description = "Auto-crops, scales, and stores a photo and associates it to facilities, courses, persons, events, and event series.",
requestBody = @RequestBody(content = @Content(
mediaType = MediaType.MULTIPART_FORM_DATA,
schemaProperties = {
@SchemaProperty(name = "file", schema = @Schema(type = "string", format = "base64", requiredMode = RequiredMode.REQUIRED)),
@SchemaProperty(name = "photo", schema = @Schema(type = "string", requiredMode = RequiredMode.REQUIRED))
},
encoding = {
@Encoding(name = "file", contentType = "image/png, image/jpeg"),
@Encoding(name = "photo", contentType = MediaType.APPLICATION_JSON + ", " + Constants.V1_JSON)
}
)),
parameters = {
@Parameter(name = "photo", description = "JSON meta-data associated with the uploaded photo", content = {
@Content(mediaType = MediaType.APPLICATION_JSON),
@Content(mediaType = Constants.V1_JSON)
}),
@Parameter(name = "file", content = {
@Content(mediaType = "image/png"),
@Content(mediaType = "image/jpeg")
})
}
)
@RolesAllowed("member")
@SecurityRequirement(name = "basic")
BigInteger uploadPhoto(MultipartFormDataInput multipart);
}

View File

@ -0,0 +1,23 @@
package com.poststats.rs.api;
import org.telegram.telegrambots.meta.api.objects.Update;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.transaction.Transactional;
import jakarta.transaction.Transactional.TxType;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.MediaType;
@Path("/telegram/webhook")
@Hidden
public interface TelegramWebhookApi {
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Transactional(TxType.REQUIRED)
void update(@HeaderParam("X-Telegram-Bot-Api-Secret-Token") String secret, final Update update);
}

View File

@ -0,0 +1,16 @@
package com.poststats.rs.api.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({
ElementType.FIELD, ElementType.METHOD
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GeocodeSource {
}

View File

@ -0,0 +1,20 @@
package com.poststats.rs.api.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({
ElementType.FIELD
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GeocodeTarget {
public enum GeocodeField { AddressLines, City, State, Country, PostalCode, FullPostalAddress, FuzzyPostalAddress }
GeocodeField value();
}

View File

@ -0,0 +1,49 @@
package com.poststats.rs.api.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Repeatable(MapConditions.class)
@Target({
ElementType.FIELD
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MapCondition {
/**
* This condition evaluates to true if not set (`null`) or the specified named
* `@MapEntry` value evaluates to boolean `true`, numeric non-zero, or any other
* not-`null` `Object`. If the specified `@MapEntry` does not exist, it returns
* `false`.
*/
String mapEntry() default "";
/**
* This condition evaluates to true if not set (`null`) or the specified field
* evaluates to boolean `true`, numeric non-zero, or any other not-`null`
* `Object`. If the specified field does not exist, an
* `IllegalArgumentException` is thrown.
*/
String field() default "";
/**
* This condition evaluates to true if not set (`null`) or the specified
* no-argument method return value evaluates to boolean `true`, numeric
* non-zero, or any other not-`null` `Object`. If the specified no-argument
* method does not exist, an `IllegalArgumentException` is thrown.
*/
String method() default "";
/**
* This condition evaluates to `true` if not set (`null`) or one of the
* specified roles returns `true` in the SecurityContext.isUserInRole(). If
* there is no SecurityContext, it returns `false`.
*/
String[] rolesAllowed() default {};
}

View File

@ -0,0 +1,18 @@
package com.poststats.rs.api.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({
ElementType.FIELD
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MapConditions {
MapCondition[] value();
}

View File

@ -0,0 +1,18 @@
package com.poststats.rs.api.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({
ElementType.FIELD
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MapEntry {
String value() default "";
}

View File

@ -0,0 +1,129 @@
package com.poststats.rs.api.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.poststats.rs.api.annotation.MapEntry;
/**
* @author brian.long@poststats.com
*/
public abstract class BaseFacility<ConcreteT extends BaseFacility<ConcreteT>> extends BaseModel<ConcreteT> {
@JsonProperty(required = true)
@MapEntry("facility")
private String name;
@JsonProperty()
@MapEntry("prefix")
private String namePrefix;
@JsonProperty(required = true)
@MapEntry("suffix")
private String nameSuffix;
@JsonProperty(required = true)
private String postalAddress;
@JsonProperty
@MapEntry("www")
private String webAddress;
@JsonProperty
@MapEntry("contact")
private String contact;
@JsonProperty
@MapEntry("phone1")
private String phoneNumber;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNamePrefix() {
return namePrefix;
}
public void setNamePrefix(String namePrefix) {
this.namePrefix = namePrefix;
}
public String getNameSuffix() {
return nameSuffix;
}
public void setNameSuffix(String nameSuffix) {
this.nameSuffix = nameSuffix;
}
public String getPostalAddress() {
return postalAddress;
}
public void setPostalAddress(String postalAddress) {
this.postalAddress = postalAddress;
}
public String getWebAddress() {
return webAddress;
}
public void setWebAddress(String webAddress) {
this.webAddress = webAddress;
}
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public ConcreteT withName(String name) {
this.name = name;
return this.withThis();
}
public ConcreteT withNamePrefix(String prefix) {
this.namePrefix = prefix;
return this.withThis();
}
public ConcreteT withNameSuffix(String suffix) {
this.nameSuffix = suffix;
return this.withThis();
}
public ConcreteT withPostalAddress(String postalAddress) {
this.postalAddress = postalAddress;
return this.withThis();
}
public ConcreteT withWebAddress(String webAddress) {
this.webAddress = webAddress;
return this.withThis();
}
public ConcreteT withContact(String contact) {
this.contact = contact;
return this.withThis();
}
public ConcreteT withPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
return this.withThis();
}
}

View File

@ -0,0 +1,13 @@
package com.poststats.rs.api.model;
/**
* @author brian.long@poststats.com
*/
public abstract class BaseModel<ConcreteT extends BaseModel<ConcreteT>> {
@SuppressWarnings("unchecked")
protected ConcreteT withThis() {
return (ConcreteT) this;
}
}

View File

@ -0,0 +1,275 @@
package com.poststats.rs.api.model;
import java.time.LocalDate;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.poststats.rs.api.Constants;
import com.poststats.rs.api.annotation.GeocodeTarget;
import com.poststats.rs.api.annotation.GeocodeTarget.GeocodeField;
import com.poststats.rs.api.annotation.MapCondition;
import com.poststats.rs.api.annotation.MapEntry;
/**
* @author brian.long@poststats.com
*/
public abstract class BasePerson<ConcreteT extends BasePerson<ConcreteT>> extends BaseModel<ConcreteT> {
@JsonProperty
@MapEntry("prefix")
private String salutation;
@JsonProperty(required = true)
@MapEntry("fname")
private String firstName;
@JsonProperty(required = true)
@MapEntry("lname")
private String lastName;
@JsonProperty
@MapEntry("suffix")
private String suffix;
@JsonProperty
@GeocodeTarget(GeocodeField.FullPostalAddress)
private String postalAddress;
@JsonProperty
@MapEntry("email")
@MapCondition(rolesAllowed = {
Constants.ADMIN_ROLE, Constants.MANAGER_ROLE, "event:admin", "event:finance", "event:membership"
})
@MapCondition(rolesAllowed = {
"buddy"
}, method = "doShowEmailAddress")
private String emailAddress;
@JsonProperty
@MapEntry("cellphone")
@MapCondition(rolesAllowed = {
Constants.ADMIN_ROLE, Constants.MANAGER_ROLE, "event:admin", "event:finance", "event:membership"
})
@MapCondition(rolesAllowed = {
"buddy"
}, method = "doShowPhoneNumber")
private String mobilePhoneNumber;
@JsonProperty
@MapEntry("birth")
@MapCondition(rolesAllowed = {
Constants.ADMIN_ROLE, Constants.MANAGER_ROLE
})
@MapCondition(rolesAllowed = {
"buddy"
}, method = "doShowBirthYear")
private LocalDate birth;
@JsonProperty
@MapEntry("gender")
private Character gender;
@JsonProperty
@MapEntry("height")
private Short height;
@JsonProperty
@MapEntry("weight")
private Integer weight;
@JsonProperty
@MapEntry("occupation")
private String occupation;
@JsonProperty
@MapEntry("healthSetback")
@MapCondition(rolesAllowed = {
Constants.ADMIN_ROLE, Constants.MANAGER_ROLE
})
private LocalDate healthSetback;
public String getSalutation() {
return salutation;
}
public void setSalutation(String salutation) {
this.salutation = salutation;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
public String getPostalAddress() {
return postalAddress;
}
public void setPostalAddress(String postalAddress) {
this.postalAddress = postalAddress;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getMobilePhoneNumber() {
return mobilePhoneNumber;
}
public void setMobilePhoneNumber(String mobilePhoneNumber) {
this.mobilePhoneNumber = mobilePhoneNumber;
}
public LocalDate getBirth() {
return birth;
}
public void setBirth(LocalDate birth) {
this.birth = birth;
}
public Character getGender() {
return gender;
}
public void setGender(Character gender) {
this.gender = gender;
}
public Short getHeight() {
return height;
}
public void setHeight(Short height) {
this.height = height;
}
public Integer getWeight() {
return weight;
}
public void setWeight(Integer weight) {
this.weight = weight;
}
public String getOccupation() {
return occupation;
}
public void setOccupation(String occupation) {
this.occupation = occupation;
}
public LocalDate getHealthSetback() {
return healthSetback;
}
public void setHealthSetback(LocalDate healthSetback) {
this.healthSetback = healthSetback;
}
public ConcreteT withSalutation(String salutation) {
this.salutation = salutation;
return this.withThis();
}
public ConcreteT withFirstName(String firstName) {
this.firstName = firstName;
return this.withThis();
}
public ConcreteT withLastName(String lastName) {
this.lastName = lastName;
return this.withThis();
}
public ConcreteT withSuffix(String suffix) {
this.suffix = suffix;
return this.withThis();
}
public ConcreteT withPostalAddress(String postalAddress) {
this.postalAddress = postalAddress;
return this.withThis();
}
public ConcreteT withEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
return this.withThis();
}
public ConcreteT withMobilePhoneNumber(String mobilePhoneNumber) {
this.mobilePhoneNumber = mobilePhoneNumber;
return this.withThis();
}
public ConcreteT withBirth(LocalDate birth) {
this.birth = birth;
return this.withThis();
}
public ConcreteT withGender(Character gender) {
this.gender = gender;
return this.withThis();
}
public ConcreteT withHeight(Short height) {
this.height = height;
return this.withThis();
}
public ConcreteT withWeight(Integer weight) {
this.weight = weight;
return this.withThis();
}
public ConcreteT withOccupation(String occupation) {
this.occupation = occupation;
return this.withThis();
}
public ConcreteT withHealthSetback(LocalDate healthSetback) {
this.healthSetback = healthSetback;
return this.withThis();
}
boolean doShowEmailAddress() {
return true;
}
boolean doShowPostalAddress() {
return true;
}
boolean doShowPhoneNumber() {
return true;
}
boolean doShowBirthYear() {
return true;
}
}

View File

@ -0,0 +1,125 @@
package com.poststats.rs.api.model;
import java.util.LinkedList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.poststats.rs.api.annotation.MapEntry;
/**
* @author brian.long@poststats.com
*/
public abstract class BasePhoto<ConcreteT extends BasePhoto<ConcreteT>> extends BaseModel<ConcreteT> {
public enum Type {
@JsonProperty("profile")
@MapEntry("profile")
Profile,
@JsonProperty("nearly-square")
@MapEntry("nearly-square")
NearlySquare,
@JsonProperty("vertical")
@MapEntry("vertical")
Vertical,
@JsonProperty("horizontal")
@MapEntry("horizontal")
Horizontal,
@JsonProperty("logo")
@MapEntry("logo")
Logo,
@JsonProperty("banner")
@MapEntry("banner")
Banner,
@JsonProperty("full")
@MapEntry("full")
Full
}
@JsonProperty(required = true)
@MapEntry("photoSizeSID")
private Type type;
@JsonProperty
@MapEntry("title")
private String caption;
@JsonProperty
@MapEntry
private String description;
@JsonProperty
private List<Integer> facilityIds;
@JsonProperty
private List<Long> personIds;
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public String getCaption() {
return caption;
}
public void setCaption(String caption) {
this.caption = caption;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<Integer> getFacilityIds() {
return facilityIds;
}
public void setFacilityIds(List<Integer> facilityIds) {
this.facilityIds = facilityIds;
}
public List<Long> getPersonIds() {
return personIds;
}
public void setPersonIds(List<Long> personIds) {
this.personIds = personIds;
}
public ConcreteT withType(Type type) {
this.type = type;
return this.withThis();
}
public ConcreteT withCaption(String caption) {
this.caption = caption;
return this.withThis();
}
public ConcreteT withDescription(String description) {
this.description = description;
return this.withThis();
}
public ConcreteT withFacilityId(int facilityId) {
if (this.facilityIds == null)
this.facilityIds = new LinkedList<>();
this.facilityIds.add(facilityId);
return this.withThis();
}
public ConcreteT withPersonId(long personId) {
if (this.personIds == null)
this.personIds = new LinkedList<>();
this.personIds.add(personId);
return this.withThis();
}
}

View File

@ -0,0 +1,147 @@
package com.poststats.rs.api.model;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;
import com.poststats.rs.api.Constants;
import com.poststats.rs.api.annotation.GeocodeSource;
import com.poststats.rs.api.annotation.GeocodeTarget;
import com.poststats.rs.api.annotation.GeocodeTarget.GeocodeField;
import com.poststats.rs.api.annotation.MapCondition;
import com.poststats.rs.api.annotation.MapEntry;
/**
* @author brian.long@poststats.com
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class Facility extends BaseFacility<Facility> implements ReferenceableFacility, PeriodConstrainable<LocalDate> {
@JsonProperty(required = true, access = Access.READ_ONLY)
@MapEntry("facilityID")
private int id;
@JsonProperty(required = true)
@MapEntry("suffixAbbrev")
private String nameSuffixAbbrev;
@MapEntry
@GeocodeTarget(GeocodeField.AddressLines)
private String addrlines;
@MapEntry
@GeocodeTarget(GeocodeField.City)
private String addrcity;
@MapEntry
@GeocodeTarget(GeocodeField.State)
private String addrstate;
@MapEntry
@GeocodeTarget(GeocodeField.Country)
private String addrcountry;
@MapEntry
@GeocodeTarget(GeocodeField.PostalCode)
private String addrzip;
@JsonProperty
@MapEntry("liveline")
@MapCondition(rolesAllowed = {
Constants.ADMIN_ROLE, "course"
})
private LocalDate liveline;
@JsonProperty
@MapEntry("deadline")
@MapCondition(rolesAllowed = {
Constants.ADMIN_ROLE, "course"
})
private LocalDate deadline;
@JsonProperty(access = Access.READ_ONLY)
@MapEntry("created")
@MapCondition(rolesAllowed = {
Constants.ADMIN_ROLE, "course"
})
private OffsetDateTime created;
@Override
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNameSuffixAbbrev() {
return nameSuffixAbbrev;
}
public void setNameSuffixAbbrev(String nameSuffixAbbrev) {
this.nameSuffixAbbrev = nameSuffixAbbrev;
}
@Override
@GeocodeSource
public String getPostalAddress() {
return super.getPostalAddress();
}
@Override
public LocalDate getLiveline() {
return liveline;
}
@Override
public void setLiveline(LocalDate liveline) {
this.liveline = liveline;
}
@Override
public LocalDate getDeadline() {
return deadline;
}
@Override
public void setDeadline(LocalDate deadline) {
this.deadline = deadline;
}
public OffsetDateTime getCreated() {
return created;
}
public void setCreated(OffsetDateTime created) {
this.created = created;
}
public Facility withId(int id) {
this.id = id;
return this;
}
public Facility withNameSuffixAbbrev(String suffixAbbrev) {
this.nameSuffixAbbrev = suffixAbbrev;
return this;
}
public Facility withLiveline(LocalDate liveline) {
this.liveline = liveline;
return this;
}
public Facility withDeadline(LocalDate deadline) {
this.deadline = deadline;
return this;
}
public Facility withCreated(OffsetDateTime created) {
this.created = created;
return this;
}
}

View File

@ -0,0 +1,85 @@
package com.poststats.rs.api.model;
import java.util.Collection;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown = true)
public class PagedCollection<T extends Collection<?>> {
@JsonProperty
private short page;
@JsonProperty
private short perPage;
@JsonProperty
private long totalResults;
@JsonProperty
private T collection;
public short getPage() {
return page;
}
public void setPage(short page) {
this.page = page;
}
public short getPerPage() {
return perPage;
}
public void setPerPage(short perPage) {
this.perPage = perPage;
}
public long getTotalResults() {
return totalResults;
}
public void setTotalResults(long totalResults) {
this.totalResults = totalResults;
}
@JsonProperty("collectionResults")
public int getResults() {
return this.collection == null ? 0 : this.collection.size();
}
@JsonProperty("hasMoreResults")
public boolean hasMore() {
return this.totalResults > ((this.page - 1) * this.perPage + this.getResults());
}
public T getCollection() {
return collection;
}
public void setCollection(T collection) {
this.collection = collection;
}
public PagedCollection<T> withPage(short page) {
this.page = page;
return this;
}
public PagedCollection<T> withPerPage(short perPage) {
this.perPage = perPage;
return this;
}
public PagedCollection<T> withTotalResults(long totalResults) {
this.totalResults = totalResults;
return this;
}
public PagedCollection<T> withCollection(T collection) {
this.collection = collection;
return this;
}
}

View File

@ -0,0 +1,50 @@
package com.poststats.rs.api.model;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Positive;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.QueryParam;
public class Pagination {
@Parameter(description = "A page number, starting at the default of 1")
@QueryParam("page")
@DefaultValue("1")
@Positive
private short page;
@Parameter(description = "A number of results per page, starting at 1; the default is 20")
@QueryParam("perPage")
@DefaultValue("20")
@Positive
@Max(value = 100)
private short perPage;
public short getPage() {
return page;
}
public void setPage(short page) {
this.page = page;
}
public short getPerPage() {
return perPage;
}
public void setPerPage(short perPage) {
this.perPage = perPage;
}
public Pagination withPage(short page) {
this.page = page;
return this;
}
public Pagination withPerPage(short perPage) {
this.perPage = perPage;
return this;
}
}

View File

@ -0,0 +1,15 @@
package com.poststats.rs.api.model;
import java.time.temporal.TemporalAccessor;
public interface PeriodConstrainable<T extends TemporalAccessor> {
T getLiveline();
void setLiveline(T liveline);
T getDeadline();
void setDeadline(T deadline);
}

View File

@ -0,0 +1,153 @@
package com.poststats.rs.api.model;
import java.time.MonthDay;
import java.time.OffsetDateTime;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;
import com.poststats.rs.api.Constants;
import com.poststats.rs.api.annotation.GeocodeSource;
import com.poststats.rs.api.annotation.GeocodeTarget;
import com.poststats.rs.api.annotation.GeocodeTarget.GeocodeField;
import com.poststats.rs.api.annotation.MapCondition;
import com.poststats.rs.api.annotation.MapEntry;
/**
* @author brian.long@poststats.com
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class Person extends BasePerson<Person> implements ReferenceablePerson {
@JsonProperty(required = true, access = Access.READ_ONLY)
@MapEntry("personID")
private long id;
@JsonProperty
private String fuzzyLocation;
@MapEntry
@MapCondition(rolesAllowed = {
Constants.ADMIN_ROLE, Constants.MANAGER_ROLE, "event:admin", "event:finance", "event:membership"
})
@MapCondition(rolesAllowed = {
"buddy"
}, method = "doShowPostalAddress")
@GeocodeTarget(GeocodeField.AddressLines)
private String addrlines;
@MapEntry
@GeocodeTarget(GeocodeField.City)
private String addrcity;
@MapEntry
@GeocodeTarget(GeocodeField.State)
private String addrstate;
@MapEntry
@GeocodeTarget(GeocodeField.Country)
private String addrcountry;
@MapEntry
@MapCondition(rolesAllowed = {
Constants.ADMIN_ROLE, Constants.MANAGER_ROLE, "event:admin", "event:finance", "event:membership"
})
@MapCondition(rolesAllowed = {
"buddy"
}, method = "doShowPostalAddress")
@GeocodeTarget(GeocodeField.PostalCode)
private String addrzip;
@MapEntry
@GeocodeTarget(GeocodeField.FuzzyPostalAddress)
private String addrfuzzy;
@MapEntry
private Boolean hideEmail = true;
@MapEntry
private Boolean hidePhone = true;
@MapEntry
protected Boolean hideAddress = true;
@MapEntry
protected Boolean hideBirthYear = true;
@JsonProperty(access = Access.READ_ONLY)
@MapEntry("birth")
@MapCondition(rolesAllowed = {
Constants.AUTH_ROLE
})
private MonthDay birthDay;
@JsonProperty(access = Access.READ_ONLY)
@MapCondition(rolesAllowed = {
Constants.ADMIN_ROLE, Constants.MANAGER_ROLE
})
@MapEntry
private OffsetDateTime created;
@Override
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@JsonProperty(access = Access.READ_ONLY)
public String getFuzzyLocation() {
return this.addrfuzzy;
}
@Override
@GeocodeSource
public String getPostalAddress() {
return super.getPostalAddress();
}
public MonthDay getBirthDay() {
return birthDay;
}
public OffsetDateTime getCreated() {
return created;
}
public void setCreated(OffsetDateTime created) {
this.created = created;
}
public Person withId(long id) {
this.id = id;
return this;
}
public Person withCreated(OffsetDateTime created) {
this.created = created;
return this;
}
@Override
boolean doShowPostalAddress() {
return Boolean.FALSE.equals(this.hideAddress);
}
@Override
boolean doShowEmailAddress() {
return Boolean.FALSE.equals(this.hideEmail);
}
@Override
boolean doShowPhoneNumber() {
return Boolean.FALSE.equals(this.hidePhone);
}
@Override
boolean doShowBirthYear() {
return Boolean.FALSE.equals(this.hideBirthYear);
}
}

View File

@ -0,0 +1,128 @@
package com.poststats.rs.api.model;
import java.math.BigInteger;
import java.time.OffsetDateTime;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;
import com.poststats.rs.api.annotation.MapEntry;
/**
* @author brian.long@poststats.com
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class Photo extends BasePhoto<Photo> implements ReferenceablePhoto {
@JsonProperty(required = true, access = Access.READ_ONLY)
@MapEntry("photoID")
private BigInteger id;
@JsonProperty
@MapEntry
private String title;
@JsonProperty
@MapEntry
private String description;
@JsonProperty
@MapEntry("mimetype")
private String mimeType;
@JsonProperty
@MapEntry("bytes")
private long size;
@JsonProperty
@MapEntry
private boolean approved;
@JsonProperty
@MapEntry
private boolean disabled;
@JsonProperty
@MapEntry
private OffsetDateTime created;
@Override
public BigInteger getId() {
return id;
}
public void setId(BigInteger id) {
this.id = id;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public boolean isApproved() {
return approved;
}
public void setApproved(boolean approved) {
this.approved = approved;
}
public boolean isDisabled() {
return disabled;
}
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
public OffsetDateTime getCreated() {
return created;
}
public void setCreated(OffsetDateTime created) {
this.created = created;
}
public Photo withId(BigInteger id) {
this.id = id;
return this;
}
public Photo withMimeType(String mimeType) {
this.mimeType = mimeType;
return this;
}
public Photo withSize(long size) {
this.size = size;
return this;
}
public Photo withApproved(boolean approved) {
this.approved = approved;
return this;
}
public Photo withDisabled(boolean disabled) {
this.disabled = disabled;
return this;
}
public Photo withCreated(OffsetDateTime created) {
this.created = created;
return this;
}
}

View File

@ -0,0 +1,7 @@
package com.poststats.rs.api.model;
public interface ReferenceableFacility {
int getId();
}

View File

@ -0,0 +1,7 @@
package com.poststats.rs.api.model;
public interface ReferenceablePerson {
long getId();
}

View File

@ -0,0 +1,9 @@
package com.poststats.rs.api.model;
import java.math.BigInteger;
public interface ReferenceablePhoto {
BigInteger getId();
}

View File

@ -0,0 +1,32 @@
package com.poststats.rs.api.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;
import com.poststats.rs.api.annotation.MapEntry;
/**
* @author brian.long@poststats.com
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class ReferencedFacility implements ReferenceableFacility {
@JsonProperty(required = true, access = Access.READ_ONLY)
@MapEntry("facilityID")
private int id;
@Override
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public ReferencedFacility withId(int id) {
this.id = id;
return this;
}
}

View File

@ -0,0 +1,32 @@
package com.poststats.rs.api.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;
import com.poststats.rs.api.annotation.MapEntry;
/**
* @author brian.long@poststats.com
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class ReferencedPerson implements ReferenceablePerson {
@JsonProperty(required = true, access = Access.READ_ONLY)
@MapEntry("personID")
private long id;
@Override
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public ReferencedPerson withId(long id) {
this.id = id;
return this;
}
}

View File

@ -0,0 +1,34 @@
package com.poststats.rs.api.model;
import java.math.BigInteger;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;
import com.poststats.rs.api.annotation.MapEntry;
/**
* @author brian.long@poststats.com
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class ReferencedPhoto implements ReferenceablePhoto {
@JsonProperty(required = true, access = Access.READ_ONLY)
@MapEntry("photoID")
private BigInteger id;
@Override
public BigInteger getId() {
return id;
}
public void setId(BigInteger id) {
this.id = id;
}
public ReferencedPhoto withId(BigInteger id) {
this.id = id;
return this;
}
}

View File

@ -0,0 +1,11 @@
package com.poststats.rs.api.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* @author brian.long@poststats.com
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class TransientFacility extends BaseFacility<TransientFacility> {
}

View File

@ -0,0 +1,11 @@
package com.poststats.rs.api.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* @author brian.long@poststats.com
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class TransientPerson extends BasePerson<TransientPerson> {
}

View File

@ -0,0 +1,11 @@
package com.poststats.rs.api.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* @author brian.long@poststats.com
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class TransientPhoto extends BasePhoto<TransientPhoto> {
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Configuration
xmlns="http://logging.apache.org/log4j/2.0/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://logging.apache.org/log4j/2.0/config https://raw.githubusercontent.com/apache/logging-log4j2/2.x/log4j-core/src/main/resources/Log4j-config.xsd">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p %c{1} - %m%n" />
</Console>
<Async name="async">
<AppenderRef ref="console" />
</Async>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="async" />
</Root>
<Logger name="com.inteligr8" level="debug" />
<Logger name="com.poststats" level="trace" />
</Loggers>
</Configuration>