diff --git a/src/main/java/be/cytomine/domain/image/AbstractImage.java b/src/main/java/be/cytomine/domain/image/AbstractImage.java index a70dbb06..7dffea8a 100644 --- a/src/main/java/be/cytomine/domain/image/AbstractImage.java +++ b/src/main/java/be/cytomine/domain/image/AbstractImage.java @@ -26,6 +26,8 @@ import javax.persistence.*; import javax.validation.constraints.Min; +import javax.validation.constraints.Pattern; + import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -38,6 +40,7 @@ public class AbstractImage extends CytomineDomain { @ManyToOne(fetch = FetchType.EAGER) private UploadedFile uploadedFile; + @Pattern(regexp = "^[^\\/:*?'<>|\r\n]+$") private String originalFilename; @Min(1) diff --git a/src/main/java/be/cytomine/domain/image/ImageInstance.java b/src/main/java/be/cytomine/domain/image/ImageInstance.java index 6fa99dca..cf7bfb97 100644 --- a/src/main/java/be/cytomine/domain/image/ImageInstance.java +++ b/src/main/java/be/cytomine/domain/image/ImageInstance.java @@ -1,5 +1,19 @@ package be.cytomine.domain.image; +import java.util.Date; +import java.util.Optional; + +import javax.persistence.Column; +import javax.persistence.DiscriminatorColumn; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.EntityManager; +import javax.persistence.FetchType; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; +import javax.validation.constraints.Pattern; + /* * Copyright (c) 2009-2022. Authors: see NOTICE file. * @@ -25,10 +39,6 @@ import lombok.Getter; import lombok.Setter; -import javax.persistence.*; -import java.util.Date; -import java.util.Optional; - @Entity @Getter @Setter @@ -46,6 +56,7 @@ public class ImageInstance extends CytomineDomain { @ManyToOne(fetch = FetchType.LAZY) private SecUser user; //owner + @Pattern(regexp = "^[^\\/:*?'<>|\r\n]+$") private String instanceFilename; private Long countImageAnnotations = 0L; diff --git a/src/main/java/be/cytomine/domain/meta/Tag.java b/src/main/java/be/cytomine/domain/meta/Tag.java index 4983cee0..3d2acc61 100644 --- a/src/main/java/be/cytomine/domain/meta/Tag.java +++ b/src/main/java/be/cytomine/domain/meta/Tag.java @@ -27,6 +27,7 @@ import javax.persistence.*; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; @Entity @Getter @@ -35,6 +36,7 @@ public class Tag extends CytomineDomain { @NotNull @NotBlank + @Pattern(regexp = "^[\\p{L}0-9]+([\\s-][\\p{L}0-9]+)*$") private String name; @ManyToOne(fetch = FetchType.LAZY) diff --git a/src/main/java/be/cytomine/domain/ontology/Ontology.java b/src/main/java/be/cytomine/domain/ontology/Ontology.java index 4ffed414..efaba1cb 100644 --- a/src/main/java/be/cytomine/domain/ontology/Ontology.java +++ b/src/main/java/be/cytomine/domain/ontology/Ontology.java @@ -26,6 +26,8 @@ import javax.persistence.*; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + import java.util.*; import java.util.stream.Collectors; @@ -36,6 +38,7 @@ public class Ontology extends CytomineDomain { @NotNull @NotBlank + @Pattern(regexp = "^[\\p{L}0-9]+([\\s-][\\p{L}0-9]+)*$") @Column(nullable = false, unique = true) protected String name; diff --git a/src/main/java/be/cytomine/domain/ontology/Term.java b/src/main/java/be/cytomine/domain/ontology/Term.java index bfb5e925..c316a27f 100644 --- a/src/main/java/be/cytomine/domain/ontology/Term.java +++ b/src/main/java/be/cytomine/domain/ontology/Term.java @@ -24,6 +24,8 @@ import javax.persistence.*; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + import java.util.HashSet; import java.util.Map; import java.util.Optional; @@ -39,6 +41,7 @@ public class Term extends CytomineDomain { @NotNull @NotBlank + @Pattern(regexp = "^[\\p{L}0-9]+([\\s-][\\p{L}0-9]+)*$") @Column(nullable = false) private String name; diff --git a/src/main/java/be/cytomine/domain/project/Project.java b/src/main/java/be/cytomine/domain/project/Project.java index 02631948..e845a3d1 100644 --- a/src/main/java/be/cytomine/domain/project/Project.java +++ b/src/main/java/be/cytomine/domain/project/Project.java @@ -27,6 +27,8 @@ import org.hibernate.annotations.LazyCollectionOption; import javax.persistence.*; +import javax.validation.constraints.Pattern; + import java.util.Set; @Entity @@ -34,6 +36,7 @@ @Setter public class Project extends CytomineDomain { + @Pattern(regexp = "^[\\p{L}0-9]+([\\s-][\\p{L}0-9]+)*$") private String name; @ManyToOne(fetch = FetchType.EAGER) diff --git a/src/main/java/be/cytomine/domain/security/SecRole.java b/src/main/java/be/cytomine/domain/security/SecRole.java index b3d74327..d0d53f3e 100644 --- a/src/main/java/be/cytomine/domain/security/SecRole.java +++ b/src/main/java/be/cytomine/domain/security/SecRole.java @@ -25,6 +25,8 @@ import javax.persistence.Entity; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + import java.io.Serializable; @Entity @@ -35,6 +37,7 @@ public class SecRole extends CytomineDomain implements Serializable { @NotNull @NotBlank @Column(unique = true) + @Pattern(regexp = "^[a-zA-Z0-9\\s]+$") private String authority; public static JsonObject getDataFromDomain(CytomineDomain domain) { diff --git a/src/main/java/be/cytomine/domain/security/SecUser.java b/src/main/java/be/cytomine/domain/security/SecUser.java index 56052bf0..edb2669a 100644 --- a/src/main/java/be/cytomine/domain/security/SecUser.java +++ b/src/main/java/be/cytomine/domain/security/SecUser.java @@ -28,6 +28,8 @@ import javax.persistence.*; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + import java.util.*; @Entity @@ -48,7 +50,7 @@ public class SecUser extends CytomineDomain { @NotNull @NotBlank @Column(nullable = false) -// @Pattern(regexp = "^[^\\ ].*[^\\ ]\\$") TODO + @Pattern(regexp = "^[a-zA-Z0-9\\s]+$") protected String username; @NotNull diff --git a/src/main/java/be/cytomine/domain/security/User.java b/src/main/java/be/cytomine/domain/security/User.java index 908fb271..91e8c38f 100644 --- a/src/main/java/be/cytomine/domain/security/User.java +++ b/src/main/java/be/cytomine/domain/security/User.java @@ -27,6 +27,7 @@ import javax.validation.constraints.Email; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; @Entity @@ -43,11 +44,13 @@ public class User extends SecUser { @NotNull @NotBlank @Column(nullable = false) + @Pattern(regexp = "^[\\p{L}0-9]+([\\s-][\\p{L}0-9]+)*$") protected String firstname; @NotNull @NotBlank @Column(nullable = false) + @Pattern(regexp = "^[\\p{L}0-9]+([\\s-][\\p{L}0-9]+)*$") protected String lastname; @NotNull diff --git a/src/main/java/be/cytomine/repository/AlgoAnnotationListing.java b/src/main/java/be/cytomine/repository/AlgoAnnotationListing.java index 9d34ff95..1ed11056 100644 --- a/src/main/java/be/cytomine/repository/AlgoAnnotationListing.java +++ b/src/main/java/be/cytomine/repository/AlgoAnnotationListing.java @@ -18,6 +18,7 @@ import javax.persistence.EntityManager; import java.util.LinkedHashMap; +import java.util.Map; import java.util.stream.Collectors; public class AlgoAnnotationListing extends AnnotationListing { @@ -111,7 +112,7 @@ LinkedHashMap getAvailableColumn() { * Generate SQL string for FROM * FROM depends on data to print (if image name is aksed, need to join with imageinstance+abstractimage,...) */ - String getFrom() { + String getFrom(Map parameters) { String from = "FROM algo_annotation a "; String where = "WHERE true\n"; @@ -163,7 +164,7 @@ String getFrom() { return from + "\n" + where; } - String buildExtraRequest() { + String buildExtraRequest(Map parameters) { return ""; } diff --git a/src/main/java/be/cytomine/repository/AnnotationListing.java b/src/main/java/be/cytomine/repository/AnnotationListing.java index 38f4aa58..5ef9373e 100644 --- a/src/main/java/be/cytomine/repository/AnnotationListing.java +++ b/src/main/java/be/cytomine/repository/AnnotationListing.java @@ -111,11 +111,11 @@ public abstract class AnnotationListing { Boolean kmeans = false; Integer kmeansValue = 3; - abstract String getFrom(); + abstract String getFrom(Map parameters); public abstract String getDomainClass(); - abstract String buildExtraRequest(); + abstract String buildExtraRequest(Map parameters); LinkedHashMap extraColmun = new LinkedHashMap<>(); @@ -205,9 +205,9 @@ public CytomineDomain container() { /** * Generate SQL request string */ - public String getAnnotationsRequest() { + public String getAnnotationsRequest(Map parameters) { - buildExtraRequest(); + buildExtraRequest(parameters); Map columns = buildColumnToPrint(); Map sqlColumns = new LinkedHashMap<>(); @@ -221,46 +221,46 @@ public String getAnnotationsRequest() { } } String whereRequest = - getProjectConst() + - getUserConst() + - getUsersConst() + + getProjectConst(parameters) + + getUserConst(parameters) + + getUsersConst(parameters) + - getImageConst() + - getImagesConst() + + getImageConst(parameters) + + getImagesConst(parameters) + - getSliceConst() + - getSlicesConst() + + getSliceConst(parameters) + + getSlicesConst(parameters) + - getTagConst() + - getTagsConst() + + getTagConst(parameters) + + getTagsConst(parameters) + - getTermConst() + - getTermsConst() + + getTermConst(parameters) + + getTermsConst(parameters) + - getTrackConst() + - getTracksConst() + - getBeforeOrAfterSliceConst() + + getTrackConst(parameters) + + getTracksConst(parameters) + + getBeforeOrAfterSliceConst(parameters) + - getUsersForTermConst() + + getUsersForTermConst(parameters) + - getUserForTermAlgoConst() + - getUsersForTermAlgoConst() + + getUserForTermAlgoConst(parameters) + + getUsersForTermAlgoConst(parameters) + - getSuggestedTermConst() + - getSuggestedTermsConst() + + getSuggestedTermConst(parameters) + + getSuggestedTermsConst(parameters) + getNotReviewedOnlyConst() + - getParentsConst() + + getParentsConst(parameters) + getAvoidEmptyCentroidConst() + - getReviewUsersConst() + + getReviewUsersConst(parameters) + - getIntersectConst() + - getIntersectAnnotationConst() + - getMaxDistanceAnnotationConst() + - getExcludedAnnotationConst() + + getIntersectConst(parameters) + + getIntersectAnnotationConst(parameters) + + getMaxDistanceAnnotationConst(parameters) + + getExcludedAnnotationConst(parameters) + - getBeforeThan() + - getAfterThan() + + getBeforeThan(parameters) + + getAfterThan(parameters) + createOrderBy(); if (term!=null || terms!=null || track!=null || tracks!=null) { @@ -293,7 +293,7 @@ else if (this instanceof ReviewedAnnotationListing) { request += "atr.track_id as track, atr.id as annotationTracks "; } - request += "FROM (" + getSelect(sqlColumns) + getFrom() + whereRequest + ") a \n"; + request += "FROM (" + getSelect(sqlColumns) + getFrom(parameters) + whereRequest + ") a \n"; if (term!=null || terms!=null) { if (this instanceof AlgoAnnotationListing) { @@ -335,7 +335,7 @@ else if (!(this instanceof ReviewedAnnotationListing)) { return request; } - return getSelect(sqlColumns) + getFrom() + whereRequest; + return getSelect(sqlColumns) + getFrom(parameters) + whereRequest; } @@ -382,77 +382,101 @@ String joinValues(List list) { return (String)list.stream().map(x -> String.valueOf(x)).collect(Collectors.joining(", ")); } - String getProjectConst() { - return (project!=null ? "AND a.project_id = " + project + "\n" : ""); + String getProjectConst(Map parameters) { + if(project!=null) { + parameters.put("project_id", project); + return "AND a.project_id = :project_id\n"; + } + return ""; } - String getUsersConst() { - return (users!=null ? "AND a.user_id IN ("+joinValues(users)+")\n" : ""); + String getUsersConst(Map parameters) { + if(users!=null) { + parameters.put("users", users); + return "AND a.user_id IN :users\n"; + } + return ""; } - String getReviewUsersConst() { - return (reviewUsers!=null ? "AND a.review_user_id IN ("+joinValues(reviewUsers)+")\n" : ""); + String getReviewUsersConst(Map parameters) { + if(reviewUsers!=null) { + parameters.put("reviewUsers", reviewUsers); + return "AND a.review_user_id IN :reviewUsers\n"; + } + return ""; } - String getUsersForTermConst() { + String getUsersForTermConst(Map parameters) { if (usersForTerm!=null) { addIfMissingColumn("term"); - return "AND at.user_id IN ("+joinValues(usersForTerm)+")\n"; + parameters.put("usersForTerm", usersForTerm); + return "AND at.user_id IN :usersForTerm\n"; } else { return ""; } } - String getImagesConst() { + String getImagesConst(Map parameters) { if (images!=null && project!=null && images.size() == entityManager.find(Project.class, project).getCountImages()) { return ""; //images number equals to project image number, no const needed } else if (images!=null && images.isEmpty()) { throw new ObjectNotFoundException("The image has been deleted!"); } else { - return (images!=null ? "AND a.image_id IN ("+joinValues(images)+")\n" : ""); + if(images!=null) { + parameters.put("images", images); + return "AND a.image_id IN :images\n"; + } + return ""; } } - String getImageConst() { + String getImageConst(Map parameters) { if (image!=null) { ImageInstance imageInstance = entityManager.find(ImageInstance.class, image); if (imageInstance==null) { throw new ObjectNotFoundException("Image " + image + " not exist!"); } - return "AND a.image_id = " + imageInstance.getId() + "\n"; + parameters.put("image_id", imageInstance.getId()); + return "AND a.image_id = :image_id \n"; } else { return ""; } } - String getSlicesConst() { + String getSlicesConst(Map parameters) { if (slices!=null && slices.isEmpty()) { throw new ObjectNotFoundException("The slice has been deleted!"); } else { - return (slices!=null ? "AND a.slice_id IN ("+joinValues(slices)+")\n" : ""); + if(slices!=null) { + parameters.put("slices", slices); + return "AND a.slice_id IN :slices\n"; + } + return ""; } } - String getSliceConst() { + String getSliceConst(Map parameters) { if (slice!=null) { if (entityManager.find(SliceInstance.class, slice)==null) { throw new ObjectNotFoundException("Slice "+slice+" not exist!"); } - return "AND a.slice_id = " + slice + "\n"; + parameters.put("slice_id", slice); + return "AND a.slice_id = :slice_id\n"; } else { return ""; } } - String getUserConst() { + String getUserConst(Map parameters) { if (user!=null) { if (entityManager.find(SecUser.class, user)==null) { throw new ObjectNotFoundException("User "+user+" not exist!"); } - return "AND a.user_id = "+user+"\n"; + parameters.put("user_id", user); + return "AND a.user_id = :user_id \n"; } else { return ""; } @@ -460,25 +484,38 @@ String getUserConst() { abstract String getNotReviewedOnlyConst(); - String getIntersectConst() { - return (bbox!=null ? "AND ST_Intersects(a.location,ST_GeometryFromText('"+bbox.toString()+"',0))\n" : ""); + String getIntersectConst(Map parameters) { + if (bbox!=null) { + parameters.put("bbox", bbox.toString()); + return "AND ST_Intersects(a.location,ST_GeometryFromText(:bbox,0))\n"; + } else { + return ""; + } } - String getIntersectAnnotationConst() { - return (bboxAnnotation!=null ? "AND ST_Intersects(a.location,ST_GeometryFromText('" + bboxAnnotation.toString() + "',0))\n" : ""); + String getIntersectAnnotationConst(Map parameters) { + if (bboxAnnotation!=null) { + parameters.put("bboxAnnotation", bboxAnnotation.toString()); + return "AND ST_Intersects(a.location,ST_GeometryFromText(:bboxAnnotation,0))\n"; + } else { + return ""; + } } - String getMaxDistanceAnnotationConst() { + String getMaxDistanceAnnotationConst(Map parameters) { if(maxDistanceBaseAnnotation!=null) { if(baseAnnotation==null) { throw new ObjectNotFoundException("You need to provide a 'baseAnnotation' parameter (annotation id/location = "+baseAnnotation+")!"); } else { + parameters.put("maxDistanceBaseAnnotation", maxDistanceBaseAnnotation); try { AnnotationDomain base = AnnotationDomain.getAnnotationDomain(entityManager, ((Long)baseAnnotation), null); //ST_distance(a.location,ST_GeometryFromText('POINT (0 0)')) - return "AND ST_distance(a.location,ST_GeometryFromText('"+base.getWktLocation() + "')) <= "+maxDistanceBaseAnnotation+"\n"; + parameters.put("getWktLocation", base.getWktLocation()); + return "AND ST_distance(a.location,ST_GeometryFromText(:getWktLocation)) <= :maxDistanceBaseAnnotation\n"; } catch (Exception e) { - return "AND ST_distance(a.location,ST_GeometryFromText('"+baseAnnotation+ "')) <= " + maxDistanceBaseAnnotation + "\n"; + parameters.put("baseAnnotation", baseAnnotation); + return "AND ST_distance(a.location,ST_GeometryFromText(:baseAnnotation)) <= :maxDistanceBaseAnnotation\n"; } } } else { @@ -490,85 +527,95 @@ String getAvoidEmptyCentroidConst() { return (avoidEmptyCentroid ? "AND ST_IsEmpty(st_centroid(a.location))=false\n" : ""); } - String getTermConst() { + String getTermConst(Map parameters) { if (term!=null) { if (entityManager.find(Term.class, term)==null) { throw new ObjectNotFoundException("Term " + term + "not exist!"); } addIfMissingColumn("term"); + parameters.put("term_id", term); if (this instanceof ReviewedAnnotationListing) - return " AND (at.term_id = "+term + ((noTerm) ? " OR at.term_id IS NULL" : "") + ")\n"; + return " AND (at.term_id = :term_id" + ((noTerm) ? " OR at.term_id IS NULL" : "") + ")\n"; else - return " AND ((at.term_id = "+term+ ")" + ((noTerm) ? " OR at.term_id IS NULL" : "") + ")\n"; + return " AND ((at.term_id = :term_id)" + ((noTerm) ? " OR at.term_id IS NULL" : "") + ")\n"; } else { return ""; } } - String getParentsConst() { + String getParentsConst(Map parameters) { if (parents!=null) { - return " AND a.parent_ident IN ("+joinValues(parents)+")\n"; + parameters.put("parents", parents); + return " AND a.parent_ident IN parents\n"; } else { return ""; } } - String getTermsConst() { + String getTermsConst(Map parameters) { if (terms!=null) { addIfMissingColumn("term"); - if (this instanceof ReviewedAnnotationListing) - return " AND (at.term_id IN ("+joinValues(terms) + ")" + ((noTerm) ? " OR at.term_id IS NULL" : "") + ")\n"; - else - return " AND ((at.term_id IN ("+joinValues(terms) + "))" + ((noTerm) ? " OR at.term_id IS NULL" : "") + ")\n"; + parameters.put("terms", terms); + if (this instanceof ReviewedAnnotationListing) { + return " AND (at.term_id IN (:terms)" + ((noTerm) ? " OR at.term_id IS NULL" : "") + ")\n"; + } else { + return " AND ((at.term_id IN (:terms))" + ((noTerm) ? " OR at.term_id IS NULL" : "") + ")\n"; + } } else { return ""; } } - String getTrackConst() { + String getTrackConst(Map parameters) { if (track!=null) { if (entityManager.find(Track.class, track)!=null) { throw new ObjectNotFoundException("Track " + track + " not exists !"); } addIfMissingColumn("track"); - return " AND (atr.track_id = "+track + ((noTrack) ? " OR atr.track_id IS NULL" : "") + ")\n"; + parameters.put("track_id", track); + return " AND (atr.track_id = :track_id" + ((noTrack) ? " OR atr.track_id IS NULL" : "") + ")\n"; } else { return ""; } } - String getTracksConst() { + String getTracksConst(Map parameters) { if (tracks!=null) { addIfMissingColumn("track"); - return "AND (atr.track_id IN ("+joinValues(tracks) +") " + ((noTrack) ? " OR atr.track_id IS NULL" : "") + ")\n"; + parameters.put("tracks", tracks); + return "AND (atr.track_id IN :tracks " + ((noTrack) ? " OR atr.track_id IS NULL" : "") + ")\n"; } else { return ""; } } - String getTagConst() { + String getTagConst(Map parameters) { if (tag!=null && noTag) { - return "AND (tda.tag_id = "+tag + " OR tda.tag_id IS NULL)\n"; + parameters.put("tag_id", tag); + return "AND (tda.tag_id = :tag_id OR tda.tag_id IS NULL)\n"; } else if (tag!=null) { - return "AND tda.tag_id = "+tag +"\n"; + parameters.put("tag_id", tag); + return "AND tda.tag_id = :tag_id\n"; } else { return ""; } } - String getTagsConst() { + String getTagsConst(Map parameters) { if (tags!=null && noTag) { - return "AND (tda.tag_id IN ("+joinValues(tags) + ") OR tda.tag_id IS NULL)\n"; + parameters.put("tags", tags); + return "AND (tda.tag_id IN :tags OR tda.tag_id IS NULL)\n"; } else if (tags!=null ) { - return "AND tda.tag_id IN (" + joinValues(tags) + ")\n"; + parameters.put("tags", tags); + return "AND tda.tag_id IN :tags)\n"; } else { return ""; } } - String getBeforeOrAfterSliceConst() { + String getBeforeOrAfterSliceConst(Map parameters) { if ((track!=null || tracks!=null) && (beforeSlice!=null || afterSlice!=null)) { addIfMissingColumn("slice"); Long sliceId = (beforeSlice!=null) ? beforeSlice : afterSlice; @@ -577,52 +624,62 @@ String getBeforeOrAfterSliceConst() { throw new ObjectNotFoundException("Slice "+ sliceId +" not exists !"); } String sign = (beforeSlice!=null) ? "<" : ">"; - return "AND (asl.channel + ai.channels * (asl.z_stack + ai.depth * asl.time)) "+sign+" " + sliceInstance.getBaseSlice().getRank() +"\n"; + parameters.put("slideInstanceRank", sliceInstance.getBaseSlice().getRank()); + return "AND (asl.channel + ai.channels * (asl.z_stack + ai.depth * asl.time)) "+sign+" :slideInstanceRank\n"; } else { return ""; } } - String getExcludedAnnotationConst() { - return (excludedAnnotation!=null ? "AND a.id <> " + excludedAnnotation + "\n" : ""); + String getExcludedAnnotationConst(Map parameters) { + if(excludedAnnotation!=null) { + parameters.put("excludedAnnotation", excludedAnnotation); + return "AND a.id <> :excludedAnnotation\n"; + } else { + return ""; + } } - String getSuggestedTermConst() { + String getSuggestedTermConst(Map parameters) { if (suggestedTerm!=null) { if (entityManager.find(Term.class, suggestedTerm)!=null) { throw new ObjectNotFoundException("Term "+suggestedTerm+" not exist!"); } addIfMissingColumn("algo"); - return "AND aat.term_id = "+suggestedTerm+" AND aat.deleted IS NULL \n"; + parameters.put("suggestedTerm", suggestedTerm); + return "AND aat.term_id = :suggestedTerm AND aat.deleted IS NULL \n"; } else { return ""; } } - String getSuggestedTermsConst() { + String getSuggestedTermsConst(Map parameters) { if (suggestedTerms!=null) { addIfMissingColumn("algo"); - return "AND aat.term_id IN ("+joinValues(suggestedTerms)+")\n"; + parameters.put("suggestedTerms", suggestedTerms); + return "AND aat.term_id IN :suggestedTerms\n"; } else { return ""; } } - String getUserForTermAlgoConst() { + String getUserForTermAlgoConst(Map parameters) { if (userForTermAlgo!=null) { addIfMissingColumn("term"); addIfMissingColumn("algo"); - return "AND aat.user_job_id = " + userForTermAlgo + "\n"; + parameters.put("userForTermAlgo", userForTermAlgo); + return "AND aat.user_job_id = :userForTermAlgo\n"; } else { return ""; } } - String getUsersForTermAlgoConst() { + String getUsersForTermAlgoConst(Map parameters) { if (usersForTermAlgo!=null) { addIfMissingColumn("algo"); addIfMissingColumn("term"); - return "AND aat.user_job_id IN ("+joinValues(usersForTermAlgo)+")\n"; + parameters.put("usersForTermAlgo", usersForTermAlgo); + return "AND aat.user_job_id IN :usersForTermAlgo\n"; } else { return ""; } @@ -630,16 +687,18 @@ String getUsersForTermAlgoConst() { abstract String createOrderBy(); - String getBeforeThan() { + String getBeforeThan(Map parameters) { if (beforeThan!=null) { - return "AND a.created < '"+beforeThan+"'\n"; + parameters.put("beforeThan", beforeThan); + return "AND a.created < :beforeThan\n"; } else { return ""; } } - String getAfterThan() { + String getAfterThan(Map parameters) { if (afterThan!=null) { - return "AND a.created > '"+afterThan+"'\n"; + parameters.put("afterThan", afterThan); + return "AND a.created > :afterThan\n"; } else { return ""; } diff --git a/src/main/java/be/cytomine/repository/ReviewedAnnotationListing.java b/src/main/java/be/cytomine/repository/ReviewedAnnotationListing.java index f2f5e23d..8c72439b 100644 --- a/src/main/java/be/cytomine/repository/ReviewedAnnotationListing.java +++ b/src/main/java/be/cytomine/repository/ReviewedAnnotationListing.java @@ -115,7 +115,7 @@ LinkedHashMap getAvailableColumn() { * Generate SQL string for FROM * FROM depends on data to print (if image name is aksed, need to join with imageinstance+abstractimage,...) */ - String getFrom() { + String getFrom(Map parameters) { String from = "FROM reviewed_annotation a "; String where = "WHERE true\n"; @@ -155,11 +155,12 @@ String getFrom() { } @Override - String getUsersForTermConst() { + String getUsersForTermConst(Map parameters) { return ""; } - String buildExtraRequest() { + String buildExtraRequest(Map parameters) { + // TODO: Protect query if (kmeansValue == 3 && image != null && bbox != null) { /** diff --git a/src/main/java/be/cytomine/repository/RoiAnnotationListing.java b/src/main/java/be/cytomine/repository/RoiAnnotationListing.java index 4404c8b2..31da78f4 100644 --- a/src/main/java/be/cytomine/repository/RoiAnnotationListing.java +++ b/src/main/java/be/cytomine/repository/RoiAnnotationListing.java @@ -18,6 +18,7 @@ import javax.persistence.EntityManager; import java.util.LinkedHashMap; +import java.util.Map; import java.util.stream.Collectors; public class RoiAnnotationListing extends AnnotationListing { @@ -92,7 +93,7 @@ LinkedHashMap getAvailableColumn() { * Generate SQL string for FROM * FROM depends on data to print (if image name is aksed, need to join with imageinstance+abstractimage,...) */ - String getFrom() { + String getFrom(Map parameters) { String from = "FROM roi_annotation a "; String where = "WHERE true\n"; @@ -110,7 +111,8 @@ String getFrom() { } if (tags != null) { - from += " LEFT OUTER JOIN tag_domain_association tda ON a.id = tda.domain_ident AND tda.domain_class_name = '" + getDomainClass() + "' "; + parameters.put("domainClassRoi", getDomainClass()); + from += " LEFT OUTER JOIN tag_domain_association tda ON a.id = tda.domain_ident AND tda.domain_class_name = :domainClassRoi "; } return from + "\n" + where; @@ -127,7 +129,7 @@ String createOrderBy() { } } - String buildExtraRequest() { + String buildExtraRequest(Map parameters) { columnsToPrint.remove("term"); return ""; } diff --git a/src/main/java/be/cytomine/repository/UserAnnotationListing.java b/src/main/java/be/cytomine/repository/UserAnnotationListing.java index 2eae2ae4..88f91ed8 100644 --- a/src/main/java/be/cytomine/repository/UserAnnotationListing.java +++ b/src/main/java/be/cytomine/repository/UserAnnotationListing.java @@ -18,6 +18,7 @@ import javax.persistence.EntityManager; import java.util.LinkedHashMap; +import java.util.Map; import java.util.stream.Collectors; public class UserAnnotationListing extends AnnotationListing { @@ -116,7 +117,7 @@ LinkedHashMap getAvailableColumn() { * Generate SQL string for FROM * FROM depends on data to print (if image name is aksed, need to join with imageinstance+abstractimage,...) */ - String getFrom() { + String getFrom(Map parameters) { String from = "FROM user_annotation a "; String where = "WHERE true\n"; @@ -182,7 +183,7 @@ String getFrom() { return from + "\n" + where; } - String buildExtraRequest() { + String buildExtraRequest(Map parameters) { return ""; } diff --git a/src/main/java/be/cytomine/service/AnnotationListingService.java b/src/main/java/be/cytomine/service/AnnotationListingService.java index 367a4780..d219fce2 100644 --- a/src/main/java/be/cytomine/service/AnnotationListingService.java +++ b/src/main/java/be/cytomine/service/AnnotationListingService.java @@ -26,6 +26,8 @@ import be.cytomine.service.utils.KmeansGeometryService; import be.cytomine.utils.GisUtils; import be.cytomine.utils.JsonObject; +import liquibase.pro.packaged.f; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -74,12 +76,13 @@ public List listGeneric(AnnotationListing al) { } public List executeRequest(AnnotationListing al) { + Map parameters = new LinkedHashMap<>(); if(al.getKmeansValue()==KmeansGeometryService.FULL) { return selectGenericAnnotation(al); } else if(al.getKmeansValue()==KmeansGeometryService.KMEANSFULL) { - return kmeansGeometryService.doKeamsFullRequest(al.getAnnotationsRequest()); + return kmeansGeometryService.doKeamsFullRequest(al.getAnnotationsRequest(parameters), parameters); } else { - return kmeansGeometryService.doKeamsSoftRequest(al.getAnnotationsRequest()); + return kmeansGeometryService.doKeamsSoftRequest(al.getAnnotationsRequest(parameters), parameters); } } @@ -96,7 +99,8 @@ private List selectGenericAnnotation(AnnotationListing al) { boolean first = true; List realColumn = new ArrayList<>(); - String request = al.getAnnotationsRequest(); + Map parameters = new LinkedHashMap<>(); + String request = al.getAnnotationsRequest(parameters); boolean termAsked = false; boolean trackAsked = false; @@ -105,6 +109,9 @@ private List selectGenericAnnotation(AnnotationListing al) { Query nativeQuery = entityManager.createNativeQuery(request, Tuple.class); + for (Map.Entry entry : parameters.entrySet()) { + nativeQuery.setParameter(entry.getKey(), entry.getValue()); + } List resultList = nativeQuery.getResultList(); for (Tuple rowResult : resultList) { diff --git a/src/main/java/be/cytomine/service/image/ImageInstanceService.java b/src/main/java/be/cytomine/service/image/ImageInstanceService.java index 0cae5429..1104cdee 100644 --- a/src/main/java/be/cytomine/service/image/ImageInstanceService.java +++ b/src/main/java/be/cytomine/service/image/ImageInstanceService.java @@ -341,6 +341,7 @@ public Page> list(SecUser user, List s String select, from, where, search, sort; String request; + // TODO: Check query security select = "SELECT distinct " + imageInstanceAlias + ".* "; from = "FROM user_image "+ imageInstanceAlias + " "; where = "WHERE user_image_id = " + user.getId() + " "; @@ -439,7 +440,7 @@ public Page> list(SecUser user, List s object.put("projectName", result.get("projectName")); results.add(result); } - + // TODO: Check query security request = "SELECT COUNT(DISTINCT " + imageInstanceAlias + ".id) " + from + where + search; query = session.createNativeQuery(request); for (Map.Entry entry : mapParams.entrySet()) { diff --git a/src/main/java/be/cytomine/service/image/UploadedFileService.java b/src/main/java/be/cytomine/service/image/UploadedFileService.java index ee6779d6..8c8492f0 100644 --- a/src/main/java/be/cytomine/service/image/UploadedFileService.java +++ b/src/main/java/be/cytomine/service/image/UploadedFileService.java @@ -38,6 +38,7 @@ import be.cytomine.utils.filters.SearchOperation; import be.cytomine.utils.filters.SearchParameterEntry; import be.cytomine.utils.filters.SearchParameterProcessed; +import liquibase.pro.packaged.q; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -437,15 +438,19 @@ private void deleteDependentUploadedFile(CytomineDomain domain, Transaction tran } String currentTree = uploadedFile.getLTree()!=null ? uploadedFile.getLTree() : ""; - String request = "UPDATE uploaded_file SET l_tree = '' WHERE id= "+uploadedFile.getId()+";\n"; + String request = "UPDATE uploaded_file SET l_tree = '' WHERE id= :id;\n"; String parentTree = (uploadedFile.getParent()!=null && uploadedFile.getParent().getLTree()!=null)? uploadedFile.getParent().getLTree() : ""; if (!parentTree.isEmpty()) { request += "UPDATE uploaded_file " + - "SET l_tree = '" +parentTree +"' || subpath(l_tree, nlevel('" +currentTree +"')) " + - "WHERE l_tree <@ '" +currentTree +"';"; + "SET l_tree = :parentTree || subpath(l_tree, nlevel(:currentTree)) " + + "WHERE l_tree <@ :currentTree;"; + } + Query query = getEntityManager().createNativeQuery(request); + query.setParameter("id", uploadedFile.getId()); + if (!parentTree.isEmpty()) { + query.setParameter("parentTree", parentTree); + query.setParameter("currentTree", currentTree); } - getEntityManager().createNativeQuery(request); - } diff --git a/src/main/java/be/cytomine/service/meta/PropertyService.java b/src/main/java/be/cytomine/service/meta/PropertyService.java index 01dde441..5d4b3d5b 100644 --- a/src/main/java/be/cytomine/service/meta/PropertyService.java +++ b/src/main/java/be/cytomine/service/meta/PropertyService.java @@ -31,6 +31,8 @@ import be.cytomine.utils.JsonObject; import be.cytomine.utils.ResourcesUtils; import be.cytomine.utils.Task; +import liquibase.pro.packaged.p; + import com.vividsolutions.jts.geom.Geometry; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -40,6 +42,7 @@ import javax.persistence.Tuple; import javax.transaction.Transactional; import java.util.*; +import java.util.HashMap; import java.util.stream.Collectors; import static be.cytomine.utils.SQLUtils.castToLong; @@ -174,29 +177,34 @@ public List> listKeysForAnnotation(Project project, ImageIns } else { securityACLService.check(image.container(),READ); } - String request = "SELECT DISTINCT p.key " + (withUser? ", ua.user_id " : "") + "FROM property as p, user_annotation as ua " + "WHERE p.domain_ident = ua.id " + - (project!=null? "AND ua.project_id = '"+ project.getId() + "' " : "") + - (image!=null? "AND ua.image_id = '"+ image.getId() + "' " : "") + + (project!=null? "AND ua.project_id = :project_id " : "") + + (image!=null? "AND ua.image_id = :image_id " : "") + "UNION " + "SELECT DISTINCT p1.key " + (withUser? ", aa.user_id " : "") + "FROM property as p1, algo_annotation as aa " + "WHERE p1.domain_ident = aa.id " + - (project!=null? "AND aa.project_id = '"+ project.getId() + "' " : "") + - (image!=null? "AND aa.image_id = '"+ image.getId() + "' " : "") + + (project!=null? "AND aa.project_id = :project_id " : "") + + (image!=null? "AND aa.image_id = :image_id " : "") + "UNION " + "SELECT DISTINCT p2.key " + (withUser? ", ra.user_id " : "") + "FROM property as p2, reviewed_annotation as ra " + "WHERE p2.domain_ident = ra.id " + - (project!=null? "AND ra.project_id = '"+ project.getId() + "' " : "") + - (image!=null? "AND ra.image_id = '"+ image.getId() + "' " : ""); - - return selectListKeyWithUser(request, Map.of()); + (project!=null? "AND ra.project_id = :project_id " : "") + + (image!=null? "AND ra.image_id = :image_id " : ""); + Map parameters = new HashMap<>(); + if(image!=null) { + parameters.put("image_id", image.getId()); + } + if(project!=null) { + parameters.put("project_id", project.getId()); + } + return selectListKeyWithUser(request, parameters); } public List listKeysForImageInstance(Project project) { @@ -218,19 +226,25 @@ public List> listAnnotationCenterPosition(SecUser user, Imag "FROM user_annotation ua, property as p " + "WHERE p.domain_ident = ua.id " + "AND p.key = :key " + - "AND ua.image_id = '"+ image.getId() +"' " + - "AND ua.user_id = '"+ user.getId() +"' " + - (boundingbox!=null ? "AND ST_Intersects(ua.location,ST_GeometryFromText('" + boundingbox.toString() + "',0)) " :"") + + "AND ua.image_id = :image_id " + + "AND ua.user_id = :user_id " + + (boundingbox!=null ? "AND ST_Intersects(ua.location,ST_GeometryFromText(:bounding_box,0)) " :"") + "UNION " + "SELECT DISTINCT aa.id, ST_X(ST_CENTROID(aa.location)) as x,ST_Y(ST_CENTROID(aa.location)) as y, p.value " + "FROM algo_annotation aa, property as p " + "WHERE p.domain_ident = aa.id " + "AND p.key = :key " + - "AND aa.image_id = '"+ image.getId() +"' " + - "AND aa.user_id = '"+ user.getId() +"' " + - (boundingbox!=null ? "AND ST_Intersects(aa.location,ST_GeometryFromText('" + boundingbox.toString() + "',0)) " :""); - - return selectsql(request, Map.of("key", (Object)key)); + "AND aa.image_id = :image_id " + + "AND aa.user_id = :user_id " + + (boundingbox!=null ? "AND ST_Intersects(aa.location,ST_GeometryFromText(:bounding_box,0)) " :""); + Map parameters = new HashMap<>(); + parameters.put("key", key); + if(boundingbox!=null) { + parameters.put("bounding_box", boundingbox.toString()); + } + parameters.put("user_id", user.getId()); + parameters.put("image_id", image.getId()); + return selectsql(request, parameters); } private List selectListkey(String request, Map parameters) { diff --git a/src/main/java/be/cytomine/service/ontology/ReviewedAnnotationService.java b/src/main/java/be/cytomine/service/ontology/ReviewedAnnotationService.java index acb305a3..b276c96d 100644 --- a/src/main/java/be/cytomine/service/ontology/ReviewedAnnotationService.java +++ b/src/main/java/be/cytomine/service/ontology/ReviewedAnnotationService.java @@ -188,100 +188,6 @@ public List listIncluded(ImageInstance image, String geometry, List terms, } - // TODO: seems useless, no migration? -// /** -// * List validate annotation -// * @param image Image filter -// * @param bbox Boundary area filter -// * @return Reviewed Annotation list -// */ -// def list(ImageInstance image, String bbox, def propertiesToShow = null) { -// Geometry boundingbox = GeometryUtils.createBoundingBox(bbox) -// list(image, boundingbox,propertiesToShow) -// } -// -// /** -// * List validate annotation -// * @param image Image filter -// * @param bbox Boundary area filter -// * @return Reviewed Annotation list -// */ -// def list(ImageInstance image, Geometry bbox, def propertiesToShow = null) { -// securityACLService.check(image.container(),READ) -// -// -// def rule = kmeansGeometryService.mustBeReduce(image,null,bbox) -// if(rule==kmeansGeometryService.FULL) { -// /** -// * We will sort annotation so that big annotation that covers a lot of annotation comes first (appear behind little annotation so we can select annotation behind other) -// * We compute in 'gc' the set of all other annotation that must be list -// * For each review annotation, we compute the number of other annotation that cover it (ST_CoveredBy => t or f => 0 or 1) -// * -// * ST_CoveredBy will return false if the annotation is not perfectly "under" the compare annotation (if some points are outside) -// * So in gc, we increase the size of each compare annotation just for the check -// * So if an annotation x is under y but x has some point next outside y, x will appear top (if no resize, it will appear top or behind). -// */ -// def xfactor = "1.28" -// def yfactor = "1.28" -// //TODO:: get zoom info from UI client, display with scaling only with hight zoom (< annotations) -// -// double imageWidth = image.baseImage.width -// double bboxWidth = bbox.getEnvelopeInternal().width -// double ratio = bboxWidth/imageWidth*100 -// -// boolean zoomToLow = ratio > 50 -// -// log.info "imageWidth=$imageWidth" -// log.info "bboxWidth=$bboxWidth" -// log.info "ratio=$ratio" -// log.info "zoomToLow="+zoomToLow -// String subRequest -// if (zoomToLow) { -// subRequest = "(SELECT SUM(ST_CoveredBy(ga.location,gb.location )::integer) " -// } else { -// //too heavy to use with little zoom -// subRequest = "(SELECT SUM(ST_CoveredBy(ga.location,ST_Translate(ST_Scale(gb.location, $xfactor, $yfactor), ST_X(ST_Centroid(gb.location))*(1 - $xfactor), ST_Y(ST_Centroid(gb.location))*(1 - $yfactor) ))::integer) " -// -// } -// -// subRequest = subRequest + -// "FROM reviewed_annotation ga, reviewed_annotation gb " + -// "WHERE ga.id=a.id " + -// "AND ga.id<>gb.id " + -// "AND ga.image_id=gb.image_id " + -// "AND ST_Intersects(gb.location,ST_GeometryFromText('" + bbox.toString() + "',0)))\n" -// -// ReviewedAnnotationListing al = new ReviewedAnnotationListing( -// columnToPrint: propertiesToShow, -// image: image.id, -// bbox : bbox, -// orderBy: ['id':'asc'] -// //orderBy: ['numberOfCoveringAnnotation':'asc','id':'asc'] -// ) -// -// //DISABLE COVER BY FOR PERF -// //al.addExtraColumn("numberOfCoveringAnnotation",subRequest) -// annotationListingService.executeRequest(al) -// -// } else { -// -// ReviewedAnnotationListing al = new ReviewedAnnotationListing( -// columnToPrint: propertiesToShow, -// kmeans: true, -// image: image.id, -// avoidEmptyCentroid : true, -// bbox : bbox -// ) -// if(rule==kmeansGeometryService.KMEANSFULL){ -// -// kmeansGeometryService.doKeamsFullRequest(al.getAnnotationsRequest()) -// } else { -// kmeansGeometryService.doKeamsSoftRequest(al.getAnnotationsRequest()) -// } -// } -// } - - public List listTerms(ReviewedAnnotation annotation) { Long reviewer = (annotation.getImage().getReviewUser()!=null? annotation.getImage().getReviewUser().getId() : null); diff --git a/src/main/java/be/cytomine/service/project/ProjectService.java b/src/main/java/be/cytomine/service/project/ProjectService.java index 300a1b60..5ea8773b 100644 --- a/src/main/java/be/cytomine/service/project/ProjectService.java +++ b/src/main/java/be/cytomine/service/project/ProjectService.java @@ -355,7 +355,7 @@ public Page list(SecUser user, ProjectSearchExtension projectSearchE "JOIN acl_object_identity as aclObjectId ON aclObjectId.object_id_identity = p.id " + "JOIN acl_entry as aclEntry ON aclEntry.acl_object_identity = aclObjectId.id " + "JOIN acl_sid as aclSid ON aclEntry.sid = aclSid.id "; - where = "WHERE aclSid.sid like '"+user.getUsername()+"' "; + where = "WHERE aclSid.sid like :username "; } else { select = "SELECT DISTINCT(p.id) as distinctId, p.* "; @@ -476,6 +476,9 @@ else if(value.contains("contributor")) { } Query query = getEntityManager().createNativeQuery(request, Tuple.class); + if (user!=null) { + query.setParameter("username", user.getUsername()); + } Map mapParams = sqlSearchConditions.getSqlParameters(); for (Map.Entry entry : mapParams.entrySet()) { query.setParameter(entry.getKey(), entry.getValue()); @@ -523,6 +526,9 @@ else if(value.contains("contributor")) { for (Map.Entry entry : mapParams.entrySet()) { query.setParameter(entry.getKey(), entry.getValue()); } + if (user!=null) { + query.setParameter("username", user.getUsername()); + } long count = ((BigInteger)query.getResultList().get(0)).longValue(); Page page = PageUtils.buildPageFromPageResults(results, max, offset, count); return page; diff --git a/src/main/java/be/cytomine/service/security/SecurityACLService.java b/src/main/java/be/cytomine/service/security/SecurityACLService.java index d3f50327..bd80050d 100644 --- a/src/main/java/be/cytomine/service/security/SecurityACLService.java +++ b/src/main/java/be/cytomine/service/security/SecurityACLService.java @@ -181,8 +181,12 @@ public List getStorageList(SecUser user, boolean adminByPass, String se "from AclObjectIdentity as aclObjectId, AclEntry as aclEntry, AclSid as aclSid, Storage as storage "+ "where aclObjectId.objectId = storage.id " + "and aclEntry.aclObjectIdentity = aclObjectId "+ - "and aclEntry.sid = aclSid and aclSid.sid like '"+user.getUsername() +"'" + (StringUtils.isNotBlank(searchString)? " and lower(storage.name) like '%" + searchString.toLowerCase() + "%'" : "")); + "and aclEntry.sid = aclSid and aclSid.sid like :username " + (StringUtils.isNotBlank(searchString)? " and lower(storage.name) like :searchString" : "")); + query.setParameter("username", user.getUsername()); + if(StringUtils.isNotBlank(searchString)) { + query.setParameter("searchString", searchString.toLowerCase()); + } } return (List) query.getResultList(); } @@ -198,8 +202,12 @@ public List getProjectList(SecUser user, Ontology ontology) { "from AclObjectIdentity as aclObjectId, AclEntry as aclEntry, AclSid as aclSid, Project as project "+ "where aclObjectId.objectId = project.id " + "and aclEntry.aclObjectIdentity = aclObjectId "+ - (ontology!=null? "and project.ontology.id = " + ontology.getId() : " ") + - "and aclEntry.sid = aclSid and aclSid.sid like '"+user.getUsername() +"'"); + (ontology!=null? "and project.ontology.id = :ontology " : " ") + + "and aclEntry.sid = aclSid and aclSid.sid like :username "); + if(ontology != null) { + query.setParameter("ontology", ontology.getId()); + } + query.setParameter("username", user.getUsername()); return query.getResultList(); } } @@ -214,7 +222,8 @@ public List getProjectUsers(Project project) { "from AclObjectIdentity as aclObjectId, AclEntry as aclEntry, AclSid as aclSid, Project as project "+ "where aclObjectId.objectId = project.id " + "and aclEntry.aclObjectIdentity = aclObjectId "+ - "and aclEntry.sid = aclSid and project.id = " + project.getId()); + "and aclEntry.sid = aclSid and project.id = :project_id "); + query.setParameter("project_id", project.getId()); List usernames = query.getResultList(); return usernames; } @@ -227,7 +236,8 @@ public List getOntologyList(SecUser user) { "from AclObjectIdentity as aclObjectId, AclEntry as aclEntry, AclSid as aclSid, Ontology as ontology "+ "where aclObjectId.objectId = ontology.id " + "and aclEntry.aclObjectIdentity = aclObjectId "+ - "and aclEntry.sid = aclSid and aclSid.sid like '"+user.getUsername() +"'"); + "and aclEntry.sid = aclSid and aclSid.sid like :username "); + query.setParameter("username", user.getUsername()); List ontologies = query.getResultList(); return ontologies; } diff --git a/src/main/java/be/cytomine/service/stats/StatsService.java b/src/main/java/be/cytomine/service/stats/StatsService.java index 6f213d0a..4f395870 100644 --- a/src/main/java/be/cytomine/service/stats/StatsService.java +++ b/src/main/java/be/cytomine/service/stats/StatsService.java @@ -143,14 +143,23 @@ public List statAnnotationEvolution(Project project, Term term, int String request = "SELECT created " + "FROM UserAnnotation " + - "WHERE project.id = " + project.getId() + " " + - (term!=null ? "AND id IN (SELECT userAnnotation.id FROM AnnotationTerm WHERE term = " + term.getId() + ") " : "") + - (startDate!=null ? " AND created > '"+startDate+"'" : "") + - (endDate!=null ? " AND created < '"+endDate+"'" : "") + + "WHERE project.id = :project_id " + + (term!=null ? "AND id IN (SELECT userAnnotation.id FROM AnnotationTerm WHERE term = :term_id) " : "") + + (startDate!=null ? " AND created > :startDate " : "") + + (endDate!=null ? " AND created < :endDate " : "") + " ORDER BY created ASC"; - - - List annotationsDates = entityManager.createQuery(request, Date.class).getResultList(); + javax.persistence.Query query = entityManager.createQuery(request, Date.class); + if(startDate!=null) { + query.setParameter("startDate", startDate); + } + if(endDate!=null) { + query.setParameter("endDate", endDate); + } + if(term!=null) { + query.setParameter("term_id", term.getId()); + } + query.setParameter("project_id", project.getId()); + List annotationsDates = query.getResultList(); List data = aggregateByPeriods(annotationsDates, daysRange, (startDate==null ? project.getCreated() : startDate), (endDate==null ? new Date() : endDate), accumulate); if(reverseOrder) { @@ -165,13 +174,23 @@ public List statAlgoAnnotationEvolution(Project project, Term term, String request = "SELECT created " + "FROM AlgoAnnotation " + - "WHERE project.id = " + project.getId() + " " + - (term!=null ? "AND id IN (SELECT annotationIdent FROM AlgoAnnotationTerm WHERE term = " + term.getId() + ") " : "") + - (startDate!=null ? "AND created > '"+startDate+"'" : "") + - (endDate!=null ? "AND created < '"+endDate+"'" : "") + + "WHERE project.id = :project_id " + + (term!=null ? "AND id IN (SELECT annotationIdent FROM AlgoAnnotationTerm WHERE term = :term_id) " : "") + + (startDate!=null ? "AND created > :startDate " : "") + + (endDate!=null ? "AND created < :endDate " : "") + "ORDER BY created ASC"; - - List annotationsDates = entityManager.createQuery(request, Date.class).getResultList(); + javax.persistence.Query query = entityManager.createQuery(request, Date.class); + if(startDate!=null) { + query.setParameter("startDate", startDate); + } + if(endDate!=null) { + query.setParameter("endDate", endDate); + } + if(term!=null) { + query.setParameter("term_id", term.getId()); + } + query.setParameter("project_id", project.getId()); + List annotationsDates = query.getResultList(); List data = aggregateByPeriods(annotationsDates, daysRange, (startDate==null ? project.getCreated() : startDate), (endDate==null ? new Date() : endDate), accumulate); if(reverseOrder) { @@ -186,13 +205,25 @@ public List statReviewedAnnotationEvolution(Project project, Term t String request = "SELECT created " + "FROM reviewed_annotation " + - "WHERE project_id = " + project.getId() + " " + - (term!=null ? "AND id IN (SELECT reviewed_annotation_terms_id FROM reviewed_annotation_term WHERE term_id = " + term.getId() + ") " : "") + - (startDate!=null ? "AND created > '"+startDate+"'" : "") + - (endDate!=null ? "AND created < '"+endDate+"'" : "") + + "WHERE project_id = :project_id " + + (term!=null ? "AND id IN (SELECT reviewed_annotation_terms_id FROM reviewed_annotation_term WHERE term_id = :term_id) " : "") + + (startDate!=null ? "AND created > :startDate " : "") + + (endDate!=null ? "AND created < :endDate " : "") + "ORDER BY created ASC"; - List annotationsDates = entityManager.createNativeQuery(request).getResultList(); + javax.persistence.Query query = entityManager.createNativeQuery(request); + if(startDate!=null) { + query.setParameter("startDate", startDate); + } + if(endDate!=null) { + query.setParameter("endDate", endDate); + } + if(term!=null) { + query.setParameter("term_id", term.getId()); + } + query.setParameter("project_id", project.getId()); + + List annotationsDates = query.getResultList(); List data = aggregateByPeriods(annotationsDates, daysRange, (startDate==null ? project.getCreated() : startDate), (endDate==null ? new Date() : endDate), accumulate); if(reverseOrder) { @@ -265,12 +296,19 @@ public List statTermSlide(Project project, Date startDate, Date endD "FROM user_annotation ua " + "LEFT JOIN annotation_term at " + "ON at.user_annotation_id = ua.id " + - "WHERE ua.project_id = "+project.getId() +" " + - (startDate!=null ? "AND at.created > '"+startDate+"'" : "") + - (endDate!=null ? "AND at.created < '"+endDate+"'" : "") + + "WHERE ua.project_id = :project_id " + + (startDate!=null ? "AND at.created > :startDate " : "") + + (endDate!=null ? "AND at.created < :endDate " : "") + "GROUP BY at.term_id "; - - List rows = entityManager.createNativeQuery(request, Tuple.class).getResultList(); + javax.persistence.Query query = entityManager.createNativeQuery(request, Tuple.class); + if(startDate!=null) { + query.setParameter("startDate", startDate); + } + if(endDate!=null) { + query.setParameter("endDate", endDate); + } + query.setParameter("project_id", project.getId()); + List rows = query.getResultList(); for (Tuple row : rows) { JsonObject value = result.get(row.get(0)==null ? 0L : ((BigInteger)row.get(0)).longValue()); @@ -291,13 +329,20 @@ public List statPerTermAndImage(Project project, Date startDate, Dat "SELECT ua.image_id, at.term_id, COUNT(ua.id) as count " + "FROM user_annotation ua " + "LEFT JOIN annotation_term at ON at.user_annotation_id = ua.id " + - "WHERE ua.deleted is NULL and at.deleted is NULL and ua.project_id = " +project.getId() + " "+ - (startDate!=null ? "AND at.created > '"+startDate+"'" : "") + - (endDate!=null ? "AND at.created < '"+endDate+"'" : "") + + "WHERE ua.deleted is NULL and at.deleted is NULL and ua.project_id = :project_id "+ + (startDate!=null ? "AND at.created > :startDate " : "") + + (endDate!=null ? "AND at.created < :endDate " : "") + "GROUP BY ua.image_id, at.term_id " + "ORDER BY ua.image_id, at.term_id "; - - List rows = entityManager.createNativeQuery(request, Tuple.class).getResultList(); + javax.persistence.Query query = entityManager.createNativeQuery(request, Tuple.class); + if(startDate!=null) { + query.setParameter("startDate", startDate); + } + if(endDate!=null) { + query.setParameter("endDate", endDate); + } + query.setParameter("project_id", project.getId()); + List rows = query.getResultList(); for (Tuple row : rows) { JsonObject value = JsonObject.of( @@ -340,12 +385,19 @@ public List statTerm(Project project, Date startDate, Date endDate, "FROM user_annotation ua " + "LEFT JOIN annotation_term at " + "ON at.user_annotation_id = ua.id " + - "WHERE ua.project_id = "+project.getId()+" " + - (startDate!=null ? "AND at.created > '"+startDate+"'" : "") + - (endDate!=null ? "AND at.created < '"+endDate+"'" : "") + + "WHERE ua.project_id = :project_id " + + (startDate!=null ? "AND at.created > :startDate " : "") + + (endDate!=null ? "AND at.created < :endDate " : "") + "GROUP BY at.term_id "; - - List rows = entityManager.createNativeQuery(request, Tuple.class).getResultList(); + javax.persistence.Query query = entityManager.createNativeQuery(request, Tuple.class); + if(startDate!=null) { + query.setParameter("startDate", startDate); + } + if(endDate!=null) { + query.setParameter("endDate", endDate); + } + query.setParameter("project_id", project.getId()); + List rows = query.getResultList(); for (Tuple row : rows) { if (row.get(0) == null) { stats.put("0", ((BigInteger)row.get(1)).longValue()); diff --git a/src/main/java/be/cytomine/service/utils/KmeansGeometryService.java b/src/main/java/be/cytomine/service/utils/KmeansGeometryService.java index 313a697b..7fc15ab4 100644 --- a/src/main/java/be/cytomine/service/utils/KmeansGeometryService.java +++ b/src/main/java/be/cytomine/service/utils/KmeansGeometryService.java @@ -69,28 +69,31 @@ public class KmeansGeometryService { ); - public List doKeamsFullRequest(String request) { + public List doKeamsFullRequest(String request, Map parameters) { String requestKmeans = "SELECT kmeans, count(*), st_astext(ST_ConvexHull(ST_Collect(location))) \n" + "FROM (\n" + request +"\n" +") AS ksub\n" + "GROUP BY kmeans\n" + "ORDER BY kmeans;"; - return selectAnnotationLightKmeans(requestKmeans); + return selectAnnotationLightKmeans(requestKmeans, parameters); } - public List doKeamsSoftRequest(String request) { + public List doKeamsSoftRequest(String request, Map parameters) { String requestKmeans = "SELECT kmeans, count(*), st_astext(ST_Centroid(ST_Collect(location))) \n" + "FROM (\n" + request +"\n" +") AS ksub\n" + "GROUP BY kmeans\n" + "ORDER BY kmeans;"; - return selectAnnotationLightKmeans(requestKmeans); + return selectAnnotationLightKmeans(requestKmeans, parameters); } - private List selectAnnotationLightKmeans(String request) { + private List selectAnnotationLightKmeans(String request, Map parameters) { List data = new ArrayList<>(); double max = 1; Query nativeQuery = entityManager.createNativeQuery(request, Tuple.class); + for (Map.Entry entry : parameters.entrySet()) { + nativeQuery.setParameter(entry.getKey(), entry.getValue()); + } List resultList = nativeQuery.getResultList(); for (Tuple tuple : resultList) { Kmeans kmeans = new Kmeans(); diff --git a/src/main/java/be/cytomine/service/utils/ValidateGeometryService.java b/src/main/java/be/cytomine/service/utils/ValidateGeometryService.java index 9967ed51..a7b20085 100644 --- a/src/main/java/be/cytomine/service/utils/ValidateGeometryService.java +++ b/src/main/java/be/cytomine/service/utils/ValidateGeometryService.java @@ -67,7 +67,6 @@ public Geometry tryToMakeItValidIfNotValid(Geometry location) { if (!geom.isValid() || geom.isEmpty()) { //if not valid after buffer(0) or empty after buffer 0 //user_image already filter nested image - log.info("Geometry is not valid, even after a buffer(0)!"); String request = "SELECT ST_AsText(ST_MakeValid(ST_AsText('" + backupLocation + "')))"; log.info(request); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 35ab2a4c..6b814b14 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -90,7 +90,7 @@ application: secret: ${JWT_SECRET} # Token is valid 24 hours token-validity-in-seconds: ${TOKEN_VALIDITY_IN_SECONDS:86400} - token-validity-in-seconds-for-remember-me: ${TOKEN_VALIDITY_IN_SECONDS_REMEMBER_ME:2592000} + token-validity-in-seconds-for-remember-me: ${TOKEN_VALIDITY_IN_SECONDS_REMEMBER_ME:604800} token-validity-in-seconds-for-short-term: ${TOKEN_VALIDITY_IN_SECONDS_SHORT_TERM:240} imageServerURL: