Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement create application endpoint #19

Merged
2 changes: 1 addition & 1 deletion _http/rems/01_create_application.http
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
###
### SPDX-License-Identifier: Apache-2.0

POST http://localhost:3000/api/applications/create
POST https://rems-demo.rahtiapp.fi/api/applications/create
Accept: application/json
Content-Type: application/json
x-rems-api-key: 42
Expand Down
4 changes: 2 additions & 2 deletions _http/rems/13_create_user.http
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
###
### SPDX-License-Identifier: Apache-2.0

POST http://rems:3000/api/users/create
POST https://rems-demo.rahtiapp.fi/api/users/create
Content-Type: application/json
x-rems-api-key: 42
x-rems-user-id: owner
Expand All @@ -14,7 +14,7 @@ x-rems-user-id: owner
}

###
GET http://rems:3000/api/users/active
GET https://rems-demo.rahtiapp.fi/api/users/active
Accept: application/json
x-rems-api-key: 42
x-rems-user-id: owner
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// SPDX-FileCopyrightText: 2024 PNED G.I.E.
//
// SPDX-License-Identifier: Apache-2.0
package io.github.genomicdatainfrastructure.daam.api;
import java.io.File;
import java.util.List;

import io.github.genomicdatainfrastructure.daam.services.CreateApplicationService;
import io.github.genomicdatainfrastructure.daam.model.AddApplicationEvent;
import io.github.genomicdatainfrastructure.daam.model.AddedAttachments;
import io.github.genomicdatainfrastructure.daam.model.CreateApplication;
import io.github.genomicdatainfrastructure.daam.model.RemoveMember;
import io.github.genomicdatainfrastructure.daam.model.SaveFormsAndDuos;
import io.github.genomicdatainfrastructure.daam.model.UpdateDatasets;
import jakarta.ws.rs.core.Response;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class ApplicationCommandApiImpl implements ApplicationCommandApi {

private final CreateApplicationService createApplicationService;

@Override
public Response acceptApplicationTermsV1(String id) {
throw new UnsupportedOperationException(
"Unimplemented method 'acceptApplicationTermsV1'"
);
}

@Override
public List<AddedAttachments> addAttachmentToApplicationV1(String id, File body) {
throw new UnsupportedOperationException(
"Unimplemented method 'addAttachmentToApplicationV1'"
);
}

@Override
public Response addEventToApplicationV1(String id, AddApplicationEvent addApplicationEvent) {
throw new UnsupportedOperationException(
"Unimplemented method 'addEventToApplicationV1'"
);
}

@Override
public Response cancelApplicationV1(String id) {
throw new UnsupportedOperationException(
"Unimplemented method 'cancelApplicationV1'"
);
}

@Override
public Response copyApplicationAsNewV1(String id) {
throw new UnsupportedOperationException(
"Unimplemented method 'copyApplicationAsNewV1'"
);
}

@Override
public Response createApplicationV1(CreateApplication createApplication) {
createApplicationService.createRemsApplication(createApplication);
return Response.noContent().build();
}

@Override
public Response inviteMemberToApplicationV1(String id) {
throw new UnsupportedOperationException(
"Unimplemented method 'inviteMemberToApplicationV1'"
);
}

@Override
public Response removeMemberFromApplicationV1(String id, RemoveMember removeMember) {
throw new UnsupportedOperationException(
"Unimplemented method 'removeMemberFromApplicationV1'"
);
}

@Override
public Response saveApplicationFormsAndDuosV1(String id, SaveFormsAndDuos saveFormsAndDuos) {
throw new UnsupportedOperationException(
"Unimplemented method 'saveApplicationFormsAndDuosV1'"
);
}

@Override
public Response submitApplicationV1(String id) {
throw new UnsupportedOperationException(
"Unimplemented method 'submitApplicationV1'"
);
}

@Override
public Response updateDatasetsOfApplicationV1(String id, List<UpdateDatasets> updateDatasets) {
throw new UnsupportedOperationException(
"Unimplemented method 'updateDatasetsOfApplicationV1'"
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-FileCopyrightText: 2024 PNED G.I.E.
//
// SPDX-License-Identifier: Apache-2.0

package io.github.genomicdatainfrastructure.daam.services;

import static io.github.genomicdatainfrastructure.daam.security.PostAuthenticationFilter.USER_ID_CLAIM;
import io.github.genomicdatainfrastructure.daam.model.CreateApplication;
import io.github.genomicdatainfrastructure.daam.remote.rems.api.RemsApplicationCommandApi;
import io.github.genomicdatainfrastructure.daam.remote.rems.model.CreateApplicationCommand;
import io.quarkus.oidc.runtime.OidcJwtCallerPrincipal;
import io.quarkus.security.identity.SecurityIdentity;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.rest.client.inject.RestClient;

import java.util.List;

@ApplicationScoped
public class CreateApplicationService {

private final SecurityIdentity identity;
private final String remsApiKey;
private final RemsApplicationCommandApi remsApplicationCommandApi;

@Inject
public CreateApplicationService(
@ConfigProperty(name = "quarkus.rest-client.rems_yaml.api-key") String remsApiKey,
SecurityIdentity identity,
@RestClient RemsApplicationCommandApi applicationsApi
) {
this.remsApiKey = remsApiKey;
this.identity = identity;
this.remsApplicationCommandApi = applicationsApi;
}

public void createRemsApplication(CreateApplication createApplication) {
var principal = (OidcJwtCallerPrincipal) identity.getPrincipal();
String userId = principal.getClaim(USER_ID_CLAIM);

List<String> catalogueItemIds = createApplication.getDatasetIds();

CreateApplicationCommand command = CreateApplicationCommand.builder()
.catalogueItemIds(catalogueItemIds)
.build();

remsApplicationCommandApi.apiApplicationsCreatePost(command, remsApiKey, userId);
}
}
2 changes: 1 addition & 1 deletion src/main/openapi/daam.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ paths:
security:
- daam_auth:
- write:applications
/api/v1/applications/create-application:
/api/v1/applications/create:
post:
summary: Create application
operationId: create_application_v1
Expand Down
57 changes: 57 additions & 0 deletions src/main/openapi/rems.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,38 @@ paths:
type: array
items:
$ref: '#/components/schemas/ApplicationOverview'
/api/applications/create:
post:
tags:
- rems-application-command
summary: 'Create a new application (roles: logged-in)'
parameters:
- in: header
name: x-rems-api-key
description: REMS API-Key (optional for UI, required for API)
required: false
schema:
type: string
- in: header
name: x-rems-user-id
description: User (optional for UI, required for API). This can be a REMS internal or an external user identity attribute (specified in config.edn).
required: false
schema:
type: string
requestBody:
description: Application creation data
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateApplicationCommand'
responses:
'200':
description: Application creation successful
content:
application/json:
schema:
$ref: '#/components/schemas/CreateApplicationResponse'
components:
schemas:
ApplicationOverview:
Expand Down Expand Up @@ -560,3 +592,28 @@ components:
type: array
items:
type: object
CreateApplicationCommand:
type: object
properties:
catalogue-item-ids:
type: array
items:
type: string
required:
- catalogue-item-ids
CreateApplicationResponse:
type: object
properties:
success:
type: boolean
errors:
type: array
items: {}
warnings:
type: array
items: {}
application-id:
type: integer
format: int64
required:
- success
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-FileCopyrightText: 2024 PNED G.I.E.
//
// SPDX-License-Identifier: Apache-2.0
package io.github.genomicdatainfrastructure.daam.api;

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
public class ApplicationCommandApiImplIT extends ApplicationCommandApiImplTest {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: 2024 PNED G.I.E.
//
// SPDX-License-Identifier: Apache-2.0
package io.github.genomicdatainfrastructure.daam.api;

import io.github.genomicdatainfrastructure.daam.model.CreateApplication;
import org.junit.jupiter.api.Test;

import static org.hamcrest.Matchers.equalTo;
import io.quarkus.test.junit.QuarkusTest;
import static io.restassured.RestAssured.given;
import io.quarkus.test.keycloak.client.KeycloakTestClient;
import java.util.Arrays;


@QuarkusTest
public class ApplicationCommandApiImplTest {

private final KeycloakTestClient keycloakClient = new KeycloakTestClient();

@Test
void unauthorized_when_no_user() {
given().when().get("/api/v1/applications/create").then().statusCode(401);
}


@Test
void createApplication_when_authenticated() {
CreateApplication createApplication = CreateApplication.builder()
.datasetIds(Arrays.asList("dataset1", "dataset2", "dataset3"))
.build();

given()
.auth()
.oauth2(getAccessToken("alice"))
.contentType("application/json")
.body(createApplication)
.when()
.post("/api/v1/applications/create")
.then()
.statusCode(204);
}

private String getAccessToken(String userName) {
return keycloakClient.getAccessToken(userName);
}
}
16 changes: 16 additions & 0 deletions src/test/resources/mappings/create_application.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"request": {
"method": "POST",
"url": "/api/applications/create"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"success": true,
"application-id": 12345
}
}
}
3 changes: 3 additions & 0 deletions src/test/resources/mappings/create_application.json.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2024 PNED G.I.E.

SPDX-License-Identifier: Apache-2.0