All constraints now have both a key and a message parameter

This commit is contained in:
paultrudel 2021-10-04 13:50:17 -04:00
parent ec3956ec94
commit 5b4ea24ea8
33 changed files with 288 additions and 40 deletions

View File

@ -15,7 +15,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface GetChecksumConstraint {
String message() default "checksumError-Checksums do not match";
String key() default "checksumError";
String message() default "Checksums do not match";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -15,7 +15,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface GuestPolicyConstraint {
String message() default "guestDeny-User denied access for this session";
String key() default "guestDeny";
String message() default "User denied access for this session";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -15,7 +15,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface IsBooleanConstraint {
String message() default "Validation error: value must be a boolean";
String key() default "validationError";
String message() default "Value must be a boolean";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -15,7 +15,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface IsIntegralConstraint {
String message() default "Validation error: value must be an integral number";
String key() default "validationError";
String message() default "Value must be an integral number";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -15,6 +15,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface MaxParticipantsConstraint {
String key() default "maxParticipantsReached";
String message() default "The maximum number of participants for the meeting has been reached";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};

View File

@ -15,7 +15,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface MeetingEndedConstraint {
String message() default "meetingEnded-You can not join a meeting that has already been forcibly ended";
String key() default "meetingForciblyEnded";
String message() default "You can not join a meeting that has already been forcibly ended";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -16,7 +16,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface MeetingExistsConstraint {
String message() default "notFound-A meeting with that ID does not exist";
String key() default "notFound";
String message() default "A meeting with that ID does not exist";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -2,16 +2,13 @@ package org.bigbluebutton.api.model.constraint;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@NotEmpty(message = "missingParamMeetingID-You must provide a meeting ID")
@NotEmpty(key = "missingParamMeetingID", message = "You must provide a meeting ID")
@Size(min = 2, max = 256, message = "Meeting ID must be between 2 and 256 characters")
@Pattern(regexp = "^[^,]+$", message = "Meeting ID cannot contain ','")
@Constraint(validatedBy = {})
@ -19,6 +16,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface MeetingIDConstraint {
String key() default "validationError";
String message() default "Invalid meeting ID";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};

View File

@ -2,23 +2,21 @@ package org.bigbluebutton.api.model.constraint;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@NotNull(message = "You must provide a meeting name")
@NotEmpty(message = "You must provide a meeting name")
@Size(min = 2, max = 256, message = "Meeting name must be between 2 and 256 characters")
//@Pattern(regexp = "^[^,]+$", message = "Meeting name cannot contain ','")
@Constraint(validatedBy = {})
@Target(FIELD)
@Retention(RUNTIME)
public @interface MeetingNameConstraint {
String key() default "validationError";
String message() default "Invalid meeting name";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};

View File

@ -15,7 +15,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface ModeratorPasswordConstraint {
String message() default "Invalid password: The supplied moderator password is incorrect";
String key() default "invalidPassword";
String message() default "The supplied moderator password is incorrect";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,20 @@
package org.bigbluebutton.api.model.constraint;
import org.bigbluebutton.api.model.constraint.list.NotEmptyList;
import org.bigbluebutton.api.model.validator.NotEmptyValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Constraint(validatedBy = NotEmptyValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(NotEmptyList.class)
public @interface NotEmpty {
String key() default "emptyError";
String message() default "Field must contain a value";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,20 @@
package org.bigbluebutton.api.model.constraint;
import org.bigbluebutton.api.model.constraint.list.NotNullList;
import org.bigbluebutton.api.model.validator.NotNullValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(NotNullList.class)
@Constraint(validatedBy = NotNullValidator.class)
public @interface NotNull {
String key() default "nullError";
String message() default "Value cannot be null";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -2,8 +2,6 @@ package org.bigbluebutton.api.model.constraint;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@ -16,7 +14,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface PasswordConstraint {
String message() default "invalidPassword-Invalid password";
String key() default "invalidPassword";
String message() default "Invalid password";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,42 @@
package org.bigbluebutton.api.model.constraint;
import org.bigbluebutton.api.model.constraint.list.PatternList;
import org.bigbluebutton.api.model.validator.PatternValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(PatternList.class)
@Constraint(validatedBy = PatternValidator.class)
public @interface Pattern {
String regexp();
Flag[] flags() default {};
String key() default "validationError";
String message() default "Value contains invalid characters";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
enum Flag {
UNIX_LINES(1),
CASE_INSENSITIVE(2),
COMMENTS(4),
MULTILINE(8),
DOTALL(32),
UNICODE_CASE(64),
CANON_EQ(128);
private final int value;
private Flag(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
}

View File

@ -15,7 +15,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface PostChecksumConstraint {
String message() default "checksumError-Checksums do not match";
String key() default "checksumError";
String message() default "Checksums do not match";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,22 @@
package org.bigbluebutton.api.model.constraint;
import org.bigbluebutton.api.model.constraint.list.SizeList;
import org.bigbluebutton.api.model.validator.SizeValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(SizeList.class)
@Constraint(validatedBy = SizeValidator.class)
public @interface Size {
String key() default "sizeError";
String message() default "Value does not conform to size restrictions";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int min() default 0;
int max() default 2147483647;
}

View File

@ -4,20 +4,20 @@ import org.bigbluebutton.api.model.validator.UserSessionValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.NotNull;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@NotNull(message = "missingToken-You must provide a session token")
@NotNull(key = "missingToken", message = "You must provide a session token")
@Constraint(validatedBy = { UserSessionValidator.class })
@Target(FIELD)
@Retention(RUNTIME)
public @interface UserSessionConstraint {
String message() default "missingSession-Invalid session token";
String key() default "missingSession";
String message() default "Invalid session token";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,14 @@
package org.bigbluebutton.api.model.constraint.list;
import org.bigbluebutton.api.model.constraint.NotEmpty;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotEmptyList {
NotEmpty[] value();
}

View File

@ -0,0 +1,14 @@
package org.bigbluebutton.api.model.constraint.list;
import org.bigbluebutton.api.model.constraint.NotNull;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNullList {
NotNull[] value();
}

View File

@ -0,0 +1,14 @@
package org.bigbluebutton.api.model.constraint.list;
import org.bigbluebutton.api.model.constraint.Pattern;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PatternList {
Pattern[] value();
}

View File

@ -0,0 +1,14 @@
package org.bigbluebutton.api.model.constraint.list;
import org.bigbluebutton.api.model.constraint.Size;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SizeList {
Size[] value();
}

View File

@ -31,7 +31,6 @@ public class CreateMeeting extends RequestWithChecksum<CreateMeeting.Params> {
@MeetingIDConstraint
private String meetingID;
//@NotEmpty(message = "You must provide a voice bridge")
@IsIntegralConstraint(message = "Voice bridge must be a 5-digit integral value")
private String voiceBridgeString;
private Integer voiceBridge;

View File

@ -2,12 +2,12 @@ package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint;
import org.bigbluebutton.api.model.constraint.MeetingIDConstraint;
import org.bigbluebutton.api.model.constraint.NotEmpty;
import org.bigbluebutton.api.model.constraint.PasswordConstraint;
import org.bigbluebutton.api.model.shared.Checksum;
import org.bigbluebutton.api.model.shared.ModeratorPassword;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.Map;
public class EndMeeting extends RequestWithChecksum<EndMeeting.Params> {

View File

@ -18,7 +18,6 @@ public class Enter implements Request<Enter.Params> {
}
@UserSessionConstraint
//@MaxParticipantsConstraint
@GuestPolicyConstraint
private String sessionToken;

View File

@ -22,7 +22,6 @@ public class GuestWait implements Request<GuestWait.Params> {
}
@UserSessionConstraint
// @MaxParticipantsConstraint
private String sessionToken;
@MeetingExistsConstraint

View File

@ -3,7 +3,6 @@ package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.*;
import org.bigbluebutton.api.model.shared.Checksum;
import javax.validation.constraints.NotEmpty;
import java.util.Map;
public class JoinMeeting extends RequestWithChecksum<JoinMeeting.Params> {
@ -25,17 +24,17 @@ public class JoinMeeting extends RequestWithChecksum<JoinMeeting.Params> {
}
@MeetingIDConstraint
@MeetingExistsConstraint
@MeetingExistsConstraint(key = "invalidMeetingIdentifier")
@MeetingEndedConstraint
private String meetingID;
private String userID;
@NotEmpty(message = "missingParamFullName-You must provide your name")
@NotEmpty(key = "missingParamFullName", message = "You must provide your name")
private String fullName;
@PasswordConstraint
@NotEmpty(message = "invalidPassword-You must provide either the moderator or attendee password")
@NotEmpty(key = "invalidPassword", message = "You must provide either the moderator or attendee password")
private String password;
@IsBooleanConstraint(message = "Guest must be a boolean value (true or false)")

View File

@ -2,9 +2,9 @@ package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint;
import org.bigbluebutton.api.model.constraint.MeetingIDConstraint;
import org.bigbluebutton.api.model.constraint.NotEmpty;
import org.bigbluebutton.api.model.shared.Checksum;
import javax.validation.constraints.NotEmpty;
import java.util.Map;
public class SetPollXML extends RequestWithChecksum<SetPollXML.Params> {
@ -21,10 +21,10 @@ public class SetPollXML extends RequestWithChecksum<SetPollXML.Params> {
}
@MeetingIDConstraint
@MeetingExistsConstraint
@MeetingExistsConstraint(key = "invalidMeetingIdentifier")
private String meetingID;
@NotEmpty(message = "You must provide the poll")
@NotEmpty(key = "configXMLError", message = "You did not pass a poll XML")
private String pollXML;
public SetPollXML(Checksum checksum) {

View File

@ -3,7 +3,6 @@ package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.*;
import org.bigbluebutton.api.service.SessionService;
import javax.validation.constraints.NotNull;
import java.util.Map;
public class Stuns implements Request<Stuns.Params> {
@ -18,7 +17,6 @@ public class Stuns implements Request<Stuns.Params> {
public String getValue() { return value; }
}
@NotNull(message = "You must provide a session token")
@UserSessionConstraint
private String sessionToken;

View File

@ -0,0 +1,18 @@
package org.bigbluebutton.api.model.validator;
import org.bigbluebutton.api.model.constraint.NotEmpty;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class NotEmptyValidator implements ConstraintValidator<NotEmpty, String> {
@Override
public void initialize(NotEmpty constraintAnnotation) {}
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
if(s == null) return true;
return !s.isEmpty();
}
}

View File

@ -0,0 +1,17 @@
package org.bigbluebutton.api.model.validator;
import org.bigbluebutton.api.model.constraint.NotNull;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class NotNullValidator implements ConstraintValidator<NotNull, Object> {
@Override
public void initialize(NotNull constraintAnnotation) {}
@Override
public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
return !(o == null);
}
}

View File

@ -0,0 +1,22 @@
package org.bigbluebutton.api.model.validator;
import org.bigbluebutton.api.model.constraint.Pattern;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class PatternValidator implements ConstraintValidator<Pattern, String> {
String regexp;
@Override
public void initialize(Pattern constraintAnnotation) {
regexp = constraintAnnotation.regexp();
}
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
if(s == null) return true;
return java.util.regex.Pattern.matches(regexp, s);
}
}

View File

@ -0,0 +1,24 @@
package org.bigbluebutton.api.model.validator;
import org.bigbluebutton.api.model.constraint.Size;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class SizeValidator implements ConstraintValidator<Size, String> {
private int min;
private int max;
@Override
public void initialize(Size constraintAnnotation) {
min = constraintAnnotation.min();
max = constraintAnnotation.max();
}
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
if(s == null) return true;
return (s.length() >= min && s.length() <= max);
}
}

View File

@ -142,14 +142,23 @@ public class ValidationService {
Map<String, String> violationMap = new HashMap<>();
for(ConstraintViolation<R> violation: violations) {
String violationMessage = violation.getMessage();
String[] s = violationMessage.split("-");
Map<String, Object> attributes = violation.getConstraintDescriptor().getAttributes();
String key;
String message;
if(s.length == 2) {
violationMap.put(s[0], s[1]);
if(attributes.containsKey("key")) {
key = (String) attributes.get("key");
} else {
violationMap.put("validationError", violationMessage);
key = "validationError";
}
if(attributes.containsKey("message")) {
message = (String) attributes.get("message");
} else {
message = "An unknown validation error occurred";
}
violationMap.put(key, message);
}
if(violationMap.isEmpty()) {