diff --git a/gradle.properties b/gradle.properties index 45a6a4e76..1f9ea4ee1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,7 +18,7 @@ nocatchVersion=1.1 junitAddonsVersion=1.4 githubApiVersion=1.84 jgitVersionn=4.5.0.201609210915-r -fafCommonsVersion=1172e1b0 +fafCommonsVersion=4ca1f756 h2Version=1.4.193 jacksonDatatypeJsr310Version=2.9.7 mockitoVersion=2.23.4 diff --git a/src/main/java/com/faforever/api/map/MapLuaAccessor.java b/src/main/java/com/faforever/api/map/MapLuaAccessor.java index f9bc3cde1..832e929db 100644 --- a/src/main/java/com/faforever/api/map/MapLuaAccessor.java +++ b/src/main/java/com/faforever/api/map/MapLuaAccessor.java @@ -21,7 +21,7 @@ public class MapLuaAccessor { private static final String CONFIGURATION_STANDARD_TEAMS = "teams"; private static final String CONFIGURATION_STANDARD_TEAMS_NAME = "name"; private static final String CONFIGURATION_STANDARD_TEAMS_ARMIES = "armies"; - + private static final String ADAPTIVE_MAP = "AdaptiveMap"; private final LuaAccessor luaAccessor; @@ -61,8 +61,12 @@ public OptionalInt getNoRushRadius() { return luaAccessor.readVariableInt(NO_RUSH_RADIUS); } - public boolean hasVariableMatching(String regex, String... names) { - return luaAccessor.hasVariableMatching(regex, names); + public Optional isAdaptive() { + return luaAccessor.readVariableBool(ADAPTIVE_MAP); + } + + public boolean hasVariableMatchingIgnoreCase(String regex, String... names) { + return luaAccessor.hasVariableMatchingIgnoreCase(regex, names); } public Optional getFirstTeam() { @@ -106,4 +110,7 @@ public boolean hasInvalidTeam() { return getFirstTeam().get(); } + public boolean isAdaptive$() { + return isAdaptive().get(); + } } diff --git a/src/main/java/com/faforever/api/map/MapService.java b/src/main/java/com/faforever/api/map/MapService.java index 446134cdc..dac9a6dfc 100644 --- a/src/main/java/com/faforever/api/map/MapService.java +++ b/src/main/java/com/faforever/api/map/MapService.java @@ -55,7 +55,7 @@ import static com.faforever.api.map.MapService.ScenarioMapInfo.FILE_ENDING_SAVE; import static com.faforever.api.map.MapService.ScenarioMapInfo.FILE_ENDING_SCENARIO; import static com.faforever.api.map.MapService.ScenarioMapInfo.FILE_ENDING_SCRIPT; -import static com.faforever.api.map.MapService.ScenarioMapInfo.REQUIRED_FILES; +import static com.faforever.api.map.MapService.ScenarioMapInfo.MANDATORY_FILES; import static com.github.nocatch.NoCatch.noCatch; import static java.text.MessageFormat.format; @@ -162,12 +162,18 @@ public void uploadMap(InputStream mapDataInputStream, String mapFilename, Player try { Path unzippedFileFolder = unzipToTemporaryDirectory(mapDataInputStream, rootTempFolder); Path mapFolder = validateMapFolderStructure(unzippedFileFolder); - validateMandatoryFiles(mapFolder); + validateRequiredFiles(mapFolder, MANDATORY_FILES); MapLuaAccessor mapLua = parseScenarioLua(mapFolder); MapNameBuilder mapNameBuilder = new MapNameBuilder(mapLua.getName() .orElseThrow(() -> ApiException.of(ErrorCode.MAP_NAME_MISSING))); + mapLua.isAdaptive().ifPresent(isAdaptive -> { + if (isAdaptive) { + validateRequiredFiles(mapFolder, ADAPTIVE_REQUIRED_FILES); + } + }); + validateScenarioLua(mapLua, mapNameBuilder); Optional existingMapOptional = validateMapMetadata(mapLua, mapNameBuilder, author); @@ -223,13 +229,14 @@ private Path validateMapFolderStructure(Path zipContentFolder) throws IOExceptio return mapFolder; } - private void validateMandatoryFiles(Path mapFolder) throws IOException { + @SneakyThrows + private void validateRequiredFiles(Path mapFolder, String[] requiredFiles) { try (Stream mapFileStream = Files.list(mapFolder)) { List fileNames = mapFileStream .map(Path::toString) .collect(Collectors.toList()); - List errors = Arrays.stream(REQUIRED_FILES) + List errors = Arrays.stream(requiredFiles) .filter(requiredEnding -> fileNames.stream().noneMatch(fileName -> fileName.endsWith(requiredEnding))) .map(requiredEnding -> new Error(ErrorCode.MAP_FILE_INSIDE_ZIP_MISSING, requiredEnding)) .collect(Collectors.toList()); @@ -293,7 +300,7 @@ private Optional validateLuaPathVariable(MapLuaAccessor mapLua, String va String regex = format("\\/maps\\/{0}(\\.v\\d{4})?\\/{1}", mapFolderNameWithoutVersion, mapFileName); - if (!mapLua.hasVariableMatching(regex, variableName)) { + if (!mapLua.hasVariableMatchingIgnoreCase(regex, variableName)) { return Optional.of(new Error(ErrorCode.MAP_SCRIPT_LINE_MISSING, format("{0} = ''/maps/{1}/{2}''", variableName, mapFolderNameWithoutVersion, mapFileName))); } @@ -425,7 +432,7 @@ static class ScenarioMapInfo { static final String FILE_DECLARATION_SCRIPT = "script"; static final String FILE_ENDING_SCRIPT = "_script.lua"; - static final String[] REQUIRED_FILES = new String[]{ + static final String[] MANDATORY_FILES = new String[]{ FILE_ENDING_SCENARIO, FILE_ENDING_MAP, FILE_ENDING_SAVE, diff --git a/src/test/java/com/faforever/api/map/MapServiceTest.java b/src/test/java/com/faforever/api/map/MapServiceTest.java index 9e832c076..257ac0993 100644 --- a/src/test/java/com/faforever/api/map/MapServiceTest.java +++ b/src/test/java/com/faforever/api/map/MapServiceTest.java @@ -290,6 +290,18 @@ void noMapName() { verify(mapRepository, never()).save(any(com.faforever.api.data.domain.Map.class)); } + @Test + void adaptiveFilesMissing() { + String zipFilename = "adaptive_map_files_missing.zip"; + InputStream mapData = loadMapAsInputSteam(zipFilename); + ApiException result = assertThrows(ApiException.class, () -> instance.uploadMap(mapData, zipFilename, author, true)); + assertThat(result, hasErrorCodes( + ErrorCode.MAP_FILE_INSIDE_ZIP_MISSING, + ErrorCode.MAP_FILE_INSIDE_ZIP_MISSING + )); + verify(mapRepository, never()).save(any(com.faforever.api.data.domain.Map.class)); + } + @Test void invalidScenario() { String zipFilename = "invalid_scenario.zip"; diff --git a/src/test/resources/maps/adaptive_map_files_missing.zip b/src/test/resources/maps/adaptive_map_files_missing.zip new file mode 100644 index 000000000..5db1a48b0 Binary files /dev/null and b/src/test/resources/maps/adaptive_map_files_missing.zip differ