mirror of
https://github.com/HangarMC/Hangar.git
synced 2024-11-27 06:01:08 +08:00
work on version downloads
This commit is contained in:
parent
04fd9bea16
commit
e375ea6dc1
@ -29,7 +29,7 @@ export default class ProjectVersionPageParent extends HangarProjectMixin {
|
||||
|
||||
async asyncData({ $api, $util, params, error, redirect, route }: Context) {
|
||||
const versions = await $api
|
||||
.requestInternal<HangarVersion[]>(`versions/version/${params.author}/${params.slug}/versions/${params.version}`)
|
||||
.requestInternal<HangarVersion[]>(`versions/version/${params.author}/${params.slug}/versions/${params.version}`, false)
|
||||
.catch<any>($util.handlePageRequestError);
|
||||
if (typeof versions === 'undefined' || versions.length < 1) {
|
||||
return error({
|
||||
|
@ -30,6 +30,7 @@ public class ProjectsConfig {
|
||||
private String checkInterval = "1h";
|
||||
private String draftExpire = "1d";
|
||||
private int userGridPageSize = 30;
|
||||
@DurationUnit(ChronoUnit.MINUTES)
|
||||
private Duration unsafeDownloadMaxAge = Duration.ofMinutes(10);
|
||||
|
||||
public String getNameRegex() {
|
||||
|
@ -17,10 +17,11 @@ import io.papermc.hangar.security.annotations.permission.PermissionRequired;
|
||||
import io.papermc.hangar.security.annotations.visibility.VisibilityRequired;
|
||||
import io.papermc.hangar.security.annotations.visibility.VisibilityRequired.Type;
|
||||
import io.papermc.hangar.service.api.VersionsApiService;
|
||||
import io.papermc.hangar.service.internal.versions.DownloadService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
@ -28,37 +29,52 @@ import java.util.Map;
|
||||
|
||||
@Anyone
|
||||
@Controller
|
||||
@ResponseBody
|
||||
public class VersionsController implements IVersionsController {
|
||||
|
||||
private final DownloadService downloadService;
|
||||
private final VersionsApiService versionsApiService;
|
||||
|
||||
@Autowired
|
||||
public VersionsController(VersionsApiService versionsApiService) {
|
||||
public VersionsController(DownloadService downloadService, VersionsApiService versionsApiService) {
|
||||
this.downloadService = downloadService;
|
||||
this.versionsApiService = versionsApiService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@VisibilityRequired(type = Type.VERSION, args = "{#author, #slug, #versionString, #platform}")
|
||||
public ResponseEntity<Version> getVersion(String author, String slug, String versionString, Platform platform) {
|
||||
return ResponseEntity.ok(versionsApiService.getVersion(author, slug, versionString, platform));
|
||||
public Version getVersion(String author, String slug, String versionString, Platform platform) {
|
||||
return versionsApiService.getVersion(author, slug, versionString, platform);
|
||||
}
|
||||
|
||||
@Override
|
||||
@VisibilityRequired(type = Type.PROJECT, args = "{#author, #slug}")
|
||||
public ResponseEntity<List<Version>> getVersions(String author, String slug, String name) {
|
||||
return ResponseEntity.ok(versionsApiService.getVersions(author, slug, name));
|
||||
public List<Version> getVersions(String author, String slug, String name) {
|
||||
return versionsApiService.getVersions(author, slug, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@VisibilityRequired(type = Type.PROJECT, args = "{#author, #slug}")
|
||||
@ApplicableFilters({VersionChannelFilter.class, VersionPlatformFilter.class, VersionTagFilter.class})
|
||||
public ResponseEntity<PaginatedResult<Version>> getVersions(String author, String slug, @NotNull RequestPagination pagination) {
|
||||
return ResponseEntity.ok(versionsApiService.getVersions(author, slug, pagination));
|
||||
public PaginatedResult<Version> getVersions(String author, String slug, @NotNull RequestPagination pagination) {
|
||||
return versionsApiService.getVersions(author, slug, pagination);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PermissionRequired(type = PermissionType.PROJECT, perms = NamedPermission.IS_SUBJECT_MEMBER, args = "{#author, #slug}")
|
||||
public ResponseEntity<Map<String, VersionStats>> getVersionStats(String author, String slug, String versionString, Platform platform, @NotNull OffsetDateTime fromDate, @NotNull OffsetDateTime toDate) {
|
||||
return ResponseEntity.ok(versionsApiService.getVersionStats(author, slug, versionString, platform, fromDate, toDate));
|
||||
public Map<String, VersionStats> getVersionStats(String author, String slug, String versionString, Platform platform, @NotNull OffsetDateTime fromDate, @NotNull OffsetDateTime toDate) {
|
||||
return versionsApiService.getVersionStats(author, slug, versionString, platform, fromDate, toDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
@VisibilityRequired(type = Type.VERSION, args = "{#author, #slug, #versionString, #platform}")
|
||||
public String confirmVersionDownload(String author, String slug, String versionString, Platform platform) {
|
||||
return downloadService.createConfirmationToken(author, slug, versionString, platform);
|
||||
}
|
||||
|
||||
@Override
|
||||
@VisibilityRequired(type = Type.VERSION, args = "{#author, #slug, #versionString, #platform}")
|
||||
public Object downloadVersion(String author, String slug, String versionString, Platform platform, String token) {
|
||||
return downloadService.getVersionFile(author, slug, versionString, platform, token);
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,7 @@ import io.papermc.hangar.model.api.PaginatedResult;
|
||||
import io.papermc.hangar.model.api.project.version.Version;
|
||||
import io.papermc.hangar.model.api.project.version.VersionStats;
|
||||
import io.papermc.hangar.model.api.requests.RequestPagination;
|
||||
import io.papermc.hangar.model.common.NamedPermission;
|
||||
import io.papermc.hangar.model.common.PermissionType;
|
||||
import io.papermc.hangar.model.common.Platform;
|
||||
import io.papermc.hangar.security.annotations.permission.PermissionRequired;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
@ -16,7 +13,6 @@ import io.swagger.annotations.ApiResponses;
|
||||
import io.swagger.annotations.Authorization;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -30,6 +26,7 @@ import java.util.Map;
|
||||
@RequestMapping(path = "/api/v1", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public interface IVersionsController {
|
||||
|
||||
// TODO implement version creation via API
|
||||
/* @ApiOperation(
|
||||
value = "Creates a new version",
|
||||
nickname = "deployVersion",
|
||||
@ -42,7 +39,7 @@ public interface IVersionsController {
|
||||
@ApiResponse(code = 401, message = "Api session missing, invalid or expired"),
|
||||
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint")
|
||||
})
|
||||
@PostMapping(value = "/projects/{author}/{slug}/versions", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
@PostMapping(path = "/projects/{author}/{slug}/versions", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
ResponseEntity<Version> deployVersion()*/
|
||||
|
||||
@ApiOperation(
|
||||
@ -57,12 +54,11 @@ public interface IVersionsController {
|
||||
@ApiResponse(code = 401, message = "Api session missing, invalid or expired"),
|
||||
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint")
|
||||
})
|
||||
@GetMapping(value = "/projects/{author}/{slug}/versions/{name}/{platform}/")
|
||||
ResponseEntity<Version> getVersion(@ApiParam("The author of the project to return the version for") @PathVariable String author,
|
||||
@ApiParam("The slug of the project to return") @PathVariable String slug,
|
||||
@ApiParam("The name of the version to return") @PathVariable("name") String versionString,
|
||||
@ApiParam("The platform of the version to return") @PathVariable Platform platform
|
||||
);
|
||||
@GetMapping("/projects/{author}/{slug}/versions/{name}/{platform}/")
|
||||
Version getVersion(@ApiParam("The author of the project to return the version for") @PathVariable String author,
|
||||
@ApiParam("The slug of the project to return") @PathVariable String slug,
|
||||
@ApiParam("The name of the version to return") @PathVariable("name") String versionString,
|
||||
@ApiParam("The platform of the version to return") @PathVariable Platform platform);
|
||||
|
||||
@ApiOperation(
|
||||
value = "Returns versions of a project with the specified version string",
|
||||
@ -76,11 +72,10 @@ public interface IVersionsController {
|
||||
@ApiResponse(code = 401, message = "Api session missing, invalid or expired"),
|
||||
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint")
|
||||
})
|
||||
@GetMapping(value = "/projects/{author}/{slug}/versions/{name}")
|
||||
ResponseEntity<List<Version>> getVersions(@ApiParam("The author of the project to return the versions for") @PathVariable String author,
|
||||
@ApiParam("The slug of the project to return") @PathVariable String slug,
|
||||
@ApiParam("The name of the versions to return") @PathVariable("name") String versionString
|
||||
);
|
||||
@GetMapping("/projects/{author}/{slug}/versions/{name}")
|
||||
List<Version> getVersions(@ApiParam("The author of the project to return the versions for") @PathVariable String author,
|
||||
@ApiParam("The slug of the project to return") @PathVariable String slug,
|
||||
@ApiParam("The name of the versions to return") @PathVariable("name") String versionString);
|
||||
|
||||
@ApiOperation(
|
||||
value = "Returns the versions of a project",
|
||||
@ -95,10 +90,9 @@ public interface IVersionsController {
|
||||
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint")
|
||||
})
|
||||
@GetMapping("/projects/{author}/{slug}/versions")
|
||||
ResponseEntity<PaginatedResult<Version>> getVersions(@ApiParam("The author of the project to return versions for") @PathVariable String author,
|
||||
@ApiParam("The slug of the project to return versions for") @PathVariable String slug,
|
||||
@ApiParam("Pagination information") @NotNull RequestPagination pagination
|
||||
);
|
||||
PaginatedResult<Version> getVersions(@ApiParam("The author of the project to return versions for") @PathVariable String author,
|
||||
@ApiParam("The slug of the project to return versions for") @PathVariable String slug,
|
||||
@ApiParam("Pagination information") @NotNull RequestPagination pagination);
|
||||
|
||||
@ApiOperation(
|
||||
value = "Returns the stats for a version",
|
||||
@ -113,13 +107,50 @@ public interface IVersionsController {
|
||||
@ApiResponse(code = 401, message = "Api session missing, invalid or expired"),
|
||||
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint")
|
||||
})
|
||||
@GetMapping(value = "/projects/{author}/{slug}/versions/{name}/{platform}/stats", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@PermissionRequired(type = PermissionType.PROJECT, perms = NamedPermission.IS_SUBJECT_MEMBER, args = "{#author, #slug}")
|
||||
ResponseEntity<Map<String, VersionStats>> getVersionStats(@ApiParam("The author of the version to return the stats for") @PathVariable String author,
|
||||
@ApiParam("The slug of the project to return stats for") @PathVariable String slug,
|
||||
@ApiParam("The version to return the stats for") @PathVariable("name") String versionString,
|
||||
@ApiParam("The platform of the version to return") @PathVariable Platform platform,
|
||||
@ApiParam(value = "The first date to include in the result", required = true) @RequestParam @NotNull OffsetDateTime fromDate,
|
||||
@ApiParam(value = "The last date to include in the result", required = true) @RequestParam @NotNull OffsetDateTime toDate
|
||||
);
|
||||
@GetMapping("/projects/{author}/{slug}/versions/{name}/{platform}/stats")
|
||||
Map<String, VersionStats> getVersionStats(@ApiParam("The author of the version to return the stats for") @PathVariable String author,
|
||||
@ApiParam("The slug of the project to return stats for") @PathVariable String slug,
|
||||
@ApiParam("The version to return the stats for") @PathVariable("name") String versionString,
|
||||
@ApiParam("The platform of the version to return") @PathVariable Platform platform,
|
||||
@ApiParam(value = "The first date to include in the result", required = true) @RequestParam @NotNull OffsetDateTime fromDate,
|
||||
@ApiParam(value = "The last date to include in the result", required = true) @RequestParam @NotNull OffsetDateTime toDate);
|
||||
|
||||
@ApiOperation(
|
||||
value = "Gets a confirmation token for downloading a version",
|
||||
nickname = "confirmVersionDownload",
|
||||
notes = "Retrieves a token to use for downloading a version which requires user confirmation",
|
||||
authorizations = @Authorization("Session"),
|
||||
tags = "Versions"
|
||||
)
|
||||
@ApiResponses({
|
||||
@ApiResponse(code = 200, message = "Ok"),
|
||||
@ApiResponse(code = 401, message = "Api session missing, invalid or expired"),
|
||||
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint")
|
||||
})
|
||||
@GetMapping("/projects/{author}/{slug}/versions/{name}/{platform}/download/confirm")
|
||||
String confirmVersionDownload(@ApiParam("The author of the project to return the version for") @PathVariable String author,
|
||||
@ApiParam("The slug of the project to return") @PathVariable String slug,
|
||||
@ApiParam("The name of the version to return") @PathVariable("name") String versionString,
|
||||
@ApiParam("The platform of the version to return") @PathVariable Platform platform);
|
||||
|
||||
@ApiOperation(
|
||||
value = "Downloads a version",
|
||||
nickname = "downloadVersion",
|
||||
notes = "Downloads the file for a specific platform of a version. Requires visibility of the project and version.",
|
||||
authorizations = @Authorization("Session"),
|
||||
tags = "Versions"
|
||||
)
|
||||
@ApiResponses({
|
||||
@ApiResponse(code = 200, message = "Ok"),
|
||||
@ApiResponse(code = 303, message = "Version has an external download url"),
|
||||
@ApiResponse(code = 401, message = "Api session missing, invalid or expired"),
|
||||
@ApiResponse(code = 403, message = "Not enough permissions to use this endpoint"),
|
||||
@ApiResponse(code = 412, message = "Requires confirmation token, and none found on request")
|
||||
})
|
||||
@GetMapping("/projects/{author}/{slug}/versions/{name}/{platform}/download")
|
||||
Object downloadVersion(@ApiParam("The author of the project to return the version for") @PathVariable String author,
|
||||
@ApiParam("The slug of the project to return") @PathVariable String slug,
|
||||
@ApiParam("The name of the version to return") @PathVariable("name") String versionString,
|
||||
@ApiParam("The platform of the version to return") @PathVariable Platform platform,
|
||||
@ApiParam(value = "The confirmation token") @RequestParam(required = false) String token);
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Controller("oldVersionsController")
|
||||
@Deprecated(forRemoval = true)
|
||||
public class VersionsController extends HangarController {
|
||||
|
||||
private final VersionService versionService;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package io.papermc.hangar.db.dao.internal.table.versions;
|
||||
package io.papermc.hangar.db.dao.internal.table.versions.dependencies;
|
||||
|
||||
import io.papermc.hangar.model.common.Platform;
|
||||
import io.papermc.hangar.model.db.versions.ProjectVersionDependencyTable;
|
||||
import io.papermc.hangar.model.db.versions.dependencies.ProjectVersionDependencyTable;
|
||||
import org.jdbi.v3.core.enums.EnumByOrdinal;
|
||||
import org.jdbi.v3.sqlobject.config.KeyColumn;
|
||||
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;
|
@ -1,7 +1,7 @@
|
||||
package io.papermc.hangar.db.dao.internal.table.versions;
|
||||
package io.papermc.hangar.db.dao.internal.table.versions.dependencies;
|
||||
|
||||
import io.papermc.hangar.model.common.Platform;
|
||||
import io.papermc.hangar.model.db.versions.ProjectVersionPlatformDependencyTable;
|
||||
import io.papermc.hangar.model.db.versions.dependencies.ProjectVersionPlatformDependencyTable;
|
||||
import org.jdbi.v3.core.enums.EnumByOrdinal;
|
||||
import org.jdbi.v3.sqlobject.config.KeyColumn;
|
||||
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;
|
@ -0,0 +1,27 @@
|
||||
package io.papermc.hangar.db.dao.internal.table.versions.downloads;
|
||||
|
||||
import io.papermc.hangar.model.db.versions.downloads.ProjectVersionDownloadWarningTable;
|
||||
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;
|
||||
import org.jdbi.v3.sqlobject.customizer.BindBean;
|
||||
import org.jdbi.v3.sqlobject.customizer.Timestamped;
|
||||
import org.jdbi.v3.sqlobject.statement.SqlQuery;
|
||||
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
@Repository
|
||||
@RegisterConstructorMapper(ProjectVersionDownloadWarningTable.class)
|
||||
public interface ProjectVersionDownloadWarningsDAO {
|
||||
|
||||
@Timestamped
|
||||
@SqlUpdate("INSERT INTO project_version_download_warnings (created_at, expires_at, token, version_id, address, download_id) VALUES (:now, :expiresAt, :token, :versionId, :address, :downloadId)")
|
||||
void insert(@BindBean ProjectVersionDownloadWarningTable projectVersionDownloadWarningTable);
|
||||
|
||||
@SqlQuery(" SELECT * " +
|
||||
" FROM project_version_download_warnings " +
|
||||
" WHERE token = :token AND" +
|
||||
" address = :address AND" +
|
||||
" version_id = :versionId")
|
||||
ProjectVersionDownloadWarningTable findWarning(String token, InetAddress address, long versionId);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package io.papermc.hangar.db.dao.internal.table.versions.downloads;
|
||||
|
||||
import io.papermc.hangar.model.db.versions.downloads.ProjectVersionUnsafeDownloadTable;
|
||||
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;
|
||||
import org.jdbi.v3.sqlobject.customizer.BindBean;
|
||||
import org.jdbi.v3.sqlobject.customizer.Timestamped;
|
||||
import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys;
|
||||
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
@RegisterConstructorMapper(ProjectVersionUnsafeDownloadTable.class)
|
||||
public interface ProjectVersionUnsafeDownloadsDAO {
|
||||
|
||||
@Timestamped
|
||||
@GetGeneratedKeys
|
||||
@SqlUpdate("INSERT INTO project_version_unsafe_downloads (created_at, user_id, address) VALUES (:now, :userId, :address)")
|
||||
ProjectVersionUnsafeDownloadTable insert(@BindBean ProjectVersionUnsafeDownloadTable projectVersionUnsafeDownloadTable);
|
||||
}
|
@ -7,6 +7,7 @@ import org.jdbi.v3.core.enums.EnumByOrdinal;
|
||||
import java.net.InetAddress;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
public class ProjectVersionUnsafeDownloadsTable {
|
||||
|
||||
private long id;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package io.papermc.hangar.model.db.versions;
|
||||
package io.papermc.hangar.model.db.versions.dependencies;
|
||||
|
||||
import io.papermc.hangar.model.common.Platform;
|
||||
import org.jdbi.v3.core.enums.EnumByOrdinal;
|
@ -1,4 +1,4 @@
|
||||
package io.papermc.hangar.model.db.versions;
|
||||
package io.papermc.hangar.model.db.versions.dependencies;
|
||||
|
||||
import org.jdbi.v3.core.mapper.reflect.JdbiConstructor;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package io.papermc.hangar.model.db.versions;
|
||||
package io.papermc.hangar.model.db.versions.dependencies;
|
||||
|
||||
import io.papermc.hangar.model.db.Table;
|
||||
|
@ -0,0 +1,82 @@
|
||||
package io.papermc.hangar.model.db.versions.downloads;
|
||||
|
||||
import io.papermc.hangar.model.db.Table;
|
||||
import org.jdbi.v3.core.mapper.reflect.JdbiConstructor;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ProjectVersionDownloadWarningTable extends Table {
|
||||
|
||||
private final OffsetDateTime expiresAt;
|
||||
private final UUID token;
|
||||
private final long versionId;
|
||||
private final InetAddress address;
|
||||
private boolean confirmed;
|
||||
private Long downloadId;
|
||||
|
||||
public ProjectVersionDownloadWarningTable(OffsetDateTime expiresAt, UUID token, long versionId, InetAddress address) {
|
||||
this.expiresAt = expiresAt;
|
||||
this.token = token;
|
||||
this.versionId = versionId;
|
||||
this.address = address;
|
||||
this.confirmed = false;
|
||||
this.downloadId = null;
|
||||
}
|
||||
|
||||
@JdbiConstructor
|
||||
public ProjectVersionDownloadWarningTable(OffsetDateTime createdAt, long id, OffsetDateTime expiresAt, UUID token, long versionId, InetAddress address, boolean confirmed, Long downloadId) {
|
||||
super(createdAt, id);
|
||||
this.expiresAt = expiresAt;
|
||||
this.token = token;
|
||||
this.versionId = versionId;
|
||||
this.address = address;
|
||||
this.confirmed = confirmed;
|
||||
this.downloadId = downloadId;
|
||||
}
|
||||
|
||||
public OffsetDateTime getExpiresAt() {
|
||||
return expiresAt;
|
||||
}
|
||||
|
||||
public UUID getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public long getVersionId() {
|
||||
return versionId;
|
||||
}
|
||||
|
||||
public InetAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public boolean isConfirmed() {
|
||||
return confirmed;
|
||||
}
|
||||
|
||||
public void setConfirmed(boolean confirmed) {
|
||||
this.confirmed = confirmed;
|
||||
}
|
||||
|
||||
public Long getDownloadId() {
|
||||
return downloadId;
|
||||
}
|
||||
|
||||
public void setDownloadId(Long downloadId) {
|
||||
this.downloadId = downloadId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProjectVersionDownloadWarningTable{" +
|
||||
"expiresAt=" + expiresAt +
|
||||
", token=" + token +
|
||||
", versionId=" + versionId +
|
||||
", address=" + address +
|
||||
", confirmed=" + confirmed +
|
||||
", downloadId=" + downloadId +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package io.papermc.hangar.model.db.versions.downloads;
|
||||
|
||||
import io.papermc.hangar.model.db.Table;
|
||||
import org.jdbi.v3.core.mapper.reflect.JdbiConstructor;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
public class ProjectVersionUnsafeDownloadTable extends Table {
|
||||
|
||||
private final Long userId;
|
||||
private final InetAddress address;
|
||||
|
||||
public ProjectVersionUnsafeDownloadTable(Long userId, InetAddress address) {
|
||||
this.userId = userId;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@JdbiConstructor
|
||||
public ProjectVersionUnsafeDownloadTable(OffsetDateTime createdAt, long id, Long userId, InetAddress address) {
|
||||
super(createdAt, id);
|
||||
this.userId = userId;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public InetAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProjectVersionUnsafeDownloadTable{" +
|
||||
"userId=" + userId +
|
||||
", address=" + address +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package io.papermc.hangar.modelold;
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
public enum DownloadType {
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,103 @@
|
||||
package io.papermc.hangar.service.internal.versions;
|
||||
|
||||
import io.papermc.hangar.HangarComponent;
|
||||
import io.papermc.hangar.db.dao.HangarDao;
|
||||
import io.papermc.hangar.db.dao.internal.table.projects.ProjectsDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionsDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.versions.downloads.ProjectVersionDownloadWarningsDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.versions.downloads.ProjectVersionUnsafeDownloadsDAO;
|
||||
import io.papermc.hangar.exceptions.HangarApiException;
|
||||
import io.papermc.hangar.model.common.Platform;
|
||||
import io.papermc.hangar.model.common.projects.ReviewState;
|
||||
import io.papermc.hangar.model.db.projects.ProjectTable;
|
||||
import io.papermc.hangar.model.db.versions.ProjectVersionTable;
|
||||
import io.papermc.hangar.model.db.versions.downloads.ProjectVersionDownloadWarningTable;
|
||||
import io.papermc.hangar.model.db.versions.downloads.ProjectVersionUnsafeDownloadTable;
|
||||
import io.papermc.hangar.service.internal.admin.StatService;
|
||||
import io.papermc.hangar.service.internal.uploads.ProjectFiles;
|
||||
import io.papermc.hangar.util.RequestUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class DownloadService extends HangarComponent {
|
||||
|
||||
private final StatService statService;
|
||||
private final ProjectFiles projectFiles;
|
||||
private final ProjectsDAO projectsDAO;
|
||||
private final ProjectVersionsDAO projectVersionsDAO;
|
||||
private final ProjectVersionUnsafeDownloadsDAO projectVersionUnsafeDownloadsDAO;
|
||||
private final ProjectVersionDownloadWarningsDAO projectVersionDownloadWarningsDAO;
|
||||
|
||||
@Autowired
|
||||
public DownloadService(StatService statService, ProjectFiles projectFiles, HangarDao<ProjectsDAO> projectsDAO, HangarDao<ProjectVersionsDAO> projectVersionsDAO, HangarDao<ProjectVersionUnsafeDownloadsDAO> projectVersionUnsafeDownloadsDAO, HangarDao<ProjectVersionDownloadWarningsDAO> projectVersionDownloadWarningsDAO) {
|
||||
this.statService = statService;
|
||||
this.projectFiles = projectFiles;
|
||||
this.projectsDAO = projectsDAO.get();
|
||||
this.projectVersionsDAO = projectVersionsDAO.get();
|
||||
this.projectVersionUnsafeDownloadsDAO = projectVersionUnsafeDownloadsDAO.get();
|
||||
this.projectVersionDownloadWarningsDAO = projectVersionDownloadWarningsDAO.get();
|
||||
}
|
||||
|
||||
public String createConfirmationToken(String author, String slug, String versionString, Platform platform) {
|
||||
ProjectVersionTable pvt = projectVersionsDAO.getProjectVersionTable(author, slug, versionString, platform);
|
||||
UUID token = UUID.randomUUID();
|
||||
OffsetDateTime expiresAt = OffsetDateTime.now().plus(config.projects.getUnsafeDownloadMaxAge().toMillis(), ChronoUnit.MILLIS);
|
||||
projectVersionDownloadWarningsDAO.insert(new ProjectVersionDownloadWarningTable(
|
||||
expiresAt,
|
||||
token,
|
||||
pvt.getId(),
|
||||
RequestUtil.getRemoteInetAddress(request)
|
||||
));
|
||||
return token.toString();
|
||||
}
|
||||
|
||||
public Object getVersionFile(String author, String slug, String versionString, Platform platform, @Nullable String token) {
|
||||
ProjectVersionTable pvt = projectVersionsDAO.getProjectVersionTable(author, slug, versionString, platform);
|
||||
if (pvt == null) {
|
||||
throw new HangarApiException(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
ProjectTable project = projectsDAO.getById(pvt.getProjectId());
|
||||
if (!isConfirmed(pvt, token)) {
|
||||
throw new HangarApiException(HttpStatus.PRECONDITION_FAILED);
|
||||
}
|
||||
|
||||
statService.addVersionDownload(pvt);
|
||||
if (pvt.getExternalUrl() != null) {
|
||||
response.setStatus(HttpStatus.SEE_OTHER.value());
|
||||
return new RedirectView(pvt.getExternalUrl());
|
||||
}
|
||||
|
||||
Path path = projectFiles.getVersionDir(project.getOwnerName(), project.getName(), versionString, platform);
|
||||
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + pvt.getFileName() + "\"");
|
||||
return new FileSystemResource(path);
|
||||
}
|
||||
|
||||
private boolean isConfirmed(ProjectVersionTable pvt, @Nullable String token) {
|
||||
if (pvt.getReviewState() == ReviewState.REVIEWED || (pvt.getExternalUrl() != null && config.security.checkSafe(pvt.getExternalUrl()))) {
|
||||
return true;
|
||||
}
|
||||
if (token == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var downloadWarning = projectVersionDownloadWarningsDAO.findWarning(token, RequestUtil.getRemoteInetAddress(request), pvt.getId());
|
||||
if (downloadWarning == null) {
|
||||
return false;
|
||||
}
|
||||
var unsafeDownload = projectVersionUnsafeDownloadsDAO.insert(new ProjectVersionUnsafeDownloadTable(getHangarUserId(), RequestUtil.getRemoteInetAddress(request)));
|
||||
downloadWarning.setConfirmed(true);
|
||||
downloadWarning.setDownloadId(unsafeDownload.getId());
|
||||
return true;
|
||||
}
|
||||
}
|
@ -4,9 +4,9 @@ import io.papermc.hangar.HangarComponent;
|
||||
import io.papermc.hangar.db.dao.HangarDao;
|
||||
import io.papermc.hangar.db.dao.internal.table.PlatformVersionDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.projects.ProjectsDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionDependenciesDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionPlatformDependenciesDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionsDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.versions.dependencies.ProjectVersionDependenciesDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.versions.dependencies.ProjectVersionPlatformDependenciesDAO;
|
||||
import io.papermc.hangar.db.dao.v1.VersionsApiDAO;
|
||||
import io.papermc.hangar.exceptions.HangarApiException;
|
||||
import io.papermc.hangar.model.api.color.TagColor;
|
||||
@ -17,9 +17,9 @@ import io.papermc.hangar.model.common.Platform;
|
||||
import io.papermc.hangar.model.db.PlatformVersionTable;
|
||||
import io.papermc.hangar.model.db.projects.ProjectChannelTable;
|
||||
import io.papermc.hangar.model.db.projects.ProjectTable;
|
||||
import io.papermc.hangar.model.db.versions.ProjectVersionDependencyTable;
|
||||
import io.papermc.hangar.model.db.versions.ProjectVersionPlatformDependencyTable;
|
||||
import io.papermc.hangar.model.db.versions.ProjectVersionTagTable;
|
||||
import io.papermc.hangar.model.db.versions.dependencies.ProjectVersionDependencyTable;
|
||||
import io.papermc.hangar.model.db.versions.dependencies.ProjectVersionPlatformDependencyTable;
|
||||
import io.papermc.hangar.model.internal.api.requests.versions.UpdatePlatformVersions;
|
||||
import io.papermc.hangar.model.internal.api.requests.versions.UpdatePluginDependencies;
|
||||
import io.papermc.hangar.model.internal.logs.LogAction;
|
||||
|
@ -3,9 +3,9 @@ package io.papermc.hangar.service.internal.versions;
|
||||
import io.papermc.hangar.HangarComponent;
|
||||
import io.papermc.hangar.db.dao.HangarDao;
|
||||
import io.papermc.hangar.db.dao.internal.table.PlatformVersionDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionDependenciesDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionPlatformDependenciesDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.versions.ProjectVersionsDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.versions.dependencies.ProjectVersionDependenciesDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.versions.dependencies.ProjectVersionPlatformDependenciesDAO;
|
||||
import io.papermc.hangar.db.dao.v1.VersionsApiDAO;
|
||||
import io.papermc.hangar.exceptions.HangarApiException;
|
||||
import io.papermc.hangar.model.api.project.version.FileInfo;
|
||||
@ -15,10 +15,10 @@ import io.papermc.hangar.model.common.projects.Visibility;
|
||||
import io.papermc.hangar.model.db.PlatformVersionTable;
|
||||
import io.papermc.hangar.model.db.projects.ProjectChannelTable;
|
||||
import io.papermc.hangar.model.db.projects.ProjectTable;
|
||||
import io.papermc.hangar.model.db.versions.ProjectVersionDependencyTable;
|
||||
import io.papermc.hangar.model.db.versions.ProjectVersionPlatformDependencyTable;
|
||||
import io.papermc.hangar.model.db.versions.ProjectVersionTable;
|
||||
import io.papermc.hangar.model.db.versions.ProjectVersionTagTable;
|
||||
import io.papermc.hangar.model.db.versions.dependencies.ProjectVersionDependencyTable;
|
||||
import io.papermc.hangar.model.db.versions.dependencies.ProjectVersionPlatformDependencyTable;
|
||||
import io.papermc.hangar.model.internal.logs.LogAction;
|
||||
import io.papermc.hangar.model.internal.logs.contexts.VersionContext;
|
||||
import io.papermc.hangar.model.internal.versions.PendingVersion;
|
||||
@ -28,6 +28,7 @@ import io.papermc.hangar.service.internal.projects.ChannelService;
|
||||
import io.papermc.hangar.service.internal.projects.ProjectService;
|
||||
import io.papermc.hangar.service.internal.uploads.ProjectFiles;
|
||||
import io.papermc.hangar.service.internal.users.NotificationService;
|
||||
import io.papermc.hangar.service.internal.versions.plugindata.PluginDataService;
|
||||
import io.papermc.hangar.service.internal.versions.plugindata.PluginFileWithData;
|
||||
import io.papermc.hangar.service.internal.visibility.ProjectVisibilityService;
|
||||
import io.papermc.hangar.util.CryptoUtils;
|
||||
|
@ -1,10 +1,7 @@
|
||||
package io.papermc.hangar.service.internal.versions;
|
||||
package io.papermc.hangar.service.internal.versions.plugindata;
|
||||
|
||||
import io.papermc.hangar.exceptions.HangarApiException;
|
||||
import io.papermc.hangar.model.common.Platform;
|
||||
import io.papermc.hangar.service.internal.versions.plugindata.DataValue;
|
||||
import io.papermc.hangar.service.internal.versions.plugindata.PluginFileData;
|
||||
import io.papermc.hangar.service.internal.versions.plugindata.PluginFileWithData;
|
||||
import io.papermc.hangar.service.internal.versions.plugindata.handler.FileTypeHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
@ -10,6 +10,7 @@ import org.springframework.stereotype.Service;
|
||||
import java.net.InetAddress;
|
||||
|
||||
@Service
|
||||
@Deprecated(forRemoval = true)
|
||||
public class DownloadsService {
|
||||
|
||||
private final HangarDao<ProjectVersionUnsafeDownloadsDao> projectVersionUnsafeDownloadsDao;
|
||||
|
@ -0,0 +1,3 @@
|
||||
ALTER TABLE project_version_unsafe_downloads DROP COLUMN download_type;
|
||||
|
||||
ALTER TABLE project_version_download_warnings RENAME expiration TO expiresAt;
|
@ -0,0 +1 @@
|
||||
ALTER TABLE project_version_download_warnings RENAME expiresat TO expires_at;
|
@ -1,7 +1,7 @@
|
||||
package io.papermc.hangar.serviceold.plugindata;
|
||||
|
||||
import io.papermc.hangar.exceptions.HangarException;
|
||||
import io.papermc.hangar.service.internal.versions.PluginDataService;
|
||||
import io.papermc.hangar.service.internal.versions.plugindata.PluginDataService;
|
||||
import io.papermc.hangar.service.internal.versions.plugindata.PluginFileData;
|
||||
import io.papermc.hangar.service.internal.versions.plugindata.handler.PaperPluginFileHandler;
|
||||
import io.papermc.hangar.service.internal.versions.plugindata.handler.VelocityFileHandler;
|
||||
|
Loading…
Reference in New Issue
Block a user