split api/impl; v2.x
This commit is contained in:
16
pom.xml
16
pom.xml
@@ -2,8 +2,8 @@
|
||||
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.golf</groupId>
|
||||
<artifactId>golf-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<artifactId>golf-rs-api</artifactId>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
@@ -40,10 +40,20 @@
|
||||
<version>5.9.2</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>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-maven-plugin-jakarta</artifactId>
|
||||
|
@@ -1,73 +0,0 @@
|
||||
package com.poststats.golf.api.impl;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.api.model.Course;
|
||||
import com.poststats.golf.api.model.CourseNine;
|
||||
import com.poststats.golf.service.CourseNineService;
|
||||
import com.poststats.golf.service.CourseService;
|
||||
import com.poststats.service.FacilityService;
|
||||
import com.poststats.transformer.impl.DaoConverter;
|
||||
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.WebApplicationException;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
|
||||
/**
|
||||
* @author brian.long@poststats.com
|
||||
*/
|
||||
@RequestScoped
|
||||
public class CourseApi implements com.poststats.golf.api.CourseApi {
|
||||
|
||||
@Inject
|
||||
private Logger logger;
|
||||
|
||||
@Inject
|
||||
private CourseService courseService;
|
||||
|
||||
@Inject
|
||||
private CourseNineService courseNineService;
|
||||
|
||||
@Inject
|
||||
private FacilityService facilityService;
|
||||
|
||||
@Inject
|
||||
private DaoConverter converter;
|
||||
|
||||
@Override
|
||||
public Course get(int courseId) {
|
||||
FlexMap row = this.courseService.get(courseId);
|
||||
if (row == null)
|
||||
throw new WebApplicationException("Course not found", Status.NOT_FOUND);
|
||||
this.logger.trace("found: {}", courseId);
|
||||
|
||||
this.facilityService.inject("facilityID", row, "facility");
|
||||
return this.converter.convertValue(row, Course.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseNine getNine(int courseId, String name) {
|
||||
FlexMap row = this.courseNineService.getNine(courseId, name);
|
||||
if (row == null)
|
||||
throw new WebApplicationException("Course nine not found", Status.NOT_FOUND);
|
||||
this.logger.trace("found: {}", courseId);
|
||||
|
||||
this.courseService.injectDeep("courseID", row, "course");
|
||||
return this.converter.convertValue(row, CourseNine.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseNine getNine(int courseId, long courseNineId) {
|
||||
FlexMap row = this.courseNineService.getNine(courseNineId);
|
||||
if (row == null)
|
||||
throw new WebApplicationException("Course nine not found", Status.NOT_FOUND);
|
||||
if (courseId != row.getInteger("courseID"))
|
||||
throw new WebApplicationException("Course nine not found", Status.NOT_FOUND);
|
||||
this.logger.trace("found: {}", courseNineId);
|
||||
|
||||
return this.converter.convertValue(row, CourseNine.class);
|
||||
}
|
||||
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
package com.poststats.golf.api.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.brianlong.util.SubList;
|
||||
import com.poststats.api.model.PagedCollection;
|
||||
import com.poststats.api.model.Pagination;
|
||||
import com.poststats.golf.api.model.Course;
|
||||
import com.poststats.golf.service.CourseService;
|
||||
import com.poststats.transformer.impl.DaoConverter;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.WebApplicationException;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
|
||||
/**
|
||||
* @author brian.long@poststats.com
|
||||
*/
|
||||
@RequestScoped
|
||||
public class CoursesApi implements com.poststats.golf.api.CoursesApi {
|
||||
|
||||
@Inject
|
||||
private Logger logger;
|
||||
|
||||
@Inject
|
||||
private CourseService courseService;
|
||||
|
||||
@Inject
|
||||
private DaoConverter converter;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.logger.debug("CoursesApi init");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PagedCollection<List<Course>> searchByName(String name, Pagination paging) {
|
||||
SubList<? extends FlexMap> rows = this.courseService.findByName(name, paging.getPage(), paging.getPerPage());
|
||||
if (rows.isEmpty())
|
||||
throw new WebApplicationException("No matching courses found", Status.NOT_FOUND);
|
||||
this.logger.trace("found: {} [{}-{}] of {}", rows.size(), rows.getStartIndex() + 1, rows.getEndIndex(),
|
||||
rows.getTotal());
|
||||
|
||||
return this.converter.convertValue(rows, Course.class).withPage(paging.getPage())
|
||||
.withPerPage(paging.getPerPage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PagedCollection<List<Course>> searchByJurisdiction(String country, String state, Pagination paging) {
|
||||
SubList<? extends FlexMap> rows = this.courseService.findByJurisdiction(country, state, paging.getPage(),
|
||||
paging.getPerPage());
|
||||
if (rows.isEmpty())
|
||||
throw new WebApplicationException("No matching golf courses found", Status.NOT_FOUND);
|
||||
this.logger.trace("found: {} [{}-{}] of {}", rows.size(), rows.getStartIndex() + 1, rows.getEndIndex(),
|
||||
rows.getTotal());
|
||||
|
||||
return this.converter.convertValue(rows, Course.class).withPage(paging.getPage())
|
||||
.withPerPage(paging.getPerPage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PagedCollection<List<Course>> searchByJurisdiction(double latitude, double longitude, Integer radiusInMiles,
|
||||
Pagination paging) {
|
||||
SubList<? extends FlexMap> rows = this.courseService.findByLocation(latitude, longitude, radiusInMiles,
|
||||
paging.getPage(), paging.getPerPage());
|
||||
if (rows.isEmpty())
|
||||
throw new WebApplicationException("No matching facilities found", Status.NOT_FOUND);
|
||||
this.logger.trace("found: {} [{}-{}] of {}", rows.size(), rows.getStartIndex() + 1, rows.getEndIndex(),
|
||||
rows.getTotal());
|
||||
|
||||
return this.converter.convertValue(rows, Course.class).withPage(paging.getPage())
|
||||
.withPerPage(paging.getPerPage());
|
||||
}
|
||||
|
||||
}
|
@@ -1,122 +0,0 @@
|
||||
package com.poststats.golf.api.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.brianlong.cache.CacheRetrievalException;
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.api.model.Event;
|
||||
import com.poststats.golf.job.EventAgendaJob;
|
||||
import com.poststats.golf.service.EventDocumentService;
|
||||
import com.poststats.golf.service.EventPersonService;
|
||||
import com.poststats.golf.service.EventService;
|
||||
import com.poststats.golf.service.SeriesService;
|
||||
import com.poststats.transformer.impl.DaoConverter;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.ws.rs.WebApplicationException;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
|
||||
/**
|
||||
* @author brian.long@poststats.com
|
||||
*/
|
||||
@RequestScoped
|
||||
public class EventApi implements com.poststats.golf.api.EventApi {
|
||||
|
||||
@Inject
|
||||
private Logger logger;
|
||||
|
||||
@Inject
|
||||
private EventService eventService;
|
||||
|
||||
@Inject
|
||||
private EventDocumentService eventDocumentService;
|
||||
|
||||
@Inject
|
||||
private EventPersonService eventPersonService;
|
||||
|
||||
@Inject
|
||||
private EventAgendaJob eventAgendaJob;
|
||||
|
||||
@Inject
|
||||
private SeriesService seriesService;
|
||||
|
||||
@Inject
|
||||
private DaoConverter converter;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.logger.debug("EventApi init");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event get(long eventId) {
|
||||
FlexMap row = this.eventService.get(eventId);
|
||||
if (row == null)
|
||||
throw new WebApplicationException("Event not found", Status.NOT_FOUND);
|
||||
return this.converter.convertValue(row, Event.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event getDetail(long eventId) {
|
||||
FlexMap row = this.eventService.get(eventId);
|
||||
if (row == null)
|
||||
throw new WebApplicationException("Event not found", Status.NOT_FOUND);
|
||||
|
||||
this.seriesService.inject("seriesID", row, "series");
|
||||
return this.converter.convertValue(row, Event.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendDocument(long eventId, long documentId) {
|
||||
FlexMap document = this.eventDocumentService.get(eventId, documentId);
|
||||
if (document == null)
|
||||
throw new WebApplicationException("Document not found", Status.NOT_FOUND);
|
||||
|
||||
switch (document.getString("type")) {
|
||||
case "agenda":
|
||||
try {
|
||||
this.eventAgendaJob.send(document);
|
||||
} catch (CacheRetrievalException | SQLException | MessagingException | IOException e) {
|
||||
throw new WebApplicationException(e);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new WebApplicationException("Document is not an agenda", Status.UNSUPPORTED_MEDIA_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTestDocument(long eventId, long documentId, long personId) {
|
||||
FlexMap document = this.eventDocumentService.get(eventId, documentId);
|
||||
if (document == null)
|
||||
throw new WebApplicationException("Document not found", Status.NOT_FOUND);
|
||||
|
||||
FlexMap eperson = this.eventPersonService.get(eventId, personId);
|
||||
if (eperson == null)
|
||||
throw new WebApplicationException("Person not found", Status.NOT_FOUND);
|
||||
|
||||
Map<Long, BigInteger> recipientIds = Collections.singletonMap(personId, eperson.getBigInteger("epersonID"));
|
||||
|
||||
switch (document.getString("type")) {
|
||||
case "agenda":
|
||||
try {
|
||||
this.eventAgendaJob.send(document, recipientIds);
|
||||
} catch (CacheRetrievalException | SQLException | MessagingException | IOException e) {
|
||||
throw new WebApplicationException(e);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new WebApplicationException("Document is not an agenda", Status.UNSUPPORTED_MEDIA_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,104 +0,0 @@
|
||||
package com.poststats.golf.api.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVPrinter;
|
||||
|
||||
import com.brianlong.sql.DataSet;
|
||||
import com.poststats.golf.service.EventFinanceService;
|
||||
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.WebApplicationException;
|
||||
import jakarta.ws.rs.core.StreamingOutput;
|
||||
|
||||
@RequestScoped
|
||||
public class EventFinanceApi implements com.poststats.golf.api.EventFinanceApi {
|
||||
|
||||
@Inject
|
||||
private EventFinanceService eventFinanceService;
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getBalanceByPersonsAsJson(long eventId, Float minBalance, Float maxBalance) {
|
||||
Map<Long, DataSet> personsBalances = this.eventFinanceService.getPersonsBalances(eventId, minBalance,
|
||||
maxBalance);
|
||||
|
||||
List<Map<String, Object>> personsBalancesJson = new ArrayList<>(personsBalances.size());
|
||||
for (DataSet personBalance : personsBalances.values()) {
|
||||
Map<String, Object> personBalanceJson = new HashMap<>(5);
|
||||
personBalanceJson.put("personId", personBalance.getLong("personID"));
|
||||
personBalanceJson.put("expense", personBalance.getFloat("expense"));
|
||||
personBalanceJson.put("paid", personBalance.getFloat("paid"));
|
||||
personBalanceJson.put("balance", personBalance.getFloat("balance"));
|
||||
personsBalancesJson.add(personBalanceJson);
|
||||
}
|
||||
|
||||
return personsBalancesJson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamingOutput getBalanceByPersonsAsCsv(long eventId) {
|
||||
Map<Long, DataSet> personsBalances = this.eventFinanceService.getPersonsBalances(eventId);
|
||||
|
||||
return new StreamingOutput() {
|
||||
@Override
|
||||
public void write(OutputStream output) throws IOException, WebApplicationException {
|
||||
PrintStream pstream = new PrintStream(output);
|
||||
CSVPrinter personsBalancesCsvPrinter = new CSVPrinter(pstream, CSVFormat.DEFAULT);
|
||||
try {
|
||||
personsBalancesCsvPrinter.printRecord("personID", "lname", "fname", "suffix", "expense", "paid",
|
||||
"balance");
|
||||
|
||||
for (DataSet personBalance : personsBalances.values()) {
|
||||
personsBalancesCsvPrinter.printRecord(personBalance.getLong("personID"),
|
||||
personBalance.getString("lname"), personBalance.getString("fname"),
|
||||
personBalance.getString("suffix"), personBalance.getFloat("expense"),
|
||||
personBalance.getFloat("paid"), personBalance.getFloat("balance"));
|
||||
}
|
||||
|
||||
personsBalancesCsvPrinter.flush();
|
||||
} finally {
|
||||
personsBalancesCsvPrinter.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getBalanceByPersonsAsJson(long eventId, long personId) {
|
||||
DataSet personBalance = this.eventFinanceService.getPersonBalance(eventId, personId);
|
||||
|
||||
Map<String, Object> personBalanceJson = new HashMap<>(5);
|
||||
personBalanceJson.put("personId", personBalance.getLong("personID"));
|
||||
personBalanceJson.put("expense", personBalance.getFloat("expense"));
|
||||
personBalanceJson.put("paid", personBalance.getFloat("paid"));
|
||||
personBalanceJson.put("balance", personBalance.getFloat("balance"));
|
||||
|
||||
return personBalanceJson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getSeriesBalanceByPersonsAsJson(long eventId) {
|
||||
Map<Long, DataSet> personsBalances = this.eventFinanceService.getSeriesPersonsPreviousBalances(eventId);
|
||||
|
||||
List<Map<String, Object>> personsBalancesJson = new ArrayList<>(personsBalances.size());
|
||||
for (DataSet personBalance : personsBalances.values()) {
|
||||
Map<String, Object> personBalanceJson = new HashMap<>(5);
|
||||
personBalanceJson.put("personId", personBalance.getLong("personID"));
|
||||
personBalanceJson.put("expense", personBalance.getFloat("expense"));
|
||||
personBalanceJson.put("paid", personBalance.getFloat("paid"));
|
||||
personBalanceJson.put("balance", personBalance.getFloat("balance"));
|
||||
personsBalancesJson.add(personBalanceJson);
|
||||
}
|
||||
|
||||
return personsBalancesJson;
|
||||
}
|
||||
|
||||
}
|
@@ -1,116 +0,0 @@
|
||||
package com.poststats.golf.api.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVPrinter;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.api.model.EventPerson;
|
||||
import com.poststats.golf.service.EventPersonService;
|
||||
import com.poststats.golf.service.EventService;
|
||||
import com.poststats.golf.service.PersonService;
|
||||
import com.poststats.transformer.impl.DaoConverter;
|
||||
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.core.StreamingOutput;
|
||||
|
||||
@RequestScoped
|
||||
public class EventPersonApi implements com.poststats.golf.api.EventPersonApi {
|
||||
|
||||
@Inject
|
||||
private EventService eventService;
|
||||
|
||||
@Inject
|
||||
private EventPersonService eventPersonService;
|
||||
|
||||
@Inject
|
||||
private PersonService golferService;
|
||||
|
||||
@Inject
|
||||
private DaoConverter converter;
|
||||
|
||||
@Override
|
||||
public List<? extends EventPerson> get(long eventId) {
|
||||
return this.converter.convertValue(this.eventPersonService.getPeople(eventId), EventPerson.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends EventPerson> getDetail(long eventId) {
|
||||
List<? extends FlexMap> persons = this.eventPersonService.getPeople(eventId);
|
||||
this.golferService.injectDeep("personID", persons, "golfer");
|
||||
return this.converter.convertValue(persons, EventPerson.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamingOutput getAsCsv(long eventId) {
|
||||
List<? extends FlexMap> persons = this.eventPersonService.getPeople(eventId);
|
||||
return this.toCsv(persons);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends EventPerson> getParticipants(long eventId) {
|
||||
List<? extends FlexMap> participants = this.eventPersonService.getParticipants(eventId);
|
||||
this.golferService.injectDeep("personID", participants, "golfer");
|
||||
return this.converter.convertValue(participants, EventPerson.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamingOutput getParticipantsAsCsv(long eventId) {
|
||||
List<? extends FlexMap> persons = this.eventPersonService.getParticipants(eventId);
|
||||
return this.toCsv(persons);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Long> getSeriesParticipants(long eventId) {
|
||||
int seriesId = this.eventService.getSeriesId(eventId);
|
||||
Set<Long> eventIds = this.eventService.getIdsBySeriesId(seriesId);
|
||||
|
||||
Set<Long> personIds = new HashSet<>();
|
||||
for (long otherEventId : eventIds) {
|
||||
List<? extends FlexMap> tmpPersons = this.eventPersonService.getParticipants(otherEventId);
|
||||
for (FlexMap person : tmpPersons)
|
||||
personIds.add(person.getLong(com.poststats.sql.Constants.PERSON_ID));
|
||||
}
|
||||
|
||||
return personIds;
|
||||
}
|
||||
|
||||
private StreamingOutput toCsv(List<? extends FlexMap> persons) {
|
||||
this.golferService.injectDeep("personID", persons, "golfer");
|
||||
|
||||
return new StreamingOutput() {
|
||||
@Override
|
||||
public void write(OutputStream output) throws IOException {
|
||||
PrintStream pstream = new PrintStream(output);
|
||||
CSVPrinter personsCsvPrinter = new CSVPrinter(pstream, CSVFormat.DEFAULT);
|
||||
try {
|
||||
personsCsvPrinter.printRecord("ID", "Prefix", "Last Name", "First Name", "Suffix", "Email Address",
|
||||
"Mobile Phone", "Address Lines", "City", "State", "Country", "Postal Code");
|
||||
|
||||
for (FlexMap eperson : persons) {
|
||||
FlexMap golfer = (FlexMap) eperson.get("golfer");
|
||||
FlexMap person = (FlexMap) golfer.get("person");
|
||||
|
||||
personsCsvPrinter.printRecord(person.getLong("personID"), person.getString("prefix"),
|
||||
person.getString("lname"), person.getString("fname"), person.getString("suffix"),
|
||||
person.getString("email"), person.getString("cellphone"), person.getString("addrlines"),
|
||||
person.getString("addrcity"), person.getString("addrstate"),
|
||||
person.getString("addrcountry"), person.getString("addrzip"));
|
||||
}
|
||||
|
||||
personsCsvPrinter.flush();
|
||||
} finally {
|
||||
personsCsvPrinter.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@@ -1,291 +0,0 @@
|
||||
package com.poststats.golf.api.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVPrinter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.formatter.PersonFormatter;
|
||||
import com.poststats.formatter.PersonsFormatter;
|
||||
import com.poststats.golf.api.model.EventRound;
|
||||
import com.poststats.golf.api.model.EventRoundPairing;
|
||||
import com.poststats.golf.api.model.EventRoundPairingOrder;
|
||||
import com.poststats.golf.formatter.GolfCourseFormatter;
|
||||
import com.poststats.golf.service.CourseService;
|
||||
import com.poststats.golf.service.EventRoundPairingService;
|
||||
import com.poststats.golf.service.EventRoundService;
|
||||
import com.poststats.golf.service.PersonService;
|
||||
import com.poststats.transformer.impl.DaoConverter;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.WebApplicationException;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import jakarta.ws.rs.core.StreamingOutput;
|
||||
|
||||
/**
|
||||
* @author brian.long@poststats.com
|
||||
*/
|
||||
@RequestScoped
|
||||
public class EventRoundApi implements com.poststats.golf.api.EventRoundApi {
|
||||
|
||||
@Inject
|
||||
private Logger logger;
|
||||
|
||||
@Inject
|
||||
private PersonService golferService;
|
||||
|
||||
@Inject
|
||||
private EventRoundService roundService;
|
||||
|
||||
@Inject
|
||||
private EventRoundPairingService pairingService;
|
||||
|
||||
@Inject
|
||||
private CourseService courseService;
|
||||
|
||||
@Inject
|
||||
private DaoConverter converter;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.logger.debug("EventRoundApi init");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EventRound> getNext(long eventId) {
|
||||
List<? extends FlexMap> rows = this.roundService.getUpcoming(eventId);
|
||||
if (rows == null || rows.isEmpty())
|
||||
throw new WebApplicationException("No event round was found", Status.NOT_FOUND);
|
||||
|
||||
this.courseService.injectDeep("courseID", rows, "course");
|
||||
return this.converter.convertValue(rows, EventRound.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventRound getOne(long eventId, long eroundId) {
|
||||
FlexMap row = this.roundService.get(eroundId);
|
||||
if (row == null)
|
||||
throw new WebApplicationException("Event round not found", Status.NOT_FOUND);
|
||||
if (eventId != row.getLong("eventID")) {
|
||||
this.logger.warn("The event round {} was requested without the appropriate event ID {}", eroundId, eventId);
|
||||
throw new WebApplicationException("Event round not found", Status.NOT_FOUND);
|
||||
}
|
||||
|
||||
this.courseService.injectDeep("courseID", row, "course");
|
||||
return this.converter.convertValue(row, EventRound.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EventRound> getAll(long eventId) {
|
||||
Map<Long, ? extends FlexMap> rows = this.roundService.getByEventId(eventId);
|
||||
if (rows.isEmpty())
|
||||
throw new WebApplicationException("No event rounds found", Status.NOT_FOUND);
|
||||
|
||||
return this.converter.convertValue(rows.values(), EventRound.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EventRoundPairing> getPairings(long eventId, long eroundId) {
|
||||
List<? extends FlexMap> rows = this.pairingService.getByRoundId(eroundId);
|
||||
if (rows == null || rows.isEmpty())
|
||||
throw new WebApplicationException("No pairings found", Status.NOT_FOUND);
|
||||
|
||||
this.courseService.inject("courseID", rows, "course");
|
||||
return this.converter.convertValue(rows, EventRoundPairing.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamingOutput getPairingsAsCsv(long eventId, long eroundId, List<EventRoundPairingOrder> orderBys,
|
||||
boolean lastNameFirst) {
|
||||
this.logger.debug("getPairingsAsCsv({}, {})", eroundId, lastNameFirst);
|
||||
|
||||
List<? extends FlexMap> rows = this.pairingService.getParticipantsByRoundId(eroundId);
|
||||
if (rows == null || rows.isEmpty())
|
||||
throw new WebApplicationException("No pairings found", Status.NOT_FOUND);
|
||||
this.logger.debug("Found {} pairings in round: {}", rows.size(), eroundId);
|
||||
|
||||
this.golferService.injectDeep("personID", rows, "golfer");
|
||||
|
||||
PersonFormatter personFormatter = new PersonFormatter();
|
||||
personFormatter.withNameReversal(lastNameFirst);
|
||||
GolfCourseFormatter courseFormatter = new GolfCourseFormatter();
|
||||
|
||||
for (FlexMap row : rows) {
|
||||
FlexMap golfer = row.get("golfer", FlexMap.class);
|
||||
FlexMap person = golfer.get("person", FlexMap.class);
|
||||
row.put("name", personFormatter.format(person));
|
||||
|
||||
FlexMap pairing = row.get("pairing", FlexMap.class);
|
||||
this.courseService.inject("courseID", pairing, "course");
|
||||
|
||||
FlexMap course = pairing.get("course", FlexMap.class);
|
||||
if (course != null)
|
||||
pairing.put("courseName", courseFormatter.format(course));
|
||||
}
|
||||
|
||||
this.sort(rows, orderBys);
|
||||
return this.toCsv(rows, lastNameFirst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventRoundPairing getPairing(long eventId, long eroundId, BigInteger pairingId) {
|
||||
FlexMap row = this.pairingService.get(pairingId);
|
||||
if (row == null)
|
||||
throw new WebApplicationException("No pairing was found", Status.NOT_FOUND);
|
||||
if (eroundId != row.getLong("eroundID")) {
|
||||
this.logger.warn("The event round pairing {} was requested without the appropriate event round ID {}",
|
||||
pairingId, eroundId);
|
||||
throw new WebApplicationException("No pairing was found", Status.NOT_FOUND);
|
||||
}
|
||||
|
||||
this.courseService.inject("courseID", row, "course");
|
||||
return this.converter.convertValue(row, EventRoundPairing.class);
|
||||
}
|
||||
|
||||
private void sort(List<? extends FlexMap> persons, List<EventRoundPairingOrder> orderBys) {
|
||||
final List<EventRoundPairingOrder> orders = new LinkedList<>((orderBys == null || orderBys.isEmpty())
|
||||
? Arrays.asList(EventRoundPairingOrder.Pairing, EventRoundPairingOrder.FormattedName)
|
||||
: orderBys);
|
||||
this.logger.debug("Sorting by: {}", orders);
|
||||
|
||||
ListIterator<EventRoundPairingOrder> i = orders.listIterator();
|
||||
while (i.hasNext()) {
|
||||
EventRoundPairingOrder order = i.next();
|
||||
if (order == EventRoundPairingOrder.Pairing) {
|
||||
i.remove();
|
||||
i.add(EventRoundPairingOrder.TeeTime);
|
||||
i.add(EventRoundPairingOrder.Course);
|
||||
i.add(EventRoundPairingOrder.CourseNine);
|
||||
i.add(EventRoundPairingOrder.HoleNumber);
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(persons, new Comparator<FlexMap>() {
|
||||
@Override
|
||||
public int compare(FlexMap person1, FlexMap person2) {
|
||||
if (person1 == null && person2 == null) {
|
||||
return 0;
|
||||
} else if (person1 == null) {
|
||||
return -1;
|
||||
} else if (person2 == null) {
|
||||
return 1;
|
||||
} else {
|
||||
for (EventRoundPairingOrder order : orders) {
|
||||
int compare = 0;
|
||||
FlexMap pairing1 = person1.get("pairing", FlexMap.class);
|
||||
FlexMap pairing2 = person2.get("pairing", FlexMap.class);
|
||||
|
||||
switch (order) {
|
||||
case FormattedName:
|
||||
compare = person1.getString("name").compareTo(person2.getString("name"));
|
||||
break;
|
||||
case LastName:
|
||||
compare = person1.get("golfer", FlexMap.class).get("person", FlexMap.class)
|
||||
.getString("lname").compareTo(person2.get("golfer", FlexMap.class)
|
||||
.get("person", FlexMap.class).getString("lname"));
|
||||
break;
|
||||
case FirstName:
|
||||
compare = person1.get("golfer", FlexMap.class).get("person", FlexMap.class)
|
||||
.getString("fname").compareTo(person2.get("golfer", FlexMap.class)
|
||||
.get("person", FlexMap.class).getString("fname"));
|
||||
break;
|
||||
case Course:
|
||||
if (!pairing1.isNotEmpty("course") && !pairing2.isNotEmpty("course")) {
|
||||
} else if (!pairing1.isNotEmpty("course")) {
|
||||
return -1;
|
||||
} else if (!pairing2.isNotEmpty("course")) {
|
||||
return 1;
|
||||
} else {
|
||||
compare = StringUtils.compare(
|
||||
pairing1.get("course", FlexMap.class).getString("nine"),
|
||||
pairing2.get("course", FlexMap.class).getString("nine"));
|
||||
}
|
||||
break;
|
||||
case CourseNine:
|
||||
if (!pairing1.isNotEmpty("nine") && !pairing2.isNotEmpty("nine")) {
|
||||
} else if (!pairing1.isNotEmpty("nine")) {
|
||||
return -1;
|
||||
} else if (!pairing2.isNotEmpty("nine")) {
|
||||
return 1;
|
||||
} else {
|
||||
compare = StringUtils.compare(pairing1.get("nine", FlexMap.class).getString("nine"),
|
||||
pairing2.get("nine", FlexMap.class).getString("nine"));
|
||||
}
|
||||
break;
|
||||
case HoleNumber:
|
||||
compare = compareTo(pairing1.getByte("number"), pairing2.getByte("number"));
|
||||
break;
|
||||
case TeeTime:
|
||||
compare = compareTo(pairing1.getTime("teetime"), pairing2.getTime("teetime"));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
if (compare != 0)
|
||||
return compare;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private StreamingOutput toCsv(List<? extends FlexMap> persons, boolean lastNameFirst) {
|
||||
return new StreamingOutput() {
|
||||
@Override
|
||||
public void write(OutputStream output) throws IOException {
|
||||
PersonsFormatter<FlexMap> personsFormatter = new PersonsFormatter<>();
|
||||
personsFormatter.withNameReversal(lastNameFirst);
|
||||
|
||||
PrintStream pstream = new PrintStream(output);
|
||||
CSVPrinter personsCsvPrinter = new CSVPrinter(pstream, CSVFormat.DEFAULT);
|
||||
try {
|
||||
personsCsvPrinter.printRecord("Name", "Tee Time", "Course", "Course Nine", "Hole Number");
|
||||
|
||||
for (FlexMap eperson : persons) {
|
||||
FlexMap pairing = eperson.get("pairing", FlexMap.class);
|
||||
FlexMap nine = pairing.get("nine", FlexMap.class);
|
||||
|
||||
personsCsvPrinter.printRecord(eperson.getString("name"), pairing.getTime("teetime"),
|
||||
pairing.getString("courseName"), nine == null ? null : nine.getString("nine"),
|
||||
pairing.getByte("number"));
|
||||
}
|
||||
|
||||
personsCsvPrinter.flush();
|
||||
} finally {
|
||||
personsCsvPrinter.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private <T extends Comparable<T>> int compareTo(T c1, T c2) {
|
||||
if (c1 == null && c2 == null) {
|
||||
return 0;
|
||||
} else if (c1 == null) {
|
||||
return -1;
|
||||
} else if (c2 == null) {
|
||||
return 1;
|
||||
} else {
|
||||
return c1.compareTo(c2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
package com.poststats.golf.api.impl;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.api.model.Golfer;
|
||||
import com.poststats.golf.service.PersonService;
|
||||
import com.poststats.transformer.impl.DaoConverter;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.WebApplicationException;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
|
||||
/**
|
||||
* @author brian.long@poststats.com
|
||||
*/
|
||||
@RequestScoped
|
||||
public class GolferApi extends com.poststats.golf.api.GolferApi {
|
||||
|
||||
@Inject
|
||||
private Logger logger;
|
||||
|
||||
@Inject
|
||||
private PersonService personService;
|
||||
|
||||
@Inject
|
||||
private com.poststats.service.PersonService poststatsPersonService;
|
||||
|
||||
@Inject
|
||||
private DaoConverter converter;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.logger.debug("GolferApi init: {}", this.getPersonId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Golfer get() {
|
||||
FlexMap row = this.personService.get(this.getPersonId());
|
||||
if (row == null)
|
||||
throw new WebApplicationException("Event not found", Status.NOT_FOUND);
|
||||
|
||||
this.poststatsPersonService.inject("personID", row, "person");
|
||||
return this.converter.convertValue(row, Golfer.class);
|
||||
}
|
||||
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
package com.poststats.golf.api.impl;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.api.model.Event;
|
||||
import com.poststats.golf.api.model.Series;
|
||||
import com.poststats.golf.service.EventService;
|
||||
import com.poststats.golf.service.SeriesService;
|
||||
import com.poststats.transformer.impl.DaoConverter;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.WebApplicationException;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
|
||||
/**
|
||||
* @author brian.long@poststats.com
|
||||
*/
|
||||
@RequestScoped
|
||||
public class SeriesApi extends com.poststats.golf.api.SeriesApi {
|
||||
|
||||
@Inject
|
||||
private Logger logger;
|
||||
|
||||
@Inject
|
||||
private SeriesService seriesService;
|
||||
|
||||
@Inject
|
||||
private EventService eventService;
|
||||
|
||||
@Inject
|
||||
private DaoConverter converter;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.logger.debug("SeriesApi init: {}", this.getSeriesId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Series get() {
|
||||
FlexMap row = this.seriesService.get(this.getSeriesId());
|
||||
if (row == null)
|
||||
throw new WebApplicationException("Series not found", Status.NOT_FOUND);
|
||||
|
||||
return this.converter.convertValue(row, Series.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Event> getEvents(Boolean reverse) {
|
||||
Map<Long, ? extends FlexMap> rows = this.eventService.getBySeriesId(this.getSeriesId());
|
||||
if (rows.isEmpty())
|
||||
throw new WebApplicationException("Series or events not found", Status.NOT_FOUND);
|
||||
|
||||
List<Event> events = this.converter.convertValue(rows.values(), Event.class);
|
||||
if (Boolean.TRUE.equals(reverse))
|
||||
Collections.reverse(events);
|
||||
return events;
|
||||
}
|
||||
|
||||
}
|
@@ -1,292 +0,0 @@
|
||||
package com.poststats.golf.job;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.methods.RequestBuilder;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.brianlong.cache.CacheRetrievalException;
|
||||
import com.brianlong.sql.DataSet;
|
||||
import com.brianlong.sql.FlexPreparedStatement;
|
||||
import com.brianlong.util.DateTimeFormatter;
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.formatter.EventFormatter;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.service.EventPersonService;
|
||||
import com.poststats.golf.service.EventService;
|
||||
import com.poststats.golf.sql.EventAutolist;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.Statement;
|
||||
import com.poststats.provider.StatementProvider;
|
||||
import com.poststats.service.PersonService;
|
||||
import com.poststats.service.file.EnvironmentConfiguration;
|
||||
import com.poststats.util.CompositeTexter;
|
||||
import com.poststats.util.Contact;
|
||||
import com.poststats.util.Emailer;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.ejb.Schedule;
|
||||
import jakarta.ejb.Singleton;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.mail.MessagingException;
|
||||
|
||||
@Singleton
|
||||
public class EventAgendaJob {
|
||||
|
||||
private final DateTimeFormatter weekdayFormatter = new DateTimeFormatter("EEEE");
|
||||
|
||||
@Inject
|
||||
private Logger logger;
|
||||
|
||||
@Inject
|
||||
private EnvironmentConfiguration envConfig;
|
||||
|
||||
@Inject
|
||||
private PersonService personService;
|
||||
|
||||
@Inject
|
||||
private EventService eventService;
|
||||
|
||||
@Inject
|
||||
private EventPersonService eventPersonService;
|
||||
|
||||
private String baseGolfUrl;
|
||||
private CompositeTexter texter;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.baseGolfUrl = this.envConfig.getString("golf.url")
|
||||
+ "/c";
|
||||
this.texter = new CompositeTexter(this.envConfig);
|
||||
}
|
||||
|
||||
@Schedule(hour = "21", timezone = "EDT")
|
||||
protected void nightly() throws CacheRetrievalException, SQLException, MessagingException, IOException {
|
||||
this.logger.trace("run()");
|
||||
|
||||
// if executed after 6p, then agendas should be for following day
|
||||
LocalDateTime now = LocalDateTime.now(); // (2016, 6, 7, 22, 0);
|
||||
LocalDate date = now.plusHours(6).toLocalDate();
|
||||
|
||||
this.logger.info("Sending agendas for {}", date);
|
||||
|
||||
List<DataSet> agendas = this.getAgendas(date);
|
||||
if (agendas.isEmpty()) {
|
||||
this.logger.debug("No agenda items to send: {}", date);
|
||||
return;
|
||||
}
|
||||
|
||||
for (DataSet agenda : agendas)
|
||||
this.send(agenda);
|
||||
}
|
||||
|
||||
private List<DataSet> getAgendas(LocalDate date) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectAgendas.buildPreparedStatement();
|
||||
try {
|
||||
fps.setDate(1, date);
|
||||
return fps.executeQuery().getAllRows();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void send(FlexMap agenda) throws CacheRetrievalException, SQLException, MessagingException, IOException {
|
||||
Long eventID = agenda.getLong("eventID");
|
||||
Map<Long, BigInteger> recipientIDs = EventAutolist.getInstance().getPersonIDMap("signed", eventID.longValue());
|
||||
this.send(agenda, recipientIDs);
|
||||
}
|
||||
|
||||
public void send(FlexMap agenda, Map<Long, BigInteger> recipientIDs)
|
||||
throws CacheRetrievalException, SQLException, MessagingException, IOException {
|
||||
boolean doEmailLink = Boolean.TRUE.equals(agenda.getBoolean("sendEmailWithLink"));
|
||||
boolean doEmail = Boolean.TRUE.equals(agenda.getBoolean("sendEmailWithContent"));
|
||||
boolean doTextLink = Boolean.TRUE.equals(agenda.getBoolean("sendTextWithLink"));
|
||||
boolean doText = Boolean.TRUE.equals(agenda.getBoolean("sendTextWithContent"));
|
||||
if (!doTextLink && !doText && !doEmailLink && !doEmail)
|
||||
return;
|
||||
|
||||
Long eventId = agenda.getLong("eventID");
|
||||
Long documentId = agenda.getLong("documentID");
|
||||
LocalDate day = agenda.getDate("day");
|
||||
|
||||
this.logger.debug("Sending agenda with document ID: {}", documentId);
|
||||
|
||||
FlexMap event = this.eventService.get(eventId);
|
||||
String subject = new EventFormatter().format(event)
|
||||
+ " Agenda for "
|
||||
+ this.weekdayFormatter.format(day);
|
||||
|
||||
Set<Long> textedPersonIDs = Collections.emptySet();
|
||||
|
||||
if (doTextLink) {
|
||||
textedPersonIDs = this.textLink(eventId, documentId, recipientIDs, subject);
|
||||
} else if (doText) {
|
||||
textedPersonIDs = this.text(eventId, documentId, recipientIDs, subject);
|
||||
}
|
||||
|
||||
if (doEmailLink) {
|
||||
this.emailLink(eventId, documentId, recipientIDs, textedPersonIDs, subject);
|
||||
} else if (doEmail) {
|
||||
this.email(eventId, documentId, recipientIDs, textedPersonIDs, subject);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<Long> textLink(long eventID, long documentID, Map<Long, BigInteger> recipientIDs, String subject)
|
||||
throws SQLException, MessagingException {
|
||||
this.logger.debug("Sending agenda links by text with document ID: {}", documentID);
|
||||
|
||||
List<Contact> recipients = this.personService.getContacts(recipientIDs.keySet(), false, true);
|
||||
|
||||
String baseUrl = baseGolfUrl
|
||||
+ "?n=documentAgenda&eventID="
|
||||
+ eventID
|
||||
+ "&documentID="
|
||||
+ documentID
|
||||
+ "&epersonID=";
|
||||
|
||||
Set<Long> textedPersonIDs = new HashSet<Long>(recipientIDs.size());
|
||||
|
||||
for (Contact recipient : recipients) {
|
||||
long personId = recipient.getPersonId();
|
||||
this.logger.debug("Sending agenda to: {}", personId);
|
||||
String message = baseUrl + recipientIDs.get(personId);
|
||||
this.texter.send(Arrays.asList(recipient), subject, message);
|
||||
|
||||
textedPersonIDs.add(personId);
|
||||
}
|
||||
|
||||
return textedPersonIDs;
|
||||
}
|
||||
|
||||
private Set<Long> text(long eventID, long documentID, Map<Long, BigInteger> recipientIDs, String subject)
|
||||
throws SQLException, MessagingException, IOException {
|
||||
this.logger.debug("Sending agenda links by text with document ID: {}", documentID);
|
||||
|
||||
List<Contact> recipients = this.personService.getContacts(recipientIDs.keySet(), false, true);
|
||||
|
||||
NameValuePair[] params = new NameValuePair[] {
|
||||
new BasicNameValuePair("n", "documentAgendaMarkdown"),
|
||||
new BasicNameValuePair("eventID", String.valueOf(eventID)),
|
||||
new BasicNameValuePair("documentID", String.valueOf(documentID))
|
||||
};
|
||||
|
||||
Set<Long> textedPersonIDs = new HashSet<Long>(recipientIDs.size());
|
||||
|
||||
for (Contact recipient : recipients) {
|
||||
long personId = recipient.getPersonId();
|
||||
this.logger.debug("Sending agenda to: {}", personId);
|
||||
|
||||
HttpUriRequest request = RequestBuilder.get(this.baseGolfUrl).addParameters(params)
|
||||
.addParameter("epersonID", recipientIDs.get(personId).toString()).build();
|
||||
|
||||
CloseableHttpClient hclient = HttpClientBuilder.create().build();
|
||||
CloseableHttpResponse response = hclient.execute(request);
|
||||
try {
|
||||
if (response.getStatusLine().getStatusCode() / 100 == 2) {
|
||||
String markdown = IOUtils.toString(response.getEntity().getContent(), "utf-8");
|
||||
this.texter.send(Arrays.asList(recipient), subject, markdown.trim());
|
||||
textedPersonIDs.add(personId);
|
||||
} else {
|
||||
this.logger.warn("The URL could not be loaded properly: {}", request.getURI());
|
||||
}
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
return textedPersonIDs;
|
||||
}
|
||||
|
||||
private void emailLink(long eventID, long documentID, Map<Long, BigInteger> recipientIDs,
|
||||
Set<Long> excludePersonIDs, String subject) throws SQLException, MessagingException {
|
||||
this.logger.debug("Sending agenda links by email with document ID: {}", documentID);
|
||||
|
||||
List<Contact> recipients = this.personService.getContacts(recipientIDs.keySet(), true, false);
|
||||
|
||||
String baseUrl = this.baseGolfUrl
|
||||
+ "?n=documentAgenda&eventID="
|
||||
+ eventID
|
||||
+ "&documentID="
|
||||
+ documentID
|
||||
+ "&epersonID=";
|
||||
for (Contact recipient : recipients) {
|
||||
long personId = recipient.getPersonId();
|
||||
if (excludePersonIDs.contains(personId))
|
||||
continue;
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Sending agenda to: {}", personId);
|
||||
String message = "<html><body><p><a href=\""
|
||||
+ baseUrl
|
||||
+ "\">"
|
||||
+ baseUrl
|
||||
+ recipientIDs.get(personId)
|
||||
+ "</a></p></body></html>";
|
||||
Emailer.getInstance(this.envConfig).send(Arrays.asList(recipient), subject, message);
|
||||
}
|
||||
}
|
||||
|
||||
private void email(long eventID, long documentID, Map<Long, BigInteger> recipientIDs, Set<Long> excludePersonIDs,
|
||||
String subject) throws SQLException, MessagingException, IOException {
|
||||
this.logger.debug("Sending agenda contents with document ID: {}", documentID);
|
||||
|
||||
List<Contact> recipients = this.personService.getContacts(recipientIDs.keySet(), true, false);
|
||||
|
||||
NameValuePair[] params = new NameValuePair[] {
|
||||
new BasicNameValuePair("n", "documentAgendaMinimal"),
|
||||
new BasicNameValuePair("eventID", String.valueOf(eventID)),
|
||||
new BasicNameValuePair("documentID", String.valueOf(documentID))
|
||||
};
|
||||
|
||||
for (Contact recipient : recipients) {
|
||||
long personId = recipient.getPersonId();
|
||||
this.logger.debug("Sending agenda to: {}", personId);
|
||||
|
||||
HttpUriRequest request = RequestBuilder.get(this.baseGolfUrl).addParameters(params)
|
||||
.addParameter("epersonID", recipientIDs.get(personId).toString()).build();
|
||||
|
||||
CloseableHttpClient hclient = HttpClientBuilder.create().build();
|
||||
CloseableHttpResponse response = hclient.execute(request);
|
||||
try {
|
||||
if (response.getStatusLine().getStatusCode() / 100 == 2) {
|
||||
String html = IOUtils.toString(response.getEntity().getContent(), "utf-8");
|
||||
Emailer.getInstance(this.envConfig).send(Arrays.asList(recipient), subject, html);
|
||||
} else {
|
||||
this.logger.warn("The URL could not be loaded properly: {}", request.getURI());
|
||||
}
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT ED.* "
|
||||
+ "FROM ~g~.EventDocument ED "
|
||||
+ "WHERE ED.day=? "
|
||||
+ " AND (ED.sendEmailWithLink IS TRUE OR ED.sendEmailWithContent IS TRUE OR ED.sendTextWithLink IS TRUE)"
|
||||
)
|
||||
private StatementProvider sqlSelectAgendas;
|
||||
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
package com.poststats.golf.provider;
|
||||
|
||||
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;
|
||||
|
||||
import jakarta.inject.Qualifier;
|
||||
|
||||
@Qualifier
|
||||
@Target({
|
||||
ElementType.TYPE, ElementType.PARAMETER, ElementType.FIELD
|
||||
})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface GolfProvider {
|
||||
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
package com.poststats.golf.provider.impl;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.provider.ConnectionProvider;
|
||||
import com.poststats.provider.DataSourceProvider;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@ApplicationScoped
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
public class DefaultConnectionProvider implements ConnectionProvider {
|
||||
|
||||
@Inject
|
||||
@GolfProvider
|
||||
private DataSourceProvider dsp;
|
||||
|
||||
private Connection dbcon;
|
||||
|
||||
@PostConstruct
|
||||
public void acquire() {
|
||||
this.dbcon = this.dsp.get().acquire(true);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void release() {
|
||||
this.dsp.get().release(this.dbcon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection get() {
|
||||
return this.dbcon;
|
||||
}
|
||||
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
package com.poststats.golf.provider.impl;
|
||||
|
||||
import com.brianlong.sql.DataSource;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.sql.GolfDataSource;
|
||||
import com.poststats.provider.impl.AbstractDataSourceProvider;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
@GolfProvider
|
||||
public class DefaultDataSourceProvider extends AbstractDataSourceProvider {
|
||||
|
||||
public DataSource createDataSource() {
|
||||
return GolfDataSource.getInstance();
|
||||
}
|
||||
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
package com.poststats.golf.provider.impl;
|
||||
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.sql.GolfSQL;
|
||||
import com.poststats.provider.ConnectionProvider;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.impl.AbstractStatementProvider;
|
||||
|
||||
import jakarta.enterprise.context.Dependent;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@Dependent
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
public class DefaultStatementProvider extends AbstractStatementProvider {
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
private ConnectionProvider cp;
|
||||
|
||||
@Override
|
||||
protected ConnectionProvider getConnectionProvider() {
|
||||
return this.cp;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String transformSchema(String sql) {
|
||||
return GolfSQL.changeSchema(sql);
|
||||
}
|
||||
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
package com.poststats.golf.provider.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Connection;
|
||||
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.provider.ConnectionProvider;
|
||||
import com.poststats.provider.DataSourceProvider;
|
||||
import com.poststats.provider.TransactionalProvider;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.transaction.TransactionScoped;
|
||||
|
||||
@TransactionScoped
|
||||
@TransactionalProvider
|
||||
@GolfProvider
|
||||
public class TxConnectionProvider implements ConnectionProvider, Serializable {
|
||||
|
||||
@Inject
|
||||
@GolfProvider
|
||||
private DataSourceProvider dsp;
|
||||
|
||||
private Connection dbcon;
|
||||
|
||||
@PostConstruct
|
||||
public void acquire() {
|
||||
this.dbcon = this.dsp.get().acquireTX(true);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void release() {
|
||||
this.dsp.get().releaseTX(this.dbcon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection get() {
|
||||
return this.dbcon;
|
||||
}
|
||||
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
package com.poststats.golf.provider.impl;
|
||||
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.sql.GolfSQL;
|
||||
import com.poststats.provider.ConnectionProvider;
|
||||
import com.poststats.provider.TransactionalProvider;
|
||||
import com.poststats.provider.impl.AbstractStatementProvider;
|
||||
|
||||
import jakarta.enterprise.context.Dependent;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@Dependent
|
||||
@TransactionalProvider
|
||||
@GolfProvider
|
||||
public class TxStatementProvider extends AbstractStatementProvider {
|
||||
|
||||
@Inject
|
||||
@TransactionalProvider
|
||||
@GolfProvider
|
||||
private ConnectionProvider cp;
|
||||
|
||||
@Override
|
||||
protected ConnectionProvider getConnectionProvider() {
|
||||
return this.cp;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String transformSchema(String sql) {
|
||||
return GolfSQL.changeSchema(sql);
|
||||
}
|
||||
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
package com.poststats.golf.security;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
public class AuthenticatedPerson extends com.poststats.security.AuthenticatedPerson {
|
||||
|
||||
private final Set<Long> buddyIds;
|
||||
private final Set<String> acSids;
|
||||
private final Map<Long, Set<String>> eventAcSids;
|
||||
|
||||
public AuthenticatedPerson(com.poststats.security.AuthenticatedPerson person, Set<Long> buddyIds,
|
||||
Set<String> acSids, Map<Long, Set<String>> eventAcSids) {
|
||||
super(person);
|
||||
this.buddyIds = buddyIds;
|
||||
this.acSids = acSids;
|
||||
this.eventAcSids = eventAcSids;
|
||||
}
|
||||
|
||||
public Set<Long> getBuddyIds() {
|
||||
return Collections.unmodifiableSet(this.buddyIds);
|
||||
}
|
||||
|
||||
public Set<String> getAccessControls() {
|
||||
return Collections.unmodifiableSet(this.acSids);
|
||||
}
|
||||
|
||||
public Set<String> getEventAccessControls(long eventId) {
|
||||
Set<String> roles = this.eventAcSids.get(eventId);
|
||||
return roles == null ? null : Collections.unmodifiableSet(roles);
|
||||
}
|
||||
|
||||
public Set<String> getAllAccessControls() {
|
||||
Set<String> roles = new HashSet<>();
|
||||
roles.addAll(this.acSids);
|
||||
for (Entry<Long, Set<String>> eroles : this.eventAcSids.entrySet())
|
||||
for (String role : eroles.getValue())
|
||||
roles.add(eroles.getKey()
|
||||
+ ":"
|
||||
+ role);
|
||||
return roles == null ? null : Collections.unmodifiableSet(roles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAccessControl(String ac) {
|
||||
return this.acSids.contains(ac);
|
||||
}
|
||||
|
||||
public boolean hasBuddy(long buddyId) {
|
||||
return this.buddyIds.contains(buddyId);
|
||||
}
|
||||
|
||||
public boolean hasAccessControl(String ac, long eventId) {
|
||||
Set<String> sids = this.eventAcSids.get(eventId);
|
||||
return sids != null && sids.contains(ac);
|
||||
}
|
||||
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
package com.poststats.golf.security;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jakarta.ws.rs.core.SecurityContext;
|
||||
|
||||
public class AuthenticatedSecurityContext implements SecurityContext {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private final SecurityContext securityContext;
|
||||
private final AuthenticatedPerson authPerson;
|
||||
|
||||
public AuthenticatedSecurityContext(SecurityContext securityContext, AuthenticatedPerson authPerson) {
|
||||
if (securityContext == null)
|
||||
throw new IllegalArgumentException();
|
||||
this.securityContext = securityContext;
|
||||
this.authPerson = authPerson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getUserPrincipal() {
|
||||
return this.authPerson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserInRole(String role) {
|
||||
this.logger.trace("isUserInRole({}, {})", this.getUserPrincipal(), role);
|
||||
|
||||
if (this.authPerson.hasAccessControl(role)) {
|
||||
this.logger.debug("user '{}' is in role '{}'", this.authPerson, role);
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.securityContext.isUserInRole(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthenticationScheme() {
|
||||
return this.securityContext.getAuthenticationScheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return this.securityContext.isSecure();
|
||||
}
|
||||
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
package com.poststats.golf.security;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.poststats.golf.api.Constants;
|
||||
|
||||
import jakarta.ws.rs.core.SecurityContext;
|
||||
|
||||
public class EventSecurityContext implements SecurityContext {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private final SecurityContext securityContext;
|
||||
private final long eventId;
|
||||
|
||||
public EventSecurityContext(SecurityContext securityContext, long eventId) {
|
||||
if (securityContext == null)
|
||||
throw new IllegalArgumentException();
|
||||
this.securityContext = securityContext;
|
||||
this.eventId = eventId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getUserPrincipal() {
|
||||
return this.securityContext.getUserPrincipal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserInRole(String role) {
|
||||
this.logger.trace("isUserInRole({}, {}, {})", this.getUserPrincipal(), role, this.eventId);
|
||||
|
||||
if (role.startsWith(Constants.EVENT_ROLE_PREFIX)) {
|
||||
if (this.getUserPrincipal() instanceof AuthenticatedPerson) {
|
||||
AuthenticatedPerson authPerson = (AuthenticatedPerson) this.getUserPrincipal();
|
||||
String eventRole = role.substring(Constants.EVENT_ROLE_PREFIX.length());
|
||||
this.logger.trace("checking if user '{}' has role '{}' in event {}", this.getUserPrincipal(), eventRole,
|
||||
this.eventId);
|
||||
|
||||
if (authPerson.hasAccessControl(eventRole, this.eventId)) {
|
||||
this.logger.debug("user '{}' has role '{}' in event {}", this.getUserPrincipal(), eventRole,
|
||||
this.eventId);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.securityContext.isUserInRole(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthenticationScheme() {
|
||||
return this.securityContext.getAuthenticationScheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return this.securityContext.isSecure();
|
||||
}
|
||||
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
package com.poststats.golf.security;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.poststats.golf.api.Constants;
|
||||
|
||||
import jakarta.ws.rs.core.SecurityContext;
|
||||
|
||||
public class PersonSecurityContext implements SecurityContext {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private final SecurityContext securityContext;
|
||||
private final long personId;
|
||||
|
||||
public PersonSecurityContext(SecurityContext securityContext, long personId) {
|
||||
if (securityContext == null)
|
||||
throw new IllegalArgumentException();
|
||||
this.securityContext = securityContext;
|
||||
this.personId = personId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getUserPrincipal() {
|
||||
return this.securityContext.getUserPrincipal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserInRole(String role) {
|
||||
this.logger.trace("isUserInRole({}, {}, {})", this.getUserPrincipal(), role, this.personId);
|
||||
|
||||
if (role.equals(Constants.BUDDY_ROLE)) {
|
||||
if (this.getUserPrincipal() instanceof AuthenticatedPerson) {
|
||||
AuthenticatedPerson authPerson = (AuthenticatedPerson) this.getUserPrincipal();
|
||||
this.logger.trace("checking if user '{}' is buddy of {}", this.getUserPrincipal(), this.personId);
|
||||
if (authPerson.hasBuddy(this.personId)) {
|
||||
this.logger.debug("user '{}' is buddy of {}", this.getUserPrincipal(), this.personId);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.securityContext.isUserInRole(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthenticationScheme() {
|
||||
return this.securityContext.getAuthenticationScheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return this.securityContext.isSecure();
|
||||
}
|
||||
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
|
||||
public interface CourseHoleService {
|
||||
|
||||
List<? extends FlexMap> getHolesByNineTee(long nineteeId);
|
||||
|
||||
List<? extends FlexMap> getHolesByEighteenTee(long eighteenteeId);
|
||||
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
|
||||
public interface CourseNineService {
|
||||
|
||||
FlexMap getNine(long courseNineId);
|
||||
|
||||
FlexMap getNine(int courseId, String name);
|
||||
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
public interface CourseRatingService<R> {
|
||||
|
||||
/**
|
||||
* This method computes a golf course eighteen/tee combination's difficulty
|
||||
* rating as of today, inclusive.
|
||||
*
|
||||
* In some cases, there is no computation, but a simple fetch from an external
|
||||
* resource. In other cases the ratings will need to be computed. In other
|
||||
* cases, a rating cannot be determined.
|
||||
*
|
||||
* @param etratingId A unique identifier for a golf course eighteen/tee
|
||||
* combination (gender) rating.
|
||||
* @return A rating for the course; `null` if one cannot be determined.
|
||||
*/
|
||||
R computeEighteenTeeRatingIndex(long etratingId);
|
||||
|
||||
/**
|
||||
* This method computes a golf course nine/tee combination's difficulty rating
|
||||
* as of today, inclusive.
|
||||
*
|
||||
* In some cases, there is no computation, but a simple fetch from an external
|
||||
* resource. In other cases the ratings will need to be computed. In other
|
||||
* cases, a rating cannot be determined.
|
||||
*
|
||||
* @param ntratingId A unique identifier for a golf course nine/tee combination
|
||||
* (gender) rating.
|
||||
* @return A rating for the course; `null` if one cannot be determined.
|
||||
*/
|
||||
R computeNineTeeRatingIndex(long ntratingId);
|
||||
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.brianlong.util.SubList;
|
||||
import com.poststats.service.CacheableService;
|
||||
|
||||
public interface CourseService extends CacheableService<Integer> {
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the specified course.
|
||||
*
|
||||
* This retrieves the facility meta-data as well.
|
||||
*
|
||||
* @param courseId A unique identifier for the course.
|
||||
* @return A map of meta-data specific to the course.
|
||||
*/
|
||||
FlexMap get(int courseId);
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the specified courses.
|
||||
*
|
||||
* This retrieves the facility meta-data as well.
|
||||
*
|
||||
* @param courseIds Unique identifier for the coursees.
|
||||
* @return A map of unique identifiers to meta-data specific to the coursees.
|
||||
*/
|
||||
Map<Integer, ? extends FlexMap> get(Collection<Integer> courseIds);
|
||||
|
||||
default SubList<? extends FlexMap> findByName(String name) {
|
||||
return this.findByName(name, 1, 10);
|
||||
}
|
||||
|
||||
SubList<? extends FlexMap> findByName(String name, int page, int perPage);
|
||||
|
||||
default SubList<? extends FlexMap> findByJurisdiction(String country, String state) {
|
||||
return this.findByJurisdiction(country, state, 1, 50);
|
||||
}
|
||||
|
||||
SubList<? extends FlexMap> findByJurisdiction(String country, String state, int page, int perPage);
|
||||
|
||||
default SubList<? extends FlexMap> findByLocation(double latitude, double longitude) {
|
||||
return this.findByLocation(latitude, longitude, 10, 1, 25);
|
||||
}
|
||||
|
||||
default SubList<? extends FlexMap> findByLocation(double latitude, double longitude, int radiusInMiles) {
|
||||
return this.findByLocation(latitude, longitude, radiusInMiles, 1, 25);
|
||||
}
|
||||
|
||||
SubList<? extends FlexMap> findByLocation(double latitude, double longitude, int radiusInMiles, int page,
|
||||
int perPage);
|
||||
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.service.CacheableService;
|
||||
|
||||
public interface EventDocumentService extends CacheableService<Long> {
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the specified event document.
|
||||
*
|
||||
* @param eventId A unique identifier for the event.
|
||||
* @param eventId A unique identifier for the document.
|
||||
* @return A map of meta-data specific to the event document.
|
||||
*/
|
||||
FlexMap get(long eventId, long documentId);
|
||||
|
||||
}
|
@@ -1,82 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.brianlong.sql.DataSet;
|
||||
|
||||
/**
|
||||
* This service provides financial metadata about the event, series, associated
|
||||
* people, or a combination of those.
|
||||
*
|
||||
* The balance metadata includes money `paid`, `expenses`, and `balance`. The
|
||||
* balance numerically consistent with the perspective of the person, not the
|
||||
* event organizers. That means it is positive when the person paid more than
|
||||
* they should owe and negative if they owe money.
|
||||
*
|
||||
* @author brian
|
||||
*/
|
||||
public interface EventFinanceService {
|
||||
|
||||
/**
|
||||
* Computes and retrieves the person balances for those associated with the
|
||||
* specified event.
|
||||
*
|
||||
* @param eventId The unique identifier of an event.
|
||||
* @return A map of `personId` to balance metadata.
|
||||
*/
|
||||
Map<Long, DataSet> getPersonsBalances(long eventId);
|
||||
|
||||
/**
|
||||
* Computes and retrieves the person balances for those associated with the
|
||||
* specified event.
|
||||
*
|
||||
* @param eventId The unique identifier of an event.
|
||||
* @param minBalance The minimum balance for returned balances; `0.01` for those
|
||||
* that have paid more than they owe; `null` for no
|
||||
* constraint.
|
||||
* @param maxBalance The maximum balance for returned balances; `-0.01` for
|
||||
* those that owe; `null` for no constraint.
|
||||
* @return A map of `personId` to balance metadata.
|
||||
*/
|
||||
Map<Long, DataSet> getPersonsBalances(long eventId, Float minBalance, Float maxBalance);
|
||||
|
||||
/**
|
||||
* Computes and retrieves the specified person's balance for the specified
|
||||
* event.
|
||||
*
|
||||
* @param eventId The unique identifier of an event.
|
||||
* @param personId The unique identifier of a person.
|
||||
* @return Balance metadata.
|
||||
*/
|
||||
DataSet getPersonBalance(long eventId, long personId);
|
||||
|
||||
/**
|
||||
* Computes and retrieves all associated persons' cumulative balance for all
|
||||
* events in the series before the specified event.
|
||||
*
|
||||
* @param eventId The unique identifier of an event.
|
||||
* @return A map of `personId` to balance metadata.
|
||||
*/
|
||||
Map<Long, DataSet> getSeriesPersonsPreviousBalances(long eventId);
|
||||
|
||||
/**
|
||||
* Computes and retrieves the specified person's balances for all events in the
|
||||
* specified series.
|
||||
*
|
||||
* @param seriesId The unique identifier of a series.
|
||||
* @param personId The unique identifier of a person.
|
||||
* @return A map of `eventId` to balance metadata.
|
||||
*/
|
||||
Map<Long, DataSet> getSeriesPersonBalances(int seriesId, long personId);
|
||||
|
||||
/**
|
||||
* Computes and retrieves the specified person's balances for all events in the
|
||||
* series before the specified event.
|
||||
*
|
||||
* @param eventId The unique identifier of an event.
|
||||
* @param personId The unique identifier of a person.
|
||||
* @return A map of `eventId` to balance metadata.
|
||||
*/
|
||||
Map<Long, DataSet> getSeriesPersonPreviousBalances(long eventId, long personId);
|
||||
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.service.CacheableService;
|
||||
import com.poststats.util.Contact;
|
||||
|
||||
public interface EventPersonService extends CacheableService<BigInteger> {
|
||||
|
||||
FlexMap get(BigInteger epersonId);
|
||||
|
||||
FlexMap get(long eventId, long personId);
|
||||
|
||||
List<? extends FlexMap> getPeople(long eventId);
|
||||
|
||||
List<? extends FlexMap> getParticipants(long eventId);
|
||||
|
||||
Set<Long> getSeriesEventFellowParticipantIds(int seriesId, long personId);
|
||||
|
||||
/**
|
||||
* This method retrieves contacts appropriate to the specified parameters.
|
||||
*
|
||||
* If both `allowEmail` and `allowText` are specified, only `allowText` will be
|
||||
* used for users with email and text capability.
|
||||
*
|
||||
* @param eventId The unique identifier of an event.
|
||||
* @param listId The unique identifier of a contact list.
|
||||
* @param allowEmail `true` to allow email contact with each person.
|
||||
* @param allowText `true` to allow text contact with each person.
|
||||
* @return A map of meta-data specific to the person.
|
||||
*/
|
||||
List<Contact> getContactsByListId(long eventId, long listId, boolean allowEmail, boolean allowText);
|
||||
|
||||
/**
|
||||
* This method retrieves contacts appropriate to the specified parameters.
|
||||
*
|
||||
* If both `allowEmail` and `allowText` are specified, only `allowText` will be
|
||||
* used for users with email and text capability.
|
||||
*
|
||||
* @param eventId The unique identifier of an event.
|
||||
* @param autolist The unique identifier of a contact list.
|
||||
* @param allowEmail `true` to allow email contact with each person.
|
||||
* @param allowText `true` to allow text contact with each person.
|
||||
* @return A map of meta-data specific to the person.
|
||||
*/
|
||||
List<Contact> getContactsByAutolist(long eventId, String autolist, boolean allowEmail, boolean allowText);
|
||||
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
|
||||
public interface EventRoundPairingService {
|
||||
|
||||
FlexMap get(BigInteger pairingId);
|
||||
|
||||
List<? extends FlexMap> getByRoundId(long eroundId);
|
||||
|
||||
List<? extends FlexMap> getParticipantsByRoundId(long eroundId);
|
||||
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
|
||||
public interface EventRoundService {
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the specified event round.
|
||||
*
|
||||
* @param eroundId A unique identifier for the event round.
|
||||
* @return A map of meta-data specific to the event round.
|
||||
*/
|
||||
FlexMap get(long eroundId);
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the next event round in the specified
|
||||
* event.
|
||||
*
|
||||
* It will only return more than one event round if the next date has more than
|
||||
* one round. It will return today's round(s) until 6p EST.
|
||||
*
|
||||
* @param eventId A unique identifier for the event.
|
||||
* @return A list of meta-data about each event round.
|
||||
*/
|
||||
List<? extends FlexMap> getUpcoming(long eventId);
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the specified event rounds.
|
||||
*
|
||||
* @param eventId A unique identifier for the event.
|
||||
* @return A map of unique identifiers to meta-data specific to each event
|
||||
* round.
|
||||
*/
|
||||
Map<Long, ? extends FlexMap> getByEventId(long eventId);
|
||||
|
||||
}
|
@@ -1,34 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.service.CacheableService;
|
||||
|
||||
public interface EventService extends CacheableService<Long> {
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the specified event.
|
||||
*
|
||||
* @param eventId A unique identifier for the event.
|
||||
* @return A map of meta-data specific to the event.
|
||||
*/
|
||||
FlexMap get(long eventId);
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the specified event.
|
||||
*
|
||||
* @param eventIds Unique identifiers for the event.
|
||||
* @return A map of unique identifiers to meta-data specific to each event.
|
||||
*/
|
||||
Map<Long, ? extends FlexMap> get(Collection<Long> eventIds);
|
||||
|
||||
Set<Long> getIdsBySeriesId(int seriesId);
|
||||
|
||||
Map<Long, ? extends FlexMap> getBySeriesId(int seriesId);
|
||||
|
||||
Integer getSeriesId(long eventId);
|
||||
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public interface HandicapIndexService<I> {
|
||||
|
||||
/**
|
||||
* This method computes a golfer's handicap index as of today, inclusive.
|
||||
*
|
||||
* This will consider the use of all individually played non-event and event
|
||||
* rounds. Each implementation may exclude more rounds, like unsigned or unrated
|
||||
* courses.
|
||||
*
|
||||
* @param personId A unique identifier for the golfer.
|
||||
* @return A handicap for the golfer.
|
||||
*/
|
||||
default I computeGolferIndex(long personId) {
|
||||
return this.computeGolferIndex(personId, LocalDate.now().plusDays(1L));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method computes a golfer's handicap index as of the specified date,
|
||||
* inclusive.
|
||||
*
|
||||
* This will consider the use of all individually played non-event and event
|
||||
* rounds. Each implementation may exclude more rounds, like unsigned or unrated
|
||||
* courses.
|
||||
*
|
||||
* @param personId A unique identifier for the golfer.
|
||||
* @param beforeDay A date to exclude all rounds on or after.
|
||||
* @return A handicap for the golfer.
|
||||
*/
|
||||
I computeGolferIndex(long personId, LocalDate beforeDay);
|
||||
|
||||
}
|
@@ -1,37 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public interface HandicapScoreService<S> {
|
||||
|
||||
/**
|
||||
* This method computes a non-event round's score.
|
||||
*
|
||||
* The score depends on the handicap system. For instance, the simple
|
||||
* stroke (non-handicap) system, it will be strokes-minus-par. For the
|
||||
* world handicap system (WHS), it will be your adjusted strokes-to-par,
|
||||
* applying the course rating, your handicap, hole handicaps, and course
|
||||
* condition adjustment. For point handicap systems, it will be your
|
||||
* points, including the course adjustment.
|
||||
*
|
||||
* @param roundId A unique identifier for the non-event round.
|
||||
* @return A score for the round.
|
||||
*/
|
||||
S computeRoundScore(BigInteger roundId);
|
||||
|
||||
/**
|
||||
* This method computes a person's event round score.
|
||||
*
|
||||
* The score depends on the handicap system. For instance, the simple
|
||||
* stroke (non-handicap) system, it will be strokes-minus-par. For the
|
||||
* world handicap system (WHS), it will be your adjusted strokes-to-par,
|
||||
* applying the course rating, your handicap, hole handicaps, and course
|
||||
* condition adjustment. For point handicap systems, it will be your
|
||||
* points, including the course adjustment.
|
||||
*
|
||||
* @param proundId A unique identifier for the event/person round.
|
||||
* @return A score for the round.
|
||||
*/
|
||||
S computeEventRoundScore(BigInteger proundId);
|
||||
|
||||
}
|
@@ -1,92 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
|
||||
public interface PersonRoundService {
|
||||
|
||||
public enum Selection { ScoreToPar, StrokeHandicapIndex }
|
||||
|
||||
public enum Filter { AttestedOnly, CourseRatedOnly }
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the specified non-event round.
|
||||
*
|
||||
* @param roundId A unique identifier for the non-event round.
|
||||
* @param selection Include `ScoreToPar` or `StrokeHandicapIndex` values in the
|
||||
* results.
|
||||
* @param filter An array of filters.
|
||||
* @return A non-event round and its meta-data.
|
||||
*/
|
||||
FlexMap fetchNonEvent(BigInteger roundId, Selection selection, Filter... filters);
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the specified golfer's event round.
|
||||
*
|
||||
* @param proundId A unique identifier for a golfer's event round.
|
||||
* @param selection Include `ScoreToPar` or `StrokeHandicapIndex` values in the
|
||||
* results.
|
||||
* @param filter An array of filters.
|
||||
* @return A golfer's event round and its meta-data.
|
||||
*/
|
||||
FlexMap fetchEvent(BigInteger proundId, Selection selection, Filter... filters);
|
||||
|
||||
/**
|
||||
* This method retrieves scores for all holes played in the specified non-event round.
|
||||
*
|
||||
* @param roundId A unique identifier for the non-event round.
|
||||
* @param selection Include `ScoreToPar` or `StrokeHandicapIndex` values in the
|
||||
* results.
|
||||
* @return A list of holes and associated scores.
|
||||
*/
|
||||
List<? extends FlexMap> fetchNonEventHoles(BigInteger roundId, Selection selection);
|
||||
|
||||
/**
|
||||
* This method retrieves scores for all holes played in the specified golfer's event round.
|
||||
*
|
||||
* @param proundId A unique identifier for the golfer's event round.
|
||||
* @param selection Include `ScoreToPar` or `StrokeHandicapIndex` values in the
|
||||
* results.
|
||||
* @return A list of holes and associated scores.
|
||||
*/
|
||||
List<? extends FlexMap> fetchEventHoles(BigInteger proundId, Selection selection);
|
||||
|
||||
/**
|
||||
* This method retrieves recent round meta-data about the specified golfer.
|
||||
*
|
||||
* The rounds are retrieved in reverse chronological order. Both Non-event and
|
||||
* event rounds are included.
|
||||
*
|
||||
* @param personId A unique identifier for the golfer.
|
||||
* @param roundCount A maximum number of rounds to return.
|
||||
* @param selection Include `ScoreToPar` or `StrokeHandicapIndex` values in the
|
||||
* results.
|
||||
* @param filter An array of filters.
|
||||
* @return A list of recent rounds played by the golfer.
|
||||
*/
|
||||
default List<? extends FlexMap> findRecent(long personId, short roundCount, Selection selection,
|
||||
Filter... filters) {
|
||||
return this.findBefore(personId, LocalDate.now().plusDays(1L), roundCount, selection, filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method retrieves recent round meta-data about the specified golfer.
|
||||
*
|
||||
* The rounds are retrieved in reverse chronological order. Both Non-event and
|
||||
* event rounds are included.
|
||||
*
|
||||
* @param personId A unique identifier for the golfer.
|
||||
* @param beforeDay A date to start excluding rounds on or after.
|
||||
* @param roundCount A maximum number of rounds to return.
|
||||
* @param selection Include `ScoreToPar` or `StrokeHandicapIndex` values in the
|
||||
* results.
|
||||
* @param filter An array of filters.
|
||||
* @return A list of recent rounds played by the golfer.
|
||||
*/
|
||||
List<? extends FlexMap> findBefore(long personId, LocalDate beforeDay, short roundCount, Selection selection,
|
||||
Filter... filters);
|
||||
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.security.AuthenticatedPerson;
|
||||
import com.poststats.service.CacheableService;
|
||||
|
||||
public interface PersonService extends CacheableService<Long> {
|
||||
|
||||
/**
|
||||
* This method builds a `UserPrincipal` object about the golfer.
|
||||
*
|
||||
* Unlike the non-golf `PersonService`, this will include golfer and event
|
||||
* roles.
|
||||
*
|
||||
* @param person A non-golf `UserPrincipal` object.
|
||||
* @return A golfer `UserPrincipal` object.
|
||||
*/
|
||||
AuthenticatedPerson getUserPrincipal(com.poststats.security.AuthenticatedPerson person);
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the specified golfer.
|
||||
*
|
||||
* If you want meta-data information about only the person, use the non-golf
|
||||
* `PersonService`.
|
||||
*
|
||||
* This retrieves everything from the non-golf `PersonService` and supplements
|
||||
* it with simple golfer meta-data, like stroke handicaps. It does not include
|
||||
* related data like point handicap or round counts.
|
||||
*
|
||||
* @param personId A unique identifier for the golfer.
|
||||
* @return A map of meta-data specific to the golfer.
|
||||
*/
|
||||
FlexMap get(long personId);
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the specified golfers.
|
||||
*
|
||||
* If you want meta-data information about only the person, use the non-golf
|
||||
* `PersonService`.
|
||||
*
|
||||
* This retrieves everything from the non-golf `PersonService` and supplements
|
||||
* it with simple golfer meta-data, like stroke handicaps. It does not include
|
||||
* related data like point handicap or round counts.
|
||||
*
|
||||
* @param personIds Unique identifiers for the golfers.
|
||||
* @return A map of unique identifiers to meta-data specific to each golfer.
|
||||
*/
|
||||
Map<Long, ? extends FlexMap> get(Collection<Long> personIds);
|
||||
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.brianlong.sql.DataSet;
|
||||
|
||||
public interface SeriesPersonService {
|
||||
|
||||
List<DataSet> getSeriesPeople(int seriesId);
|
||||
|
||||
List<DataSet> getSeriesParticipants(int seriesId);
|
||||
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
package com.poststats.golf.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.service.CacheableService;
|
||||
|
||||
public interface SeriesService extends CacheableService<Integer> {
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the specified series.
|
||||
*
|
||||
* @param seriesId A unique identifier for the series.
|
||||
* @return A map of meta-data specific to the series.
|
||||
*/
|
||||
FlexMap get(int seriesId);
|
||||
|
||||
/**
|
||||
* This method retrieves meta-data about the specified series.
|
||||
*
|
||||
* @param seriesIds Unique identifiers for the series.
|
||||
* @return A map of unique identifiers to meta-data specific to each series.
|
||||
*/
|
||||
Map<Integer, ? extends FlexMap> get(Collection<Integer> seriesIds);
|
||||
|
||||
/**
|
||||
* This method retrieves series meta-data about the specified event.
|
||||
*
|
||||
* @param eventId A unique identifier for the event.
|
||||
* @return A map of meta-data specific to the series.
|
||||
*/
|
||||
FlexMap getByEventId(long eventId);
|
||||
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
package com.poststats.golf.service.compute;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.service.CourseRatingService;
|
||||
import com.poststats.golf.service.HandicapIndexService;
|
||||
import com.poststats.golf.service.HandicapScoreService;
|
||||
import com.poststats.golf.service.PersonRoundService;
|
||||
import com.poststats.golf.service.PersonRoundService.Filter;
|
||||
import com.poststats.golf.service.PersonRoundService.Selection;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
public abstract class AbstractHandicappingService<I, R, S> implements HandicapIndexService<I>, CourseRatingService<R>, HandicapScoreService<S> {
|
||||
|
||||
@Inject
|
||||
protected PersonRoundService personRoundService;
|
||||
|
||||
protected short getMinimumRounds() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected abstract short getMaximumRounds();
|
||||
|
||||
protected abstract Selection getRoundSelection();
|
||||
|
||||
protected Filter[] getRoundFilter() {
|
||||
return new Filter[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public I computeGolferIndex(long personId, LocalDate beforeDay) {
|
||||
List<? extends FlexMap> rounds = this.personRoundService.findBefore(personId, beforeDay,
|
||||
this.getMaximumRounds(), this.getRoundSelection(), this.getRoundFilter());
|
||||
if (rounds.size() < this.getMinimumRounds())
|
||||
throw new IllegalStateException("The person does not have enough rounds to compute a handicap index");
|
||||
|
||||
return this.compute(rounds);
|
||||
}
|
||||
|
||||
public abstract I compute(List<? extends FlexMap> rounds);
|
||||
|
||||
}
|
@@ -1,242 +0,0 @@
|
||||
package com.poststats.golf.service.compute;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.brianlong.util.MapUtil;
|
||||
import com.poststats.golf.service.PersonRoundService.Selection;
|
||||
import com.poststats.golf.service.model.PointHandicapIndex;
|
||||
|
||||
public abstract class AbstractPointHandicappingService extends AbstractHandicappingService<PointHandicapIndex, Byte, Short> {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Override
|
||||
protected short getMaximumRounds() {
|
||||
return 15;
|
||||
}
|
||||
|
||||
protected short getBestRoundsToToss(short roundCount) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected abstract short getWorstRoundsToToss(short roundCount);
|
||||
|
||||
protected abstract short getPointTarget();
|
||||
|
||||
protected abstract float getAccelerant();
|
||||
|
||||
protected float getHomeCourseZeroRate() {
|
||||
return 0.25f;
|
||||
}
|
||||
|
||||
protected float getHomeCourseMultiplier() {
|
||||
return 4f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Selection getRoundSelection() {
|
||||
return Selection.ScoreToPar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointHandicapIndex compute(List<? extends FlexMap> rounds) {
|
||||
short target = this.getPointTarget();
|
||||
short bestRoundsToToss = this.getBestRoundsToToss((short) rounds.size());
|
||||
short worstRoundsToToss = this.getWorstRoundsToToss((short) rounds.size());
|
||||
short roundsToCount = (short) (rounds.size() - bestRoundsToToss - worstRoundsToToss);
|
||||
float forgiveness = 0.5f;
|
||||
|
||||
Map<Integer, Float> computedPoints = new HashMap<>();
|
||||
PointHandicapIndex bestLowPhi = null;
|
||||
PointHandicapIndex bestHighPhi = null;
|
||||
|
||||
Pair<Integer, Float> homeCourseAdj = this.computeHomeCourseAdjustment(rounds);
|
||||
this.logger.debug("Computed home course adjustment: {}", homeCourseAdj);
|
||||
|
||||
short[] scoreToParCounts = this.computeScoreToParCounts(rounds);
|
||||
byte[] mostCommonScoreToPar = this.determineMostCommonStoresToPar(scoreToParCounts, (byte) 2);
|
||||
this.logger.debug("Determined most common score-to-par: {}", mostCommonScoreToPar);
|
||||
|
||||
PointHandicapIndex phi = this.generateIndexBy2MostCommon(mostCommonScoreToPar[0],
|
||||
scoreToParCounts[(mostCommonScoreToPar[0] + 10) % 10], mostCommonScoreToPar[1],
|
||||
scoreToParCounts[(mostCommonScoreToPar[1] + 10) % 10], target, this.getAccelerant());
|
||||
this.logger.debug("Base point handicap index: {}", phi);
|
||||
|
||||
byte lastHighScoreToPar = 6;
|
||||
byte lastLowScoreToPar = -4;
|
||||
|
||||
while (true) {
|
||||
List<Integer> roundsPoints = new ArrayList<>(rounds.size());
|
||||
for (FlexMap round : rounds) {
|
||||
int points = round.getByte("bogey5") * phi.getQuintupleBogeyPoints()
|
||||
+ round.getByte("bogey4") * phi.getQuadrupleBogeyPoints()
|
||||
+ round.getByte("bogey3") * phi.getTripleBogeyPoints()
|
||||
+ round.getByte("bogey2") * phi.getDoubleBogeyPoints()
|
||||
+ round.getByte("bogey") * phi.getBogeyPoints() + round.getByte("par") * phi.getParPoints()
|
||||
+ round.getByte("birdie") * phi.getBirdiePoints()
|
||||
+ round.getByte("eagle") * phi.getEaglePoints()
|
||||
+ round.getByte("alby") * phi.getAlbatrossPoints() + round.getByte("pointAdj");
|
||||
if (round.getInteger("courseID").equals(homeCourseAdj.getKey())) {
|
||||
// always negative, so we are making the course seem easier for the home course
|
||||
// player
|
||||
points += homeCourseAdj.getValue().intValue();
|
||||
}
|
||||
|
||||
roundsPoints.add(points);
|
||||
}
|
||||
|
||||
Collections.sort(roundsPoints);
|
||||
float points = 0f;
|
||||
for (Integer roundPoints : roundsPoints.subList(worstRoundsToToss, roundsPoints.size() - bestRoundsToToss))
|
||||
points += roundPoints.floatValue();
|
||||
points /= roundsToCount;
|
||||
computedPoints.put(phi.getId(), points);
|
||||
this.logger.debug("Computed {} points with index: {}", points, phi);
|
||||
|
||||
if (Math.abs(points - target) < forgiveness) {
|
||||
System.out.println(points);
|
||||
return phi;
|
||||
}
|
||||
forgiveness += 0.02f;
|
||||
|
||||
if (points > target) {
|
||||
this.logger.debug("{} points are higher than the target {}; trying something lower", points, target);
|
||||
if (lastHighScoreToPar < -2)
|
||||
lastHighScoreToPar = 6;
|
||||
lastHighScoreToPar--;
|
||||
phi = phi.decrement(lastHighScoreToPar);
|
||||
} else {
|
||||
this.logger.debug("{} points are lower than the target {}; trying something higher", points, target);
|
||||
if (lastLowScoreToPar > 4)
|
||||
lastLowScoreToPar = -4;
|
||||
lastLowScoreToPar++;
|
||||
phi = phi.increment(lastLowScoreToPar);
|
||||
}
|
||||
|
||||
// make sure we are not guaranteed to be outside the bounds of the best low/high
|
||||
// if the best low/high with nothing possible in between, pick the one that is
|
||||
// closest
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Short computeRoundScore(BigInteger roundId) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Short computeEventRoundScore(BigInteger proundId) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private PointHandicapIndex generateIndexBy2MostCommon(byte mostCommonScoreToParIndex,
|
||||
short mostCommonScoreToParCount, byte nextMostCommonScoreToParIndex, short nextMostCommonScoreToParCount,
|
||||
short pointTarget, float accelerant) {
|
||||
boolean roundDown = nextMostCommonScoreToParIndex < mostCommonScoreToParCount;
|
||||
float targetPerHole = pointTarget / 18f;
|
||||
int[] pointsForScoreToPar = new int[10];
|
||||
int targetScoreToParIndex = (mostCommonScoreToParIndex + 10) % 10;
|
||||
double factor = Math.pow(Math.E, accelerant);
|
||||
|
||||
// floor the target, so we target low
|
||||
byte lastPointsForScoreToPar = roundDown ? (byte) targetPerHole : (byte) Math.ceil(targetPerHole);
|
||||
pointsForScoreToPar[targetScoreToParIndex] = lastPointsForScoreToPar;
|
||||
|
||||
// go forward: higher scores; lower points; eventually 0 points
|
||||
for (byte scoreToPar = (byte) (mostCommonScoreToParIndex + 1); scoreToPar < 6; scoreToPar++) {
|
||||
int scoreToParIndex = (scoreToPar + 10) % 10;
|
||||
lastPointsForScoreToPar = (byte) Math.max(0,
|
||||
Math.min(lastPointsForScoreToPar - 1, Math.ceil(lastPointsForScoreToPar / factor)));
|
||||
pointsForScoreToPar[scoreToParIndex] = lastPointsForScoreToPar;
|
||||
}
|
||||
|
||||
lastPointsForScoreToPar = (byte) pointsForScoreToPar[targetScoreToParIndex];
|
||||
|
||||
// go backwards; lower scores; higher points
|
||||
for (byte scoreToPar = (byte) (mostCommonScoreToParIndex - 1); scoreToPar > -4; scoreToPar--) {
|
||||
int scoreToParIndex = (scoreToPar + 10) % 10;
|
||||
lastPointsForScoreToPar = (byte) Math.max(lastPointsForScoreToPar + 1,
|
||||
Math.floor(lastPointsForScoreToPar * factor));
|
||||
pointsForScoreToPar[scoreToParIndex] = lastPointsForScoreToPar;
|
||||
}
|
||||
|
||||
return new PointHandicapIndex(pointsForScoreToPar);
|
||||
}
|
||||
|
||||
protected Pair<Integer, Float> computeHomeCourseAdjustment(List<? extends FlexMap> rounds) {
|
||||
Pair<Integer, Float> maxHomeCourseAdj = Pair.of(null, 0f);
|
||||
float zeroRate = this.getHomeCourseMultiplier() * this.getHomeCourseZeroRate();
|
||||
|
||||
Map<Integer, Integer> courseIdCounts = MapUtil.countKeys(rounds, "courseID", Integer.class);
|
||||
for (Entry<Integer, Integer> courseIdCount : courseIdCounts.entrySet()) {
|
||||
float homeCourseAdj = courseIdCount.getValue() * -this.getHomeCourseMultiplier() / rounds.size() + zeroRate;
|
||||
if (homeCourseAdj < maxHomeCourseAdj.getRight())
|
||||
maxHomeCourseAdj = Pair.of(courseIdCount.getKey(), homeCourseAdj);
|
||||
if (homeCourseAdj <= -1f)
|
||||
// over 50%; we are done
|
||||
break;
|
||||
}
|
||||
|
||||
return maxHomeCourseAdj;
|
||||
}
|
||||
|
||||
protected short[] computeScoreToParCounts(List<? extends FlexMap> rounds) {
|
||||
short[] scoreToParTotalHoles = new short[10];
|
||||
|
||||
for (FlexMap round : rounds) {
|
||||
scoreToParTotalHoles[5] += round.getByte("bogey5");
|
||||
scoreToParTotalHoles[4] += round.getByte("bogey4");
|
||||
scoreToParTotalHoles[3] += round.getByte("bogey3");
|
||||
scoreToParTotalHoles[2] += round.getByte("bogey2");
|
||||
scoreToParTotalHoles[1] += round.getByte("bogey");
|
||||
scoreToParTotalHoles[0] += round.getByte("par");
|
||||
scoreToParTotalHoles[9] += round.getByte("birdie");
|
||||
scoreToParTotalHoles[8] += round.getByte("eagle");
|
||||
scoreToParTotalHoles[7] += round.getByte("alby");
|
||||
}
|
||||
|
||||
return scoreToParTotalHoles;
|
||||
}
|
||||
|
||||
protected byte[] determineMostCommonStoresToPar(short[] scoreToParCounts, byte xNumberOfMostCommonIndex) {
|
||||
byte[] maxScoreToPar = new byte[xNumberOfMostCommonIndex];
|
||||
for (byte i = 0; i < xNumberOfMostCommonIndex; i++)
|
||||
maxScoreToPar[i] = 6; // unused and always 0
|
||||
|
||||
for (byte scoreToPar = 0; scoreToPar < 10; scoreToPar++) {
|
||||
for (int i = 0; i < xNumberOfMostCommonIndex; i++) {
|
||||
if (scoreToParCounts[maxScoreToPar[i]] < scoreToParCounts[scoreToPar]) {
|
||||
for (int i2 = xNumberOfMostCommonIndex - 1; i2 > 0; i2--) {
|
||||
maxScoreToPar[i2] = maxScoreToPar[i2 - 1];
|
||||
break;
|
||||
}
|
||||
|
||||
maxScoreToPar[i] = scoreToPar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < maxScoreToPar.length; i++)
|
||||
maxScoreToPar[i] = maxScoreToPar[i] < 0 ? (byte) (maxScoreToPar[i] - 10) : maxScoreToPar[i];
|
||||
return maxScoreToPar;
|
||||
}
|
||||
|
||||
}
|
@@ -1,415 +0,0 @@
|
||||
package com.poststats.golf.service.compute;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.brianlong.sql.FlexPreparedStatement;
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.service.PersonRoundService.Selection;
|
||||
import com.poststats.golf.service.PersonService;
|
||||
import com.poststats.golf.service.model.StrokeCourseRating;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.Statement;
|
||||
import com.poststats.provider.StatementProvider;
|
||||
import com.poststats.provider.TransactionalProvider;
|
||||
import com.poststats.service.ServiceException;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
public abstract class AbstractStrokeHandicappingService
|
||||
extends AbstractHandicappingService<Float, StrokeCourseRating, Float> {
|
||||
|
||||
@Inject
|
||||
private Logger logger;
|
||||
|
||||
@Inject
|
||||
private PersonService personService;
|
||||
|
||||
private final Comparator<FlexMap> roundComparator;
|
||||
|
||||
public AbstractStrokeHandicappingService() {
|
||||
this.roundComparator = new Comparator<FlexMap>() {
|
||||
@Override
|
||||
public int compare(FlexMap round1, FlexMap round2) {
|
||||
Float sh1 = round1.getFloat(getStrokeHandicapColumn());
|
||||
Float sh2 = round2.getFloat(getStrokeHandicapColumn());
|
||||
return sh1.compareTo(sh2);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract String getStrokeHandicapColumn();
|
||||
|
||||
protected abstract String getHoleHandicapColumn();
|
||||
|
||||
@Override
|
||||
protected Selection getRoundSelection() {
|
||||
return Selection.StrokeHandicapIndex;
|
||||
}
|
||||
|
||||
protected short getRoundsToCount(short rounds) {
|
||||
switch (rounds) {
|
||||
case 0:
|
||||
throw new IllegalArgumentException();
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
return 1;
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
return 2;
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
return 3;
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
return 4;
|
||||
case 15:
|
||||
case 16:
|
||||
return 5;
|
||||
case 17:
|
||||
case 18:
|
||||
return 6;
|
||||
case 19:
|
||||
return 7;
|
||||
case 20:
|
||||
return 8;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float compute(List<? extends FlexMap> rounds) {
|
||||
Collections.sort(rounds, this.roundComparator);
|
||||
short roundsToCount = this.getRoundsToCount((short) rounds.size());
|
||||
return this.compute(rounds.subList(0, roundsToCount), (short) rounds.size());
|
||||
}
|
||||
|
||||
public Float compute(List<? extends FlexMap> rounds, short roundsConsidered) {
|
||||
float sh = 0f;
|
||||
for (FlexMap round : rounds)
|
||||
sh += round.getFloat(this.getStrokeHandicapColumn());
|
||||
sh /= rounds.size();
|
||||
|
||||
float adjustment = this.getHandicapAdjustment(roundsConsidered);
|
||||
return sh + adjustment;
|
||||
}
|
||||
|
||||
protected float getHandicapAdjustment(short rounds) {
|
||||
switch (rounds) {
|
||||
case 0:
|
||||
throw new IllegalArgumentException();
|
||||
case 1:
|
||||
return -3f;
|
||||
case 2:
|
||||
case 3:
|
||||
return -2f;
|
||||
case 4:
|
||||
case 6:
|
||||
return -1f;
|
||||
default:
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public StrokeCourseRating computeNineTeeRatingIndex(long ntratingId) {
|
||||
FlexMap ntrating = this.getNineTeeRating(ntratingId);
|
||||
if (ntrating == null)
|
||||
return null;
|
||||
|
||||
LocalDateTime syncd = ntrating.getDateTime("syncd");
|
||||
if (LocalDateTime.now().getYear() == syncd.getYear() && LocalDateTime.now().minusMonths(3).isBefore(syncd))
|
||||
// assume it hasn't changed if sync'd within the last 3 months and still the same calendar year
|
||||
return new StrokeCourseRating(ntrating.getShort("slopeRating"), ntrating.getFloat("courseRating"));
|
||||
|
||||
CourseMetadata courseMeta = this.fetchNineTeeRating(ntratingId);
|
||||
if (courseMeta == null)
|
||||
return null;
|
||||
|
||||
this.updateNineTeeRating(ntratingId, courseMeta);
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
// FIXME return new StrokeCourseRating(courseMeta.getSlopeRating(), courseMeta.getCourseRating());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StrokeCourseRating computeEighteenTeeRatingIndex(long etratingId) {
|
||||
FlexMap etrating = this.getNineTeeRating(etratingId);
|
||||
if (etrating == null)
|
||||
return null;
|
||||
|
||||
LocalDateTime syncd = etrating.getDateTime("syncd");
|
||||
if (LocalDateTime.now().getYear() == syncd.getYear() && LocalDateTime.now().minusMonths(3).isBefore(syncd))
|
||||
// assume it hasn't changed if sync'd within the last 3 months and still the same calendar year
|
||||
return new StrokeCourseRating(etrating.getShort("slopeRating"), etrating.getFloat("courseRating"));
|
||||
|
||||
CourseMetadata courseMeta = this.fetchEighteenTeeRating(etratingId);
|
||||
if (courseMeta == null)
|
||||
return null;
|
||||
|
||||
this.updateEighteenTeeRating(etratingId, courseMeta);
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
// FIXME return new StrokeCourseRating(courseMeta.getSlopeRating(), courseMeta.getCourseRating());
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Float computeEighteenTeeRatingHandicap(long etratingId, long personId) {
|
||||
FlexMap person = this.personService.get(personId);
|
||||
Float strokeHandicap = person.getFloat(this.getStrokeHandicapColumn());
|
||||
if (strokeHandicap == null)
|
||||
return null;
|
||||
|
||||
CourseMetadata courseMeta = this.fetchEighteenTeeRating(etratingId);
|
||||
|
||||
float handicap = strokeHandicap.floatValue();
|
||||
if (courseMeta.getSlopeRating() != null)
|
||||
handicap = handicap * courseMeta.getSlopeRating() / 113f;
|
||||
if (courseMeta.getCourseRating() != null)
|
||||
handicap += courseMeta.getCourseRating() - courseMeta.getPar();
|
||||
return handicap;
|
||||
}
|
||||
|
||||
public Float computeNineTeeRatingHandicap(long ntratingId, long personId) {
|
||||
FlexMap person = this.personService.get(personId);
|
||||
Float strokeHandicap = person.getFloat(this.getStrokeHandicapColumn());
|
||||
if (strokeHandicap == null)
|
||||
return null;
|
||||
|
||||
CourseMetadata courseMeta = this.fetchNineTeeRating(ntratingId);
|
||||
|
||||
float handicap = strokeHandicap.floatValue() / 2f;
|
||||
if (courseMeta.getSlopeRating() != null)
|
||||
handicap = handicap * courseMeta.getSlopeRating() / 113f;
|
||||
if (courseMeta.getCourseRating() != null)
|
||||
handicap += courseMeta.getCourseRating() - courseMeta.getPar();
|
||||
return handicap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float computeRoundScore(BigInteger roundId) {
|
||||
FlexMap round = this.personRoundService.fetchNonEvent(roundId, this.getRoundSelection(), this.getRoundFilter());
|
||||
if (round == null) {
|
||||
this.logger.debug("The round does not exist or does not meeting the requirements to be handicap scored: {}", roundId);
|
||||
return null;
|
||||
}
|
||||
|
||||
List<? extends FlexMap> holes = this.personRoundService.fetchNonEventHoles(roundId, this.getRoundSelection());
|
||||
if (holes.size() != 18) {
|
||||
this.logger.debug("The round does not have 18 scored holes; cannot compute handicap score: {}", roundId);
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.computeRoundScore(round, holes, roundId, "round");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float computeEventRoundScore(BigInteger proundId) {
|
||||
FlexMap pround = this.personRoundService.fetchEvent(proundId, this.getRoundSelection(), this.getRoundFilter());
|
||||
if (pround == null) {
|
||||
// the round either doesn't exist or it is not eligible for handicap computation
|
||||
return null;
|
||||
}
|
||||
|
||||
int totalHolesNeeded = pround.isNotEmpty("ntratingID") ? 9 : 18;
|
||||
List<? extends FlexMap> holes = this.personRoundService.fetchEventHoles(proundId, this.getRoundSelection());
|
||||
if (holes.size() != totalHolesNeeded) {
|
||||
this.logger.debug("The pround does not have {} scored holes; cannot compute handicap score: {}", totalHolesNeeded, proundId);
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.computeRoundScore(pround, holes, proundId, "pround");
|
||||
}
|
||||
|
||||
private Float computeRoundScore(FlexMap round, List<? extends FlexMap> holes, Object roundId, String msgName) {
|
||||
// prepare for equitable stroke control
|
||||
Pair<Byte, Byte> esc = this.computeEquitableStrokeControl(round.getLong("personID"));
|
||||
|
||||
int escStrokes = 0;
|
||||
for (FlexMap hole : holes) {
|
||||
Byte strokeIndex = hole.getByte(this.getHoleHandicapColumn());
|
||||
if (strokeIndex == null) {
|
||||
this.logger.debug("The course for the {} does not have the appropriate hole handicaps to compute the handicap with equitable stroke control: {}", msgName, roundId);
|
||||
return null;
|
||||
}
|
||||
|
||||
int scoreToPar = hole.getByte("strokes") - hole.getByte("par");
|
||||
if (strokeIndex.byteValue() <= esc.getRight().byteValue()) {
|
||||
scoreToPar = Math.min(scoreToPar, esc.getLeft() + 1);
|
||||
} else {
|
||||
scoreToPar = Math.min(scoreToPar, esc.getLeft());
|
||||
}
|
||||
|
||||
escStrokes += scoreToPar + hole.getByte("par");
|
||||
}
|
||||
|
||||
float adjStrokes = (float) escStrokes;
|
||||
if (round.getFloat("courseRating") != null) {
|
||||
adjStrokes -= round.getFloat("courseRating").floatValue();
|
||||
} else {
|
||||
adjStrokes -= round.getByte("par").floatValue();
|
||||
}
|
||||
|
||||
if (round.getShort("slopeRating") != null)
|
||||
adjStrokes = adjStrokes * 113 / round.getShort("slopeRating").floatValue();
|
||||
|
||||
return adjStrokes;
|
||||
}
|
||||
|
||||
private Pair<Byte, Byte> computeEquitableStrokeControl(long personId) {
|
||||
byte netDoubleBogey = 5;
|
||||
byte netDoubleBogeyRemainder = 0;
|
||||
FlexMap person = this.personService.get(personId);
|
||||
Float strokeHandicap = person.getFloat(this.getStrokeHandicapColumn());
|
||||
if (strokeHandicap != null) {
|
||||
byte baseHandicap = (byte) Math.round(strokeHandicap.floatValue());
|
||||
netDoubleBogey = (byte) (baseHandicap / 18 + 2);
|
||||
netDoubleBogeyRemainder = (byte) (baseHandicap % 18);
|
||||
}
|
||||
|
||||
return Pair.of(netDoubleBogey, netDoubleBogeyRemainder);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private CourseMetadata fetchNineTeeRating(long ntratingId) {
|
||||
// TODO call WHS service for the information
|
||||
return null;
|
||||
}
|
||||
|
||||
private CourseMetadata fetchEighteenTeeRating(long etratingId) {
|
||||
// TODO call WHS service for the information
|
||||
return null;
|
||||
}
|
||||
|
||||
private FlexMap getNineTeeRating(long ntratingId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectCourseNineTeeRating.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, ntratingId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT CNTR.*, CNT.par, CNT.yards "
|
||||
+ "FROM ~g~.CourseNineTeeRating CNTR "
|
||||
+ " INNER JOIN ~g~.CourseNineTee CNT ON (CNTR.nineteeID=CNT.nineteeID) "
|
||||
+ "WHERE CNTR.ntratingID=? "
|
||||
)
|
||||
private StatementProvider sqlSelectCourseNineTeeRating;
|
||||
|
||||
private FlexMap getEighteenTeeRating(long etratingId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectCourseEighteenTeeRating.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, etratingId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT CETR.*, CET.par, CET.yards "
|
||||
+ "FROM ~g~.CourseEighteenTeeRating CETR "
|
||||
+ " INNER JOIN ~g~.CourseEighteenTee CET ON (CETR.eighteenteeID=CET.eighteenteeID) "
|
||||
+ "WHERE CETR.etratingID=? "
|
||||
)
|
||||
private StatementProvider sqlSelectCourseEighteenTeeRating;
|
||||
|
||||
private void updateNineTeeRating(long ntratingId, CourseMetadata courseMeta) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlUpdateCourseNineTeeRating.buildPreparedStatement();
|
||||
try {
|
||||
//fps.setTinyintU(1, courseMeta.getSlopeRating());
|
||||
//fps.setTinyintU(2, courseMeta.getCourseRating());
|
||||
fps.setIntegerU(3, ntratingId);
|
||||
fps.executeUpdate();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@TransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "UPDATE ~g~.CourseNineTeeRating "
|
||||
+ "SET slopeRating=?, courseRating=? "
|
||||
+ "WHERE ntratingID=? "
|
||||
)
|
||||
private StatementProvider sqlUpdateCourseNineTeeRating;
|
||||
|
||||
private void updateEighteenTeeRating(long etratingId, CourseMetadata courseMeta) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlUpdateCourseEighteenTeeRating.buildPreparedStatement();
|
||||
try {
|
||||
//fps.setTinyintU(1, courseMeta.getSlopeRating());
|
||||
//fps.setTinyintU(2, courseMeta.getCourseRating());
|
||||
fps.setIntegerU(3, etratingId);
|
||||
fps.executeUpdate();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@TransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "UPDATE ~g~.CourseEighteenTeeRating "
|
||||
+ "SET slopeRating=?, courseRating=? "
|
||||
+ "WHERE etratingID=? "
|
||||
)
|
||||
private StatementProvider sqlUpdateCourseEighteenTeeRating;
|
||||
|
||||
|
||||
|
||||
private interface CourseMetadata {
|
||||
// TODO replace with WHS model
|
||||
Short getSlopeRating();
|
||||
Float getCourseRating();
|
||||
byte getPar();
|
||||
}
|
||||
|
||||
}
|
@@ -1,117 +0,0 @@
|
||||
package com.poststats.golf.service.compute;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
public class LegacyPostStatsPointHandicapIndexService extends AbstractPointHandicappingService {
|
||||
|
||||
@Override
|
||||
protected float getAccelerant() {
|
||||
return 0.6f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected short getPointTarget() {
|
||||
return 60;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected short getWorstRoundsToToss(short roundCount) {
|
||||
switch (roundCount) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return 0;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
return 1;
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
return 2;
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
return 3;
|
||||
case 15:
|
||||
return 4;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected short getBestRoundsToToss(short roundCount) {
|
||||
return (short) (roundCount < 13 ? 0 : 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte computeEighteenTeeRatingIndex(long etratingId) {
|
||||
FlexMap etrating = this.courseRatingService.getEighteenTeeRating(etratingId);
|
||||
return this.computeEighteenTeeRatingIndex(etrating);
|
||||
}
|
||||
|
||||
protected Byte computeEighteenTeeRatingIndex(FlexMap etrating) {
|
||||
Short slopeRating = etrating.getShort("slopeRating");
|
||||
Float courseRating = etrating.getFloat("courseRating");
|
||||
char gender = etrating.getString("gender").charAt(0);
|
||||
short yards = etrating.getShort("yards");
|
||||
byte par = etrating.getByte("par");
|
||||
return this.computeRatingIndex(slopeRating, courseRating, gender, yards, par);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte computeNineTeeRatingIndex(long ntratingId) {
|
||||
FlexMap ntrating = this.courseRatingService.getNineTeeRating(ntratingId);
|
||||
return this.computeNineTeeRatingIndex(ntrating);
|
||||
}
|
||||
|
||||
protected Byte computeNineTeeRatingIndex(FlexMap ntrating) {
|
||||
Short slopeRating = ntrating.getShort("slopeRating");
|
||||
Float courseRating = ntrating.getFloat("courseRating");
|
||||
char gender = ntrating.getString("gender").charAt(0);
|
||||
short yards = ntrating.getShort("yards");
|
||||
byte par = ntrating.getByte("par");
|
||||
return this.computeRatingIndex(slopeRating, courseRating, gender, yards, par);
|
||||
}
|
||||
|
||||
protected Byte computeRatingIndex(Short slopeRating, Float courseRating, char gender, short yards, byte par) {
|
||||
// A par X hole assumes (X-2) non-putts and 2 putts to complete par
|
||||
// So an 18 hole course assumes 36 putts and (X-36) non-putts to complete par
|
||||
int nonPuttPar = par - 36;
|
||||
// we normalize those (X-2) full strokes, so par 60 courses get a normalization
|
||||
// ratio of 36/24 or 1.5
|
||||
// that means we need to 1.5x any yards/par/ratings to make it look like a
|
||||
// standard par 72 course
|
||||
double normalizedRatioNonPuttPar = 36.0 / nonPuttPar;
|
||||
// we normalize the yards to look like a standard par 72 course
|
||||
double normalizedYards = yards * normalizedRatioNonPuttPar;
|
||||
|
||||
// we are linearly applying the yards, where:
|
||||
// 6000 yd par 72 has 0 points
|
||||
// 6350 yd par 72 has 6 points
|
||||
// 6500 yd par 70 has 9 points
|
||||
// 7000 yd par 71 has 18 points
|
||||
// 3000 yd par 54 has 0 points
|
||||
// 2000 yd par 54 has -34 points
|
||||
int genderYards = gender == 'M' ? 6000 : 5000;
|
||||
double adjYards = normalizedYards - genderYards;
|
||||
byte yardBonus = (byte) (adjYards * 3.0 / 175.0);
|
||||
|
||||
if (slopeRating == null)
|
||||
return (byte) (yardBonus * 2);
|
||||
|
||||
// a 130 slope course has 10 points
|
||||
// a 155 slope (max) course has 21 points
|
||||
// a 55 slope (min) course has -21 points
|
||||
byte slopeBonus = (byte) ((slopeRating - 105) * 3 / 7);
|
||||
return (byte) (yardBonus + slopeBonus);
|
||||
}
|
||||
|
||||
}
|
@@ -1,136 +0,0 @@
|
||||
package com.poststats.golf.service.compute;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.service.CourseHoleService;
|
||||
import com.poststats.golf.service.CourseRatingService;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@ApplicationScoped
|
||||
public class PostStatsPointHandicapIndexService extends AbstractPointHandicappingService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Inject
|
||||
private CourseRatingService courseRatingService;
|
||||
|
||||
@Inject
|
||||
private CourseHoleService courseHoleService;
|
||||
|
||||
@Override
|
||||
protected float getAccelerant() {
|
||||
return 0.5f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected short getPointTarget() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected short getWorstRoundsToToss(short roundCount) {
|
||||
switch (roundCount) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
return 0;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
return 1;
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
return 2;
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
return 3;
|
||||
case 15:
|
||||
return 4;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected short getBestRoundsToToss(short roundCount) {
|
||||
return (short) (roundCount < 10 ? 0 : 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte computeEighteenTeeRatingIndex(long etratingId) {
|
||||
FlexMap etrating = this.courseRatingService.getEighteenTeeRating(etratingId);
|
||||
List<? extends FlexMap> holes = this.courseHoleService.getHolesByEighteenTee(etrating.getLong("eighteenteeID"));
|
||||
return this.computeRatingIndex(etrating, holes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte computeNineTeeRatingIndex(long ntratingId) {
|
||||
FlexMap ntrating = this.courseRatingService.getNineTeeRating(ntratingId);
|
||||
List<? extends FlexMap> holes = this.courseHoleService.getHolesByEighteenTee(ntrating.getLong("nineteeID"));
|
||||
return this.computeRatingIndex(ntrating, holes);
|
||||
}
|
||||
|
||||
protected Byte computeRatingIndex(FlexMap netrating, List<? extends FlexMap> holes) {
|
||||
// M normalized to 150 yd (150 + 3 * 8) par 3s
|
||||
// F normalized to 125 yd (125 + 3 * 8) par 3s
|
||||
char gender = netrating.getString("gender").charAt(0);
|
||||
float divisorBase = gender == 'M' ? 165f : 140f;
|
||||
|
||||
// capture running total for points
|
||||
float points = 0;
|
||||
|
||||
for (FlexMap hole : holes) {
|
||||
short yards = hole.getShort("yards");
|
||||
byte par = hole.getByte("par");
|
||||
|
||||
// par assumes 2 putts per hole
|
||||
int nonPuttPar = par - 2;
|
||||
float nonPuttYardsPerStroke = 1f * yards / nonPuttPar;
|
||||
|
||||
// make longer par 4s/5s correlate with shorter par 3s, as it is harder to
|
||||
// "score" (birdies/eagles) on par 3s than par 5s
|
||||
float exponentDivisor = divisorBase - (par * 5);
|
||||
|
||||
// 80 yd par 3 will be -3.89 pts
|
||||
// 100 yd par 3 will be -3.16 pts
|
||||
// 125 yd par 3 (272/4 or 446/5) will be -2.1 pts
|
||||
// 150 yd par 3 (326/4 or 536/5) will be -0.85 pts
|
||||
// 200 yd par 3 (435/4 or 714/5) will be +2.38 pts
|
||||
// 225 yd par 3 (489/4 or 804/5) will be +4.45 pts
|
||||
points += Math.pow(Math.E, nonPuttYardsPerStroke / exponentDivisor) * 3f - 9f;
|
||||
}
|
||||
|
||||
if (netrating.isNotEmpty("etratingID")) {
|
||||
this.logger.debug("computed course rating: et #{} => {}", netrating.get("etratingID"), points);
|
||||
} else {
|
||||
this.logger.debug("computed course rating: nt #{} => {}", netrating.get("ntratingID"), points);
|
||||
}
|
||||
|
||||
Float courseRating = netrating.getFloat("courseRating");
|
||||
if (courseRating == null)
|
||||
return (byte) points;
|
||||
|
||||
byte par = netrating.getByte("par");
|
||||
float difficulty = courseRating - par;
|
||||
|
||||
// 69 rating on par 72 gets -9 pts
|
||||
// 72 rating on par 72 gets +0 pts
|
||||
// 73 rating on par 72 gets +3 pts
|
||||
// 75 rating on par 72 gets +9 pts
|
||||
double ratingAdj = 3 * difficulty;
|
||||
|
||||
return (byte) (points + ratingAdj);
|
||||
}
|
||||
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
package com.poststats.golf.service.compute;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
public class PostStatsStrokeHandicappingService extends AbstractStrokeHandicappingService {
|
||||
|
||||
@Override
|
||||
protected short getMaximumRounds() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStrokeHandicapColumn() {
|
||||
return "strokeHandicapIndex";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHoleHandicapColumn() {
|
||||
return "handicap";
|
||||
}
|
||||
|
||||
}
|
@@ -1,37 +0,0 @@
|
||||
package com.poststats.golf.service.compute;
|
||||
|
||||
import com.poststats.golf.service.PersonRoundService.Filter;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
public class WhsStrokeHandicapIndexService extends AbstractStrokeHandicappingService {
|
||||
|
||||
@Override
|
||||
protected short getMinimumRounds() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected short getMaximumRounds() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStrokeHandicapColumn() {
|
||||
return "whsStrokeHandicapIndex";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHoleHandicapColumn() {
|
||||
return "whsHandicap";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Filter[] getRoundFilter() {
|
||||
return new Filter[] {
|
||||
Filter.AttestedOnly, Filter.CourseRatedOnly
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@@ -1,277 +0,0 @@
|
||||
package com.poststats.golf.service.db;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.brianlong.sql.DataSet;
|
||||
import com.brianlong.sql.FlexManyToOneDef;
|
||||
import com.brianlong.sql.FlexPreparedStatement;
|
||||
import com.brianlong.sql.ResultSubSetFeature;
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.brianlong.util.SubList;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.service.CourseHoleService;
|
||||
import com.poststats.golf.service.CourseNineService;
|
||||
import com.poststats.golf.service.CourseService;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.Statement;
|
||||
import com.poststats.provider.StatementProvider;
|
||||
import com.poststats.service.FacilityService;
|
||||
import com.poststats.service.ServiceException;
|
||||
import com.poststats.service.db.CacheableServiceDAO;
|
||||
import com.poststats.sql.PostStatsSQL;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@ApplicationScoped
|
||||
public class CourseServiceDAO extends CacheableServiceDAO<Integer>
|
||||
implements CourseService, CourseNineService, CourseHoleService {
|
||||
|
||||
private final int defaultCacheExpirationInSeconds = 600;
|
||||
private final FlexManyToOneDef facilityManyToOneDef = new FlexManyToOneDef("facilityID", "facility");
|
||||
|
||||
@Inject
|
||||
private FacilityService facilityService;
|
||||
|
||||
@Override
|
||||
public FlexMap get(int courseId) {
|
||||
return this.get(Integer.valueOf(courseId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlexMap injectDeep(String idKey, FlexMap parentMap, String mapKey) {
|
||||
FlexMap map = this.inject(idKey, parentMap, mapKey);
|
||||
return this.facilityService.inject("facilityID", map, "facility");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends FlexMap> injectDeep(String idKey, Collection<? extends FlexMap> parentMaps,
|
||||
String mapKey) {
|
||||
Collection<? extends FlexMap> maps = this.inject(idKey, parentMaps, mapKey);
|
||||
return this.facilityService.inject("facilityID", maps, "facility");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubList<? extends FlexMap> findByName(String name, int page, int perPage) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectByName.buildPreparedStatement();
|
||||
try {
|
||||
fps.setVarchar(1, "%"
|
||||
+ name
|
||||
+ "%");
|
||||
fps.setVarchar(2, "%"
|
||||
+ name
|
||||
+ "%");
|
||||
fps.setSmallintU(3, (page - 1) * perPage);
|
||||
fps.setSmallintU(4, perPage);
|
||||
return (SubList<? extends FlexMap>) fps.executeQuery().getAllRows(this.facilityManyToOneDef);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
feature = ResultSubSetFeature.class,
|
||||
sql = "SELECT C.courseID, C.course, C.access, CP.prefix, "
|
||||
+ " F.*, FP.prefix, FS.suffix, FS.suffixAbbrev "
|
||||
+ "FROM ~g~.Course C "
|
||||
+ " LEFT JOIN ~g~.CoursePrefix CP ON (C.prefixID=CP.prefixID) "
|
||||
+ " INNER JOIN ~p~.Facility F ON (C.facilityID=F.facilityID) "
|
||||
+ " LEFT JOIN ~p~.FacilityPrefix FP ON (F.prefixID=FP.prefixID) "
|
||||
+ " LEFT JOIN ~p~.FacilitySuffix FS ON (F.suffixID=FS.suffixID) "
|
||||
+ "WHERE C.course LIKE ? OR F.facility LIKE ? "
|
||||
)
|
||||
private StatementProvider sqlSelectByName;
|
||||
|
||||
@Override
|
||||
public SubList<? extends FlexMap> findByJurisdiction(String country, String state, int page, int perPage) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectByJurisdiction.buildPreparedStatement();
|
||||
try {
|
||||
fps.setVarchar(1, country);
|
||||
fps.setVarchar(2, state);
|
||||
fps.setSmallintU(3, (page - 1) * perPage);
|
||||
fps.setSmallintU(4, perPage);
|
||||
return (SubList<? extends FlexMap>) fps.executeQuery().getAllRows(this.facilityManyToOneDef);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
feature = ResultSubSetFeature.class,
|
||||
sql = "SELECT C.courseID, C.course, C.access, CP.prefix, "
|
||||
+ " F.*, FP.prefix, FS.suffix, FS.suffixAbbrev "
|
||||
+ "FROM ~g~.Course C "
|
||||
+ " LEFT JOIN ~g~.CoursePrefix CP ON (C.prefixID=CP.prefixID) "
|
||||
+ " INNER JOIN ~p~.Facility F ON (C.facilityID=F.facilityID) "
|
||||
+ " LEFT JOIN ~p~.FacilityPrefix FP ON (F.prefixID=FP.prefixID) "
|
||||
+ " LEFT JOIN ~p~.FacilitySuffix FS ON (F.suffixID=FS.suffixID) "
|
||||
+ "WHERE F.addrcountry=? AND F.addrstate=? "
|
||||
+ " AND C.deadline IS NULL "
|
||||
)
|
||||
private StatementProvider sqlSelectByJurisdiction;
|
||||
|
||||
@Override
|
||||
public SubList<? extends FlexMap> findByLocation(double latitude, double longitude, int radiusInMiles, int page,
|
||||
int perPage) {
|
||||
double degrees = PostStatsSQL.miles2degrees(radiusInMiles);
|
||||
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectByGeolocation.buildPreparedStatement();
|
||||
try {
|
||||
fps.setDouble(1, latitude - degrees);
|
||||
fps.setDouble(2, latitude + degrees);
|
||||
fps.setDouble(3, longitude - degrees);
|
||||
fps.setDouble(4, longitude + degrees);
|
||||
fps.setSmallintU(5, (page - 1) * perPage);
|
||||
fps.setSmallintU(6, perPage);
|
||||
return (SubList<? extends FlexMap>) fps.executeQuery().getAllRows(this.facilityManyToOneDef);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
feature = ResultSubSetFeature.class,
|
||||
sql = "SELECT C.courseID, C.course, C.access, CP.prefix, "
|
||||
+ " F.*, FP.prefix, FS.suffix, FS.suffixAbbrev "
|
||||
+ "FROM ~g~.Course C "
|
||||
+ " LEFT JOIN ~g~.CoursePrefix CP ON (C.prefixID=CP.prefixID) "
|
||||
+ " INNER JOIN ~p~.Facility F ON (C.facilityID=F.facilityID) "
|
||||
+ " LEFT JOIN ~p~.FacilityPrefix FP ON (F.prefixID=FP.prefixID) "
|
||||
+ " LEFT JOIN ~p~.FacilitySuffix FS ON (F.suffixID=FS.suffixID) "
|
||||
+ "WHERE F.latitude>=? AND F.latitude<=? AND F.longitude>=? AND F.longitude<=? "
|
||||
+ " AND C.deadline IS NULL "
|
||||
)
|
||||
private StatementProvider sqlSelectByGeolocation;
|
||||
|
||||
@Override
|
||||
protected long getCacheExpirationInSeconds() {
|
||||
return this.defaultCacheExpirationInSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSet fetchOne(Integer courseId) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectCourse.buildPreparedStatement();
|
||||
try {
|
||||
fps.setSmallintU(1, courseId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT CP.*, C.* "
|
||||
+ "FROM ~g~.Course C "
|
||||
+ " LEFT JOIN ~g~.CoursePrefix CP ON (C.prefixID=CP.prefixID) "
|
||||
+ "WHERE C.courseID=? "
|
||||
)
|
||||
private StatementProvider sqlSelectCourse;
|
||||
|
||||
@Override
|
||||
protected Map<Integer, DataSet> fetchBulk(Collection<Integer> courseIds) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectCourses.buildPreparedStatement(courseIds);
|
||||
try {
|
||||
return fps.executeQuery().getAllRows("courseID", Integer.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT CP.*, C.* "
|
||||
+ "FROM ~g~.Course C "
|
||||
+ " LEFT JOIN ~g~.CoursePrefix CP ON (C.prefixID=CP.prefixID) "
|
||||
+ "WHERE C.courseID IN (??) "
|
||||
)
|
||||
private StatementProvider sqlSelectCourses;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public FlexMap getNine(long nineId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectCourseNine.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, nineId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT * FROM ~g~.CourseNine WHERE nineID=? ")
|
||||
private StatementProvider sqlSelectCourseNine;
|
||||
|
||||
@Override
|
||||
public FlexMap getNine(int courseId, String name) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectCourseNineByName.buildPreparedStatement();
|
||||
try {
|
||||
fps.setSmallintU(1, courseId);
|
||||
fps.setVarchar(2, name);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT * FROM ~g~.CourseNine WHERE courseID=? AND nine=? AND deadline IS NULL ")
|
||||
private StatementProvider sqlSelectCourseNineByName;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public List<? extends FlexMap> getHolesByEighteenTee(long eighteenteeId) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends FlexMap> getHolesByNineTee(long nineteeId) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
package com.poststats.golf.service.db;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import com.brianlong.sql.DataSet;
|
||||
import com.brianlong.sql.FlexPreparedStatement;
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.service.EventDocumentService;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.Statement;
|
||||
import com.poststats.provider.StatementProvider;
|
||||
import com.poststats.service.db.CacheableServiceDAO;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@ApplicationScoped
|
||||
public class EventDocumentServiceDAO extends CacheableServiceDAO<Long> implements EventDocumentService {
|
||||
|
||||
private final long defaultCacheExpirationInSeconds = 3600;
|
||||
|
||||
@Override
|
||||
public FlexMap get(long eventId, long documentId) {
|
||||
FlexMap document = this.get(documentId);
|
||||
if (document != null && eventId != document.getLong("eventID"))
|
||||
return null;
|
||||
return document;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getCacheExpirationInSeconds() {
|
||||
return this.defaultCacheExpirationInSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSet fetchOne(Long documentId) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectEventDocument.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, documentId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT ED.* "
|
||||
+ "FROM ~g~.EventDocument ED "
|
||||
+ "WHERE ED.documentId=? "
|
||||
)
|
||||
private StatementProvider sqlSelectEventDocument;
|
||||
|
||||
@Override
|
||||
protected Map<Long, DataSet> fetchBulk(Collection<Long> documentIds) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectEvents.buildPreparedStatement(documentIds);
|
||||
try {
|
||||
return fps.executeQuery().getAllRows("documentID", Long.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT ED.* "
|
||||
+ "FROM ~g~.EventDocument ED "
|
||||
+ "WHERE ED.documentId IN (??) "
|
||||
)
|
||||
private StatementProvider sqlSelectEvents;
|
||||
|
||||
}
|
@@ -1,300 +0,0 @@
|
||||
package com.poststats.golf.service.db;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Map;
|
||||
|
||||
import com.brianlong.sql.DataSet;
|
||||
import com.brianlong.sql.FlexPreparedStatement;
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.service.EventFinanceService;
|
||||
import com.poststats.golf.service.EventService;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.Statement;
|
||||
import com.poststats.provider.StatementProvider;
|
||||
import com.poststats.service.ServiceException;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@ApplicationScoped
|
||||
public class EventFinanceServiceDAO implements EventFinanceService {
|
||||
|
||||
@Inject
|
||||
private EventService eventService;
|
||||
|
||||
@Override
|
||||
public Map<Long, DataSet> getPersonsBalances(long eventId) {
|
||||
return this.getPersonsBalances(eventId, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, DataSet> getPersonsBalances(long eventId, Float minBalance, Float maxBalance) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectBalances.buildPreparedStatement();
|
||||
try {
|
||||
for (int i = 1; i <= 5; i++)
|
||||
fps.setIntegerU(i, eventId);
|
||||
fps.setFloat(6, minBalance == null ? -1e20f : minBalance);
|
||||
fps.setFloat(7, maxBalance == null ? 1e20f : maxBalance);
|
||||
return fps.executeQuery().getAllRows("personID", Long.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSet getPersonBalance(long eventId, long personId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectPersonBalances.buildPreparedStatement();
|
||||
try {
|
||||
for (int i = 1; i <= 10; i += 2) {
|
||||
fps.setIntegerU(i, eventId);
|
||||
fps.setIntegerU(i + 1, personId);
|
||||
}
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, DataSet> getSeriesPersonsPreviousBalances(long eventId) {
|
||||
FlexMap event = this.eventService.get(eventId);
|
||||
int seriesId = event.getInteger("seriesID");
|
||||
LocalDate liveline = event.getDate("liveline");
|
||||
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectSeriesBalances.buildPreparedStatement();
|
||||
try {
|
||||
for (int i = 1; i <= 15; i += 3) {
|
||||
fps.setSmallintU(i, seriesId);
|
||||
fps.setIntegerU(i + 1, eventId);
|
||||
fps.setDate(i + 2, liveline);
|
||||
}
|
||||
return fps.executeQuery().getAllRows("personID", Long.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, DataSet> getSeriesPersonBalances(int seriesId, long personId) {
|
||||
return this.getSeriesPersonBalances(seriesId, null, null, personId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, DataSet> getSeriesPersonPreviousBalances(long eventId, long personId) {
|
||||
FlexMap event = this.eventService.get(eventId);
|
||||
int seriesId = event.getInteger("seriesID");
|
||||
LocalDate liveline = event.getDate("liveline");
|
||||
return this.getSeriesPersonBalances(seriesId, eventId, liveline, personId);
|
||||
}
|
||||
|
||||
private Map<Long, DataSet> getSeriesPersonBalances(int seriesId, Long eventId, LocalDate liveline, long personId) {
|
||||
if (eventId == null)
|
||||
eventId = -1L;
|
||||
if (liveline == null)
|
||||
liveline = LocalDate.now().plusYears(10L);
|
||||
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectSeriesPersonEventBalances.buildPreparedStatement();
|
||||
try {
|
||||
for (int i = 1; i <= 20; i += 4) {
|
||||
fps.setSmallintU(i, seriesId);
|
||||
fps.setIntegerU(i + 1, eventId);
|
||||
fps.setDate(i + 2, liveline);
|
||||
fps.setIntegerU(i + 3, personId);
|
||||
}
|
||||
return fps.executeQuery().getAllRows("personID", Long.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT TT.personID, TT.epersonID, SUM(TT.expenses) expenses, SUM(TT.paid) paid, (SUM(TT.paid)-SUM(TT.expenses)) balance "
|
||||
+ "FROM ("
|
||||
+ " SELECT ALL EP.personID, EP.epersonID, IF(EB.projectedValue IS NULL, 0, EB.projectedValue) expenses, 0 paid "
|
||||
+ " FROM ~g~.EventPerson EP "
|
||||
+ " LEFT JOIN ~g~.EventBudget EB ON (EP.eventID=EB.eventID) "
|
||||
+ " WHERE EP.eventID=? "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL EP.personID, EP.epersonID, EO.amount expenses, 0 paid "
|
||||
+ " FROM ~g~.EventPerson EP "
|
||||
+ " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
|
||||
+ " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
|
||||
+ " WHERE EP.eventID=? AND EPO.answer='Y' AND EO.amount IS NOT NULL AND EO.waive IS FALSE "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL EP.personID, EP.epersonID, EO.amount expenses, 0 paid "
|
||||
+ " FROM ~g~.EventPerson EP "
|
||||
+ " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
|
||||
+ " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
|
||||
+ " WHERE EP.eventID=? AND EPO.itemID IS NOT NULL "
|
||||
+ " AND (EO.multiple IS FALSE OR EO.funded='option' OR EO.static IS NOT NULL) "
|
||||
+ " AND EO.amount IS NOT NULL AND EO.waive IS FALSE "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL EP.personID, EP.epersonID, EOI.amount expenses, 0 paid "
|
||||
+ " FROM ~g~.EventPerson EP "
|
||||
+ " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
|
||||
+ " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
|
||||
+ " INNER JOIN ~g~.EventOptionItem EOI ON (EPO.itemID=EOI.itemID) "
|
||||
+ " WHERE EP.eventID=? AND EO.waive IS FALSE AND EO.funded='selection' AND EOI.amount IS NOT NULL "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL EPP.personID, EP.epersonID, 0 expenses, EPP.amount paid "
|
||||
+ " FROM ~g~.EventPersonPayment EPP "
|
||||
+ " LEFT JOIN ~g~.EventPerson EP ON (EPP.eventID=EP.eventID AND EPP.personID=EP.personID) "
|
||||
+ " WHERE EPP.eventID=?) TT "
|
||||
+ "GROUP BY TT.personID "
|
||||
+ "HAVING (SUM(TT.paid)-SUM(TT.expenses))>=? AND (SUM(TT.paid)-SUM(TT.expenses))<=? "
|
||||
)
|
||||
private StatementProvider sqlSelectBalances;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT SUM(TT.expenses) expenses, SUM(TT.paid) paid, (SUM(TT.paid)-SUM(TT.expenses)) balance "
|
||||
+ "FROM ("
|
||||
+ " SELECT ALL EP.personID, EP.epersonID, IF(EB.projectedValue IS NULL, 0, EB.projectedValue) expenses, 0 paid "
|
||||
+ " FROM ~g~.EventPerson EP "
|
||||
+ " LEFT JOIN ~g~.EventBudget EB ON (EP.eventID=EB.eventID) "
|
||||
+ " WHERE EP.eventID=? AND EP.personID=? "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL EP.personID, EP.epersonID, EO.amount expenses, 0 paid "
|
||||
+ " FROM ~g~.EventPerson EP "
|
||||
+ " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
|
||||
+ " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
|
||||
+ " WHERE EP.eventID=? AND EP.personID=? AND EPO.answer='Y' AND EO.amount IS NOT NULL AND EO.waive IS FALSE "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL EP.personID, EP.epersonID, EO.amount expenses, 0 paid "
|
||||
+ " FROM ~g~.EventPerson EP "
|
||||
+ " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
|
||||
+ " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
|
||||
+ " WHERE EP.eventID=? AND EP.personID=? AND EPO.itemID IS NOT NULL "
|
||||
+ " AND (EO.multiple IS FALSE OR EO.funded='option' OR EO.static IS NOT NULL) "
|
||||
+ " AND EO.amount IS NOT NULL AND EO.waive IS FALSE "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL EP.personID, EP.epersonID, EOI.amount expenses, 0 paid "
|
||||
+ " FROM ~g~.EventPerson EP "
|
||||
+ " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
|
||||
+ " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
|
||||
+ " INNER JOIN ~g~.EventOptionItem EOI ON (EPO.itemID=EOI.itemID) "
|
||||
+ " WHERE EP.eventID=? AND EP.personID=? AND EO.waive IS FALSE AND EO.funded='selection' AND EOI.amount IS NOT NULL "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL EPP.personID, EP.epersonID, 0 expenses, EPP.amount paid "
|
||||
+ " FROM ~g~.EventPersonPayment EPP "
|
||||
+ " LEFT JOIN ~g~.EventPerson EP ON (EPP.eventID=EP.eventID AND EPP.personID=EP.personID) "
|
||||
+ " WHERE EPP.eventID=? AND EPP.personID=?) TT "
|
||||
)
|
||||
private StatementProvider sqlSelectPersonBalances;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT TT.personID, TT.epersonID, SUM(TT.expenses) expenses, SUM(TT.paid) paid, (SUM(TT.paid)-SUM(TT.expenses)) balance "
|
||||
+ "FROM ("
|
||||
+ " SELECT ALL EP.personID, EP.epersonID, IF(EB.projectedValue IS NULL, 0, EB.projectedValue) expenses, 0 paid "
|
||||
+ " FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (E.eventID=EP.eventID) "
|
||||
+ " INNER JOIN ~g~.EventBudget EB ON (EP.eventID=EB.eventID) "
|
||||
+ " WHERE E.seriesID=? AND E.eventID<>? AND E.liveline<? "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL EP.personID, EP.epersonID, EO.amount expenses, 0 paid "
|
||||
+ " FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (E.eventID=EP.eventID) "
|
||||
+ " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
|
||||
+ " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
|
||||
+ " WHERE E.seriesID=? AND E.eventID<>? AND E.liveline<? AND EPO.answer='Y' AND EO.amount IS NOT NULL AND EO.waive IS FALSE "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL EP.personID, EP.epersonID, EO.amount expenses, 0 paid "
|
||||
+ " FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (E.eventID=EP.eventID) "
|
||||
+ " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
|
||||
+ " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
|
||||
+ " WHERE E.seriesID=? AND E.eventID<>? AND E.liveline<? AND EPO.itemID IS NOT NULL "
|
||||
+ " AND (EO.multiple IS FALSE OR EO.funded='option' OR EO.static IS NOT NULL) "
|
||||
+ " AND EO.amount IS NOT NULL AND EO.waive IS FALSE "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL EP.personID, EP.epersonID, EOI.amount expenses, 0 paid "
|
||||
+ " FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (E.eventID=EP.eventID) "
|
||||
+ " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
|
||||
+ " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
|
||||
+ " INNER JOIN ~g~.EventOptionItem EOI ON (EPO.itemID=EOI.itemID) "
|
||||
+ " WHERE E.seriesID=? AND E.eventID<>? AND E.liveline<? AND EO.waive IS FALSE AND EO.funded='selection' AND EOI.amount IS NOT NULL "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL EPP.personID, EP.epersonID, 0 expenses, EPP.amount paid "
|
||||
+ " FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.EventPersonPayment EPP ON (E.eventID=EPP.eventID) "
|
||||
+ " LEFT JOIN ~g~.EventPerson EP ON (EPP.eventID=EP.eventID AND EPP.personID=EP.personID) "
|
||||
+ " WHERE E.seriesID=? AND E.eventID<>? AND E.liveline<?) TT "
|
||||
+ "GROUP BY TT.personID"
|
||||
)
|
||||
private StatementProvider sqlSelectSeriesBalances;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT TT.eventID, TT.epersonID, SUM(TT.expenses) expenses, SUM(TT.paid) paid, (SUM(TT.paid)-SUM(TT.expenses)) balance "
|
||||
+ "FROM ("
|
||||
+ " SELECT ALL E.eventID, EP.epersonID, IF(EB.projectedValue IS NULL, 0, EB.projectedValue) expenses, 0 paid "
|
||||
+ " FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (E.eventID=EP.eventID) "
|
||||
+ " INNER JOIN ~g~.EventBudget EB ON (EP.eventID=EB.eventID) "
|
||||
+ " WHERE E.seriesID=? AND E.eventID<>? AND E.liveline<? AND EP.personID=? "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL E.eventID, EP.epersonID, EO.amount expenses, 0 paid "
|
||||
+ " FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (E.eventID=EP.eventID) "
|
||||
+ " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
|
||||
+ " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
|
||||
+ " WHERE E.seriesID=? AND E.eventID<>? AND E.liveline<? AND EP.personID=? "
|
||||
+ " AND EPO.answer='Y' AND EO.amount IS NOT NULL AND EO.waive IS FALSE "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL E.eventID, EP.epersonID, EO.amount expenses, 0 paid "
|
||||
+ " FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (E.eventID=EP.eventID) "
|
||||
+ " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
|
||||
+ " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
|
||||
+ " WHERE E.seriesID=? AND E.eventID<>? AND E.liveline<? AND EP.personID=? AND EPO.itemID IS NOT NULL "
|
||||
+ " AND (EO.multiple IS FALSE OR EO.funded='option' OR EO.static IS NOT NULL) "
|
||||
+ " AND EO.amount IS NOT NULL AND EO.waive IS FALSE "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL E.eventID, EP.epersonID, EOI.amount expenses, 0 paid "
|
||||
+ " FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (E.eventID=EP.eventID) "
|
||||
+ " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
|
||||
+ " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
|
||||
+ " INNER JOIN ~g~.EventOptionItem EOI ON (EPO.itemID=EOI.itemID) "
|
||||
+ " WHERE E.seriesID=? AND E.eventID<>? AND E.liveline<? AND EP.personID=? "
|
||||
+ " AND EO.waive IS FALSE AND EO.funded='selection' AND EOI.amount IS NOT NULL "
|
||||
+ " UNION ALL "
|
||||
+ " SELECT ALL E.eventID, EP.epersonID, 0 expenses, EPP.amount paid "
|
||||
+ " FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.EventPersonPayment EPP ON (E.eventID=EPP.eventID) "
|
||||
+ " LEFT JOIN ~g~.EventPerson EP ON (EPP.eventID=EP.eventID AND EPP.personID=EP.personID) "
|
||||
+ " WHERE E.seriesID=? AND E.eventID<>? AND E.liveline<? AND EPP.personID=?) TT "
|
||||
+ "GROUP BY TT.eventID"
|
||||
)
|
||||
private StatementProvider sqlSelectSeriesPersonEventBalances;
|
||||
|
||||
}
|
@@ -1,404 +0,0 @@
|
||||
package com.poststats.golf.service.db;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.brianlong.sql.DataSet;
|
||||
import com.brianlong.sql.FlexPreparedStatement;
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.service.EventFinanceService;
|
||||
import com.poststats.golf.service.EventPersonService;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.Statement;
|
||||
import com.poststats.provider.StatementProvider;
|
||||
import com.poststats.service.ServiceException;
|
||||
import com.poststats.service.db.CacheableServiceDAO;
|
||||
import com.poststats.util.Contact;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.mail.MessagingException;
|
||||
|
||||
@ApplicationScoped
|
||||
public class EventPersonServiceDAO extends CacheableServiceDAO<BigInteger> implements EventPersonService {
|
||||
|
||||
@Inject
|
||||
private EventFinanceService eventFinanceService;
|
||||
|
||||
@Override
|
||||
public FlexMap get(long eventId, long personId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectEventPersonByEventIdPersonId.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, eventId);
|
||||
fps.setIntegerU(2, personId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT * FROM ~g~.EventPerson WHERE eventID=? AND personID=?")
|
||||
private StatementProvider sqlSelectEventPersonByEventIdPersonId;
|
||||
|
||||
@Override
|
||||
public List<? extends FlexMap> getPeople(long eventId) {
|
||||
try {
|
||||
return this.query(this.sqlSelectPersons, eventId, 2);
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT EP.* FROM ~g~.EventPerson EP WHERE EP.eventID=? "
|
||||
+ "UNION "
|
||||
+ "SELECT DISTINCT NULL, personID "
|
||||
+ "FROM ~g~.EventPersonAccessControl EPAC "
|
||||
+ " LEFT JOIN ~g~.EventPerson EP ON (EPAC.eventID=EP.eventID AND EPAC.personID=EP.personID) "
|
||||
+ "WHERE EPAC.eventID=? AND EP.personID IS NULL "
|
||||
)
|
||||
private StatementProvider sqlSelectPersons;
|
||||
|
||||
@Override
|
||||
public List<? extends FlexMap> getParticipants(long eventId) {
|
||||
try {
|
||||
return this.query(this.sqlSelectParticipantIds, eventId, 1);
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT * FROM ~g~.EventPerson WHERE eventID=? AND pending IS FALSE")
|
||||
private StatementProvider sqlSelectParticipantIds;
|
||||
|
||||
@Override
|
||||
public Set<Long> getSeriesEventFellowParticipantIds(int seriesId, long personId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectFellowParticipants.buildPreparedStatement();
|
||||
try {
|
||||
fps.setSmallintU(1, seriesId);
|
||||
fps.setIntegerU(2, personId);
|
||||
return fps.executeQuery().getFirstColumn(Long.class, new HashSet<>());
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT DISTINCT EP2.personID "
|
||||
+ "FROM ~g~.EventPerson EP1 "
|
||||
+ " INNER JOIN Event E ON (EP1.eventID=E.eventID) "
|
||||
+ " INNER JOIN EventPerson EP2 ON (E.eventID=EP2.eventID) "
|
||||
+ "WHERE EP1.personID=? AND EP1.pending IS FALSE AND E.seriesID=? AND EP2.pending IS FALSE "
|
||||
)
|
||||
private StatementProvider sqlSelectFellowParticipants;
|
||||
|
||||
private List<? extends FlexMap> query(StatementProvider provider, long eventId, int parameterCount)
|
||||
throws SQLException {
|
||||
FlexPreparedStatement fps = provider.buildPreparedStatement();
|
||||
try {
|
||||
for (int i = 1; i <= parameterCount; i++)
|
||||
fps.setIntegerU(i, eventId);
|
||||
return fps.executeQuery().getAllRows();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Contact> getContactsByListId(long eventId, long listId, boolean allowEmail, boolean allowText) {
|
||||
try {
|
||||
List<? extends FlexMap> persons = this.getByContactListIds(eventId, listId);
|
||||
|
||||
List<Contact> contacts = new ArrayList<>(persons.size());
|
||||
for (FlexMap person : persons)
|
||||
contacts.add(new Contact(person, allowEmail, allowText));
|
||||
return contacts;
|
||||
} catch (MessagingException me) {
|
||||
throw new ServiceException(me);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Contact> getContactsByAutolist(long eventId, String autolist, boolean allowEmail, boolean allowText) {
|
||||
try {
|
||||
List<? extends FlexMap> persons = this.getByAutolist(eventId, autolist);
|
||||
|
||||
List<Contact> contacts = new ArrayList<>(persons.size());
|
||||
for (FlexMap person : persons)
|
||||
contacts.add(new Contact(person, allowEmail, allowText));
|
||||
return contacts;
|
||||
} catch (MessagingException me) {
|
||||
throw new ServiceException(me);
|
||||
}
|
||||
}
|
||||
|
||||
public List<? extends FlexMap> getByContactListIds(long eventId, long listId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectByListId.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, eventId);
|
||||
fps.setIntegerU(2, listId);
|
||||
return fps.executeQuery().getAllRows();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT P.* "
|
||||
+ "FROM ~g~.EventContactList ECL "
|
||||
+ " INNER JOIN ~p~.ContactListPerson CLP ON (ECL.listID=CLP.listID) "
|
||||
+ " INNER JOIN ~p~.Person P ON (CLP.personID=P.personID) "
|
||||
+ "WHERE ECL.eventID=? AND ECL.listID=? "
|
||||
)
|
||||
private StatementProvider sqlSelectByListId;
|
||||
|
||||
public List<? extends FlexMap> getByAutolist(long eventId, String autolist) {
|
||||
switch (autolist) {
|
||||
case "balance":
|
||||
Map<Long, DataSet> balances = this.eventFinanceService.getPersonsBalances(eventId, null, -0.01f);
|
||||
return new ArrayList<>(balances.values());
|
||||
default:
|
||||
}
|
||||
|
||||
StatementProvider statementProvider = this.getStatementProviderByAutolist(autolist);
|
||||
try {
|
||||
FlexPreparedStatement fps = this.getStatementByAutolist(statementProvider, eventId, autolist);
|
||||
try {
|
||||
return fps.executeQuery().getAllRows();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
private StatementProvider getStatementProviderByAutolist(String autolist) {
|
||||
switch (autolist) {
|
||||
case "all":
|
||||
return this.sqlSelectEventAllIds;
|
||||
case "signed":
|
||||
return this.sqlSelectEventParticipantIds;
|
||||
case "unsigned":
|
||||
return this.sqlSelectEventRumormillIds;
|
||||
case "rookies":
|
||||
return this.sqlSelectEventRookieIds;
|
||||
case "rookies-refs":
|
||||
return this.sqlSelectEventRookieReferralIds;
|
||||
case "options":
|
||||
return this.sqlSelectEventParticipantIdsWithUnansweredOptions;
|
||||
default:
|
||||
}
|
||||
|
||||
if (autolist.startsWith("previous")) {
|
||||
if (autolist.length() > "previous".length()) {
|
||||
return this.sqlSelectRecentSeriesParticipantIds;
|
||||
} else {
|
||||
return this.sqlSelectSeriesParticipantIds;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private FlexPreparedStatement getStatementByAutolist(StatementProvider statementProvider, long eventId,
|
||||
String autolist) throws SQLException {
|
||||
int weeks = -1;
|
||||
if (autolist.startsWith("previous") && autolist.length() > "previous".length())
|
||||
weeks = Integer.parseInt(autolist.substring("previous".length() + 1));
|
||||
|
||||
FlexPreparedStatement fps = statementProvider.buildPreparedStatement();
|
||||
try {
|
||||
int c = 1;
|
||||
fps.setIntegerU(c++, eventId);
|
||||
if (weeks >= 0) {
|
||||
fps.setIntegerU(c++, eventId);
|
||||
fps.setSmallintU(c++, weeks);
|
||||
fps.setSmallintU(c++, weeks);
|
||||
}
|
||||
if (autolist.equals("all") || autolist.equals("rookies-refs") || autolist.startsWith("previous")) {
|
||||
fps.setIntegerU(c++, eventId);
|
||||
}
|
||||
|
||||
return fps;
|
||||
} catch (SQLException se) {
|
||||
fps.close();
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT personID, epersonID FROM ~g~.EventPerson WHERE eventID=?")
|
||||
private StatementProvider sqlSelectEventParticipantIds;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT personID, NULL epersonID FROM ~g~.EventPersonContract WHERE eventID=?")
|
||||
private StatementProvider sqlSelectEventRumormillIds;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT personID, epersonID FROM ~g~.EventPerson WHERE eventID=? "
|
||||
+ "UNION "
|
||||
+ "SELECT personID, NULL epersonID FROM ~g~.EventPersonContract WHERE eventID=? "
|
||||
)
|
||||
private StatementProvider sqlSelectEventAllIds;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT DISTINCT EP.personID, EP.epersonID "
|
||||
+ "FROM ~g~.EventPerson EP "
|
||||
+ " LEFT JOIN ~g~.EventPerson EP2 ON (EP.eventID<>EP2.eventID AND EP.personID=EP2.personID) "
|
||||
+ "WHERE EP.eventID=? AND EP2.epersonID IS NULL"
|
||||
)
|
||||
private StatementProvider sqlSelectEventRookieIds;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT DISTINCT EP.personID "
|
||||
+ "FROM ~g~.EventPerson EP "
|
||||
+ " LEFT JOIN ~g~.EventPerson EP2 ON (EP.eventID<>EP2.eventID AND EP.personID=EP2.personID) "
|
||||
+ "WHERE EP.eventID=? AND EP2.epersonID IS NULL "
|
||||
+ "UNION "
|
||||
+ "SELECT DISTINCT P.referralPersonID "
|
||||
+ "FROM ~g~.EventPerson EP "
|
||||
+ " LEFT JOIN ~g~.EventPerson EP2 ON (EP.eventID<>EP2.eventID AND EP.personID=EP2.personID) "
|
||||
+ " INNER JOIN ~p~.Person P ON (EP.personID=P.personID) "
|
||||
+ "WHERE EP.eventID=? AND EP2.epersonID IS NULL AND P.referralPersonID IS NOT NULL"
|
||||
)
|
||||
private StatementProvider sqlSelectEventRookieReferralIds;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT EP.personID, EP.epersonID "
|
||||
+ "FROM ~g~.EventPerson EP "
|
||||
+ " INNER JOIN ?TT? TT1 ON (EP.personID=TT1.personID) "
|
||||
+ "WHERE EP.eventID=? "
|
||||
+ "GROUP BY EP.personID HAVING SUM(TT1.balance) < 0 "
|
||||
)
|
||||
private StatementProvider sqlSelectEventParticipantIdsWithBalance;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT DISTINCT EP.personID, EP.epersonID "
|
||||
+ "FROM ~g~.EventOption EO "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (EO.eventID=EP.eventID) "
|
||||
+ " LEFT JOIN ~g~.EventPersonOption EPO ON (EO.optionID=EPO.optionID AND EP.epersonID=EPO.epersonID) "
|
||||
+ "WHERE EO.eventID=? "
|
||||
+ " AND (EO.liveline IS NULL OR EO.liveline<=CURRENT_DATE) "
|
||||
+ " AND (EO.deadline IS NULL OR EO.deadline>=CURRENT_DATE) "
|
||||
+ " AND EPO.optionID IS NULL "
|
||||
)
|
||||
private StatementProvider sqlSelectEventParticipantIdsWithUnansweredOptions;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT DISTINCT EP.personID "
|
||||
+ "FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.Event E2 ON (E.seriesID=E2.seriesID) "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (E2.eventID=EP.eventID) "
|
||||
+ "WHERE E.eventID=? AND E2.eventID<>? "
|
||||
+ "UNION DISTINCT "
|
||||
+ "SELECT personID FROM ~g~.EventPersonContract WHERE eventID=? "
|
||||
)
|
||||
private StatementProvider sqlSelectSeriesParticipantIds;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT DISTINCT EP.personID "
|
||||
+ "FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.Event E2 ON (E.seriesID=E2.seriesID) "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (E2.eventID=EP.eventID) "
|
||||
+ "WHERE E.eventID=? AND E2.eventID<>? "
|
||||
+ " AND ((E2.deadline IS NOT NULL AND DATE_ADD(E2.deadline, INTERVAL ? WEEK)>=CURRENT_DATE) "
|
||||
+ " OR (E2.liveline IS NOT NULL AND DATE_ADD(E2.liveline, INTERVAL ? WEEK)>=CURRENT_DATE)) "
|
||||
+ "UNION DISTINCT "
|
||||
+ "SELECT personID FROM ~g~.EventPersonContract WHERE eventID=? "
|
||||
)
|
||||
private StatementProvider sqlSelectRecentSeriesParticipantIds;
|
||||
|
||||
@Override
|
||||
protected DataSet fetchOne(BigInteger epersonId) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectEventPersonByIds.buildPreparedStatement();
|
||||
try {
|
||||
fps.setBigintU(1, epersonId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT * FROM ~g~.EventPerson WHERE epersonID=?")
|
||||
private StatementProvider sqlSelectEventPersonById;
|
||||
|
||||
@Override
|
||||
protected Map<BigInteger, DataSet> fetchBulk(Collection<BigInteger> epersonIds) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectEventPersonByIds.buildPreparedStatement(epersonIds);
|
||||
try {
|
||||
return fps.executeQuery().getAllRows("epersonID", BigInteger.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT * FROM ~g~.EventPerson WHERE epersonID IN (??)")
|
||||
private StatementProvider sqlSelectEventPersonByIds;
|
||||
|
||||
}
|
@@ -1,108 +0,0 @@
|
||||
package com.poststats.golf.service.db;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import com.brianlong.sql.DataSet;
|
||||
import com.brianlong.sql.FlexManyToOneDef;
|
||||
import com.brianlong.sql.FlexPreparedStatement;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.service.EventRoundPairingService;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.Statement;
|
||||
import com.poststats.provider.StatementProvider;
|
||||
import com.poststats.service.ServiceException;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@ApplicationScoped
|
||||
public class EventRoundPairingServiceDAO implements EventRoundPairingService {
|
||||
|
||||
@Override
|
||||
public DataSet get(BigInteger pairingId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelect.buildPreparedStatement();
|
||||
try {
|
||||
fps.setBigintU(1, pairingId);
|
||||
return fps.executeQuery().getNextRow(new FlexManyToOneDef("nineID", "nine"));
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT ERP.pairingID, ERP.teetime, ERP.eroundID, ERP.courseID, ERP.number, "
|
||||
+ " CN.nineID, CN.nine, CN.courseID "
|
||||
+ "FROM ~g~.EventRoundPairing ERP "
|
||||
+ " LEFT JOIN ~g~.CourseNine CN ON (ERP.nineID=CN.nineID) "
|
||||
+ "WHERE ERP.pairingID=? "
|
||||
)
|
||||
private StatementProvider sqlSelect;
|
||||
|
||||
@Override
|
||||
public List<DataSet> getByRoundId(long eroundId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectByRoundId.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, eroundId);
|
||||
return fps.executeQuery().getAllRows(new FlexManyToOneDef("nineID", "nine"));
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT ERP.pairingID, ERP.teetime, ERP.eroundID, ERP.courseID, ERP.number, "
|
||||
+ " CN.nineID, CN.nine, CN.courseID "
|
||||
+ "FROM ~g~.EventRoundPairing ERP "
|
||||
+ " LEFT JOIN ~g~.CourseNine CN ON (ERP.nineID=CN.nineID) "
|
||||
+ "WHERE ERP.eroundID=? "
|
||||
)
|
||||
private StatementProvider sqlSelectByRoundId;
|
||||
|
||||
@Override
|
||||
public List<DataSet> getParticipantsByRoundId(long eroundId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectParticipantsByRoundId.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, eroundId);
|
||||
return fps.executeQuery().getAllRows(new FlexManyToOneDef("pairingID", "pairing"),
|
||||
new FlexManyToOneDef("nineID", "pairing", "nine"));
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT EPR.epersonID, EP.personID, "
|
||||
+ " ERP.pairingID, ERP.teetime, ERP.eroundID, ERP.courseID, ERP.number, "
|
||||
+ " CN.nineID, CN.nine, CN.courseID "
|
||||
+ "FROM ~g~.EventRoundPairing ERP "
|
||||
+ " INNER JOIN ~g~.EventPersonRound EPR ON (ERP.pairingID=EPR.pairingID) "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (EPR.epersonID=EP.epersonID) "
|
||||
+ " LEFT JOIN ~g~.CourseNine CN ON (ERP.nineID=CN.nineID) "
|
||||
+ "WHERE ERP.eroundID=? "
|
||||
)
|
||||
private StatementProvider sqlSelectParticipantsByRoundId;
|
||||
|
||||
}
|
@@ -1,138 +0,0 @@
|
||||
package com.poststats.golf.service.db;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.brianlong.sql.DataSet;
|
||||
import com.brianlong.sql.FlexPreparedStatement;
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.service.EventRoundService;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.Statement;
|
||||
import com.poststats.provider.StatementProvider;
|
||||
import com.poststats.service.ServiceException;
|
||||
import com.poststats.service.db.CacheableServiceDAO;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@ApplicationScoped
|
||||
public class EventRoundServiceDAO extends CacheableServiceDAO<Long> implements EventRoundService {
|
||||
|
||||
private final long defaultCacheExpirationInSeconds = 3600;
|
||||
|
||||
@Override
|
||||
public FlexMap get(long eroundId) {
|
||||
return this.get(Long.valueOf(eroundId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends FlexMap> getUpcoming(long eventId) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
if (now.getHour() > 17)
|
||||
now.plusDays(1);
|
||||
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectUpcoming.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, eventId);
|
||||
fps.setDate(2, now.toLocalDate());
|
||||
return fps.executeQuery().getAllRows();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT TF.*, ER.* "
|
||||
+ "FROM ~g~.EventRound ER "
|
||||
+ " LEFT JOIN ~g~.TeeFormat TF ON (ER.teeFormatID=TF.teeFormatID) "
|
||||
+ "WHERE ER.eventID=? AND ER.date>=? AND MIN(ER.date)=ER.date "
|
||||
)
|
||||
private StatementProvider sqlSelectUpcoming;
|
||||
|
||||
@Override
|
||||
public Map<Long, DataSet> getByEventId(long eventId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectByEventId.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, eventId);
|
||||
return fps.executeQuery().getAllRows("eroundID", Long.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT TF.*, ER.* "
|
||||
+ "FROM ~g~.EventRound ER "
|
||||
+ " LEFT JOIN ~g~.TeeFormat TF ON (ER.teeFormatID=TF.teeFormatID) "
|
||||
+ "WHERE ER.eventID=? "
|
||||
)
|
||||
private StatementProvider sqlSelectByEventId;
|
||||
|
||||
@Override
|
||||
protected long getCacheExpirationInSeconds() {
|
||||
return this.defaultCacheExpirationInSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSet fetchOne(Long eroundId) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelect.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, eroundId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT TF.*, ER.* "
|
||||
+ "FROM ~g~.EventRound ER "
|
||||
+ " LEFT JOIN ~g~.TeeFormat TF ON (ER.teeFormatID=TF.teeFormatID) "
|
||||
+ "WHERE ER.eroundID=? "
|
||||
)
|
||||
private StatementProvider sqlSelect;
|
||||
|
||||
@Override
|
||||
protected Map<Long, DataSet> fetchBulk(Collection<Long> eroundIds) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectManys.buildPreparedStatement(eroundIds);
|
||||
try {
|
||||
return fps.executeQuery().getAllRows("eroundID", Long.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT TF.*, ER.* "
|
||||
+ "FROM ~g~.EventRound ER "
|
||||
+ " LEFT JOIN ~g~.TeeFormat TF ON (ER.teeFormatID=TF.teeFormatID) "
|
||||
+ "WHERE ER.eroundID IN (??) "
|
||||
)
|
||||
private StatementProvider sqlSelectManys;
|
||||
|
||||
}
|
@@ -1,148 +0,0 @@
|
||||
package com.poststats.golf.service.db;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.brianlong.sql.DataSet;
|
||||
import com.brianlong.sql.FlexPreparedStatement;
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.service.EventService;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.Statement;
|
||||
import com.poststats.provider.StatementProvider;
|
||||
import com.poststats.service.ServiceException;
|
||||
import com.poststats.service.db.CacheableServiceDAO;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@ApplicationScoped
|
||||
public class EventServiceDAO extends CacheableServiceDAO<Long> implements EventService {
|
||||
|
||||
private final long defaultCacheExpirationInSeconds = 3600;
|
||||
|
||||
@Override
|
||||
public FlexMap get(long eventId) {
|
||||
return this.get(Long.valueOf(eventId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Long> getIdsBySeriesId(int seriesId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectIdsBySeriesId.buildPreparedStatement();
|
||||
try {
|
||||
fps.setSmallintU(1, seriesId);
|
||||
return fps.executeQuery().getFirstColumn(Long.class, new HashSet<>());
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT eventId FROM ~g~.Event WHERE seriesID=? ")
|
||||
private StatementProvider sqlSelectIdsBySeriesId;
|
||||
|
||||
@Override
|
||||
public Map<Long, DataSet> getBySeriesId(int seriesId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectBySeriesId.buildPreparedStatement();
|
||||
try {
|
||||
fps.setSmallintU(1, seriesId);
|
||||
return fps.executeQuery().getAllRows("eventID", Long.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT * FROM ~g~.Event WHERE seriesID=? ORDER BY liveline DESC ")
|
||||
private StatementProvider sqlSelectBySeriesId;
|
||||
|
||||
@Override
|
||||
public Integer getSeriesId(long eventId) {
|
||||
FlexMap event = this.getIfHit(eventId);
|
||||
if (event != null)
|
||||
return event.getInteger("seriesID");
|
||||
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectSeriesId.buildPreparedStatement();
|
||||
try {
|
||||
fps.setSmallintU(1, eventId);
|
||||
return fps.executeQuery().getOne(Integer.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT seriesID FROM ~g~.Event WHERE eventID=? ")
|
||||
private StatementProvider sqlSelectSeriesId;
|
||||
|
||||
@Override
|
||||
protected long getCacheExpirationInSeconds() {
|
||||
return this.defaultCacheExpirationInSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSet fetchOne(Long eventId) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectEvent.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, eventId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT EF.*, E.* "
|
||||
+ "FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.EventFeature EF ON (E.eventID=EF.eventID) "
|
||||
+ "WHERE E.eventID=? "
|
||||
)
|
||||
private StatementProvider sqlSelectEvent;
|
||||
|
||||
@Override
|
||||
protected Map<Long, DataSet> fetchBulk(Collection<Long> eventIds) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectEvents.buildPreparedStatement(eventIds);
|
||||
try {
|
||||
return fps.executeQuery().getAllRows("eventID", Long.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT EF.*, E.* "
|
||||
+ "FROM ~g~.Event E "
|
||||
+ " INNER JOIN ~g~.EventFeature EF ON (E.eventID=EF.eventID) "
|
||||
+ "WHERE E.eventID IN (??) "
|
||||
)
|
||||
private StatementProvider sqlSelectEvents;
|
||||
|
||||
}
|
@@ -1,740 +0,0 @@
|
||||
package com.poststats.golf.service.db;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.brianlong.sql.FlexPreparedStatement;
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.service.PersonRoundService;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.Statement;
|
||||
import com.poststats.provider.StatementProvider;
|
||||
import com.poststats.service.ServiceException;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@ApplicationScoped
|
||||
public class PersonRoundServiceDAO implements PersonRoundService {
|
||||
|
||||
@Override
|
||||
public FlexMap fetchNonEvent(BigInteger roundId, Selection selection, Filter... filters) {
|
||||
StatementProvider stmt = this.getNonEventRoundStatementProvider(selection, filters);
|
||||
|
||||
try {
|
||||
FlexPreparedStatement fps = stmt.buildPreparedStatement();
|
||||
try {
|
||||
for (int c = 1; c <= fps.getPreparedStatement().getParameterMetaData().getParameterCount(); c++)
|
||||
fps.setBigintU(c, roundId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlexMap fetchEvent(BigInteger proundId, Selection selection, Filter... filters) {
|
||||
StatementProvider stmt = this.getEventRoundStatementProvider(selection, filters);
|
||||
|
||||
try {
|
||||
FlexPreparedStatement fps = stmt.buildPreparedStatement();
|
||||
try {
|
||||
for (int c = 1; c <= fps.getPreparedStatement().getParameterMetaData().getParameterCount(); c++)
|
||||
fps.setBigintU(c, proundId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends FlexMap> fetchNonEventHoles(BigInteger roundId, Selection selection) {
|
||||
StatementProvider stmt = this.getNonEventRoundHolesStatementProvider(selection);
|
||||
|
||||
try {
|
||||
FlexPreparedStatement fps = stmt.buildPreparedStatement();
|
||||
try {
|
||||
for (int c = 1; c <= fps.getPreparedStatement().getParameterMetaData().getParameterCount(); c++)
|
||||
fps.setBigintU(c, roundId);
|
||||
return fps.executeQuery().getAllRows();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends FlexMap> fetchEventHoles(BigInteger proundId, Selection selection) {
|
||||
StatementProvider stmt = this.getEventRoundHolesStatementProvider(selection);
|
||||
|
||||
try {
|
||||
FlexPreparedStatement fps = stmt.buildPreparedStatement();
|
||||
try {
|
||||
for (int c = 1; c <= fps.getPreparedStatement().getParameterMetaData().getParameterCount(); c++)
|
||||
fps.setBigintU(c, proundId);
|
||||
return fps.executeQuery().getAllRows();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends FlexMap> findBefore(long personId, LocalDate beforeDay, short roundCount, Selection selection,
|
||||
Filter... filters) {
|
||||
StatementProvider stmt = this.getRoundsStatementProvider(selection, filters);
|
||||
|
||||
try {
|
||||
FlexPreparedStatement fps = stmt.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, personId); // for non-event rounds
|
||||
fps.setDate(2, beforeDay);
|
||||
fps.setIntegerU(3, personId); // for 18-hole event rounds
|
||||
fps.setDate(4, beforeDay);
|
||||
fps.setIntegerU(5, personId); // for 9-hole event rounds
|
||||
fps.setDate(6, beforeDay);
|
||||
fps.setSmallint(7, roundCount); // limit
|
||||
return fps.executeQuery().getAllRows();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
private StatementProvider getNonEventRoundStatementProvider(Selection selection, Filter... filters) {
|
||||
Set<Filter> filterSet = new HashSet<>();
|
||||
for (Filter filter : filters)
|
||||
filterSet.add(filter);
|
||||
|
||||
switch (selection) {
|
||||
case StrokeHandicapIndex:
|
||||
if (filterSet.contains(Filter.AttestedOnly)) {
|
||||
if (filterSet.contains(Filter.CourseRatedOnly)) {
|
||||
return this.sqlSelectSignedRatedNonEventRoundWithStrokeHandicap;
|
||||
} else {
|
||||
return this.sqlSelectSignedNonEventRoundWithStrokeHandicap;
|
||||
}
|
||||
} else {
|
||||
if (filterSet.contains(Filter.CourseRatedOnly)) {
|
||||
return this.sqlSelectRatedNonEventRoundWithStrokeHandicap;
|
||||
} else {
|
||||
return this.sqlSelectNonEventRoundWithStrokeHandicap;
|
||||
}
|
||||
}
|
||||
case ScoreToPar:
|
||||
if (filterSet.contains(Filter.AttestedOnly)) {
|
||||
if (filterSet.contains(Filter.CourseRatedOnly)) {
|
||||
return this.sqlSelectSignedRatedNonEventRoundWithScoreToPar;
|
||||
} else {
|
||||
return this.sqlSelectSignedNonEventRoundWithScoreToPar;
|
||||
}
|
||||
} else {
|
||||
if (filterSet.contains(Filter.CourseRatedOnly)) {
|
||||
return this.sqlSelectRatedNonEventRoundWithScoreToPar;
|
||||
} else {
|
||||
return this.sqlSelectNonEventRoundWithScoreToPar;
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private StatementProvider getEventRoundStatementProvider(Selection selection, Filter... filters) {
|
||||
Set<Filter> filterSet = new HashSet<>();
|
||||
for (Filter filter : filters)
|
||||
filterSet.add(filter);
|
||||
|
||||
switch (selection) {
|
||||
case StrokeHandicapIndex:
|
||||
if (filterSet.contains(Filter.AttestedOnly)) {
|
||||
if (filterSet.contains(Filter.CourseRatedOnly)) {
|
||||
return this.sqlSelectSignedRatedEventRoundWithStrokeHandicap;
|
||||
} else {
|
||||
return this.sqlSelectSignedEventRoundWithStrokeHandicap;
|
||||
}
|
||||
} else {
|
||||
if (filterSet.contains(Filter.CourseRatedOnly)) {
|
||||
return this.sqlSelectRatedEventRoundWithStrokeHandicap;
|
||||
} else {
|
||||
return this.sqlSelectEventRoundWithStrokeHandicap;
|
||||
}
|
||||
}
|
||||
case ScoreToPar:
|
||||
if (filterSet.contains(Filter.AttestedOnly)) {
|
||||
if (filterSet.contains(Filter.CourseRatedOnly)) {
|
||||
return this.sqlSelectSignedRatedEventRoundWithScoreToPar;
|
||||
} else {
|
||||
return this.sqlSelectSignedEventRoundWithScoreToPar;
|
||||
}
|
||||
} else {
|
||||
if (filterSet.contains(Filter.CourseRatedOnly)) {
|
||||
return this.sqlSelectRatedEventRoundWithScoreToPar;
|
||||
} else {
|
||||
return this.sqlSelectEventRoundWithScoreToPar;
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private StatementProvider getNonEventRoundHolesStatementProvider(Selection selection) {
|
||||
switch (selection) {
|
||||
case StrokeHandicapIndex:
|
||||
return this.sqlSelectNonEventRoundHolesWithStrokeHandicap;
|
||||
case ScoreToPar:
|
||||
return this.sqlSelectNonEventRoundHolesWithScoreToPar;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private StatementProvider getEventRoundHolesStatementProvider(Selection selection) {
|
||||
switch (selection) {
|
||||
case StrokeHandicapIndex:
|
||||
return this.sqlSelectEventRoundHolesWithStrokeHandicap;
|
||||
case ScoreToPar:
|
||||
return this.sqlSelectEventRoundHolesWithScoreToPar;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private StatementProvider getRoundsStatementProvider(Selection selection, Filter... filters) {
|
||||
Set<Filter> filterSet = new HashSet<>();
|
||||
for (Filter filter : filters)
|
||||
filterSet.add(filter);
|
||||
|
||||
switch (selection) {
|
||||
case StrokeHandicapIndex:
|
||||
if (filterSet.contains(Filter.AttestedOnly)) {
|
||||
if (filterSet.contains(Filter.CourseRatedOnly)) {
|
||||
return this.sqlSelectSignedRatedRoundsWithStrokeHandicap;
|
||||
} else {
|
||||
return this.sqlSelectSignedRoundsWithStrokeHandicap;
|
||||
}
|
||||
} else {
|
||||
if (filterSet.contains(Filter.CourseRatedOnly)) {
|
||||
return this.sqlSelectRatedRoundsWithStrokeHandicap;
|
||||
} else {
|
||||
return this.sqlSelectRoundsWithStrokeHandicap;
|
||||
}
|
||||
}
|
||||
case ScoreToPar:
|
||||
if (filterSet.contains(Filter.AttestedOnly)) {
|
||||
if (filterSet.contains(Filter.CourseRatedOnly)) {
|
||||
return this.sqlSelectSignedRatedRoundsWithScoreToPar;
|
||||
} else {
|
||||
return this.sqlSelectSignedRoundsWithScoreToPar;
|
||||
}
|
||||
} else {
|
||||
if (filterSet.contains(Filter.CourseRatedOnly)) {
|
||||
return this.sqlSelectRatedRoundsWithScoreToPar;
|
||||
} else {
|
||||
return this.sqlSelectRoundsWithScoreToPar;
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private final static String nonEventRoundSqlSelectClause = "SELECT R.roundID, NULL proundID, NULL linkProundID, R.personID, R.etratingID, R.courseID, R.teedate, R.teetime, R.strokes, ";
|
||||
private final static String nonEventRoundSqlFromClause = "FROM ~g~.Round R "
|
||||
+ " INNER JOIN ~p~.Person P ON (R.personID=P.personID) ";
|
||||
private final static String nonEventRoundSqlWhereClause = "WHERE R.roundID=? ";
|
||||
private final static String nonEventRoundsSqlWhereClause = "WHERE R.personID=? AND R.complete IS TRUE AND R.teedate<? "
|
||||
+ " AND (P.healthSetback IS NULL OR R.teedate>P.healthSetback) ";
|
||||
|
||||
private final static String event18RoundSqlSelectClause = "SELECT NULL roundID, EPR.proundID, NULL linkProundID, EP.personID, EPR.etratingID, EPR.courseID, ER.date, ERP.teetime, EPR.strokes, ";
|
||||
private final static String event18RoundSqlFromClause = "FROM ~g~.EventPersonRound EPR "
|
||||
+ " INNER JOIN ~g~.EventRound ER ON (EPR.eroundID=ER.eroundID) "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (EPR.epersonID=EP.epersonID) "
|
||||
+ " INNER JOIN ~p~.Person P ON (EP.personID=P.personID) "
|
||||
+ " LEFT JOIN ~g~.EventRoundPairing ERP ON (EPR.pairingID=ERP.pairingID) ";
|
||||
private final static String event18RoundSqlWhereClause = "WHERE EPR.proundID=? ";
|
||||
private final static String event18RoundsSqlWhereClause = "WHERE EP.personID=? AND EPR.complete IS TRUE AND EPR.etratingID IS NOT NULL AND ER.date<? "
|
||||
+ " AND (P.healthSetback IS NULL OR ER.date>P.healthSetback) ";
|
||||
|
||||
private final static String event9RoundSqlSelectClause = "SELECT NULL roundID, EPR.proundID, EPR.linkProundID, EP.personID, CETR.etratingID, EPR.courseID, ER.date, ERP.teetime, "
|
||||
+ " (EPR.strokes+EPR2.strokes) strokes, ";
|
||||
private final static String event9RoundSqlFromClause = "FROM ~g~.EventPersonRound EPR "
|
||||
+ " INNER JOIN ~g~.EventPersonRound EPR2 ON (EPR.linkProundID=EPR2.proundID AND EPR.proundID>EPR2.proundID) "
|
||||
+ " INNER JOIN ~g~.CourseNineTeeRating CNTR1 ON (EPR.ntratingID=CNTR1.ntratingID) "
|
||||
+ " INNER JOIN ~g~.CourseNineTeeRating CNTR2 ON (EPR2.ntratingID=CNTR2.ntratingID) "
|
||||
+ " INNER JOIN ~g~.CourseEighteenTee CET ON ((CNTR1.nineteeID=CET.nineteeID1 AND CNTR2.nineteeID=CET.nineteeID2) "
|
||||
+ " OR (CNTR2.nineteeID=CET.nineteeID1 AND CNTR1.nineteeID=CET.nineteeID2)) "
|
||||
+ " INNER JOIN ~g~.CourseEighteenTeeRating CETR ON (CET.eighteenteeID=CETR.eighteenteeID "
|
||||
+ " AND CNTR1.gender=CETR.gender "
|
||||
+ " AND CETR.liveline<=ER.date AND (CETR.deadline IS NULL OR ER.date<=CETR.deadline)) "
|
||||
+ " INNER JOIN ~g~.EventRound ER ON (EPR.eroundID=ER.eroundID) "
|
||||
+ " INNER JOIN ~g~.EventPerson EP ON (EPR.epersonID=EP.epersonID) "
|
||||
+ " INNER JOIN ~p~.Person P ON (EP.personID=P.personID) "
|
||||
+ " LEFT JOIN ~g~.EventRoundPairing ERP ON (EPR.pairingID=ERP.pairingID) ";
|
||||
private final static String event9RoundSqlWhereClause = "WHERE EPR.proundID=? ";
|
||||
private final static String event9RoundsSqlWhereClause = "WHERE EP.personID=? AND EPR.complete IS TRUE AND ER.date<? "
|
||||
+ " AND (P.healthSetback IS NULL OR ER.date>P.healthSetback) ";
|
||||
|
||||
private final static String nonEventRoundSqlSelectStrokeHandicap = nonEventRoundSqlSelectClause
|
||||
+ " R.strokeHandicapIndex, R.whsStrokeHandicapIndex "
|
||||
+ nonEventRoundSqlFromClause
|
||||
+ nonEventRoundSqlWhereClause;
|
||||
private final static String nonEventRoundsSqlSelectStrokeHandicap = nonEventRoundSqlSelectClause
|
||||
+ " R.strokeHandicapIndex, R.whsStrokeHandicapIndex "
|
||||
+ nonEventRoundSqlFromClause
|
||||
+ nonEventRoundsSqlWhereClause;
|
||||
|
||||
private final static String event18RoundSqlSelectStrokeHandicap = event18RoundSqlSelectClause
|
||||
+ " EPR.strokeHandicapIndex, EPR.whsStrokeHandicapIndex "
|
||||
+ event18RoundSqlFromClause
|
||||
+ event18RoundSqlWhereClause;
|
||||
private final static String event18RoundsSqlSelectStrokeHandicap = event18RoundSqlSelectClause
|
||||
+ " EPR.strokeHandicapIndex, EPR.whsStrokeHandicapIndex "
|
||||
+ event18RoundSqlFromClause
|
||||
+ event18RoundsSqlWhereClause;
|
||||
|
||||
private final static String event9RoundSqlSelectStrokeHandicap = event9RoundSqlSelectClause
|
||||
+ " (EPR.strokeHandicapIndex+EPR2.strokeHandicapIndex) strokeHandicapIndex, "
|
||||
+ " (EPR.whsStrokeHandicapIndex+EPR2.whsStrokeHandicapIndex) whsStrokeHandicapIndex "
|
||||
+ event9RoundSqlFromClause
|
||||
+ event9RoundSqlWhereClause;
|
||||
private final static String event9RoundsSqlSelectStrokeHandicap = event9RoundSqlSelectClause
|
||||
+ " (EPR.strokeHandicapIndex+EPR2.strokeHandicapIndex) strokeHandicapIndex, "
|
||||
+ " (EPR.whsStrokeHandicapIndex+EPR2.whsStrokeHandicapIndex) whsStrokeHandicapIndex "
|
||||
+ event9RoundSqlFromClause
|
||||
+ event9RoundsSqlWhereClause;
|
||||
|
||||
private final static String nonEventRoundSqlSelectPointsClause =
|
||||
" SUM(CASE WHEN (RX.strokes - CNTH.par) = 5 THEN 1 ELSE 0 END) bogey5, "
|
||||
+ " SUM(CASE WHEN (RX.strokes - CNTH.par) = 4 THEN 1 ELSE 0 END) bogey4, "
|
||||
+ " SUM(CASE WHEN (RX.strokes - CNTH.par) = 3 THEN 1 ELSE 0 END) bogey3, "
|
||||
+ " SUM(CASE WHEN (RX.strokes - CNTH.par) = 2 THEN 1 ELSE 0 END) bogey2, "
|
||||
+ " SUM(CASE WHEN (RX.strokes - CNTH.par) = 1 THEN 1 ELSE 0 END) bogey, "
|
||||
+ " SUM(CASE WHEN RX.strokes = CNTH.par THEN 1 ELSE 0 END) par, "
|
||||
+ " SUM(CASE WHEN (CNTH.par - RX.strokes) = 1 THEN 1 ELSE 0 END) birdie, "
|
||||
+ " SUM(CASE WHEN (CNTH.par - RX.strokes) = 2 THEN 1 ELSE 0 END) eagle, "
|
||||
+ " SUM(CASE WHEN (CNTH.par - RX.strokes) = 3 THEN 1 ELSE 0 END) alby, ";
|
||||
private final static String nonEventRoundSqlFromPointsClause =
|
||||
" INNER JOIN ~g~.RoundScore RX ON (R.roundID=RX.roundID) "
|
||||
+ " INNER JOIN ~g~.CourseNineTeeHole CNTH ON (RX.holeID=CNTH.holeID) "
|
||||
+ " INNER JOIN ~g~.CourseEighteenTeeRating CETR ON (R.etratingID=CETR.etratingID) ";
|
||||
private final static String nonEventRoundSqlSelectScoreToPar = nonEventRoundSqlSelectClause
|
||||
+ nonEventRoundSqlSelectPointsClause
|
||||
+ " CETR.pointAdj "
|
||||
+ nonEventRoundSqlFromClause
|
||||
+ nonEventRoundSqlFromPointsClause
|
||||
+ nonEventRoundSqlWhereClause
|
||||
+ "GROUP BY R.roundID ";
|
||||
private final static String nonEventRoundsSqlSelectScoreToPar = nonEventRoundSqlSelectClause
|
||||
+ nonEventRoundSqlSelectPointsClause
|
||||
+ " CETR.pointAdj "
|
||||
+ nonEventRoundSqlFromClause
|
||||
+ nonEventRoundSqlFromPointsClause
|
||||
+ nonEventRoundsSqlWhereClause
|
||||
+ "GROUP BY R.roundID ";
|
||||
|
||||
private final static String eventRoundSqlSelectPointsClause =
|
||||
"SUM(CASE WHEN (EPRS.strokes - CNTH.par) = 5 THEN 1 ELSE 0 END) bogey5, "
|
||||
+ " SUM(CASE WHEN (EPRS.strokes - CNTH.par) = 4 THEN 1 ELSE 0 END) bogey4, "
|
||||
+ " SUM(CASE WHEN (EPRS.strokes - CNTH.par) = 3 THEN 1 ELSE 0 END) bogey3, "
|
||||
+ " SUM(CASE WHEN (EPRS.strokes - CNTH.par) = 2 THEN 1 ELSE 0 END) bogey2, "
|
||||
+ " SUM(CASE WHEN (EPRS.strokes - CNTH.par) = 1 THEN 1 ELSE 0 END) bogey, "
|
||||
+ " SUM(CASE WHEN EPRS.strokes = CNTH.par THEN 1 ELSE 0 END) par, "
|
||||
+ " SUM(CASE WHEN (CNTH.par - EPRS.strokes) = 1 THEN 1 ELSE 0 END) birdie, "
|
||||
+ " SUM(CASE WHEN (CNTH.par - EPRS.strokes) = 2 THEN 1 ELSE 0 END) eagle, "
|
||||
+ " SUM(CASE WHEN (CNTH.par - EPRS.strokes) = 3 THEN 1 ELSE 0 END) alby, ";
|
||||
private final static String event18RoundSqlFromPointsClause =
|
||||
" INNER JOIN ~g~.EventPersonRoundScore EPRS ON (EPR.proundID=EPRS.proundID) "
|
||||
+ " INNER JOIN ~g~.CourseNineTeeHole CNTH ON (EPRS.holeID=CNTH.holeID) "
|
||||
+ " INNER JOIN ~g~.CourseEighteenTeeRating CETR ON (EPR.etratingID=CETR.etratingID) ";
|
||||
private final static String event9RoundSqlFromPointsClause =
|
||||
" INNER JOIN ~g~.EventPersonRoundScore EPRS ON (EPR.proundID=EPRS.proundID OR EPR.linkProundID=EPRS.proundID) "
|
||||
+ " INNER JOIN ~g~.CourseNineTeeHole CNTH ON (EPRS.holeID=CNTH.holeID) "
|
||||
+ " INNER JOIN ~g~.CourseNineTeeRating CNTR ON (EPR.ntratingID=CNTR.ntratingID) ";
|
||||
|
||||
private final static String event18RoundSqlSelectScoreToPar = event18RoundSqlSelectClause
|
||||
+ eventRoundSqlSelectPointsClause
|
||||
+ " CETR.pointAdj "
|
||||
+ event18RoundSqlFromClause
|
||||
+ event18RoundSqlFromPointsClause
|
||||
+ event18RoundSqlWhereClause
|
||||
+ "GROUP BY EPR.proundID ";
|
||||
private final static String event18RoundsSqlSelectScoreToPar = event18RoundSqlSelectClause
|
||||
+ eventRoundSqlSelectPointsClause
|
||||
+ " CETR.pointAdj "
|
||||
+ event18RoundSqlFromClause
|
||||
+ event18RoundSqlFromPointsClause
|
||||
+ event18RoundsSqlWhereClause
|
||||
+ "GROUP BY EPR.proundID ";
|
||||
|
||||
private final static String event9RoundSqlSelectScoreToPar = event9RoundSqlSelectClause
|
||||
+ eventRoundSqlSelectPointsClause
|
||||
+ " CNTR.pointAdj "
|
||||
+ event9RoundSqlFromClause
|
||||
+ event9RoundSqlFromPointsClause
|
||||
+ event9RoundSqlWhereClause
|
||||
+ "GROUP BY EPR.proundID ";
|
||||
private final static String event9RoundsSqlSelectScoreToPar = event9RoundSqlSelectClause
|
||||
+ eventRoundSqlSelectPointsClause
|
||||
+ " CNTR.pointAdj "
|
||||
+ event9RoundSqlFromClause
|
||||
+ event9RoundSqlFromPointsClause
|
||||
+ event9RoundsSqlWhereClause
|
||||
+ "GROUP BY EPR.proundID ";
|
||||
|
||||
private final static String nonEventRoundHoleSqlSelectClause = "SELECT RX.holeID, RX.strokes, CNTH.par, ";
|
||||
private final static String nonEventRoundHoleSqlFromClause =
|
||||
"FROM ~g~.RoundScore RX "
|
||||
+ " INNER JOIN ~g~.CourseNineTeeHole CNTH ON (RX.holeID=CNTH.holeID) ";
|
||||
private final static String nonEventRoundHolesSqlSelectStrokeHandicap =
|
||||
nonEventRoundHoleSqlSelectClause
|
||||
+ " CNTH.handicap, CNTH.whsHandicap "
|
||||
+ nonEventRoundHoleSqlFromClause
|
||||
+ "WHERE RX.roundID=? ";
|
||||
private final static String nonEventRoundHolesSqlSelectScoreToPar =
|
||||
nonEventRoundHoleSqlSelectClause
|
||||
+ nonEventRoundHoleSqlFromClause
|
||||
+ "WHERE RX.roundID=? ";
|
||||
|
||||
private final static String eventRoundHoleSqlSelectClause = "SELECT EPRS.holeID, EPRS.strokes, CNTH.par, ";
|
||||
private final static String eventRoundHoleSqlFromClause =
|
||||
"FROM ~g~.EventPersonRoundScore EPRS "
|
||||
+ " INNER JOIN ~g~.CourseNineTeeHole CNTH ON (EPRS.holeID=CNTH.holeID) "
|
||||
+ " INNER JOIN ~g~.EventPersonRound EPR ON (EPRS.proundID=EPR.proundID) ";
|
||||
private final static String eventRoundHolesSqlSelectStrokeHandicap =
|
||||
eventRoundHoleSqlSelectClause
|
||||
+ " CNTH.handicap, CNTH.whsHandicap "
|
||||
+ eventRoundHoleSqlFromClause
|
||||
+ "WHERE EPRS.proundID=? ";
|
||||
private final static String eventRoundHolesSqlSelectScoreToPar =
|
||||
eventRoundHoleSqlSelectClause
|
||||
+ eventRoundHoleSqlFromClause
|
||||
+ "WHERE EPRS.roundID=? ";
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = nonEventRoundSqlSelectStrokeHandicap)
|
||||
private StatementProvider sqlSelectNonEventRoundWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = event18RoundsSqlSelectStrokeHandicap
|
||||
+ "UNION "
|
||||
+ event9RoundsSqlSelectStrokeHandicap
|
||||
)
|
||||
private StatementProvider sqlSelectEventRoundWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundsSqlSelectStrokeHandicap
|
||||
+ "UNION "
|
||||
+ event18RoundsSqlSelectStrokeHandicap
|
||||
+ "UNION "
|
||||
+ event9RoundsSqlSelectStrokeHandicap
|
||||
+ "ORDER BY teedate DESC, teetime DESC "
|
||||
+ "LIMIT ?"
|
||||
)
|
||||
private StatementProvider sqlSelectRoundsWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundsSqlSelectStrokeHandicap
|
||||
+ " AND R.whsStrokeHandicapIndex IS NOT NULL "
|
||||
)
|
||||
private StatementProvider sqlSelectRatedNonEventRoundWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = event18RoundsSqlSelectStrokeHandicap
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "UNION "
|
||||
+ event9RoundsSqlSelectStrokeHandicap
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
)
|
||||
private StatementProvider sqlSelectRatedEventRoundWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundsSqlSelectStrokeHandicap
|
||||
+ " AND R.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "UNION "
|
||||
+ event18RoundsSqlSelectStrokeHandicap
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "UNION "
|
||||
+ event9RoundsSqlSelectStrokeHandicap
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "ORDER BY teedate DESC, teetime DESC "
|
||||
+ "LIMIT ?"
|
||||
)
|
||||
private StatementProvider sqlSelectRatedRoundsWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundSqlSelectStrokeHandicap
|
||||
+ " AND EXISTS (SELECT RS.signerID FROM ~g~.RoundSigning RS WHERE RS.roundID=R.roundID) "
|
||||
)
|
||||
private StatementProvider sqlSelectSignedNonEventRoundWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = event18RoundSqlSelectStrokeHandicap
|
||||
+ "UNION "
|
||||
+ event9RoundSqlSelectStrokeHandicap
|
||||
)
|
||||
private StatementProvider sqlSelectSignedEventRoundWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundsSqlSelectStrokeHandicap
|
||||
+ " AND EXISTS (SELECT RS.signerID FROM ~g~.RoundSigning RS WHERE RS.roundID=R.roundID) "
|
||||
+ "UNION "
|
||||
+ event18RoundsSqlSelectStrokeHandicap
|
||||
+ "UNION "
|
||||
+ event9RoundsSqlSelectStrokeHandicap
|
||||
+ "ORDER BY teedate DESC, teetime DESC "
|
||||
+ "LIMIT ?"
|
||||
)
|
||||
private StatementProvider sqlSelectSignedRoundsWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundSqlSelectStrokeHandicap
|
||||
+ " AND R.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ " AND EXISTS (SELECT RS.signerID FROM ~g~.RoundSigning RS WHERE RS.roundID=R.roundID) "
|
||||
)
|
||||
private StatementProvider sqlSelectSignedRatedNonEventRoundWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = event18RoundSqlSelectStrokeHandicap
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "UNION "
|
||||
+ event9RoundSqlSelectStrokeHandicap
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
)
|
||||
private StatementProvider sqlSelectSignedRatedEventRoundWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundsSqlSelectStrokeHandicap
|
||||
+ " AND R.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ " AND EXISTS (SELECT RS.signerID FROM ~g~.RoundSigning RS WHERE RS.roundID=R.roundID) "
|
||||
+ "UNION "
|
||||
+ event18RoundsSqlSelectStrokeHandicap
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "UNION "
|
||||
+ event9RoundsSqlSelectStrokeHandicap
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "ORDER BY teedate DESC, teetime DESC "
|
||||
+ "LIMIT ?"
|
||||
)
|
||||
private StatementProvider sqlSelectSignedRatedRoundsWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = nonEventRoundSqlSelectScoreToPar)
|
||||
private StatementProvider sqlSelectNonEventRoundWithScoreToPar;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = event18RoundSqlSelectScoreToPar
|
||||
+ "UNION "
|
||||
+ event9RoundSqlSelectScoreToPar
|
||||
)
|
||||
private StatementProvider sqlSelectEventRoundWithScoreToPar;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundsSqlSelectScoreToPar
|
||||
+ "UNION "
|
||||
+ event18RoundsSqlSelectScoreToPar
|
||||
+ "UNION "
|
||||
+ event9RoundsSqlSelectScoreToPar
|
||||
+ "ORDER BY teedate DESC, teetime DESC "
|
||||
+ "LIMIT ?"
|
||||
)
|
||||
private StatementProvider sqlSelectRoundsWithScoreToPar;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundSqlSelectScoreToPar
|
||||
+ " AND R.whsStrokeHandicapIndex IS NOT NULL "
|
||||
)
|
||||
private StatementProvider sqlSelectRatedNonEventRoundWithScoreToPar;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = event18RoundSqlSelectScoreToPar
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "UNION "
|
||||
+ event9RoundSqlSelectScoreToPar
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
)
|
||||
private StatementProvider sqlSelectRatedEventRoundWithScoreToPar;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundsSqlSelectScoreToPar
|
||||
+ " AND R.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "UNION "
|
||||
+ event18RoundsSqlSelectScoreToPar
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "UNION "
|
||||
+ event9RoundsSqlSelectScoreToPar
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "ORDER BY teedate DESC, teetime DESC "
|
||||
+ "LIMIT ?"
|
||||
)
|
||||
private StatementProvider sqlSelectRatedRoundsWithScoreToPar;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundSqlSelectScoreToPar
|
||||
+ " AND EXISTS (SELECT RS.signerID FROM ~g~.RoundSigning RS WHERE RS.roundID=R.roundID) "
|
||||
)
|
||||
private StatementProvider sqlSelectSignedNonEventRoundWithScoreToPar;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = event18RoundSqlSelectScoreToPar
|
||||
+ "UNION "
|
||||
+ event9RoundSqlSelectScoreToPar
|
||||
)
|
||||
private StatementProvider sqlSelectSignedEventRoundWithScoreToPar;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundsSqlSelectScoreToPar
|
||||
+ " AND EXISTS (SELECT RS.signerID FROM ~g~.RoundSigning RS WHERE RS.roundID=R.roundID) "
|
||||
+ "UNION "
|
||||
+ event18RoundsSqlSelectScoreToPar
|
||||
+ "UNION "
|
||||
+ event9RoundsSqlSelectScoreToPar
|
||||
+ "ORDER BY teedate DESC, teetime DESC "
|
||||
+ "LIMIT ?"
|
||||
)
|
||||
private StatementProvider sqlSelectSignedRoundsWithScoreToPar;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundSqlSelectScoreToPar
|
||||
+ " AND R.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ " AND EXISTS (SELECT RS.signerID FROM ~g~.RoundSigning RS WHERE RS.roundID=R.roundID) "
|
||||
)
|
||||
private StatementProvider sqlSelectSignedRatedNonEventRoundWithScoreToPar;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = event18RoundSqlSelectScoreToPar
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "UNION "
|
||||
+ event9RoundSqlSelectScoreToPar
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
)
|
||||
private StatementProvider sqlSelectSignedRatedEventRoundWithScoreToPar;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = nonEventRoundsSqlSelectScoreToPar
|
||||
+ " AND R.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ " AND EXISTS (SELECT RS.signerID FROM ~g~.RoundSigning RS WHERE RS.roundID=R.roundID) "
|
||||
+ "UNION "
|
||||
+ event18RoundsSqlSelectScoreToPar
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "UNION "
|
||||
+ event9RoundsSqlSelectScoreToPar
|
||||
+ " AND EPR.whsStrokeHandicapIndex IS NOT NULL "
|
||||
+ "ORDER BY teedate DESC, teetime DESC "
|
||||
+ "LIMIT ?"
|
||||
)
|
||||
private StatementProvider sqlSelectSignedRatedRoundsWithScoreToPar;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = nonEventRoundHolesSqlSelectStrokeHandicap)
|
||||
private StatementProvider sqlSelectNonEventRoundHolesWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = eventRoundHolesSqlSelectStrokeHandicap)
|
||||
private StatementProvider sqlSelectEventRoundHolesWithStrokeHandicap;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = nonEventRoundHolesSqlSelectScoreToPar)
|
||||
private StatementProvider sqlSelectNonEventRoundHolesWithScoreToPar;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = eventRoundHolesSqlSelectScoreToPar)
|
||||
private StatementProvider sqlSelectEventRoundHolesWithScoreToPar;
|
||||
|
||||
}
|
@@ -1,209 +0,0 @@
|
||||
package com.poststats.golf.service.db;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.brianlong.cache.CacheException;
|
||||
import com.brianlong.cache.CacheableFetcher;
|
||||
import com.brianlong.cache.ClusterAwareMemoryCacher;
|
||||
import com.brianlong.sql.DataSet;
|
||||
import com.brianlong.sql.FlexPreparedStatement;
|
||||
import com.brianlong.sql.FlexStatement;
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.security.AuthenticatedPerson;
|
||||
import com.poststats.golf.service.PersonService;
|
||||
import com.poststats.golf.sql.GolfDataSource;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.Statement;
|
||||
import com.poststats.provider.StatementProvider;
|
||||
import com.poststats.service.ServiceException;
|
||||
import com.poststats.service.db.CacheableServiceDAO;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@ApplicationScoped
|
||||
public class PersonServiceDAO extends CacheableServiceDAO<Long> implements PersonService {
|
||||
|
||||
@Inject
|
||||
private com.poststats.service.PersonService poststatsPersonService;
|
||||
|
||||
private final int roleCacheExpirationInSeconds = 300;
|
||||
private final int infoCacheExpirationInSeconds = 120;
|
||||
|
||||
private ClusterAwareMemoryCacher<Long, AuthenticatedPerson> principalCacher;
|
||||
|
||||
@PostConstruct
|
||||
private void initCache() {
|
||||
this.principalCacher = new ClusterAwareMemoryCacher<Long, AuthenticatedPerson>(
|
||||
this.roleCacheExpirationInSeconds * 1000L, this.clusterService.getHazelcastInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getCacheExpirationInSeconds() {
|
||||
return this.infoCacheExpirationInSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticatedPerson getUserPrincipal(com.poststats.security.AuthenticatedPerson person) {
|
||||
try {
|
||||
return this.principalCacher.get(person.getId(), new PrincipalCacheableFetcher() {
|
||||
@Override
|
||||
public com.poststats.security.AuthenticatedPerson getPerson() {
|
||||
return person;
|
||||
}
|
||||
});
|
||||
} catch (CacheException ce) {
|
||||
throw new ServiceException(ce);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlexMap get(long personId) {
|
||||
return this.get(Long.valueOf(personId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlexMap injectDeep(String idKey, FlexMap parentMap, String mapKey) {
|
||||
FlexMap map = this.inject(idKey, parentMap, mapKey);
|
||||
return this.poststatsPersonService.inject("personID", map, "person");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends FlexMap> injectDeep(String idKey, Collection<? extends FlexMap> parentMaps,
|
||||
String mapKey) {
|
||||
Collection<? extends FlexMap> maps = this.inject(idKey, parentMaps, mapKey);
|
||||
return this.poststatsPersonService.inject("personID", maps, "person");
|
||||
}
|
||||
|
||||
private abstract class PrincipalCacheableFetcher implements CacheableFetcher<Long, AuthenticatedPerson> {
|
||||
|
||||
public abstract com.poststats.security.AuthenticatedPerson getPerson();
|
||||
|
||||
@Override
|
||||
public AuthenticatedPerson get(Long personId) throws SQLException {
|
||||
Connection dbcon = GolfDataSource.getInstance().acquire(true);
|
||||
try {
|
||||
return new AuthenticatedPerson(this.getPerson(), queryBuddies(personId), queryAccessControls(personId),
|
||||
queryEventAccessControls(personId));
|
||||
} finally {
|
||||
GolfDataSource.getInstance().release(dbcon);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, AuthenticatedPerson> get(Collection<Long> personIds) throws SQLException, IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private Set<Long> queryBuddies(long personId) throws SQLException {
|
||||
FlexPreparedStatement fps = sqlSelectBuddyIds.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, personId);
|
||||
|
||||
Set<Long> set = new HashSet<>();
|
||||
fps.executeQuery().getFirstColumn(Long.class, set);
|
||||
return set;
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> queryAccessControls(long personId) throws SQLException {
|
||||
FlexPreparedStatement fps = sqlSelectAcs.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, personId);
|
||||
|
||||
Set<String> set = new HashSet<>();
|
||||
fps.executeQuery().getFirstColumn(String.class, set);
|
||||
return set;
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Long, Set<String>> queryEventAccessControls(long personId) throws SQLException {
|
||||
FlexPreparedStatement fps = sqlSelectEventAcs.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, personId);
|
||||
return fps.executeQuery().getFirstTwoColumnsOneToMany(Long.class, String.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT PS1.personID "
|
||||
+ "FROM ~g~.PersonSpectator PS1 "
|
||||
+ " INNER JOIN ~g~.PersonSpectator PS2 ON (PS1.personID=PS2.watchedPersonID AND PS1.watchedPersonID=PS2.personID) "
|
||||
+ "WHERE PS1.watchedPersonID=?"
|
||||
)
|
||||
private StatementProvider sqlSelectBuddyIds;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT AC.acSID "
|
||||
+ "FROM ~g~.PersonAccessControl PAC "
|
||||
+ " INNER JOIN ~p~.AccessControl AC ON (PAC.acID=AC.acID) "
|
||||
+ "WHERE PAC.personID=?"
|
||||
)
|
||||
private StatementProvider sqlSelectAcs;
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "SELECT EPAC.eventID, AC.acSID "
|
||||
+ "FROM ~g~.EventPersonAccessControl EPAC "
|
||||
+ " INNER JOIN ~p~.AccessControl AC ON (EPAC.acID=AC.acID) "
|
||||
+ "WHERE EPAC.personID=?"
|
||||
)
|
||||
private StatementProvider sqlSelectEventAcs;
|
||||
|
||||
@Override
|
||||
protected DataSet fetchOne(Long personId) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectPerson.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, personId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT GP.* FROM ~g~.Person GP WHERE GP.personID=?")
|
||||
private StatementProvider sqlSelectPerson;
|
||||
|
||||
@Override
|
||||
protected Map<Long, DataSet> fetchBulk(Collection<Long> personIds) throws SQLException {
|
||||
FlexStatement fs = this.sqlSelectPersons.buildStatement(personIds);
|
||||
try {
|
||||
return fs.executeQuery().getAllRows("personID", Long.class);
|
||||
} finally {
|
||||
fs.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT GP.* FROM ~g~.Person GP WHERE GP.personID IN (??)")
|
||||
private StatementProvider sqlSelectPersons;
|
||||
|
||||
}
|
@@ -1,90 +0,0 @@
|
||||
package com.poststats.golf.service.db;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import com.brianlong.sql.DataSet;
|
||||
import com.brianlong.sql.FlexPreparedStatement;
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.service.SeriesService;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.Statement;
|
||||
import com.poststats.provider.StatementProvider;
|
||||
import com.poststats.service.ServiceException;
|
||||
import com.poststats.service.db.CacheableServiceDAO;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@ApplicationScoped
|
||||
public class SeriesServiceDAO extends CacheableServiceDAO<Integer> implements SeriesService {
|
||||
|
||||
private final long defaultCacheExpirationInSeconds = 3600;
|
||||
|
||||
@Override
|
||||
public FlexMap get(int seriesId) {
|
||||
return this.get(Integer.valueOf(seriesId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSet getByEventId(long eventId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlSelectByEventId.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, eventId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT * FROM ~g~.Series WHERE eventID=? ")
|
||||
private StatementProvider sqlSelectByEventId;
|
||||
|
||||
@Override
|
||||
protected long getCacheExpirationInSeconds() {
|
||||
return this.defaultCacheExpirationInSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSet fetchOne(Integer seriesId) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectSeries.buildPreparedStatement();
|
||||
try {
|
||||
fps.setSmallintU(1, seriesId);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT S.* FROM ~g~.Series S WHERE seriesID=? ")
|
||||
private StatementProvider sqlSelectSeries;
|
||||
|
||||
@Override
|
||||
protected Map<Integer, DataSet> fetchBulk(Collection<Integer> seriesIds) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectSerieses.buildPreparedStatement(seriesIds);
|
||||
try {
|
||||
return fps.executeQuery().getAllRows("seriesID", Integer.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT S.* FROM ~g~.Series S WHERE seriesID IN (??) ")
|
||||
private StatementProvider sqlSelectSerieses;
|
||||
|
||||
}
|
@@ -1,404 +0,0 @@
|
||||
package com.poststats.golf.service.model;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PointHandicapIndex implements Comparable<PointHandicapIndex> {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final int pointIndexId;
|
||||
|
||||
public PointHandicapIndex(int pointIndexId) {
|
||||
this.pointIndexId = pointIndexId;
|
||||
}
|
||||
|
||||
public PointHandicapIndex(byte alby, byte eagle, byte birdie, byte par, byte bogey, byte bogey2, byte bogey3,
|
||||
byte bogey4, byte bogey5) {
|
||||
int pointIndexId = 0;
|
||||
|
||||
if (bogey5 > 1)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) 5);
|
||||
pointIndexId += bogey5;
|
||||
|
||||
if (bogey4 > 3 || bogey4 > 0 && bogey5 >= bogey4)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) 4);
|
||||
pointIndexId += bogey4;
|
||||
|
||||
if (bogey3 > 3 || bogey3 > 0 && bogey4 >= bogey3)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) 3);
|
||||
pointIndexId += bogey3;
|
||||
|
||||
if (bogey2 > 7 || bogey2 > 0 && bogey3 >= bogey2)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) 2);
|
||||
pointIndexId += bogey2;
|
||||
|
||||
if (bogey > 7 || bogey > 0 && bogey2 >= bogey)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) 1);
|
||||
pointIndexId += bogey;
|
||||
|
||||
if (par > 15 || par > 0 && bogey >= par)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) 0);
|
||||
pointIndexId += par;
|
||||
|
||||
if (birdie > 15 || birdie > 0 && par >= birdie)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) -1);
|
||||
pointIndexId += birdie;
|
||||
|
||||
if (eagle > 31 || eagle > 0 && birdie >= eagle)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) -2);
|
||||
pointIndexId += eagle;
|
||||
|
||||
if (alby > 63 || alby > 0 && eagle >= alby)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) -3);
|
||||
pointIndexId += alby;
|
||||
|
||||
this.pointIndexId = pointIndexId;
|
||||
}
|
||||
|
||||
public PointHandicapIndex(int alby, int eagle, int birdie, int par, int bogey, int bogey2, int bogey3, int bogey4,
|
||||
int bogey5) {
|
||||
int pointIndexId = 0;
|
||||
|
||||
if (bogey5 > 1)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) 5);
|
||||
pointIndexId += bogey5;
|
||||
|
||||
if (bogey4 > 3 || bogey4 > 0 && bogey5 >= bogey4)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) 4);
|
||||
pointIndexId += bogey4;
|
||||
|
||||
if (bogey3 > 3 || bogey3 > 0 && bogey4 >= bogey3)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) 3);
|
||||
pointIndexId += bogey3;
|
||||
|
||||
if (bogey2 > 7 || bogey2 > 0 && bogey3 >= bogey2)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) 2);
|
||||
pointIndexId += bogey2;
|
||||
|
||||
if (bogey > 7 || bogey > 0 && bogey2 >= bogey)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) 1);
|
||||
pointIndexId += bogey;
|
||||
|
||||
if (par > 15 || par > 0 && bogey >= par)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) 0);
|
||||
pointIndexId += par;
|
||||
|
||||
if (birdie > 15 || birdie > 0 && par >= birdie)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) -1);
|
||||
pointIndexId += birdie;
|
||||
|
||||
if (eagle > 31 || eagle > 0 && birdie >= eagle)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) -2);
|
||||
pointIndexId += eagle;
|
||||
|
||||
if (alby > 63 || alby > 0 && eagle >= alby)
|
||||
throw new IllegalArgumentException();
|
||||
pointIndexId <<= this.getBits((byte) -3);
|
||||
pointIndexId += alby;
|
||||
|
||||
this.pointIndexId = pointIndexId;
|
||||
}
|
||||
|
||||
public PointHandicapIndex(int[] scoresToPar) {
|
||||
this(scoresToPar[7], scoresToPar[8], scoresToPar[9], scoresToPar[0], scoresToPar[1], scoresToPar[2],
|
||||
scoresToPar[3], scoresToPar[4], scoresToPar[5]);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return this.pointIndexId;
|
||||
}
|
||||
|
||||
public byte getPointsWithScoreToPar(byte scoreToPar) {
|
||||
int shift = this.getShift(scoreToPar);
|
||||
int bits = this.getBits(scoreToPar);
|
||||
int mask = ((1 << bits) - 1) << (shift - bits);
|
||||
return (byte) ((this.pointIndexId & mask) >> (shift - bits));
|
||||
}
|
||||
|
||||
public byte getQuintupleBogeyPoints() {
|
||||
return this.getPointsWithScoreToPar((byte) 5);
|
||||
}
|
||||
|
||||
public byte getQuadrupleBogeyPoints() {
|
||||
return this.getPointsWithScoreToPar((byte) 4);
|
||||
}
|
||||
|
||||
public byte getTripleBogeyPoints() {
|
||||
return this.getPointsWithScoreToPar((byte) 3);
|
||||
}
|
||||
|
||||
public byte getDoubleBogeyPoints() {
|
||||
return this.getPointsWithScoreToPar((byte) 2);
|
||||
}
|
||||
|
||||
public byte getBogeyPoints() {
|
||||
return this.getPointsWithScoreToPar((byte) 1);
|
||||
}
|
||||
|
||||
public byte getParPoints() {
|
||||
return this.getPointsWithScoreToPar((byte) 0);
|
||||
}
|
||||
|
||||
public byte getBirdiePoints() {
|
||||
return this.getPointsWithScoreToPar((byte) -1);
|
||||
}
|
||||
|
||||
public byte getEaglePoints() {
|
||||
return this.getPointsWithScoreToPar((byte) -2);
|
||||
}
|
||||
|
||||
public byte getAlbatrossPoints() {
|
||||
return this.getPointsWithScoreToPar((byte) -3);
|
||||
}
|
||||
|
||||
private int getShift(byte scoreToPar) {
|
||||
if (scoreToPar < -2) {
|
||||
return 6; // 0-63
|
||||
} else switch (scoreToPar) {
|
||||
case -2:
|
||||
return 11; // 0-31
|
||||
case -1:
|
||||
return 15; // 0-15
|
||||
case 0:
|
||||
return 19; // 0-15
|
||||
case 1:
|
||||
return 22; // 0-7
|
||||
case 2:
|
||||
return 25; // 0-7
|
||||
case 3:
|
||||
return 27; // 0-3
|
||||
case 4:
|
||||
return 29; // 0-3
|
||||
case 5:
|
||||
return 30; // 0-1
|
||||
default:
|
||||
return 31; // 0
|
||||
}
|
||||
}
|
||||
|
||||
private int getBits(byte scoreToPar) {
|
||||
if (scoreToPar < -2) {
|
||||
return 6; // 0-63
|
||||
} else switch (scoreToPar) {
|
||||
case -2:
|
||||
return 5; // 0-31
|
||||
case -1:
|
||||
return 4; // 0-15
|
||||
case 0:
|
||||
return 4; // 0-15
|
||||
case 1:
|
||||
return 3; // 0-7
|
||||
case 2:
|
||||
return 3; // 0-7
|
||||
case 3:
|
||||
return 2; // 0-3
|
||||
case 4:
|
||||
return 2; // 0-3
|
||||
case 5:
|
||||
return 1; // 0-1
|
||||
default:
|
||||
return 0; // 0
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof PointHandicapIndex))
|
||||
return false;
|
||||
return this.getId() == ((PointHandicapIndex) obj).getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append(this.getQuintupleBogeyPoints()).append('/')
|
||||
.append(this.getQuadrupleBogeyPoints()).append('/').append(this.getTripleBogeyPoints()).append('/')
|
||||
.append(this.getDoubleBogeyPoints()).append('/').append(this.getBogeyPoints()).append('/')
|
||||
.append(this.getParPoints()).append('/').append(this.getBirdiePoints()).append('/')
|
||||
.append(this.getEaglePoints()).append('/').append(this.getAlbatrossPoints()).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(PointHandicapIndex o) {
|
||||
float compare = this.diff(o);
|
||||
if (Float.isNaN(compare)) {
|
||||
return 0;
|
||||
} else if (compare == 0f) {
|
||||
return 0;
|
||||
} else if (compare < 0f) {
|
||||
return (int) Math.floor(compare);
|
||||
} else {
|
||||
return (int) Math.ceil(compare);
|
||||
}
|
||||
}
|
||||
|
||||
private float diff(PointHandicapIndex o) {
|
||||
if (this.getId() == o.getId())
|
||||
return 0f;
|
||||
|
||||
boolean pos = false;
|
||||
boolean neg = false;
|
||||
|
||||
int compare = Byte.compare(this.getAlbatrossPoints(), o.getAlbatrossPoints());
|
||||
if (compare < 0)
|
||||
neg = true;
|
||||
else if (compare > 0)
|
||||
pos = true;
|
||||
|
||||
compare = Byte.compare(this.getEaglePoints(), o.getEaglePoints());
|
||||
if (compare < 0)
|
||||
neg = true;
|
||||
else if (compare > 0)
|
||||
pos = true;
|
||||
if (neg && pos)
|
||||
return Float.NaN;
|
||||
|
||||
compare = Byte.compare(this.getBirdiePoints(), o.getBirdiePoints());
|
||||
if (compare < 0)
|
||||
neg = true;
|
||||
else if (compare > 0)
|
||||
pos = true;
|
||||
if (neg && pos)
|
||||
return Float.NaN;
|
||||
|
||||
compare = Byte.compare(this.getParPoints(), o.getParPoints());
|
||||
if (compare < 0)
|
||||
neg = true;
|
||||
else if (compare > 0)
|
||||
pos = true;
|
||||
if (neg && pos)
|
||||
return Float.NaN;
|
||||
|
||||
compare = Byte.compare(this.getBogeyPoints(), o.getBogeyPoints());
|
||||
if (compare < 0)
|
||||
neg = true;
|
||||
else if (compare > 0)
|
||||
pos = true;
|
||||
if (neg && pos)
|
||||
return Float.NaN;
|
||||
|
||||
compare = Byte.compare(this.getDoubleBogeyPoints(), o.getDoubleBogeyPoints());
|
||||
if (compare < 0)
|
||||
neg = true;
|
||||
else if (compare > 0)
|
||||
pos = true;
|
||||
if (neg && pos)
|
||||
return Float.NaN;
|
||||
|
||||
compare = Byte.compare(this.getTripleBogeyPoints(), o.getTripleBogeyPoints());
|
||||
if (compare < 0)
|
||||
neg = true;
|
||||
else if (compare > 0)
|
||||
pos = true;
|
||||
if (neg && pos)
|
||||
return Float.NaN;
|
||||
|
||||
compare = Byte.compare(this.getQuadrupleBogeyPoints(), o.getQuadrupleBogeyPoints());
|
||||
if (compare < 0)
|
||||
neg = true;
|
||||
else if (compare > 0)
|
||||
pos = true;
|
||||
if (neg && pos)
|
||||
return Float.NaN;
|
||||
|
||||
compare = Byte.compare(this.getQuintupleBogeyPoints(), o.getQuintupleBogeyPoints());
|
||||
if (compare < 0)
|
||||
neg = true;
|
||||
else if (compare > 0)
|
||||
pos = true;
|
||||
|
||||
if (neg && pos) {
|
||||
return Float.NaN;
|
||||
} else if (neg) {
|
||||
return -1;
|
||||
} else if (pos) {
|
||||
return 1;
|
||||
} else {
|
||||
this.logger.warn("This should never happen");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public PointHandicapIndex decrement(byte scoreToPar) {
|
||||
return this.minus(scoreToPar, (byte) 1);
|
||||
}
|
||||
|
||||
public PointHandicapIndex increment(byte scoreToPar) {
|
||||
return this.plus(scoreToPar, (byte) 1);
|
||||
}
|
||||
|
||||
public PointHandicapIndex minus(byte scoreToPar, byte points) {
|
||||
return this.plus(scoreToPar, (byte) -points);
|
||||
}
|
||||
|
||||
public PointHandicapIndex plus(byte scoreToPar, byte points) {
|
||||
int shift = this.getShift(scoreToPar);
|
||||
int bits = this.getBits(scoreToPar);
|
||||
int mask = ((1 << bits) - 1) << (shift - bits);
|
||||
int oldPointIndexMasked = this.pointIndexId & mask;
|
||||
byte oldPoints = (byte) (oldPointIndexMasked >> (shift - bits));
|
||||
|
||||
if (points < 0) {
|
||||
if (oldPoints == 0)
|
||||
return this;
|
||||
} else {
|
||||
if (oldPoints + points >= this.getPointsWithScoreToPar((byte) (scoreToPar - 1)))
|
||||
return this;
|
||||
}
|
||||
|
||||
if (oldPoints + points >= Math.pow(2, bits))
|
||||
throw new IllegalArgumentException();
|
||||
int pointIndexMasked = (oldPoints + points) << (shift - bits);
|
||||
|
||||
return new PointHandicapIndex(this.pointIndexId - oldPointIndexMasked + pointIndexMasked);
|
||||
}
|
||||
|
||||
public PointHandicapIndex avg(PointHandicapIndex phi, int roundingBias) {
|
||||
return new PointHandicapIndex(
|
||||
this.computeAvg(this.getAlbatrossPoints(), phi.getAlbatrossPoints(), roundingBias),
|
||||
this.computeAvg(this.getEaglePoints(), phi.getEaglePoints(), roundingBias),
|
||||
this.computeAvg(this.getBirdiePoints(), phi.getBirdiePoints(), roundingBias),
|
||||
this.computeAvg(this.getParPoints(), phi.getParPoints(), roundingBias),
|
||||
this.computeAvg(this.getBogeyPoints(), phi.getBogeyPoints(), roundingBias),
|
||||
this.computeAvg(this.getDoubleBogeyPoints(), phi.getDoubleBogeyPoints(), roundingBias),
|
||||
this.computeAvg(this.getTripleBogeyPoints(), phi.getTripleBogeyPoints(), roundingBias),
|
||||
this.computeAvg(this.getQuadrupleBogeyPoints(), phi.getQuadrupleBogeyPoints(), roundingBias),
|
||||
this.computeAvg(this.getQuintupleBogeyPoints(), phi.getQuintupleBogeyPoints(), roundingBias));
|
||||
}
|
||||
|
||||
private byte computeAvg(byte points1, byte points2, int roundingBias) {
|
||||
if (points1 == points2)
|
||||
return points1;
|
||||
float avg = (points1 + points2) / 2f;
|
||||
if (roundingBias == 0) {
|
||||
return (byte) Math.round(avg);
|
||||
} else if (roundingBias < 0) {
|
||||
return (byte) Math.floor(avg);
|
||||
} else {
|
||||
return (byte) Math.ceil(avg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
package com.poststats.golf.service.model;
|
||||
|
||||
public class StrokeCourseRating {
|
||||
|
||||
private final short slopeRating;
|
||||
private final float courseRating;
|
||||
|
||||
public StrokeCourseRating(short slopeRating, float courseRating) {
|
||||
this.slopeRating = slopeRating;
|
||||
this.courseRating = courseRating;
|
||||
}
|
||||
|
||||
public short getSlopeRating() {
|
||||
return this.slopeRating;
|
||||
}
|
||||
|
||||
public float getCourseRating() {
|
||||
return this.courseRating;
|
||||
}
|
||||
|
||||
}
|
@@ -1,380 +0,0 @@
|
||||
package com.poststats.golf.service.telegram;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.http.client.HttpResponseException;
|
||||
import org.slf4j.Logger;
|
||||
import org.telegram.telegrambots.meta.api.methods.groupadministration.CreateChatInviteLink;
|
||||
import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChat;
|
||||
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
|
||||
import org.telegram.telegrambots.meta.api.objects.Chat;
|
||||
import org.telegram.telegrambots.meta.api.objects.ChatInviteLink;
|
||||
import org.telegram.telegrambots.meta.api.objects.ChatMemberUpdated;
|
||||
import org.telegram.telegrambots.meta.api.objects.Message;
|
||||
import org.telegram.telegrambots.meta.api.objects.chatmember.ChatMemberAdministrator;
|
||||
import org.telegram.telegrambots.meta.api.objects.chatmember.ChatMemberBanned;
|
||||
import org.telegram.telegrambots.meta.api.objects.chatmember.ChatMemberLeft;
|
||||
import org.telegram.telegrambots.meta.api.objects.chatmember.ChatMemberMember;
|
||||
|
||||
import com.brianlong.sql.DataSet;
|
||||
import com.brianlong.sql.FlexPreparedStatement;
|
||||
import com.poststats.golf.provider.GolfProvider;
|
||||
import com.poststats.golf.service.PersonService;
|
||||
import com.poststats.provider.NonTransactionalProvider;
|
||||
import com.poststats.provider.PostStatsProvider;
|
||||
import com.poststats.provider.Statement;
|
||||
import com.poststats.provider.StatementProvider;
|
||||
import com.poststats.provider.TransactionalProvider;
|
||||
import com.poststats.service.ConfigurationAccessor;
|
||||
import com.poststats.service.ServiceException;
|
||||
import com.poststats.service.TelegramChannelManager;
|
||||
import com.poststats.service.TelegramChannelSubscriber;
|
||||
import com.poststats.service.TelegramPushService;
|
||||
import com.poststats.service.TelegramUpdateSubscriber.TelegramMessageReplier;
|
||||
import com.poststats.service.model.TelegramCommand;
|
||||
import com.poststats.transformer.JacksonObjectMapper;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.transaction.Transactional;
|
||||
import jakarta.transaction.Transactional.TxType;
|
||||
|
||||
@ApplicationScoped
|
||||
public class TelegramEventService implements TelegramChannelSubscriber, TelegramChannelManager<Long> {
|
||||
|
||||
@Inject
|
||||
private Logger logger;
|
||||
|
||||
@Inject
|
||||
private PersonService personService;
|
||||
|
||||
@Inject
|
||||
private JacksonObjectMapper om;
|
||||
|
||||
@Inject
|
||||
private ConfigurationAccessor config;
|
||||
|
||||
@Inject
|
||||
private TelegramPushService telegramService;
|
||||
|
||||
private final List<String> helpLines = Arrays.asList("`/event_sub {shared_secret}`", "`/event_unsub`");
|
||||
|
||||
@Override
|
||||
public Collection<String> getCommandLines() {
|
||||
return this.helpLines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void memberStatusReceived(ChatMemberUpdated member, TelegramMessageReplier replier) {
|
||||
if (Boolean.TRUE.equals(member.getNewChatMember().getUser().getIsBot())) {
|
||||
if (!"poststats_bot".equals(member.getNewChatMember().getUser().getUserName())) {
|
||||
this.logger.debug("Ignoring unregulated bot: {}", member.getNewChatMember().getUser().getUserName());
|
||||
} else {
|
||||
switch (member.getNewChatMember().getStatus()) {
|
||||
case ChatMemberBanned.STATUS:
|
||||
case ChatMemberLeft.STATUS:
|
||||
this.unsetInDatabase(member.getChat().getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (member.getNewChatMember().getStatus()) {
|
||||
case ChatMemberBanned.STATUS:
|
||||
case ChatMemberLeft.STATUS:
|
||||
this.setInChannelInDatabase(member.getNewChatMember().getUser().getId(), member.getChat().getId(),
|
||||
false);
|
||||
break;
|
||||
case ChatMemberMember.STATUS:
|
||||
case ChatMemberAdministrator.STATUS:
|
||||
this.setInChannelInDatabase(member.getNewChatMember().getUser().getId(), member.getChat().getId(),
|
||||
true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(Message message, TelegramMessageReplier replier) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(TxType.REQUIRED)
|
||||
public boolean commandReceived(TelegramCommand command, TelegramMessageReplier replier) {
|
||||
switch (command.getCommand()) {
|
||||
case "event_sub":
|
||||
if (command.getText() != null) {
|
||||
if (this.setInDatabase(command.getUserId(), command.getChannelId(), command.getText())) {
|
||||
replier.reply("You have successfully subscribed this channel to your PostStats Event!");
|
||||
} else {
|
||||
replier.reply("The supplied shared secret or Event authority is not valid.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case "event_unsub":
|
||||
if (this.unsetInDatabase(command.getUserId())) {
|
||||
replier.reply(
|
||||
"You have successfully unsubscribed this channel from PostStats Event communications.");
|
||||
} else {
|
||||
replier.reply(
|
||||
"This channel was not and continue to not be subscribed to PostStats Event communications.");
|
||||
}
|
||||
return true;
|
||||
case "start":
|
||||
default:
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addUserToChannel(Long eventId, long personId) {
|
||||
try {
|
||||
Long channelId = this.findEventChannelId(eventId);
|
||||
if (channelId == null) {
|
||||
this.logger.warn("The event is not linked to a Telegram channel");
|
||||
return false;
|
||||
}
|
||||
|
||||
Long userId = this.findPersonUserId(personId);
|
||||
if (userId == null) {
|
||||
this.logger.debug("An channel invite cannot be created for users without a linked Telegram account");
|
||||
return false;
|
||||
}
|
||||
|
||||
Chat chat = this.telegramService.callEndpoint(GetChat.builder().chatId(channelId).build());
|
||||
if (chat == null) {
|
||||
this.logger.warn("The channel could not be found");
|
||||
return false;
|
||||
}
|
||||
|
||||
ChatInviteLink inviteLink = this.telegramService
|
||||
.callEndpoint(CreateChatInviteLink.builder().chatId(channelId).build());
|
||||
if (inviteLink == null)
|
||||
throw new ServiceException("An invite could not be created");
|
||||
|
||||
SendMessage sendMessage = SendMessage.builder().allowSendingWithoutReply(true).chatId(userId)
|
||||
.text("You have been invited to join the "
|
||||
+ chat.getTitle()
|
||||
+ " channel: "
|
||||
+ inviteLink.getInviteLink())
|
||||
.build();
|
||||
this.telegramService.callEndpoint(sendMessage);
|
||||
|
||||
return true;
|
||||
} catch (HttpResponseException hre) {
|
||||
throw new ServiceException(hre);
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeUserFromChannel(Long eventId, long personId) {
|
||||
try {
|
||||
Long channelId = this.findEventChannelId(eventId);
|
||||
if (channelId == null)
|
||||
return false;
|
||||
|
||||
Long userId = this.findPersonUserId(personId);
|
||||
if (userId == null) {
|
||||
this.logger.debug("An channel invite cannot be created for users without a linked Telegram account");
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reconcileChannelMembers(Long poststatsId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reconcileChannels(long personId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private boolean setInDatabase(long telegramUserId, long channelId, String sharedSecret) {
|
||||
try {
|
||||
DataSet row = this.querySharedSecretByCode(sharedSecret);
|
||||
if (row == null) {
|
||||
this.logger.debug("A shared secret was provided but not found: {}", sharedSecret);
|
||||
return false;
|
||||
} else if (row.isNotEmpty("eventID")) {
|
||||
long eventId = row.getLong("eventID");
|
||||
if (!this.checkAuthority(telegramUserId, eventId))
|
||||
return false;
|
||||
this.updateEvent(eventId, channelId);
|
||||
this.deleteSharedSecret(row.getLong("sharedSecretId"));
|
||||
} else {
|
||||
this.logger.warn("A shared secret was shared by {} for something other than an 'event'",
|
||||
telegramUserId);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
private DataSet querySharedSecretByCode(String sharedSecret) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectSharedSecret.buildPreparedStatement();
|
||||
try {
|
||||
fps.setVarchar(1, sharedSecret);
|
||||
return fps.executeQuery().getNextRow();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@PostStatsProvider
|
||||
@Statement(sql = "SELECT * FROM ~p~.SharedSecret WHERE sharedSecret=? AND expiration>NOW()")
|
||||
private StatementProvider sqlSelectSharedSecret;
|
||||
|
||||
private void deleteSharedSecret(long sharedSecretId) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlDeleteSharedSecret.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, sharedSecretId);
|
||||
fps.executeUpdate();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@TransactionalProvider
|
||||
@PostStatsProvider
|
||||
@Statement(sql = "DELETE FROM ~p~.SharedSecret WHERE sharedSecretId=?")
|
||||
private StatementProvider sqlDeleteSharedSecret;
|
||||
|
||||
private boolean checkAuthority(long telegramUserId, long eventId) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectAuthority.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, eventId);
|
||||
fps.setBigint(2, telegramUserId);
|
||||
return fps.executeQuery().getOne(Integer.class) > 0;
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@TransactionalProvider
|
||||
@PostStatsProvider
|
||||
@Statement(
|
||||
sql = "SELECT COUNT(*) "
|
||||
+ "FROM ~g~.EventPersonAccessControl EPAC "
|
||||
+ " INNER JOIN ~p~.Person P ON (EPAC.personID=P.personID) "
|
||||
+ " INNER JOIN ~p~.AccessControl AC ON (EPAC.acID=AC.acID) "
|
||||
+ "WHERE EPAC.eventID=? AND P.telegramUserId=? AND AC.acSID IN ('admin', 'communicate')"
|
||||
)
|
||||
private StatementProvider sqlSelectAuthority;
|
||||
|
||||
private Long findEventChannelId(long eventId) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectEventChannel.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, eventId);
|
||||
return fps.executeQuery().getOne(Long.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "SELECT telegramChannelId FROM ~g~.Event WHERE eventId=?")
|
||||
private StatementProvider sqlSelectEventChannel;
|
||||
|
||||
private Long findPersonUserId(long personId) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlSelectEventChannel.buildPreparedStatement();
|
||||
try {
|
||||
fps.setIntegerU(1, personId);
|
||||
return fps.executeQuery().getOne(Long.class);
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@NonTransactionalProvider
|
||||
@PostStatsProvider
|
||||
@Statement(sql = "SELECT telegramUserId FROM ~p~.Person WHERE personId=?")
|
||||
private StatementProvider sqlSelectPersonUser;
|
||||
|
||||
private void updateEvent(long eventId, long telegramChannelId) throws SQLException {
|
||||
FlexPreparedStatement fps = this.sqlUpdateEvent.buildPreparedStatement();
|
||||
try {
|
||||
fps.setBigint(1, telegramChannelId);
|
||||
fps.setIntegerU(2, eventId);
|
||||
fps.executeUpdate();
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@TransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "UPDATE ~g~.Event SET telegramChannelId=? WHERE eventID=?")
|
||||
private StatementProvider sqlUpdateEvent;
|
||||
|
||||
private boolean unsetInDatabase(long telegramChannelId) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlUpdateEventUnset.buildPreparedStatement();
|
||||
try {
|
||||
fps.setBigint(1, telegramChannelId);
|
||||
return fps.executeUpdate() > 0;
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@TransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(sql = "UPDATE ~g~.Event SET telegramChannelId=NULL WHERE telegramChannelId=?")
|
||||
private StatementProvider sqlUpdateEventUnset;
|
||||
|
||||
private boolean setInChannelInDatabase(long telegramUserId, long channelId, boolean in) {
|
||||
try {
|
||||
FlexPreparedStatement fps = this.sqlUpdateEventPersonSet.buildPreparedStatement();
|
||||
try {
|
||||
fps.setBoolean(1, in);
|
||||
fps.setBigint(2, channelId);
|
||||
fps.setBigint(3, telegramUserId);
|
||||
return fps.executeUpdate() > 0;
|
||||
} finally {
|
||||
fps.close();
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
throw new ServiceException(se);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@TransactionalProvider
|
||||
@GolfProvider
|
||||
@Statement(
|
||||
sql = "UPDATE ~g~.EventPerson "
|
||||
+ "SET inTelegramChannel=? "
|
||||
+ "WHERE eventID IN (SELECT eventID FROM ~g~.Event WHERE telegramChannelId=?) "
|
||||
+ " AND personID IN (SELECT personID FROM ~p~.Person WHERE telegramUserId=?) "
|
||||
)
|
||||
private StatementProvider sqlUpdateEventPersonSet;
|
||||
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
package com.poststats.golf.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.poststats.golf.security.AuthenticatedSecurityContext;
|
||||
import com.poststats.golf.service.PersonService;
|
||||
import com.poststats.security.AuthenticatedPerson;
|
||||
|
||||
import jakarta.annotation.Priority;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.Priorities;
|
||||
import jakarta.ws.rs.container.ContainerRequestContext;
|
||||
import jakarta.ws.rs.container.ContainerRequestFilter;
|
||||
import jakarta.ws.rs.core.SecurityContext;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
@ApplicationScoped
|
||||
@Provider
|
||||
@Priority(Priorities.AUTHENTICATION + 5)
|
||||
public class AuthenticationFilter implements ContainerRequestFilter {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Inject
|
||||
private PersonService personService;
|
||||
|
||||
@Override
|
||||
public void filter(ContainerRequestContext requestContext) throws IOException {
|
||||
SecurityContext scontext = requestContext.getSecurityContext();
|
||||
if (scontext == null || scontext.getUserPrincipal() == null)
|
||||
return;
|
||||
|
||||
AuthenticatedPerson authPerson = (AuthenticatedPerson) scontext.getUserPrincipal();
|
||||
|
||||
this.logger.debug("Gathering roles for golf: {}", authPerson);
|
||||
|
||||
com.poststats.golf.security.AuthenticatedPerson gauthPerson = this.personService.getUserPrincipal(authPerson);
|
||||
|
||||
if (this.logger.isTraceEnabled())
|
||||
this.logger.trace("Authorized roles: {} => {}", gauthPerson.getId(), gauthPerson.getAllAccessControls());
|
||||
|
||||
scontext = new AuthenticatedSecurityContext(scontext, gauthPerson);
|
||||
|
||||
requestContext.setSecurityContext(scontext);
|
||||
}
|
||||
|
||||
}
|
@@ -1,63 +0,0 @@
|
||||
package com.poststats.golf.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.brianlong.util.StringUtil;
|
||||
import com.poststats.golf.api.Constants;
|
||||
import com.poststats.golf.security.AuthenticatedPerson;
|
||||
import com.poststats.golf.security.EventSecurityContext;
|
||||
|
||||
import jakarta.annotation.Priority;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.ws.rs.Priorities;
|
||||
import jakarta.ws.rs.container.ContainerRequestContext;
|
||||
import jakarta.ws.rs.container.ContainerRequestFilter;
|
||||
import jakarta.ws.rs.core.SecurityContext;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
@ApplicationScoped
|
||||
@Provider
|
||||
@Priority(Priorities.AUTHORIZATION - 5)
|
||||
public class EventFilter implements ContainerRequestFilter {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Override
|
||||
public void filter(ContainerRequestContext requestContext) throws IOException {
|
||||
String eventIdStr = requestContext.getUriInfo().getPathParameters().getFirst(Constants.EVENT_ID);
|
||||
eventIdStr = StringUtil.getInstance().trim(eventIdStr);
|
||||
|
||||
if (eventIdStr == null) {
|
||||
eventIdStr = requestContext.getUriInfo().getQueryParameters().getFirst(Constants.EVENT_ID);
|
||||
eventIdStr = StringUtil.getInstance().trim(eventIdStr);
|
||||
}
|
||||
|
||||
if (eventIdStr == null)
|
||||
return;
|
||||
|
||||
this.logger.debug("Entering event context: {}", eventIdStr);
|
||||
|
||||
long eventId = Long.valueOf(eventIdStr);
|
||||
requestContext.setProperty(Constants.EVENT_ID, eventId);
|
||||
|
||||
SecurityContext scontext = requestContext.getSecurityContext();
|
||||
if (scontext.getUserPrincipal() == null)
|
||||
return;
|
||||
|
||||
this.logger.debug("Narrowing authorization for event: {} => {}", scontext.getUserPrincipal(), eventId);
|
||||
|
||||
EventSecurityContext epscontext = new EventSecurityContext(scontext, eventId);
|
||||
|
||||
if (this.logger.isTraceEnabled()) {
|
||||
AuthenticatedPerson person = (AuthenticatedPerson) epscontext.getUserPrincipal();
|
||||
this.logger.trace("Authorized event roles: {} => {}", person.getId(),
|
||||
person.getEventAccessControls(eventId));
|
||||
}
|
||||
|
||||
requestContext.setSecurityContext(epscontext);
|
||||
}
|
||||
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
package com.poststats.golf.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.poststats.golf.api.Constants;
|
||||
import com.poststats.golf.security.PersonSecurityContext;
|
||||
import com.poststats.golf.service.PersonService;
|
||||
|
||||
import jakarta.annotation.Priority;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.Priorities;
|
||||
import jakarta.ws.rs.container.ContainerRequestContext;
|
||||
import jakarta.ws.rs.container.ContainerRequestFilter;
|
||||
import jakarta.ws.rs.core.SecurityContext;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
@ApplicationScoped
|
||||
@Provider
|
||||
@Priority(Priorities.AUTHORIZATION - 8)
|
||||
public class PersonFilter implements ContainerRequestFilter {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Inject
|
||||
private PersonService personService;
|
||||
|
||||
@Override
|
||||
public void filter(ContainerRequestContext requestContext) throws IOException {
|
||||
Long personId = (Long) requestContext.getProperty(Constants.PERSON_ID);
|
||||
if (personId == null)
|
||||
return;
|
||||
|
||||
SecurityContext scontext = requestContext.getSecurityContext();
|
||||
if (scontext == null || scontext.getUserPrincipal() == null)
|
||||
return;
|
||||
|
||||
this.logger.debug("Entering golfer context: {}", personId);
|
||||
|
||||
scontext = new PersonSecurityContext(scontext, personId);
|
||||
requestContext.setSecurityContext(scontext);
|
||||
}
|
||||
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
package com.poststats.golf.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.brianlong.util.StringUtil;
|
||||
import com.poststats.golf.api.Constants;
|
||||
|
||||
import jakarta.annotation.Priority;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.ws.rs.Priorities;
|
||||
import jakarta.ws.rs.container.ContainerRequestContext;
|
||||
import jakarta.ws.rs.container.ContainerRequestFilter;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
@ApplicationScoped
|
||||
@Provider
|
||||
@Priority(Priorities.HEADER_DECORATOR + 10)
|
||||
public class SeriesFilter implements ContainerRequestFilter {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Override
|
||||
public void filter(ContainerRequestContext requestContext) throws IOException {
|
||||
String seriesIdStr = requestContext.getUriInfo().getPathParameters().getFirst(Constants.EVENT_SERIES_ID);
|
||||
seriesIdStr = StringUtil.getInstance().trim(seriesIdStr);
|
||||
|
||||
if (seriesIdStr == null) {
|
||||
seriesIdStr = requestContext.getUriInfo().getQueryParameters().getFirst(Constants.EVENT_SERIES_ID);
|
||||
seriesIdStr = StringUtil.getInstance().trim(seriesIdStr);
|
||||
}
|
||||
|
||||
if (seriesIdStr == null)
|
||||
return;
|
||||
|
||||
this.logger.debug("Entering series context: {}", seriesIdStr);
|
||||
|
||||
int seriesId = Integer.valueOf(seriesIdStr);
|
||||
requestContext.setProperty(Constants.EVENT_SERIES_ID, seriesId);
|
||||
}
|
||||
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
<beans version="4.0"
|
||||
xmlns="https://jakarta.ee/xml/ns/jakartaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd">
|
||||
</beans>
|
@@ -1,31 +0,0 @@
|
||||
package com.poststats.golf.service.compute;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ComputeLegacyPointCourseRatingUnitTest {
|
||||
|
||||
private static LegacyPostStatsPointHandicapIndexService service;
|
||||
|
||||
@BeforeAll
|
||||
public static void stage() {
|
||||
service = new LegacyPostStatsPointHandicapIndexService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cypressLandingGold() {
|
||||
Assertions.assertEquals(-4f, service.computeRatingIndex((short) 117, 66.8f, 'M', (short) 5473, (byte) 72), 1f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cypressLandingWhite() {
|
||||
Assertions.assertEquals(12f, service.computeRatingIndex((short) 127, 69.7f, 'M', (short) 6124, (byte) 72), 1f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cypressLandingBlue() {
|
||||
Assertions.assertEquals(19f, service.computeRatingIndex((short) 131, 71.1f, 'M', (short) 6442, (byte) 72), 1f);
|
||||
}
|
||||
|
||||
}
|
@@ -1,124 +0,0 @@
|
||||
package com.poststats.golf.service.compute;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
|
||||
public class ComputePointCourseRatingUnitTest {
|
||||
|
||||
private static PostStatsPointHandicapIndexService service;
|
||||
|
||||
@BeforeAll
|
||||
public static void stage() {
|
||||
service = new PostStatsPointHandicapIndexService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cypressLandingGold() {
|
||||
Assertions.assertEquals(-25f, service.computeRatingIndex(this.mockEighteenTeeRating('M', (byte) 72, 66.8f),
|
||||
Arrays.asList(this.mockHole(301, 4), this.mockHole(295, 4), this.mockHole(136, 3),
|
||||
this.mockHole(297, 4), this.mockHole(460, 5), this.mockHole(349, 4), this.mockHole(140, 3),
|
||||
this.mockHole(492, 5), this.mockHole(323, 4), this.mockHole(314, 4), this.mockHole(118, 3),
|
||||
this.mockHole(461, 5), this.mockHole(301, 4), this.mockHole(351, 4), this.mockHole(113, 3),
|
||||
this.mockHole(279, 4), this.mockHole(450, 5), this.mockHole(293, 4))),
|
||||
1f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cypressLandingWhite() {
|
||||
Assertions.assertEquals(5f, service.computeRatingIndex(this.mockEighteenTeeRating('M', (byte) 72, 69.7f),
|
||||
Arrays.asList(this.mockHole(345, 4), this.mockHole(316, 4), this.mockHole(136, 3),
|
||||
this.mockHole(371, 4), this.mockHole(503, 5), this.mockHole(404, 4), this.mockHole(184, 3),
|
||||
this.mockHole(501, 5), this.mockHole(348, 4), this.mockHole(341, 4), this.mockHole(166, 3),
|
||||
this.mockHole(532, 5), this.mockHole(318, 4), this.mockHole(385, 4), this.mockHole(129, 3),
|
||||
this.mockHole(303, 4), this.mockHole(489, 5), this.mockHole(353, 4))),
|
||||
1f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cypressLandingBlue() {
|
||||
Assertions.assertEquals(22f, service.computeRatingIndex(this.mockEighteenTeeRating('M', (byte) 72, 71.1f),
|
||||
Arrays.asList(this.mockHole(373, 4), this.mockHole(316, 4), this.mockHole(166, 3),
|
||||
this.mockHole(389, 4), this.mockHole(520, 5), this.mockHole(412, 4), this.mockHole(203, 3),
|
||||
this.mockHole(520, 5), this.mockHole(366, 4), this.mockHole(374, 4), this.mockHole(185, 3),
|
||||
this.mockHole(554, 5), this.mockHole(319, 4), this.mockHole(406, 4), this.mockHole(144, 3),
|
||||
this.mockHole(318, 4), this.mockHole(489, 5), this.mockHole(388, 4))),
|
||||
1f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void heronGlenBlue() {
|
||||
Assertions.assertEquals(26f, service.computeRatingIndex(this.mockEighteenTeeRating('M', (byte) 72, 71.7f),
|
||||
Arrays.asList(this.mockHole(395, 4), this.mockHole(581, 5), this.mockHole(424, 4),
|
||||
this.mockHole(361, 4), this.mockHole(179, 3), this.mockHole(371, 4), this.mockHole(146, 3),
|
||||
this.mockHole(512, 5), this.mockHole(378, 4), this.mockHole(545, 5), this.mockHole(308, 4),
|
||||
this.mockHole(155, 3), this.mockHole(514, 5), this.mockHole(378, 4), this.mockHole(204, 3),
|
||||
this.mockHole(473, 5), this.mockHole(158, 3), this.mockHole(449, 4))),
|
||||
1f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metamoreFieldsBlue() {
|
||||
Assertions.assertEquals(17f, service.computeRatingIndex(this.mockEighteenTeeRating('M', (byte) 71, 70f),
|
||||
Arrays.asList(this.mockHole(388, 4), this.mockHole(121, 3), this.mockHole(523, 5),
|
||||
this.mockHole(326, 4), this.mockHole(170, 3), this.mockHole(526, 5), this.mockHole(338, 4),
|
||||
this.mockHole(181, 3), this.mockHole(427, 4), this.mockHole(392, 4), this.mockHole(152, 3),
|
||||
this.mockHole(485, 5), this.mockHole(344, 4), this.mockHole(164, 3), this.mockHole(385, 4),
|
||||
this.mockHole(504, 5), this.mockHole(382, 4), this.mockHole(401, 4))),
|
||||
1f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pinonHillsBlue() {
|
||||
Assertions.assertEquals(35f, service.computeRatingIndex(this.mockEighteenTeeRating('M', (byte) 72, 71.7f),
|
||||
Arrays.asList(this.mockHole(387, 4), this.mockHole(398, 4), this.mockHole(412, 4),
|
||||
this.mockHole(178, 3), this.mockHole(331, 4), this.mockHole(198, 3), this.mockHole(395, 4),
|
||||
this.mockHole(537, 5), this.mockHole(572, 5), this.mockHole(404, 4), this.mockHole(397, 4),
|
||||
this.mockHole(200, 3), this.mockHole(505, 5), this.mockHole(321, 4), this.mockHole(140, 3),
|
||||
this.mockHole(405, 4), this.mockHole(520, 5), this.mockHole(446, 4))),
|
||||
1f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void worthingtonHillsBlue() {
|
||||
Assertions.assertEquals(48f, service.computeRatingIndex(this.mockEighteenTeeRating('M', (byte) 71, 72.7f),
|
||||
Arrays.asList(this.mockHole(419, 4), this.mockHole(388, 4), this.mockHole(187, 3),
|
||||
this.mockHole(520, 5), this.mockHole(420, 4), this.mockHole(560, 5), this.mockHole(200, 3),
|
||||
this.mockHole(351, 4), this.mockHole(430, 4), this.mockHole(441, 4), this.mockHole(345, 4),
|
||||
this.mockHole(192, 3), this.mockHole(365, 4), this.mockHole(398, 4), this.mockHole(172, 3),
|
||||
this.mockHole(448, 4), this.mockHole(364, 4), this.mockHole(521, 5))),
|
||||
1f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void darbyCreekBlue() {
|
||||
Assertions.assertEquals(34f, service.computeRatingIndex(this.mockEighteenTeeRating('M', (byte) 72, 72.2f),
|
||||
Arrays.asList(this.mockHole(350, 4), this.mockHole(374, 4), this.mockHole(169, 3),
|
||||
this.mockHole(529, 5), this.mockHole(339, 4), this.mockHole(486, 5), this.mockHole(144, 3),
|
||||
this.mockHole(418, 4), this.mockHole(438, 4), this.mockHole(309, 4), this.mockHole(168, 3),
|
||||
this.mockHole(411, 4), this.mockHole(435, 4), this.mockHole(492, 5), this.mockHole(419, 4),
|
||||
this.mockHole(188, 3), this.mockHole(540, 5), this.mockHole(452, 4))),
|
||||
1f);
|
||||
}
|
||||
|
||||
private FlexMap mockEighteenTeeRating(char gender, int par, float courseRating) {
|
||||
FlexMap map = new FlexMap();
|
||||
map.put("etratingID", 0L);
|
||||
map.put("gender", String.valueOf(gender));
|
||||
map.put("par", (byte) par);
|
||||
map.put("courseRating", courseRating);
|
||||
return map;
|
||||
}
|
||||
|
||||
private FlexMap mockHole(int yards, int par) {
|
||||
FlexMap map = new FlexMap();
|
||||
map.put("yards", (short) yards);
|
||||
map.put("par", (byte) par);
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
@@ -1,59 +0,0 @@
|
||||
package com.poststats.golf.service.compute;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.brianlong.util.FlexMap;
|
||||
import com.poststats.golf.service.model.PointHandicapIndex;
|
||||
|
||||
public class ComputePointHandicapIndexUnitTest {
|
||||
|
||||
private static PostStatsPointHandicapIndexService service;
|
||||
|
||||
@BeforeAll
|
||||
public static void stage() {
|
||||
service = new PostStatsPointHandicapIndexService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void brian() {
|
||||
PointHandicapIndex phi = service.compute(Arrays.asList(this.mockRound(0, 22, 0, 0, 1, 5, 5, 6, 1, 0, 0),
|
||||
this.mockRound(0, 22, 0, 1, 2, 5, 6, 4, 0, 0, 0), this.mockRound(0, 22, 0, 0, 1, 3, 7, 7, 0, 0, 0),
|
||||
this.mockRound(0, 22, 0, 2, 2, 4, 8, 1, 1, 0, 0), this.mockRound(1, 26, 0, 0, 1, 5, 5, 6, 1, 0, 0),
|
||||
this.mockRound(2, 17, 0, 1, 0, 4, 7, 6, 0, 0, 0), this.mockRound(2, 17, 0, 1, 2, 4, 5, 6, 0, 0, 0),
|
||||
this.mockRound(2, 17, 0, 2, 0, 2, 7, 6, 1, 0, 0), this.mockRound(2, 17, 1, 0, 0, 3, 4, 8, 2, 0, 0),
|
||||
this.mockRound(3, 35, 0, 3, 2, 2, 6, 4, 1, 0, 0), this.mockRound(3, 35, 0, 0, 1, 5, 4, 8, 0, 0, 0),
|
||||
this.mockRound(3, 35, 1, 1, 3, 3, 3, 6, 1, 0, 0), this.mockRound(3, 35, 0, 2, 2, 5, 5, 4, 0, 0, 0)));
|
||||
System.out.println(phi);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ridgeway() {
|
||||
PointHandicapIndex phi = service.compute(Arrays.asList(this.mockRound(0, 22, 0, 0, 0, 0, 7, 9, 2, 0, 0),
|
||||
this.mockRound(0, 22, 0, 0, 0, 4, 5, 7, 2, 0, 0), this.mockRound(0, 22, 0, 0, 0, 0, 5, 11, 2, 0, 0),
|
||||
this.mockRound(1, 48, 0, 0, 0, 2, 5, 9, 2, 0, 0), this.mockRound(2, 34, 0, 0, 0, 1, 3, 8, 6, 0, 0),
|
||||
this.mockRound(1, 48, 0, 0, 0, 1, 4, 11, 2, 0, 0), this.mockRound(2, 34, 0, 0, 0, 1, 2, 12, 3, 0, 0),
|
||||
this.mockRound(2, 34, 0, 0, 0, 2, 4, 8, 4, 0, 0), this.mockRound(3, 17, 0, 0, 0, 0, 4, 10, 4, 0, 0),
|
||||
this.mockRound(3, 17, 0, 0, 0, 0, 3, 11, 4, 0, 0), this.mockRound(3, 17, 0, 0, 0, 0, 5, 10, 3, 0, 0)));
|
||||
System.out.println(phi);
|
||||
}
|
||||
|
||||
private FlexMap mockRound(int courseId, int pointAdj, int... scoreToParCounts) {
|
||||
FlexMap map = new FlexMap();
|
||||
map.put("courseID", courseId);
|
||||
map.put("pointAdj", (byte) pointAdj);
|
||||
map.put("bogey5", (byte) scoreToParCounts[0]);
|
||||
map.put("bogey4", (byte) scoreToParCounts[1]);
|
||||
map.put("bogey3", (byte) scoreToParCounts[2]);
|
||||
map.put("bogey2", (byte) scoreToParCounts[3]);
|
||||
map.put("bogey", (byte) scoreToParCounts[4]);
|
||||
map.put("par", (byte) scoreToParCounts[5]);
|
||||
map.put("birdie", (byte) scoreToParCounts[6]);
|
||||
map.put("eagle", (byte) scoreToParCounts[7]);
|
||||
map.put("alby", (byte) scoreToParCounts[8]);
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
@@ -1,90 +0,0 @@
|
||||
package com.poststats.golf.service.model;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class PointHandicapIndexUnitTest {
|
||||
|
||||
@Test
|
||||
public void zero() {
|
||||
PointHandicapIndex phi = new PointHandicapIndex(0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
Assertions.assertEquals(0, phi.getId());
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) -10));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) -3));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) 5));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void alby1() {
|
||||
PointHandicapIndex phi = new PointHandicapIndex(1, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
Assertions.assertEquals(1, phi.getPointsWithScoreToPar((byte) -3));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) -2));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) 5));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void alby2eagle1() {
|
||||
PointHandicapIndex phi = new PointHandicapIndex(2, 1, 0, 0, 0, 0, 0, 0, 0);
|
||||
Assertions.assertEquals(2, phi.getPointsWithScoreToPar((byte) -3));
|
||||
Assertions.assertEquals(1, phi.getPointsWithScoreToPar((byte) -2));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) -1));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) 5));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typicalScratch() {
|
||||
PointHandicapIndex phi = new PointHandicapIndex(25, 14, 9, 2, 0, 0, 0, 0, 0);
|
||||
Assertions.assertEquals(25, phi.getPointsWithScoreToPar((byte) -3));
|
||||
Assertions.assertEquals(14, phi.getPointsWithScoreToPar((byte) -2));
|
||||
Assertions.assertEquals(9, phi.getPointsWithScoreToPar((byte) -1));
|
||||
Assertions.assertEquals(2, phi.getPointsWithScoreToPar((byte) 0));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) 1));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) 5));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typicalBogey() {
|
||||
PointHandicapIndex phi = new PointHandicapIndex(25, 16, 7, 4, 2, 1, 0, 0, 0);
|
||||
Assertions.assertEquals(25, phi.getPointsWithScoreToPar((byte) -3));
|
||||
Assertions.assertEquals(16, phi.getPointsWithScoreToPar((byte) -2));
|
||||
Assertions.assertEquals(7, phi.getPointsWithScoreToPar((byte) -1));
|
||||
Assertions.assertEquals(4, phi.getPointsWithScoreToPar((byte) 0));
|
||||
Assertions.assertEquals(2, phi.getPointsWithScoreToPar((byte) 1));
|
||||
Assertions.assertEquals(1, phi.getPointsWithScoreToPar((byte) 2));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) 4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typicalBad() {
|
||||
PointHandicapIndex phi = new PointHandicapIndex(40, 18, 10, 6, 4, 3, 1, 0, 0);
|
||||
Assertions.assertEquals(40, phi.getPointsWithScoreToPar((byte) -3));
|
||||
Assertions.assertEquals(18, phi.getPointsWithScoreToPar((byte) -2));
|
||||
Assertions.assertEquals(10, phi.getPointsWithScoreToPar((byte) -1));
|
||||
Assertions.assertEquals(6, phi.getPointsWithScoreToPar((byte) 0));
|
||||
Assertions.assertEquals(4, phi.getPointsWithScoreToPar((byte) 1));
|
||||
Assertions.assertEquals(3, phi.getPointsWithScoreToPar((byte) 2));
|
||||
Assertions.assertEquals(1, phi.getPointsWithScoreToPar((byte) 3));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) 4));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) 5));
|
||||
Assertions.assertEquals(0, phi.getPointsWithScoreToPar((byte) 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void plusBogey() {
|
||||
PointHandicapIndex basephi = new PointHandicapIndex(40, 18, 10, 6, 4, 3, 1, 0, 0);
|
||||
PointHandicapIndex phi = basephi.plus((byte) 1, (byte) 1);
|
||||
Assertions.assertEquals(5, phi.getPointsWithScoreToPar((byte) 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void plus2Birdie() {
|
||||
PointHandicapIndex basephi = new PointHandicapIndex(40, 18, 10, 6, 4, 3, 1, 0, 0);
|
||||
PointHandicapIndex phi = basephi.plus((byte) -1, (byte) 2);
|
||||
Assertions.assertEquals(12, phi.getPointsWithScoreToPar((byte) -1));
|
||||
}
|
||||
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
rootLogger.level = debug
|
||||
rootLogger.appenderRef.stdout.ref = api
|
||||
|
||||
appender.rolling.type = RollingFile
|
||||
appender.rolling.name = api
|
||||
appender.rolling.fileName = ${catalina.base}/logs/api.log
|
||||
appender.rolling.filePattern = ${catalina.base}/logs/api-%d{MM-dd-yyyy}.log.gz
|
||||
appender.rolling.layout.type = PatternLayout
|
||||
appender.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n
|
||||
appender.rolling.policies.type = Policies
|
||||
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
|
||||
appender.rolling.strategy.type = DefaultRolloverStrategy
|
||||
appender.rolling.strategy.max = 10
|
||||
|
||||
logger.brianlong.name = com.brianlong
|
||||
logger.brianlong.level = debug
|
||||
|
||||
logger.poststats.name = com.poststats
|
||||
logger.poststats.level = debug
|
24
src/test/resources/log4j2.xml
Normal file
24
src/test/resources/log4j2.xml
Normal 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>
|
Reference in New Issue
Block a user