use of jetbrains.buildServer.server.rest.errors.BadRequestException in project teamcity-rest by JetBrains.
the class TimeWithPrecision method parse.
@NotNull
public static TimeWithPrecision parse(@NotNull String timeString, @NotNull final TimeService timeService) {
Locator.processHelpRequest(timeString, "Date/time string in format '" + DateTimeFormat.forPattern(Constants.TIME_FORMAT).withLocale(Locale.ENGLISH).print(Instant.now()) + "'" + " or offset in format '-4w2d5h30m5s'");
if (timeString.contains(" ")) {
throw new BadRequestException("Invalid date/time string '" + timeString + "'. Note that '+' should be escaped in URL as '%2B'.");
}
// compatibility switch to mimic pre-2018.2 behavior
boolean useSecondsPrecision = TeamCityProperties.getBoolean("rest.timeMatching.roundEntityTimeToSeconds");
if (timeString.startsWith("-")) {
return new TimeWithPrecision(new Date(timeService.now() - TimeWithPrecision.getMsFromRelativeTime(timeString.substring("-".length()))), useSecondsPrecision);
} else if (timeString.startsWith("+")) {
return new TimeWithPrecision(new Date(timeService.now() + TimeWithPrecision.getMsFromRelativeTime(timeString.substring("+".length()))), useSecondsPrecision);
}
// try different parsers
// the order can be important as SimpleDateFormat will parse the beginning of the string ignoring any unparsed trailing characters
BadRequestException firstError;
if (TeamCityProperties.getBoolean("rest.compatibilityDateParsing")) {
try {
return new TimeWithPrecision(new SimpleDateFormat(Constants.TIME_FORMAT, Locale.ENGLISH).parse(timeString), true);
} catch (ParseException e) {
firstError = new BadRequestException("Was not able to parse date '" + timeString + "' using format '" + Constants.TIME_FORMAT + "' and others." + " Supported format example: '" + new SimpleDateFormat(Constants.TIME_FORMAT, Locale.ENGLISH).format(new Date()) + "'." + " Error: " + e.toString(), e);
}
} else {
try {
return new TimeWithPrecision(DateTimeFormat.forPattern(Constants.TIME_FORMAT).withLocale(Locale.ENGLISH).parseDateTime(timeString).toDate(), useSecondsPrecision);
} catch (Exception e) {
firstError = new BadRequestException("Was not able to parse date '" + timeString + "' using format '" + Constants.TIME_FORMAT + "' and others." + " Supported format example: '" + DateTimeFormat.forPattern(Constants.TIME_FORMAT).withLocale(Locale.ENGLISH).withZone(DateTimeZone.getDefault()).print(Instant.now()) + "'. Error: " + e.toString(), e);
}
}
try {
return new TimeWithPrecision(ISODateTimeFormat.localTimeParser().withLocale(Locale.ENGLISH).parseLocalTime(timeString).toDateTime(new DateTime(timeService.now())).toDate(), false);
} catch (Exception e) {
// ignore
if (LOG.isDebugEnabled())
LOG.debug("Was not able to parse date/time '" + timeString + "' using ISODateTimeFormat.localTimeParser. Error: " + e.toString(), e);
}
try {
return new TimeWithPrecision(ISODateTimeFormat.dateTimeParser().withLocale(Locale.ENGLISH).parseDateTime(timeString).toDate(), false);
} catch (Exception e) {
// ignore
if (LOG.isDebugEnabled())
LOG.debug("Was not able to parse date/time '" + timeString + "' using ISODateTimeFormat.dateTimeParser. Error: " + e.toString(), e);
}
try {
return new TimeWithPrecision(ISODateTimeFormat.basicDateTime().withLocale(Locale.ENGLISH).parseDateTime(timeString).toDate(), false);
} catch (Exception e) {
// ignore
if (LOG.isDebugEnabled())
LOG.debug("Was not able to parse date/time '" + timeString + "' using ISODateTimeFormat.basicDateTime. Error: " + e.toString(), e);
}
try {
return new TimeWithPrecision(ISODateTimeFormat.basicDateTimeNoMillis().withLocale(Locale.ENGLISH).parseDateTime(timeString).toDate(), false);
} catch (Exception e) {
// ignore
if (LOG.isDebugEnabled())
LOG.debug("Was not able to parse date/time '" + timeString + "' using ISODateTimeFormat.basicDateTimeNoMillis. Error: " + e.toString(), e);
}
try {
DateTime dateTime = ISODateTimeFormat.localDateOptionalTimeParser().withLocale(Locale.ENGLISH).parseDateTime(timeString).withZoneRetainFields(DateTimeZone.getDefault());
return new TimeWithPrecision(dateTime.toDate(), false);
} catch (Exception e) {
// ignore
if (LOG.isDebugEnabled())
LOG.debug("Was not able to parse date/time '" + timeString + "' using ISODateTimeFormat.localDateOptionalTimeParser. Error: " + e.toString(), e);
}
try {
return new TimeWithPrecision(LocalTime.parse(timeString).toDateTime(new DateTime(timeService.now()).withMillisOfDay(0)).toDate(), false);
} catch (Exception e) {
// ignore
if (LOG.isDebugEnabled())
LOG.debug("Was not able to parse date/time '" + timeString + "' using LocalTime. Error: " + e.toString(), e);
}
try {
return new TimeWithPrecision(DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss.SSS").withLocale(Locale.ENGLISH).parseLocalDateTime(timeString).toDate(), false);
// return new TimeWithPrecision(new SimpleDateFormat("yyyyMMdd'T'HHmmss.SSS", Locale.ENGLISH).parse(timeString), false);
} catch (Exception e) {
// ignore
if (LOG.isDebugEnabled())
LOG.debug("Was not able to parse date/time '" + timeString + "' using format '" + "yyyyMMdd'T'HHmmss.SSS" + "'. Error: " + e.toString(), e);
}
try {
return new TimeWithPrecision(DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss").withLocale(Locale.ENGLISH).parseLocalDateTime(timeString).toDate(), false);
// return new TimeWithPrecision(new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ENGLISH).parse(timeString), false);
} catch (Exception e) {
// ignore
if (LOG.isDebugEnabled())
LOG.debug("Was not able to parse date/time '" + timeString + "' using format '" + "yyyyMMdd'T'HHmmss" + "'. Error: " + e.toString(), e);
}
StringBuilder message = new StringBuilder();
Date exampleTime = new Date();
// throwing original error
message.append("Could not parse date from value '").append(timeString).append("'. Supported formats are ISO8601 or for example: ");
message.append(new SimpleDateFormat(Constants.TIME_FORMAT, Locale.ENGLISH).format(exampleTime));
message.append(". First reported error: ").append(firstError.getMessage());
throw firstError;
}
use of jetbrains.buildServer.server.rest.errors.BadRequestException in project teamcity-rest by JetBrains.
the class TypedFinderBuilder method dimensionFixedText.
public TypedFinderDimensionWithDefaultChecker<ITEM, String, String> dimensionFixedText(@NotNull final Dimension<String> dimension, @NotNull final String... values) {
Set<String> lowerCaseValues = Arrays.stream(values).map(String::toLowerCase).collect(Collectors.toSet());
String supportedValuesText = StringUtil.join(values, ", ");
return dimension(dimension, type(dimensionValue -> {
if (lowerCaseValues.contains(dimensionValue.toLowerCase())) {
return dimensionValue;
}
throw new BadRequestException("Unsupported value '" + dimensionValue + "'. Supported values are: " + supportedValuesText);
}).description("one of " + supportedValuesText)).defaultFilter(String::equalsIgnoreCase);
}
use of jetbrains.buildServer.server.rest.errors.BadRequestException in project teamcity-rest by JetBrains.
the class ChangeFinder method getPrefilteredItems.
@NotNull
@Override
public ItemHolder<SVcsModificationOrChangeDescriptor> getPrefilteredItems(@NotNull final Locator locator) {
final String internalVersion = locator.getSingleDimensionValue(INTERNAL_VERSION);
if (internalVersion != null) {
return wrapModifications(((VcsModificationHistoryEx) myVcsModificationHistory).findModificationsByVersion(internalVersion));
}
ValueCondition displayVersionCondition = ParameterCondition.createValueCondition(locator.lookupSingleDimensionValue(VERSION));
final String displayVersion = displayVersionCondition != null ? displayVersionCondition.getConstantValueIfSimpleEqualsCondition() : null;
if (displayVersion != null) {
locator.markUsed(Collections.singleton(VERSION));
return wrapModifications(((VcsModificationHistoryEx) myVcsModificationHistory).findModificationsByDisplayVersion(displayVersion));
}
Boolean personal = locator.lookupSingleDimensionValueAsBoolean(PERSONAL);
if (personal != null && personal) {
if (locator.lookupSingleDimensionValue(BUILD) == null && locator.lookupSingleDimensionValue(USER) == null) {
throw new BadRequestException("Filtering personal changes is supported only when '" + DIMENSION_ID + "', '" + USER + "' or '" + BUILD + "' dimensions are specified");
}
}
final String buildLocator = locator.getSingleDimensionValue(BUILD);
if (buildLocator != null) {
BuildPromotion buildFromBuildFinder;
try {
buildFromBuildFinder = myBuildPromotionFinder.getItem(buildLocator);
} catch (Exception e) {
if (!TeamCityProperties.getBoolean("rest.request.changes.legacySingleBuildSearch")) {
throw e;
}
// support for finished builds
// todo: use buildPromotionFinder here (ensure it also supports finished builds)
// THIS SHOULD NEVER HAPPEN
buildFromBuildFinder = myBuildFinder.getBuildPromotion(null, buildLocator);
}
return wrapDescriptors(getBuildChangeDescriptors(buildFromBuildFinder, locator));
}
// pre-9.0 compatibility
final Long promotionLocator = locator.getSingleDimensionValueAsLong(PROMOTION);
if (promotionLocator != null) {
// noinspection ConstantConditions
return wrapDescriptors(getBuildChangeDescriptors(BuildFinder.getBuildPromotion(promotionLocator, myServiceLocator.findSingletonService(BuildPromotionManager.class)), locator));
}
final String parentChangeLocator = locator.getSingleDimensionValue(CHILD_CHANGE);
if (parentChangeLocator != null) {
final SVcsModification parentChange = getItem(parentChangeLocator).getSVcsModification();
return wrapModifications(getChangesWhichHasChild(parentChange, locator.getSingleDimensionValueAsLong(DIMENSION_LOOKUP_LIMIT)));
// todo: return iterator instead of processing lookup limit here
}
final String childChangeLocator = locator.getSingleDimensionValue(PARENT_CHANGE);
if (childChangeLocator != null) {
final SVcsModification parentChange = getItem(childChangeLocator).getSVcsModification();
return wrapModifications(getChangesWhichHasParent(parentChange, locator.getSingleDimensionValueAsLong(DIMENSION_LOOKUP_LIMIT)));
}
final String graphLocator = locator.getSingleDimensionValue(DAG_TRAVERSE);
if (graphLocator != null) {
final GraphFinder<SVcsModification> graphFinder = new GraphFinder<SVcsModification>(locatorText -> getItems(locatorText).myEntries.stream().map(SVcsModificationOrChangeDescriptor::getSVcsModification).collect(Collectors.toList()), new ChangesGraphTraverser());
graphFinder.setDefaultLookupLimit(1000L);
return wrapModifications(graphFinder.getItems(graphLocator).myEntries);
}
final String userLocator = locator.getSingleDimensionValue(USER);
if (userLocator != null) {
final SUser user = myUserFinder.getItem(userLocator);
return wrapModifications(myServiceLocator.getSingletonService(UserChangesFacade.class).getAllVcsModifications(user));
}
final String username = locator.getSingleDimensionValue(USERNAME);
if (username != null) {
return wrapModifications(myServiceLocator.getSingletonService(VcsModificationsStorage.class).findModificationsByUsername(username));
}
Long sinceChangeId = null;
final String sinceChangeLocator = locator.getSingleDimensionValue(SINCE_CHANGE);
if (sinceChangeLocator != null) {
sinceChangeId = getChangeIdBySinceChangeLocator(sinceChangeLocator);
}
final String vcsRootInstanceLocator = locator.getSingleDimensionValue(VCS_ROOT_INSTANCE);
if (vcsRootInstanceLocator != null) {
final VcsRootInstance vcsRootInstance = myVcsRootInstanceFinder.getItem(vcsRootInstanceLocator);
if (sinceChangeId != null) {
// todo: use lookupLimit here or otherwise limit processing
return wrapModifications(myVcsModificationHistory.getModificationsInRange(vcsRootInstance, sinceChangeId, null));
} else {
// todo: highly inefficient!
return wrapModifications(myVcsModificationHistory.getAllModifications(vcsRootInstance));
}
}
SBuildType buildType = null;
// todo: support multiple buildTypes here
final String buildTypeLocator = locator.getSingleDimensionValue(BUILD_TYPE);
if (buildTypeLocator != null) {
buildType = myBuildTypeFinder.getBuildType(null, buildTypeLocator, false);
}
Boolean pending = locator.getSingleDimensionValueAsBoolean(PENDING);
if (pending != null) {
if (pending) {
Stream<SVcsModificationOrChangeDescriptor> changes = getPendingChanges(buildType, locator);
return processor -> changes.allMatch(processor::processItem);
} else {
locator.markUnused(PENDING);
}
}
if (buildType != null) {
Stream<SVcsModificationOrChangeDescriptor> changes = getBranchChanges(buildType, SelectPrevBuildPolicy.SINCE_NULL_BUILD, locator);
return processor -> changes.allMatch(processor::processItem);
}
if (locator.lookupSingleDimensionValue(BRANCH) != null) {
throw new BadRequestException("Filtering changes by branch is only supported when buildType is specified.");
}
final String projectLocator = locator.getSingleDimensionValue(PROJECT);
if (projectLocator != null) {
return wrapModifications(getProjectChanges(myProjectFinder.getItem(projectLocator), sinceChangeId));
}
if (sinceChangeId != null) {
// todo: use lookupLimit here or otherwise limit processing
return wrapModifications(myVcsModificationHistory.getModificationsInRange(null, sinceChangeId, null));
}
// ItemHolder
return wrapModifications(((VcsModificationHistoryEx) myVcsModificationHistory)::processModifications);
}
use of jetbrains.buildServer.server.rest.errors.BadRequestException in project teamcity-rest by JetBrains.
the class ParameterCondition method createValueCondition.
@Nullable
@Contract("!null -> !null; null -> null")
private static ValueCondition createValueCondition(@Nullable final String propertyConditionLocator, boolean surroundingBracesHaveSpecialMeaning) {
if (propertyConditionLocator == null) {
return null;
}
final Locator locator = new Locator(propertyConditionLocator, new Locator.Metadata(false, surroundingBracesHaveSpecialMeaning), VALUE, TYPE, IGNORE_CASE, Locator.LOCATOR_SINGLE_VALUE_UNUSED_NAME);
final String value = locator.isSingleValue() ? locator.getSingleValue() : locator.getSingleDimensionValue(VALUE);
RequirementType requirement;
final String type = locator.getSingleDimensionValue(TYPE);
if (type != null) {
requirement = RequirementType.findByName(type);
if (requirement == null || RequirementType.EXISTS.equals(requirement) || RequirementType.NOT_EXISTS.equals(requirement)) {
List<String> supportedSingleValueRequirementTypes = new ArrayList<>(getAllRequirementTypes());
supportedSingleValueRequirementTypes.remove(RequirementType.EXISTS.getName());
supportedSingleValueRequirementTypes.remove(RequirementType.NOT_EXISTS.getName());
throw new BadRequestException("Unsupported value '" + type + "' for '" + TYPE + "' for single value condition. Supported are: " + supportedSingleValueRequirementTypes);
}
} else {
if (locator.isSingleValue()) {
requirement = RequirementType.EQUALS;
} else {
requirement = getDefaultMatchCondition(locator);
}
}
Boolean ignoreCase = locator.getSingleDimensionValueAsBoolean(IGNORE_CASE);
locator.checkLocatorFullyProcessed();
return new ValueCondition(requirement, value, ignoreCase);
}
use of jetbrains.buildServer.server.rest.errors.BadRequestException in project teamcity-rest by JetBrains.
the class PermissionAssignmentFinder method getPermissions.
@NotNull
private FinderDataBinding.ItemHolder<PermissionAssignmentData> getPermissions(@NotNull final TypedFinderBuilder.DimensionObjects dimensions, @NotNull final AuthorityHolder authorityHolder, @NotNull final ServiceLocator serviceLocator) {
/* The rest of the code in this method is mostly performance optimization producing the same results (with possibly changed sorting).
if (true) {
List<Permission> globalPermissions = authorityHolder.getGlobalPermissions().toList();
Set<Permission> globalPermissionsSet = new HashSet<>(globalPermissions); //TeamCity API issue: this set is used to exclude global permissions from project-level ones
return FinderDataBinding.getItemHolder(Stream.concat(
globalPermissions.stream().map(p -> new PermissionAssignmentData(p)),
authorityHolder.getProjectsPermissions().entrySet().stream().flatMap(
entry -> entry.getValue().toList().stream().filter(p -> !globalPermissionsSet.contains(p)).map(p -> new PermissionAssignmentData(p, entry.getKey())))));
}
*/
List<Permission> permissions_raw = dimensions.get(PERMISSION);
List<List<SProject>> projects_raw = dimensions.get(PROJECT);
if (projects_raw != null && !projects_raw.isEmpty() && projects_raw.size() > 1) {
throw new BadRequestException("Multiple projects dimensions are not supported");
}
@Nullable List<SProject> projects = projects_raw == null || projects_raw.isEmpty() ? null : projects_raw.get(0);
if (permissions_raw != null && !permissions_raw.isEmpty() && permissions_raw.size() > 1) {
throw new BadRequestException("Multiple permissions dimensions are not supported");
}
// permissions_raw is ANDed, permissions is ORed, but so far it is not supported: todo implement
List<Permission> permissions = permissions_raw;
Stream<PermissionAssignmentData> result = Stream.empty();
List<Boolean> global_raw = dimensions.get(GLOBAL);
if (global_raw != null && !global_raw.isEmpty() && global_raw.size() > 1) {
throw new BadRequestException("Multiple global dimensions are not supported");
}
Boolean global = global_raw == null ? null : global_raw.get(0);
if ((permissions == null || permissions.isEmpty())) {
if (projects == null) {
if (global == null || global) {
result = Stream.concat(result, authorityHolder.getGlobalPermissions().toList().stream().map(p -> new PermissionAssignmentData(p)));
}
if (global == null || !global) {
result = Stream.concat(result, authorityHolder.getProjectsPermissions().entrySet().stream().flatMap(entry -> entry.getValue().toList().stream().filter(p -> p.isProjectAssociationSupported()).map(p -> new PermissionAssignmentData(p, entry.getKey()))));
}
return FinderDataBinding.getItemHolder(result);
}
if (global == null || global) {
result = Stream.concat(result, authorityHolder.getGlobalPermissions().toList().stream().filter(p -> p.isProjectAssociationSupported()).map(p -> new PermissionAssignmentData(p)));
}
if (global == null || !global) {
result = Stream.concat(result, projects.stream().flatMap(project -> {
Permissions projectPermissions = authorityHolder.getProjectsPermissions().get(project.getProjectId());
return projectPermissions == null ? Stream.empty() : projectPermissions.toList().stream().filter(p -> p.isProjectAssociationSupported()).map(p -> new PermissionAssignmentData(p, project.getProjectId()));
}));
}
return FinderDataBinding.getItemHolder(result);
}
if (projects == null) {
if (global == null || global) {
result = Stream.concat(result, permissions.stream().filter(p -> authorityHolder.isPermissionGrantedGlobally(p)).map(p -> new PermissionAssignmentData(p)));
}
if (global == null || !global) {
List<SProject> allProjects = serviceLocator.getSingletonService(ProjectManager.class).getProjects();
result = Stream.concat(result, permissions.stream().filter(p -> p.isProjectAssociationSupported()).flatMap(p -> allProjects.stream().filter(project -> {
Permissions projectPermissions = authorityHolder.getProjectsPermissions().get(project.getProjectId());
return projectPermissions != null && projectPermissions.contains(p);
}).map(project -> new PermissionAssignmentData(p, project.getProjectId()))));
}
return FinderDataBinding.getItemHolder(result);
}
if (global == null || global) {
result = Stream.concat(result, permissions.stream().filter(p -> p.isProjectAssociationSupported()).filter(p -> authorityHolder.isPermissionGrantedGlobally(p)).map(p -> new PermissionAssignmentData(p)));
}
if (global == null || !global) {
result = Stream.concat(result, projects.stream().flatMap(project -> permissions.stream().filter(p -> p.isProjectAssociationSupported()).filter(p -> {
Permissions projectPermissions = authorityHolder.getProjectsPermissions().get(project.getProjectId());
return projectPermissions != null && projectPermissions.contains(p);
}).map(p -> new PermissionAssignmentData(p, project.getProjectId()))));
}
return FinderDataBinding.getItemHolder(result);
}
Aggregations