Skip to content

Commit 3731bf3

Browse files
committed
New submission data format
relates to #5
1 parent 5aa9d1d commit 3731bf3

File tree

5 files changed

+92
-24
lines changed

5 files changed

+92
-24
lines changed

common/src/main/java/net/modfest/platform/gson/GsonCommon.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public static void configureGson(GsonBuilder builder) {
1717
.registerTypeHierarchyAdapter(Enum.class, new EnumToLowerCaseJsonConverter())
1818
.registerTypeAdapter(Instant.class, new InstantSerializer())
1919
.registerTypeAdapter(EventData.DescriptionItem.class, new EventData.DescriptionItem.TypeAdapter())
20-
.registerTypeAdapter(SubmissionData.FileData.class, new SubmissionData.FileData.TypeAdapter())
20+
.registerTypeAdapter(SubmissionData.AssociatedData.class, new SubmissionData.AssociatedData.TypeAdapter())
2121
.setPrettyPrinting()
2222
.serializeNulls()
2323
.setLenient();

common/src/main/java/net/modfest/platform/pojo/SubmissionData.java

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ public record SubmissionData(@NonNull String id,
1212
@NonNull String name,
1313
@NonNull String description,
1414
@NonNull Set<String> authors,
15-
@Nullable FileData platform,
15+
SubmissionData.@NonNull AssociatedData platform,
1616
@NonNull Images images,
17-
@Nullable String download,
1817
@Nullable String source,
1918
@NonNull Awards awards
2019
) implements Data {
@@ -25,21 +24,27 @@ public record Images(@Nullable String icon, @Nullable String screenshot) {
2524
public record Awards(Set<String> theme, Set<String> extra) {
2625
}
2726

28-
public record FileData(Object inner) {
29-
30-
public record Modrinth(String projectId, String versionId) {
27+
/**
28+
* <ul>
29+
* <li>Modrinth mod: Contains a {@link Modrinth} object with a version id. Url is based on the project id, and the version id is used for inclusion in the pack</li>
30+
* <li>Modrinth non-project: Contains a {@link Modrinth} object but without a version id. Not included in the pack</li>
31+
* <li>Other mod: Contains a {@link Other} object. If it has a {@link Other#downloadUrl} then it's included in the pack</li>
32+
* </ul>
33+
*/
34+
public record AssociatedData(Object inner) {
35+
public record Modrinth(String projectId, @Nullable String versionId) {
3136
public static final String KEY = "modrinth";
3237
}
3338

34-
public record Github(String namespace, String repo) {
35-
public static final String KEY = "github";
39+
public record Other(@Nullable String homepageUrl, @Nullable String downloadUrl) {
40+
public static final String KEY = "other";
3641
}
3742

38-
public static class TypeAdapter implements JsonSerializer<FileData>, JsonDeserializer<FileData> {
43+
public static class TypeAdapter implements JsonSerializer<AssociatedData>, JsonDeserializer<AssociatedData> {
3944
@Override
40-
public FileData deserialize(JsonElement json,
41-
Type typeOfT,
42-
JsonDeserializationContext context) throws JsonParseException {
45+
public AssociatedData deserialize(JsonElement json,
46+
Type typeOfT,
47+
JsonDeserializationContext context) throws JsonParseException {
4348
JsonObject jsonObject = json.getAsJsonObject();
4449

4550
if (jsonObject == null) {
@@ -49,21 +54,21 @@ public FileData deserialize(JsonElement json,
4954
var typeKey = jsonObject.remove("type").getAsString();
5055

5156
return switch (typeKey) {
52-
case Modrinth.KEY -> new FileData(context.deserialize(jsonObject, Modrinth.class));
53-
case Github.KEY -> new FileData(context.deserialize(jsonObject, Github.class));
57+
case Modrinth.KEY -> new AssociatedData(context.deserialize(jsonObject, Modrinth.class));
58+
case Other.KEY -> new AssociatedData(context.deserialize(jsonObject, Other.class));
5459
default -> null;
5560
};
5661
}
5762

5863
@Override
59-
public JsonElement serialize(FileData src,
64+
public JsonElement serialize(AssociatedData src,
6065
Type typeOfSrc,
6166
JsonSerializationContext context) {
6267
var jsonObj = context.serialize(src.inner).getAsJsonObject();
6368

6469
var typeKey = switch (src.inner) {
6570
case Modrinth a -> Modrinth.KEY;
66-
case Github a -> Github.KEY;
71+
case Other a -> Other.KEY;
6772
default -> throw new IllegalStateException();
6873
};
6974
jsonObj.addProperty("type", typeKey);

platform_api/src/main/java/net/modfest/platform/migrations/Migrator.java

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@
1313
import java.text.SimpleDateFormat;
1414
import java.util.*;
1515
import java.util.function.Function;
16+
import java.util.regex.Pattern;
1617

1718
/**
1819
* Contains ad-hoc migrations to our json format
1920
*/
2021
public record Migrator(JsonUtil json, Path root) {
21-
static final int CURRENT_VERSION = 5;
22+
static final int CURRENT_VERSION = 6;
2223
static final Map<Integer,MigrationManager.Migration> MIGRATIONS = new HashMap<>();
2324

2425
static {
@@ -27,6 +28,7 @@ public record Migrator(JsonUtil json, Path root) {
2728
MIGRATIONS.put(3, Migrator::migrateTo3);
2829
MIGRATIONS.put(4, Migrator::migrateTo4);
2930
MIGRATIONS.put(5, Migrator::migrateTo5);
31+
MIGRATIONS.put(6, Migrator::migrateTo6);
3032
}
3133

3234

@@ -222,4 +224,69 @@ public void migrateTo5() {
222224
}
223225
});
224226
}
227+
228+
/**
229+
* V6
230+
* Submission data no longer has a "download" field.
231+
* The "github" platform type was removed.
232+
* There's now an "other" platform type which can optionally contain a
233+
* homepage url (used for frontend) and/or a download url (used for pack)
234+
*/
235+
public void migrateTo6() {
236+
var cursePattern = Pattern.compile("(https://www\\.curseforge\\.com/minecraft/mc-mods/[^/.]+)(/files)?");
237+
var modrinthPattern = Pattern.compile("https://cdn\\.modrinth\\.com/data/([^/]+)/versions/([^/]+)/.*");
238+
var submissions = root.resolve("submissions");
239+
MigratorUtils.executeForAllFiles(submissions, eventDir -> {
240+
MigratorUtils.executeForAllFiles(eventDir, submissionFile -> {
241+
var submission = json.readJson(submissionFile, JsonObject.class);
242+
var id = submission.get("id");
243+
try {
244+
var downloadLink = submission.has("download") ? submission.get("download").getAsString() : null;
245+
submission.remove("download");
246+
247+
var platformData = submission.get("platform");
248+
var type = platformData == null ? "unknown" : platformData.getAsJsonObject().get("type").getAsString();
249+
if (type.equals("unknown")) {
250+
var newPlatformData = new JsonObject();
251+
newPlatformData.addProperty("type", "other");
252+
var cfMatch = downloadLink == null ? null : cursePattern.matcher(downloadLink);
253+
if (downloadLink != null && cfMatch.matches()) {
254+
newPlatformData.add("downloadUrl", JsonNull.INSTANCE);
255+
newPlatformData.addProperty("homepageUrl", cfMatch.group(1));
256+
} else {
257+
newPlatformData.addProperty("downloadUrl", downloadLink);
258+
newPlatformData.add("homepageUrl", JsonNull.INSTANCE);
259+
}
260+
submission.add("platform", newPlatformData);
261+
} else {
262+
if (type.equals("github")) {
263+
throw new IllegalStateException("Github project type no longer exists");
264+
} else if (!type.equals("modrinth")) {
265+
throw new IllegalStateException("Project type "+type+" is invalid");
266+
} else {
267+
// Some sanity checks on the data
268+
if (downloadLink != null) {
269+
var matcher = modrinthPattern.matcher(downloadLink);
270+
if (!matcher.matches()) {
271+
throw new IllegalStateException("Modrinth project should have modrinth download url");
272+
}
273+
var projId = platformData.getAsJsonObject().get("project_id").getAsString();
274+
var versId = platformData.getAsJsonObject().get("version_id").getAsString();
275+
if (!matcher.group(1).equals(projId)) {
276+
throw new IllegalStateException("project id in download url doesn't match modrinth project data");
277+
}
278+
if (!matcher.group(2).equals(versId) && !matcher.group(2).contains(".")) {
279+
throw new IllegalStateException("version id in download url doesn't match modrinth project data");
280+
}
281+
}
282+
}
283+
}
284+
json.writeJson(submissionFile, submission);
285+
} catch (Throwable e) {
286+
throw new IllegalStateException("Error migrating "+id, e);
287+
}
288+
});
289+
});
290+
291+
}
225292
}

platform_api/src/main/java/net/modfest/platform/service/SubmissionService.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,23 +84,20 @@ public SubmissionData makeModrinthSubmission(String eventId, String mrProjectId)
8484
throw new RuntimeException("No latest version");
8585
}
8686

87-
var primaryFile = latest.files.stream().filter(f -> f.primary).findAny().orElse(latest.files.get(0));
88-
8987
submissionRepository.save(
9088
new SubmissionData(
9189
subId,
9290
eventId,
9391
project.title,
9492
project.description,
9593
authors.map(UserData::id).collect(Collectors.toSet()),
96-
new SubmissionData.FileData(
97-
new SubmissionData.FileData.Modrinth(
94+
new SubmissionData.AssociatedData(
95+
new SubmissionData.AssociatedData.Modrinth(
9896
project.id,
9997
latest.id
10098
)
10199
),
102100
getImages(project),
103-
primaryFile.url,
104101
project.sourceUrl,
105102
new SubmissionData.Awards(
106103
Set.of(),

platform_api/src/test/java/net/modfest/platform/JsonTests.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,14 @@ public static List<Object> testObjects() {
7373
"a b",
7474
"dawda",
7575
Set.of("Bob"),
76-
new SubmissionData.FileData(new SubmissionData.FileData.Modrinth(
76+
new SubmissionData.AssociatedData(new SubmissionData.AssociatedData.Modrinth(
7777
"dwaodi",
7878
"dwdadw"
7979
)),
8080
new SubmissionData.Images(
8181
"e",
8282
"b"
8383
),
84-
"https://a",
8584
"bb",
8685
new SubmissionData.Awards(
8786
Set.of(),

0 commit comments

Comments
 (0)