API documentation

This commit is contained in:
Armin Friedl 2020-07-01 20:52:56 +02:00
parent 77ce39244d
commit 3a05120da4
Signed by: armin
GPG key ID: 48C726EEE7FBCBC8
13 changed files with 103 additions and 12 deletions

View file

@ -46,7 +46,7 @@ steps:
dockerfile: container/Dockerfile dockerfile: container/Dockerfile
context: ./container context: ./container
repo: arminfriedl/fling repo: arminfriedl/fling
tags: latest tags: dev
when: when:
branch: branch:
- master - master

View file

@ -21,6 +21,7 @@
<bouncycastle.version>1.64</bouncycastle.version> <bouncycastle.version>1.64</bouncycastle.version>
<jwt.version>0.11.1</jwt.version> <jwt.version>0.11.1</jwt.version>
<spring.version>${project.parent.version}</spring.version> <spring.version>${project.parent.version}</spring.version>
<fling.api.version>${project.version}</fling.api.version>
</properties> </properties>
<dependencies> <dependencies>
@ -102,8 +103,12 @@
<build> <build>
<resources> <resources>
<resource> <resource>
<!-- Replace @spring.profiles.active@ in application.yml by setting <!--
in maven profile See also: profiles section --> Replace @...@ placeholder in resources.
Replaces:
- application.yml | @spring.profiles.active@ | see also: profiles section
- application.yml | @fling.api.version@ | see also: properties
-->
<directory>src/main/resources</directory> <directory>src/main/resources</directory>
<filtering>true</filtering> <filtering>true</filtering>
</resource> </resource>

View file

@ -16,6 +16,12 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.friedl.fling.model.dto.ArtifactDto; import net.friedl.fling.model.dto.ArtifactDto;
import net.friedl.fling.service.ArtifactService; import net.friedl.fling.service.ArtifactService;
@ -24,6 +30,7 @@ import net.friedl.fling.service.archive.ArchiveService;
@Slf4j @Slf4j
@RestController @RestController
@RequestMapping("/api/artifacts") @RequestMapping("/api/artifacts")
@Tag(name = "artifact", description = "Operations on /api/artifacts")
public class ArtifactController { public class ArtifactController {
private ArtifactService artifactService; private ArtifactService artifactService;
@ -45,6 +52,8 @@ public class ArtifactController {
artifactService.delete(id); artifactService.delete(id);
} }
@Operation(requestBody = @RequestBody(
content = @Content(schema = @Schema(type = "string", format = "binary"))))
@PostMapping(path = "/{id}/data") @PostMapping(path = "/{id}/data")
public void uploadArtifactData(@PathVariable UUID id, HttpServletRequest request) { public void uploadArtifactData(@PathVariable UUID id, HttpServletRequest request) {
try { try {
@ -55,6 +64,12 @@ public class ArtifactController {
} }
} }
@Operation(responses = {
@ApiResponse(responseCode = "200",
content = @Content(
mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE,
schema = @Schema(type = "string", format = "binary")))
})
@GetMapping(path = "/{id}/data") @GetMapping(path = "/{id}/data")
public ResponseEntity<Resource> downloadArtifact(@PathVariable UUID id) { public ResponseEntity<Resource> downloadArtifact(@PathVariable UUID id) {
ArtifactDto artifactDto = artifactService.getById(id); ArtifactDto artifactDto = artifactService.getById(id);

View file

@ -15,6 +15,11 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import net.friedl.fling.model.dto.ArtifactDto; import net.friedl.fling.model.dto.ArtifactDto;
import net.friedl.fling.model.dto.FlingDto; import net.friedl.fling.model.dto.FlingDto;
import net.friedl.fling.service.ArtifactService; import net.friedl.fling.service.ArtifactService;
@ -23,6 +28,7 @@ import net.friedl.fling.service.archive.ArchiveService;
@RestController @RestController
@RequestMapping("/api/fling") @RequestMapping("/api/fling")
@Tag(name = "fling", description = "Operations on /api/fling")
public class FlingController { public class FlingController {
private FlingService flingService; private FlingService flingService;
@ -68,6 +74,12 @@ public class FlingController {
flingService.delete(id); flingService.delete(id);
} }
@Operation(responses = {
@ApiResponse(responseCode = "200",
content = @Content(
mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE,
schema = @Schema(type = "string", format = "binary")))
})
@GetMapping(path = "/{id}/data") @GetMapping(path = "/{id}/data")
public ResponseEntity<Resource> getFlingData(@PathVariable UUID id) { public ResponseEntity<Resource> getFlingData(@PathVariable UUID id) {
FlingDto flingDto = flingService.getById(id); FlingDto flingDto = flingService.getById(id);

View file

@ -4,6 +4,8 @@ import java.nio.file.Path;
import java.time.Instant; import java.time.Instant;
import java.util.UUID; import java.util.UUID;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.AccessMode;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@ -13,18 +15,24 @@ import lombok.NoArgsConstructor;
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Schema(name = "Artifact")
public class ArtifactDto { public class ArtifactDto {
@Schema(accessMode = AccessMode.READ_ONLY, type = "string")
@NotNull @NotNull
private UUID id; private UUID id;
@Schema(type = "string",
description = "Path of the artifact")
@NotNull @NotNull
private Path path; private Path path;
@Schema(type = "integer", format = "int64",
description = "Upload time in milliseconds since the unix epoch 01.01.1970 00:00:00 UTC")
@Builder.Default @Builder.Default
private Instant uploadTime = Instant.now(); private Instant uploadTime = Instant.now();
private String archiveId; @Schema(accessMode = AccessMode.READ_ONLY, type = "boolean",
description = "Whether the artifact was successfully persisted in the archive.")
@Builder.Default @Builder.Default
private Boolean archived = false; private Boolean archived = false;
} }

View file

@ -3,6 +3,8 @@ package net.friedl.fling.model.dto;
import java.time.Instant; import java.time.Instant;
import java.util.UUID; import java.util.UUID;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.AccessMode;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@ -12,32 +14,46 @@ import lombok.NoArgsConstructor;
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Schema(name = "Fling")
public class FlingDto { public class FlingDto {
@Schema(accessMode = AccessMode.READ_ONLY, type = "string")
@NotNull @NotNull
private UUID id; private UUID id;
@Schema(description = "Name of the fling")
@NotNull @NotNull
private String name; private String name;
@Schema(type = "integer", format = "int64",
description = "Creation time in milliseconds since the unix epoch 01.01.1970 00:00:00 UTC")
@NotNull @NotNull
@Builder.Default @Builder.Default
private Instant creationTime = Instant.now(); private Instant creationTime = Instant.now();
@Schema(description = "Share id of the fling. Used in the share link.")
@NotNull @NotNull
private String shareId; private String shareId;
@Schema(description = "Authentication code for password protecting a fling.")
private String authCode; private String authCode;
@Schema(description = "Whether users should be redirected to fling download when accessing the "
+ "fling by share id")
@Builder.Default @Builder.Default
private Boolean directDownload = false; private Boolean directDownload = false;
@Schema(description = "Allow uploads to the fling by users")
@Builder.Default @Builder.Default
private Boolean allowUpload = false; private Boolean allowUpload = false;
@Schema(description = "Whether the fling is accessible by users via the share id")
@Builder.Default @Builder.Default
private Boolean shared = true; private Boolean shared = true;
@Schema(description = "How many clicks are left until the fling access by share id is disallowed")
private Integer expirationClicks; private Integer expirationClicks;
@Schema(type = "integer", format = "int64",
description = "Expiration time in milliseconds since the unix epoch 01.01.1970 00:00:00 UTC")
private Instant expirationTime; private Instant expirationTime;
} }

View file

@ -11,8 +11,8 @@ import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys; import io.jsonwebtoken.security.Keys;
import lombok.Data; import lombok.Data;
@Configuration
@Data @Data
@Configuration
@ConfigurationProperties("fling.security") @ConfigurationProperties("fling.security")
public class FlingSecurityConfiguration { public class FlingSecurityConfiguration {
private List<String> allowedOrigins; private List<String> allowedOrigins;

View file

@ -5,11 +5,13 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.tags.Tag;
import net.friedl.fling.security.authentication.dto.OwnerAuthDto; import net.friedl.fling.security.authentication.dto.OwnerAuthDto;
import net.friedl.fling.security.authentication.dto.UserAuthDto; import net.friedl.fling.security.authentication.dto.UserAuthDto;
@RestController @RestController
@RequestMapping("/api") @RequestMapping("/api/auth")
@Tag(name = "auth", description = "Operations on /api/auth")
public class AuthenticationController { public class AuthenticationController {
private AuthenticationService authenticationService; private AuthenticationService authenticationService;
@ -19,12 +21,12 @@ public class AuthenticationController {
this.authenticationService = authenticationService; this.authenticationService = authenticationService;
} }
@PostMapping(path = "/auth/owner") @PostMapping(path = "/owner")
public String authenticateOwner(@RequestBody OwnerAuthDto ownerAuthDto) { public String authenticateOwner(@RequestBody OwnerAuthDto ownerAuthDto) {
return authenticationService.authenticate(ownerAuthDto); return authenticationService.authenticate(ownerAuthDto);
} }
@PostMapping("/auth/user") @PostMapping("/user")
public String authenticateUser(@RequestBody UserAuthDto userAuthDto) { public String authenticateUser(@RequestBody UserAuthDto userAuthDto) {
return authenticationService.authenticate(userAuthDto); return authenticationService.authenticate(userAuthDto);
} }

View file

@ -1,8 +1,10 @@
package net.friedl.fling.security.authentication.dto; package net.friedl.fling.security.authentication.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@Data @Data
@Schema(name = "OwnerAuth")
public class OwnerAuthDto { public class OwnerAuthDto {
private String username; private String username;
private String password; private String password;

View file

@ -1,8 +1,10 @@
package net.friedl.fling.security.authentication.dto; package net.friedl.fling.security.authentication.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@Data @Data
@Schema(name = "UserAuth")
public class UserAuthDto { public class UserAuthDto {
String shareId; String shareId;
String code; String code;

View file

@ -9,9 +9,32 @@
"name": "fling.security", "name": "fling.security",
"type": "net.friedl.fling.security.FlingWebSecurityConfiguration", "type": "net.friedl.fling.security.FlingWebSecurityConfiguration",
"sourceType": "net.friedl.fling.security.FlingWebSecurityConfiguration" "sourceType": "net.friedl.fling.security.FlingWebSecurityConfiguration"
},
{
"name": "fling.api",
"type": "net.friedl.fling.controller.OpenApiConfiguration",
"sourceType": "net.friedl.fling.controller.OpenApiConfiguration"
} }
], ],
"properties": [ "properties": [
{
"name": "fling.api.version",
"type": "java.lang.String",
"description": "Fling API version",
"sourceType": "net.friedl.fling.controller.OpenApiConfiguration"
},
{
"name": "fling.api.server-url",
"type": "java.lang.String",
"description": "Base URL for the fling api",
"sourceType": "net.friedl.fling.controller.OpenApiConfiguration"
},
{
"name": "fling.api.server-description",
"type": "java.lang.String",
"description": "A description for the server to be shown in OAS",
"sourceType": "net.friedl.fling.controller.OpenApiConfiguration"
},
{ {
"name": "fling.archive.filesystem.archive-path", "name": "fling.archive.filesystem.archive-path",
"type": "java.lang.String", "type": "java.lang.String",

View file

@ -31,4 +31,8 @@ fling:
admin-user: "${FLING_ADMIN_USER:admin}" admin-user: "${FLING_ADMIN_USER:admin}"
admin-password: "${FLING_ADMIN_PASSWORD:123}" admin-password: "${FLING_ADMIN_PASSWORD:123}"
signing-key: "${FLING_SIGNING_KEY:changeitchangeitchangeitchangeit}" signing-key: "${FLING_SIGNING_KEY:changeitchangeitchangeitchangeit}"
jwt-expiration: "${FLING_JWT_EXPIRATION:180000}" jwt-expiration: "${FLING_JWT_EXPIRATION:180000}"
api:
version: "0"
server-url: "http://localhost:8080"
server-description: "API server for dev"

View file

@ -1 +1,3 @@
spring.profiles.active: "@spring.profiles.active@" # To be replaced by maven according to profile settings # To be replaced by maven
spring.profiles.active: "@spring.profiles.active@"
fling.api.version: "@fling.api.version@"