Commit db4acc8b by Tuomas Riihimäki

Initial graphql api implementation

1 parent 42d57068
Showing with 1093 additions and 16 deletions
......@@ -2,6 +2,7 @@ package fi.codecrew.moya.beans;
import fi.codecrew.moya.model.Allergy;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.User;
import fi.codecrew.moya.model.UsersAllergy;
import javax.ejb.Local;
......@@ -13,6 +14,7 @@ public interface AllergyBeanLocal {
List<Allergy> getAllergies();
List<UsersAllergy> getUserAllergies(User currentUser);
List<UsersAllergy> getUserAllergies(EventUser currentUser);
List<UsersAllergy> saveAllergies(ArrayList<UsersAllergy> allergylist);
......
......@@ -208,4 +208,12 @@ public interface UserBeanLocal {
* @return EventUser with the matching code
*/
EventUser findUserByCodeToken(String code);
/**
* Return eventusers of all events for user
* This function can only be used by users themselves, and superadmins.
* @param user User to fetch eventusers for
* @return Eventusers for all events this user has been associated to.
*/
List<EventUser> findAllEventusers(User user);
}
......@@ -4,6 +4,7 @@ import fi.codecrew.moya.facade.AllergyFacade;
import fi.codecrew.moya.facade.UsersAllergyFacade;
import fi.codecrew.moya.model.Allergy;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.User;
import fi.codecrew.moya.model.UsersAllergy;
import javax.ejb.EJB;
......@@ -27,11 +28,16 @@ public class AllergyBean implements AllergyBeanLocal {
}
@Override
public List<UsersAllergy> getUserAllergies(EventUser user) {
public List<UsersAllergy> getUserAllergies(User user) {
return userAllergyFacade.findForUser(user);
}
@Override
public List<UsersAllergy> getUserAllergies(EventUser user) {
return userAllergyFacade.findForUser(user.getUser());
}
@Override
public List<UsersAllergy> saveAllergies(ArrayList<UsersAllergy> allergylist) {
ArrayList<UsersAllergy> ret = new ArrayList<>();
for (UsersAllergy a : allergylist) {
......
......@@ -1180,6 +1180,17 @@ public class UserBean implements UserBeanLocal {
return eventUser;
}
@Override
@RolesAllowed(SpecialPermission.S_USER)
public List<EventUser> findAllEventusers(User user) {
user = userFacade.reload(user);
if (!permbean.isCurrentUser(user) && !permbean.getCurrentUser().isSuperadmin()) {
throw new EJBAccessException("Only users themselves can fetch all eventusers for all events");
}
return eventUserFacade.findForUser(user);
}
@Override
@RolesAllowed(EventPermission.S_MANAGE_EVENT)
......
......@@ -211,6 +211,14 @@ public class EventUserFacade extends IntegerPkGenericFacade<EventUser> {
return getSingleNullableResult(getEm().createQuery(cq));
}
public List<EventUser> findForUser(User user) {
CriteriaBuilder cb = getEm().getCriteriaBuilder();
CriteriaQuery<EventUser> cq = cb.createQuery(EventUser.class);
Root<EventUser> root = cq.from(EventUser.class);
cq.where(cb.equal(root.get(EventUser_.user), user));
return getEm().createQuery(cq).getResultList();
}
// private Predicate addAcPredicate(CriteriaBuilder cb, UserSearchQuery
// query, Root<AccountEvent> root) {
// Expression<BigDecimal> sum =
......
......@@ -18,10 +18,7 @@
*/
package fi.codecrew.moya.facade;
import fi.codecrew.moya.model.Allergy;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.UsersAllergy;
import fi.codecrew.moya.model.UsersAllergy_;
import fi.codecrew.moya.model.*;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
......@@ -39,12 +36,12 @@ public class UsersAllergyFacade extends IntegerPkGenericFacade<UsersAllergy> {
}
public List<UsersAllergy> findForUser(EventUser user) {
public List<UsersAllergy> findForUser(User user) {
CriteriaBuilder cb = getEm().getCriteriaBuilder();
CriteriaQuery<UsersAllergy> cq = cb.createQuery(UsersAllergy.class);
Root<UsersAllergy> root = cq.from(UsersAllergy.class);
cq.where(cb.equal(root.get(UsersAllergy_.user), user.getUser()));
cq.where(cb.equal(root.get(UsersAllergy_.user), user));
return getEm().createQuery(cq).getResultList();
}
......
......@@ -25,6 +25,9 @@ public class LanguageAwareString {
}
return ret;
}
public String getDefaultValue(){
return getValue(defaultLanguage);
}
public String getDefaultLanguage() {
return defaultLanguage;
......
......@@ -3,34 +3,35 @@ package fi.codecrew.moya.model;
import javax.persistence.*;
import java.util.Date;
@Table(name="user_allergies")
@Table(name = "user_allergies")
@Entity
public class UsersAllergy extends GenericEntity {
@Column(nullable=false, name = "selected")
@Column(nullable = false, name = "selected")
private boolean selected = false;
@Enumerated(EnumType.STRING)
@Column(name="severity")
@Column(name = "severity")
private AllergySeverity severity = AllergySeverity.NORMAL;
@ManyToOne
@JoinColumn(name="user_id", updatable = false, referencedColumnName = "id", nullable = false)
@JoinColumn(name = "user_id", updatable = false, referencedColumnName = "id", nullable = false)
private User user;
@ManyToOne
@JoinColumn(name="allergy_id", updatable = false, referencedColumnName = "id", nullable = false)
@JoinColumn(name = "allergy_id", updatable = false, referencedColumnName = "id", nullable = false)
private Allergy allergy;
@Column(name="created")
@Column(name = "created")
@Temporal(TemporalType.TIMESTAMP)
private Date created;
@Lob
@Column(name="notes")
@Column(name = "notes")
private String notes;
public UsersAllergy() {
super();
}
......@@ -80,4 +81,12 @@ public class UsersAllergy extends GenericEntity {
public void setSelected(boolean selected) {
this.selected = selected;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
}
......@@ -170,6 +170,11 @@
<version>${findbugs.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
<version>9.0</version>
</dependency>
</dependencies>
<reporting>
<plugins>
......
......@@ -20,6 +20,7 @@ package fi.codecrew.moya;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
import java.util.Base64;
......@@ -185,7 +186,7 @@ public class HostnameFilter implements Filter {
if (!restAuth(httpRequest, response) && RestApplicationEntrypoint.REST_PATH.equals(httpRequest.getServletPath())) {
response.reset();
response.getOutputStream().write("Rest auth failed! ".getBytes( Charsets.UTF_8));
response.getOutputStream().write("Rest auth failed! ".getBytes( StandardCharsets.UTF_8));
if (response instanceof HttpServletResponse) {
HttpServletResponse httpResp = (HttpServletResponse) response;
......
package fi.codecrew.moya.graphql;
public class AlreadyBuiltException extends RuntimeException {
public AlreadyBuiltException(String s) {
super(s);
}
}
package fi.codecrew.moya.graphql;
import graphql.schema.*;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.PluralAttribute;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import static graphql.Scalars.*;
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
import static graphql.schema.GraphQLObjectType.newObject;
public class EntityGQLBuilder<T> {
private final GraphQLObjectType.Builder builder;
private final GraphQLBuilder parent;
private final String typeName;
private final List<GraphQLFieldDefinition.Builder> fields = new ArrayList<>();
private GraphQLObjectType builtObject;
public EntityGQLBuilder(String name, GraphQLBuilder bld) {
this.typeName = name;
this.parent = bld;
this.builder = newObject().name(name);
}
public GraphQLFieldDefinition.Builder addField() {
if (builtObject != null) {
throw new AlreadyBuiltException("This method can not be called after 'build()'-function has been called");
}
GraphQLFieldDefinition.Builder ret = newFieldDefinition();
fields.add(ret);
return ret;
}
public GraphQLFieldDefinition.Builder addField(Class<?> clz) {
return addField()
.type(typeForClass(clz))
.name(clz.getSimpleName().toLowerCase());
}
public GraphQLFieldDefinition.Builder addListField(Class<?> clz) {
return addField()
.type(GraphQLList.list(typeForClass(clz)))
.name((clz.getSimpleName() + "s").toLowerCase());
}
/**
* Add a field to graphql schema from JPA metamodel.
* This function will set a name and DataFetcher to the fieldDefinition builder,
* which then can be overriden from the returned builder, if needed
*
* @param field JPA metamodel field to be added to the graphql schema
* @return Field definition builder, where type, name and data fetcher are set according to the {@param field}
*/
public GraphQLFieldDefinition.Builder addField(Attribute<? super T, ?> field) {
GraphQLOutputType type = typeForClass(field.getJavaType());
if (field instanceof PluralAttribute) {
type = GraphQLList.list(typeForClass(((PluralAttribute) field).getBindableJavaType()));
}
return addField()
.type(type)
.name(field.getName().toLowerCase())
.dataFetcher(new PropertyDataFetcher<>(field.getName()));
}
private GraphQLOutputType typeForClass(Class<?> type) {
if (Boolean.class.isAssignableFrom(type) || boolean.class.isAssignableFrom(type)) {
return GraphQLBoolean;
}
if (Double.class.isAssignableFrom(type) || double.class.isAssignableFrom(type)) {
return GraphQLFloat;
}
if (Byte.class.isAssignableFrom(type) || byte.class.isAssignableFrom(type)) {
return GraphQLByte;
}
if (Character.class.isAssignableFrom(type) || char.class.isAssignableFrom(type)) {
return GraphQLChar;
}
if (Short.class.isAssignableFrom(type) || short.class.isAssignableFrom(type)) {
return GraphQLShort;
}
if (Integer.class.isAssignableFrom(type) || int.class.isAssignableFrom(type)) {
return GraphQLInt;
}
if (Long.class.isAssignableFrom(type) || long.class.isAssignableFrom(type)) {
return GraphQLLong;
}
if (BigInteger.class.isAssignableFrom(type)) {
return GraphQLBigInteger;
}
if (BigDecimal.class.isAssignableFrom(type)) {
return GraphQLBigDecimal;
}
if (String.class.isAssignableFrom(type)) {
return GraphQLString;
}
if (byte[].class.isAssignableFrom(type) || Byte[].class.isAssignableFrom(type)) {
return GraphQLUtils.GRAPHQL_BYTE_TO_BASE64_TYPE;
}
if (Enum.class.isAssignableFrom(type)) {
return parent.getEnum((Class<Enum>) type);
}
if (Date.class.isAssignableFrom(type)
|| Calendar.class.isAssignableFrom(type)
|| OffsetDateTime.class.isAssignableFrom(type)
|| LocalDateTime.class.isAssignableFrom(type)
|| LocalDate.class.isAssignableFrom(type)) {
return GraphQLUtils.GRAPHQL_DATE_TYPE;
}
return parent.typeFor(type);
}
public GraphQLObjectType build() {
if (builtObject == null) {
fields.forEach(f -> builder.field(f));
builtObject = builder.build();
}
return builtObject;
}
public GraphQLObjectType.Builder getRawTypeBuilder() {
return builder;
}
public EntityGQLBuilder<T> description(String s) {
builder.description(s);
return this;
}
public GraphQLType getRef() {
return parent.typeFor(typeName);
}
}
package fi.codecrew.moya.graphql;
public class GRPDException extends RuntimeException {
public GRPDException(String reason) {
super(reason);
}
}
package fi.codecrew.moya.graphql;
import graphql.schema.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Collectors;
import static graphql.schema.GraphQLEnumType.newEnum;
public class GraphQLBuilder {
private final Map<String, EntityGQLBuilder<?>> entities = new HashMap<>();
private final Map<String, GraphQLEnumType> enums = new HashMap<>();
private final Set<String> uncheckedTypes = new HashSet<>();
private static final Logger logger = LoggerFactory.getLogger(GraphQLBuilder.class);
public <T> EntityGQLBuilder<T> createEntity(Class<T> entityClass) {
return createEntity(entityClass.getSimpleName());
}
public <T> EntityGQLBuilder<T> createEntity(String name) {
EntityGQLBuilder<T> ret = new EntityGQLBuilder<>(name, this);
entities.put(name, ret);
return ret;
}
public Set<GraphQLType> getTypes() {
Set<GraphQLType> ret = new HashSet<>(enums.values());
List<GraphQLObjectType> retEnt = entities.values().stream().map(v -> v.build()).collect(Collectors.toList());
logger.warn("Returning entities", retEnt);
ret.addAll(retEnt);
logger.warn("Enums {}, entities {}", enums, entities);
logger.warn("Builder returning types: {}", ret);
return ret;
}
public GraphQLTypeReference typeFor(String typeName) {
logger.warn("Adding typeFor: {}", typeName);
if (!entities.containsKey(typeName) && !enums.containsKey(typeName)) {
logger.warn("Adding unknown type: this might be an error!"+ typeName, new RuntimeException().fillInStackTrace());
uncheckedTypes.add(typeName);
}
return GraphQLTypeReference.typeRef(typeName);
}
public GraphQLTypeReference typeFor(Class<?> clz) {
return typeFor(clz.getSimpleName());
}
public <X extends Enum> GraphQLOutputType getEnum(Class<X> type) {
String name = type.getSimpleName();
if (name == null) {
throw new NullPointerException("Trying to get enum with type " + type);
}
if (!enums.containsKey(name)) {
GraphQLEnumType.Builder ret = newEnum().name(name);
for (Enum c : type.getEnumConstants()) {
ret.value(c.name());
}
enums.put(name, ret.build());
}
return typeFor(type);
}
}
package fi.codecrew.moya.graphql;
import graphql.schema.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class GraphQLUtils {
public static final GraphQLScalarType GRAPHQL_BYTE_TO_BASE64_TYPE = new GraphQLScalarType("Base64Data", "Binary data in base64 format", new Coercing<byte[], String>() {
@Override
public String serialize(Object dataFetcherResult) throws CoercingSerializeException {
byte[] data = (byte[]) dataFetcherResult;
if (data == null || data.length == 0) {
return "";
}
return Base64.getEncoder().encodeToString(data);
}
@Override
public byte[] parseValue(Object input) throws CoercingParseValueException {
return Base64.getDecoder().decode(input.toString());
}
@Override
public byte[] parseLiteral(Object input) throws CoercingParseLiteralException {
return Base64.getDecoder().decode(input.toString());
}
});
public static final GraphQLScalarType GRAPHQL_DATE_TYPE = new GraphQLScalarType("Date", "Date in ISO-8601 format: yyyymmddThhmmssZ (for example: 2011-12-03T10:15:30Z')", new Coercing<Object, String>() {
@Override
public String serialize(Object dataFetcherResult) throws CoercingSerializeException {
if (dataFetcherResult == null) {
return null;
}
try {
if (dataFetcherResult instanceof Date) {
return Instant
.ofEpochMilli(((Date) dataFetcherResult).getTime())
.atZone(ZoneId.systemDefault())
.toOffsetDateTime()
.format(DateTimeFormatter.ISO_INSTANT);
} else if (dataFetcherResult instanceof Calendar) {
return Instant
.ofEpochMilli(((Calendar) dataFetcherResult).getTime().getTime())
.atZone(ZoneId.systemDefault())
.toOffsetDateTime()
.format(DateTimeFormatter.ISO_INSTANT);
} else if (dataFetcherResult instanceof OffsetDateTime) {
return ((OffsetDateTime) dataFetcherResult).format(DateTimeFormatter.ISO_INSTANT);
} else if (dataFetcherResult instanceof LocalDateTime) {
return ((LocalDateTime) dataFetcherResult).format(DateTimeFormatter.ISO_INSTANT);
} else if (dataFetcherResult instanceof LocalDate) {
return ((LocalDate) dataFetcherResult).format(DateTimeFormatter.ISO_INSTANT);
}
} catch (Exception e) {
throw new CoercingSerializeException("Error converting detected dateformat: " + dataFetcherResult, e);
}
throw new CoercingSerializeException("Unknonw date type " + dataFetcherResult.getClass());
}
@Override
public Object parseValue(Object input) throws CoercingParseValueException {
throw new UnsupportedOperationException("Not yet implemented... TODO... ");
}
@Override
public Object parseLiteral(Object input) throws CoercingParseLiteralException {
throw new UnsupportedOperationException("Not yet implemented... TODO... ");
}
});
}
package fi.codecrew.moya.graphql;
import com.google.gson.Gson;
import fi.codecrew.moya.beans.*;
import fi.codecrew.moya.entitysearch.UserSearchQuery;
import fi.codecrew.moya.graphql.util.JSONPropertyDataFetcher;
import fi.codecrew.moya.graphql.util.PropertyFetchWrapper;
import fi.codecrew.moya.model.*;
import fi.codecrew.moya.utilities.SearchQuery;
import fi.codecrew.moya.utilities.SearchResult;
import graphql.*;
import graphql.schema.*;
import graphql.schema.idl.SchemaPrinter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ejb.EJB;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static graphql.Scalars.*;
import static graphql.schema.GraphQLArgument.newArgument;
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
@WebServlet(name = "MoyaGraphQLServlet", urlPatterns = {"/graphql/*"})
public class MoyaGraphQLServlet extends HttpServlet {
private static final Logger logger = LoggerFactory.getLogger(MoyaGraphQLServlet.class);
private GraphQLSchema schema;
private static final String SIMPLE_EVENT_TYPE_NAME = "SimpleEvent";
@EJB
private UserBeanLocal userbean;
@EJB
private PlaceBeanLocal placebean;
@EJB
private PermissionBeanLocal permbean;
@EJB
private RoleBeanLocal rolebean;
@EJB
private AllergyBeanLocal allergybean;
@EJB
private EventBeanLocal eventbean;
@EJB
private PlaceBeanLocal mapBean;
@EJB
private ProductBeanLocal productbean;
@EJB
private VotingBeanLocal votebean;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
this.schema = createSchema();
logger.warn("Initinqlizing graphql servlet");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doQuery(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doQuery(request, response);
}
private void doQuery(HttpServletRequest request, HttpServletResponse response) throws IOException {
logger.warn("Graphql pathinfo: {}, uri: {}, url: {}", request.getPathInfo(), request.getRequestURI(), request.getRequestURL());
if (request.getPathInfo() != null) {
if (request.getPathInfo().equals("/schema")) {
SchemaPrinter.Options opts = SchemaPrinter.Options.defaultOptions().includeScalarTypes(true);
if (request.getParameter("introspection") != null) {
opts = opts.includeIntrospectionTypes(true);
}
if (request.getParameter("schema") != null) {
opts = opts.includeSchemaDefintion(true);
}
if (request.getParameter("ext") != null) {
opts = opts.includeExtendedScalarTypes(true);
}
if (request.getParameter("scalar") != null) {
opts = opts.includeScalarTypes(true);
}
printSchema(response, opts);
return;
}
}
String query = request.getParameter("query");
executeQuery(query, response);
}
private void executeQuery(String query, HttpServletResponse response) throws IOException {
GraphQL graphql = GraphQL.newGraphQL(schema).build();
PrintWriter writer = response.getWriter();
try {
Gson gson = new Gson();
ExecutionResult exec = graphql.execute(query);
logger.warn("Executed stuff errors: {}", exec.getErrors());
if (exec.getErrors() != null && !exec.getErrors().isEmpty()) {
writer.write(gson.toJson(new ErrorContainer(exec.getErrors())));
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
} else {
Map<String, Object> data = exec.getData();
writer.write(gson.toJson(data));
}
} catch (Exception e) {
logger.warn("Got exception at graphql ", e);
writer.write("Error completing the query because of exception: " + e.getMessage());
}
writer.close();
}
private static class ErrorContainer {
static class Error {
final String message;
final ErrorType type;
final List<Object> path;
final String exceptionMessage;
final boolean isException;
final String exceptionClass;
public Error(GraphQLError error) {
type = error.getErrorType();
message = error.getMessage();
path = error.getPath();
if (error instanceof ExceptionWhileDataFetching) {
Throwable e = ((ExceptionWhileDataFetching) error).getException();
isException = true;
exceptionMessage = e.getMessage();
exceptionClass = e.getClass().getCanonicalName();
} else {
isException = false;
exceptionMessage = null;
exceptionClass = null;
}
}
}
final List<Error> errors = new ArrayList<>();
public ErrorContainer(List<GraphQLError> e) {
e.forEach(graphQLError -> errors.add(new Error(graphQLError)));
}
}
private void printSchema(HttpServletResponse response, SchemaPrinter.Options options) throws IOException {
GraphQLSchema s = schema;
logger.warn("Returning graphql schema, with options {} ", options);
SchemaPrinter printer = new SchemaPrinter(options);
PrintWriter writer = response.getWriter();
writer.print(printer.print(s));
writer.close();
}
private GraphQLBuilder initSchema() {
GraphQLBuilder builder = new GraphQLBuilder();
{
EntityGQLBuilder<Role> b = builder.createEntity(Role.class);
b.addField(Role_.id);
b.addField(Role_.name);
b.addField(Role_.parents);
b.addField(Role_.children);
}
{
EntityGQLBuilder<EventMap> b = builder.createEntity(EventMap.class);
b.addField(EventMap_.id);
b.addField(EventMap_.name);
b.addField(EventMap_.width);
b.addField(EventMap_.height);
b.addField(EventMap_.places);
b.addField(EventMap_.active);
b.addField(EventMap_.mimeType);
b.addField(EventMap_.mapData);
}
{
EntityGQLBuilder<Place> b = builder.createEntity(Place.class);
b.addField(Place_.id);
b.addField(Place_.name);
b.addField(Place_.mapX);
b.addField(Place_.mapY);
b.addField(Place_.width);
b.addField(Place_.height);
b.addField(Place_.reserveTime);
b.addField(Place_.details);
b.addField(Place_.buyable);
b.addField(Place_.disabled);
b.addField(Place_.map);
b.addField(Place_.providesRole);
b.addField(Place_.product);
b.addField(Place_.currentUser);
}
{
EntityGQLBuilder<EventUser> b = builder.createEntity(EventUser.class);
b.addField(EventUser_.id);
b.addField(EventUser_.user);
b.addField(EventUser_.event).type(builder.typeFor(SIMPLE_EVENT_TYPE_NAME));
b.addField(EventUser_.eventuserCreated);
b.addField(EventUser_.id);
b.addListField(Role.class).dataFetcher(environment -> userbean.findUsersRoles(environment.getSource()));
b.addField(EventUser_.currentPlaces);
}
{
EntityGQLBuilder<User> b = builder.createEntity(User.class);
b.addField(User_.id);
b.addField(User_.firstnames);
b.addField(User_.lastname);
b.addField(User_.birthday);
b.addField(User_.nick);
b.addField(User_.login);
b.addField(User_.email);
b.addField(User_.address);
b.addField(User_.zip);
b.addField(User_.postalTown);
b.addField(User_.town);
b.addField(User_.phone);
b.addField(User_.gender);
b.addField().name("tshirtSize").type(GraphQLString).dataFetcher(new PropertyFetchWrapper("user", new JSONPropertyDataFetcher("meta", "shirtSize")));
b.addField().name("allergiesFreetext").type(GraphQLString).dataFetcher(new JSONPropertyDataFetcher("meta", "allergies"));
b.addListField(UsersAllergy.class)
.name("allergies")
.argument(newArgument()
.description("By default, show only allergies, user has selected")
.type(GraphQLBoolean)
.defaultValue(true)
.name("onlySelected"))
.dataFetcher(environment -> {
List<UsersAllergy> allergies = allergybean.getUserAllergies((User) environment.getSource());
logger.warn("Got allergies for user {}", allergies);
if (environment.getArgument("onlySelected")) {
logger.warn("Filtering allergies");
return allergies.stream().filter(a -> a.isSelected()).collect(Collectors.toList());
}
return allergies;
});
b.addListField(EventUser.class)
.dataFetcher(environment -> userbean.findAllEventusers(environment.getSource()))
.description("Only users themselves can fetch eventusers for other events. If another user tries to fetch this data, an exception will be thrown");
}
{
EntityGQLBuilder<UsersAllergy> b = builder.createEntity(UsersAllergy.class);
b.description("Note that user 'selected' field notes wether user has this allergy, or not!");
b.addField(UsersAllergy_.allergy);
b.addField(UsersAllergy_.severity);
b.addField(UsersAllergy_.user);
b.addField(UsersAllergy_.created);
b.addField(UsersAllergy_.notes);
b.addField(UsersAllergy_.selected);
b.addField().type(GraphQLString)
.name("allergyname")
.dataFetcher(environment -> ((UsersAllergy) environment.getSource()).getAllergy().getName().getDefaultValue())
.description("Shorthand for { allergy {name {defaultvalue}}}");
}
{
EntityGQLBuilder<Allergy> b = builder.createEntity(Allergy.class);
b.addField(Allergy_.allergyType);
b.addField(Allergy_.description);
b.addField(Allergy_.name);
}
{
EntityGQLBuilder<Object> valB = builder.createEntity("LanguageValue");
valB.addField().name("language").type(GraphQLString).dataFetcher(new PropertyDataFetcher<String>("key"));
valB.addField().name("value").type(GraphQLString);
EntityGQLBuilder<LanguageAwareString> b = builder.createEntity(LanguageAwareString.class);
b.addField().name("defaultvalue").type(GraphQLString);
b.addField().name("defaultlanguage").type(GraphQLString);
b.addField().name("values").type(GraphQLList.list(valB.getRef()));
}
{
EntityGQLBuilder<PlaceSlot> b = builder.createEntity(PlaceSlot.class);
b.addField(PlaceSlot_.id);
b.addField(PlaceSlot_.product);
b.addField(PlaceSlot_.place);
b.addField(PlaceSlot_.description);
b.addField(PlaceSlot_.used);
b.addField(PlaceSlot_.created);
}
{
EntityGQLBuilder<Bill> b = builder.createEntity(Bill.class);
b.addField(Bill_.id);
b.addField(Bill_.paidDate);
b.addField(Bill_.sentDate);
b.addField(Bill_.billNumber);
b.addField().name("paid").type(GraphQLBoolean);
b.addField(Bill_.addr1);
b.addField(Bill_.addr2);
b.addField(Bill_.addr3);
b.addField(Bill_.addr4);
b.addField(Bill_.addr5);
b.addField(Bill_.user);
}
{
EntityGQLBuilder<Product> b = builder.createEntity(Product.class);
b.addField(Product_.id);
b.addField(Product_.name);
b.addField(Product_.description);
b.addField(Product_.price);
b.addField(Product_.vat);
b.addField(Product_.provides).description("Role provided to user when this product is bought and paid");
b.addField(Product_.shopRequiredRole).description("Role required to shop this product");
b.addField(Product_.sort);
b.addField(Product_.discounts);
b.addField(Product_.unitName);
b.addField(Product_.productFlags);
}
{
EntityGQLBuilder<Discount> b = builder.createEntity(Discount.class);
b.addField(Discount_.id);
b.addField(Discount_.active);
b.addField(Discount_.amountMax);
b.addField(Discount_.amountMin);
b.addField(Discount_.code);
b.addField(Discount_.details);
b.addField(Discount_.maxNum);
b.addField(Discount_.percentage);
b.addField(Discount_.perUser);
b.addField(Discount_.role);
b.addField(Discount_.shortdesc);
b.addField(Discount_.validFrom);
b.addField(Discount_.validTo);
b.addField(Discount_.products);
b.addField(Discount_.shortdesc);
}
{
EntityGQLBuilder<LanEvent> b = builder.createEntity(SIMPLE_EVENT_TYPE_NAME);
b.addField(LanEvent_.id);
b.addField(LanEvent_.name);
b.addField(LanEvent_.startTime);
b.addField(LanEvent_.endTime);
b.addField(LanEvent_.ticketSalesBegin);
b.addField(LanEvent_.domains).type(GraphQLList.list(GraphQLString)).dataFetcher(environment -> ((LanEvent) environment.getSource()).getDomains().stream().map(d -> d.getDomain()).collect(Collectors.toList()));
}
{
EntityGQLBuilder<Compo> b = builder.createEntity(Compo.class);
b.addField(Compo_.id);
b.addField(Compo_.name);
b.addField(Compo_.hidden);
b.addField(Compo_.startTime);
b.addField(Compo_.endTime);
b.addField(Compo_.voteStart);
b.addField(Compo_.voteEnd);
b.addField(Compo_.submitStart);
b.addField(Compo_.submitEnd);
b.addField(Compo_.description);
b.addField(Compo_.maxParticipantCount);
b.addField(Compo_.holdVoting);
b.addField(Compo_.compoEntries);
}
{
EntityGQLBuilder<CompoEntry> b = builder.createEntity(CompoEntry.class);
b.addField(CompoEntry_.id);
b.addField(CompoEntry_.created);
b.addField(CompoEntry_.creator);
b.addField(CompoEntry_.title);
b.addField(CompoEntry_.author);
b.addField(CompoEntry_.notes);
b.addField(CompoEntry_.screenMessage);
b.addField(CompoEntry_.sort);
b.addField(CompoEntry_.compo);
b.addField(CompoEntry_.currentFile);
}
{
EntityGQLBuilder<CompoEntryFile> b = builder.createEntity(CompoEntryFile.class);
b.addField(CompoEntryFile_.id);
b.addField(CompoEntryFile_.mimeType);
b.addField(CompoEntryFile_.fileName);
b.addField(CompoEntryFile_.description);
b.addField(CompoEntryFile_.uploaded);
b.addField(CompoEntryFile_.fileData);
b.addField(CompoEntryFile_.entry);
b.addField(CompoEntryFile_.hash).description("SHA1 hash of the file data");
}
{
EntityGQLBuilder<LanEventDomain> b = builder.createEntity(LanEventDomain.class);
b.addField(LanEventDomain_.id);
b.addField(LanEventDomain_.domain);
b.addField(LanEventDomain_.event);
b.addField(LanEventDomain_.description);
b.addField(LanEventDomain_.overridePriority);
}
/**
* This event should only be used to return stuff for current event.
* For oher events, use {#getSimpleEventType()}
*
* @return
*/
{
EntityGQLBuilder<LanEvent> b = builder.createEntity(LanEvent.class);
b.addField(LanEvent_.id);
b.addField(LanEvent_.name);
b.addField(LanEvent_.startTime);
b.addField(LanEvent_.endTime);
b.addField(LanEvent_.ticketSalesBegin);
b.addField(LanEvent_.domains);
b.addListField(EventMap.class).dataFetcher(environment -> placebean.getMaps());
b.addListField(Role.class).dataFetcher(environment -> rolebean.listRoles());
b.addListField(Product.class).dataFetcher(environment -> productbean.findProductsForEvent());
b.addListField(Compo.class).dataFetcher(environment -> votebean.getCompoList(true));
b.addField(LanEvent_.id);
}
return builder;
}
private GraphQLSchema createSchema() {
GraphQLBuilder builder = initSchema();
GraphQLSchema.Builder schemaBld = GraphQLSchema.newSchema();
schemaBld.additionalTypes(builder.getTypes());
schemaBld.query(GraphQLObjectType.newObject()
.name("moyaQuery")
.field(getUserSearchField(builder))
.field(getEventSearchQuery(builder))
.field(getSingleUserQuery(builder)));
return schemaBld.build();
}
private GraphQLFieldDefinition getSingleUserQuery(GraphQLBuilder builder) {
return newFieldDefinition()
.name("user")
.argument(newArgument().name("id").type(GraphQLInt).description("Id of the global user object. If id is 0, currently logged in user is used"))
.type(builder.typeFor(User.class))
.dataFetcher(environment -> {
Integer id = environment.getArgument("userId");
EventUser user;
if (id == null || id.equals(0)) {
user = permbean.getCurrentUser();
} else {
user = userbean.findByUserId(id, false);
}
if (user == null) {
throw new NullPointerException("User not found with id " + id);
}
return user.getUser();
}).build();
}
private GraphQLFieldDefinition.Builder getEventSearchQuery(GraphQLBuilder builder) {
return newFieldDefinition()
.name("currentevent")
.type(builder.typeFor(LanEvent.class))
.dataFetcher(environment -> eventbean.getCurrentEvent());
}
private GraphQLFieldDefinition.Builder getUserSearchField(GraphQLBuilder builder) {
return newFieldDefinition()
.type(new GraphQLList(builder.typeFor(EventUser.class)))
.name("usersearch")
.description("Search users. Using this method requires admin acccess to the database")
//.argument(newArgument().name("reason").type(GraphQLString).description("Reason for the data request. Reason and requested fields are stored to audit log."))
.argument(newArgument().name("roles").defaultValue(Collections.emptyList()).description("(Optional) Filter users that belong to a role").type(GraphQLList.list(GraphQLInt)))
.argument(newArgument().name("search").type(GraphQLString).defaultValue("").description("(Optional) Filter users that contain the search parameter in their firstname, lastname, nick or email").type(GraphQLString))
.argument(newArgument().name("page").type(GraphQLInt).defaultValue(0).description("Pagination page ( 0 is the first page)"))
.argument(newArgument().name("pagesize").type(GraphQLInt).defaultValue(0).description("Pagination pagesize (0 disables pagination)"))
.dataFetcher((DataFetcher<List<EventUser>>) environment -> {
/*
String reason = environment.getArgument("reason");
if (reason == null || reason.isEmpty()) {
throw new GRPDException("Query did not provide a reason for the request");
}*/
UserSearchQuery query = new UserSearchQuery(environment.getArgument("page"), environment.getArgument("pagesize"), null, null, SearchQuery.QuerySortOrder.UNSORTED);
String searchArg = environment.getArgument("search");
if (searchArg != null && !searchArg.isEmpty()) {
query.setSearch(searchArg);
}
List<Integer> roleArgument = environment.getArgument("roles");
if (roleArgument != null && !roleArgument.isEmpty()) {
query.setFilterRoles(roleArgument.stream().map(id -> rolebean.find(id)).collect(Collectors.toList()));
}
SearchResult<EventUser> ret = userbean.getThisEventsUsers(query);
return ret.getResults();
});
}
}
package fi.codecrew.moya.graphql.util;
import graphql.execution.ExecutionContext;
import graphql.execution.ExecutionId;
import graphql.execution.ExecutionTypeInfo;
import graphql.language.Field;
import graphql.language.FragmentDefinition;
import graphql.schema.*;
import java.util.List;
import java.util.Map;
public class DataFetchingEnvironmentWrapper<SRCT> implements DataFetchingEnvironment {
private final SRCT source;
private final DataFetchingEnvironment env;
public DataFetchingEnvironmentWrapper(DataFetchingEnvironment environment, SRCT source) {
this.env = environment;
this.source = source;
}
@Override
public SRCT getSource() {
return source;
}
@Override
public Map<String, Object> getArguments() {
return env.getArguments();
}
@Override
public boolean containsArgument(String name) {
return env.containsArgument(name);
}
@Override
public <T> T getArgument(String name) {
return env.getArgument(name);
}
@Override
public <T> T getContext() {
return env.getContext();
}
@Override
public <T> T getRoot() {
return env.getRoot();
}
@Override
public GraphQLFieldDefinition getFieldDefinition() {
return env.getFieldDefinition();
}
@Override
public List<Field> getFields() {
return env.getFields();
}
@Override
public Field getField() {
return env.getField();
}
@Override
public GraphQLOutputType getFieldType() {
return env.getFieldType();
}
@Override
public ExecutionTypeInfo getFieldTypeInfo() {
return env.getFieldTypeInfo();
}
@Override
public GraphQLType getParentType() {
return env.getParentType();
}
@Override
public GraphQLSchema getGraphQLSchema() {
return env.getGraphQLSchema();
}
@Override
public Map<String, FragmentDefinition> getFragmentsByName() {
return env.getFragmentsByName();
}
@Override
public ExecutionId getExecutionId() {
return env.getExecutionId();
}
@Override
public DataFetchingFieldSelectionSet getSelectionSet() {
return env.getSelectionSet();
}
@Override
public ExecutionContext getExecutionContext() {
return env.getExecutionContext();
}
}
package fi.codecrew.moya.graphql.util;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.PropertyDataFetcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.json.JsonObject;
public class JSONPropertyDataFetcher implements DataFetcher<String> {
private static final Logger logger = LoggerFactory.getLogger(JSONPropertyDataFetcher.class);
private final PropertyDataFetcher<JsonObject> fetcher;
private final String[] path;
public JSONPropertyDataFetcher(String field, String... path) {
fetcher = new PropertyDataFetcher<>(field);
this.path = path;
}
@Override
public String get(DataFetchingEnvironment environment) {
JsonObject obj = fetcher.get(environment);
for (int i = 0; i < path.length; ++i) {
if (obj == null || !obj.containsKey(path[i])) {
logger.debug("Json Object null, or key null {}, path {}", obj, path[i] );
return null;
}
if(i + 1 == path.length){
return obj.getString(path[i]);
} else {
obj = obj.getJsonObject(path[i]);
}
}
return null;
}
}
package fi.codecrew.moya.graphql.util;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.PropertyDataFetcher;
public class PropertyFetchWrapper<T, INNER> implements DataFetcher<T> {
private final DataFetcher<INNER> fetcher;
private final DataFetcher<T> innerFetcher;
public PropertyFetchWrapper(String field, DataFetcher<T> innerFetcher) {
this.fetcher = new PropertyDataFetcher<>(field);
this.innerFetcher = innerFetcher;
}
@Override
public T get(DataFetchingEnvironment environment) {
INNER field = fetcher.get(environment);
return innerFetcher.get(new DataFetchingEnvironmentWrapper(environment, field));
}
}
......@@ -22,7 +22,7 @@ public class PojoFactoryV2 implements Serializable {
*/
private static final long serialVersionUID = 1L;
public UserPojo createUserPojo(EventUser eventUser) {
public static UserPojo createUserPojo(EventUser eventUser) {
User user = eventUser.getUser();
UserPojo pojo = new UserPojo();
pojo.eventuserId = eventUser.getId();
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!