Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.7.0</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down Expand Up @@ -296,7 +301,7 @@
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.15.2</version>
<version>1.15.3</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.breedinginsight.api.v1.controller;

import io.micronaut.http.HttpResponse;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.PathVariable;
import io.micronaut.http.annotation.Produces;
import lombok.extern.slf4j.Slf4j;
import org.breedinginsight.api.auth.AuthenticatedUser;
import org.breedinginsight.api.auth.ProgramSecured;
import org.breedinginsight.api.auth.ProgramSecuredRoleGroup;
import org.breedinginsight.api.auth.SecurityService;
import org.breedinginsight.api.model.v1.response.DataResponse;
import org.breedinginsight.api.model.v1.response.Response;
import org.breedinginsight.api.model.v1.response.metadata.Metadata;
import org.breedinginsight.api.model.v1.response.metadata.Pagination;
import org.breedinginsight.api.model.v1.response.metadata.Status;
import org.breedinginsight.api.model.v1.response.metadata.StatusCode;
import org.breedinginsight.api.v1.controller.metadata.AddMetadata;
import org.breedinginsight.model.job.Job;
import org.breedinginsight.services.exceptions.DoesNotExistException;
import org.breedinginsight.services.job.JobService;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Slf4j
@Controller("/${micronaut.bi.api.version}")
public class JobController {
private SecurityService securityService;
private JobService jobService;

@Inject
public JobController(SecurityService securityService, JobService jobService) {
this.securityService = securityService;
this.jobService = jobService;
}

@Get("programs/{programId}/jobs")
@Produces(MediaType.APPLICATION_JSON)
@AddMetadata
@ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.ALL})
public HttpResponse<Response<DataResponse<Job>>> getProgramJobs(@PathVariable UUID programId) {
log.debug(String.format("fetching jobs for program: %s", programId));
try {
AuthenticatedUser actingUser = securityService.getUser();
var programJobs = jobService.getProgramJobs(programId);
List<Status> metadataStatus = new ArrayList<>();
metadataStatus.add(new Status(StatusCode.INFO, "Successful Query"));
Pagination pagination = new Pagination(programJobs.size(), programJobs.size(), 1, 0);
Metadata metadata = new Metadata(pagination, metadataStatus);
Response<DataResponse<Job>> response = new Response<>(metadata, new DataResponse<>(programJobs));
return HttpResponse.ok(response);
} catch (DoesNotExistException e) {
log.info(e.getMessage(), e);
return HttpResponse.notFound();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public HttpResponse<Response<ImportResponse>> getUploadData(@PathVariable UUID p
return HttpResponse.ok(response);
}
} catch (DoesNotExistException e) {
log.info(e.getMessage());
log.error(e.getMessage(), e);
return HttpResponse.notFound();
}
}
Expand All @@ -117,16 +117,16 @@ public HttpResponse<Response<ImportResponse>> commitData(@PathVariable UUID prog
Response<ImportResponse> response = new Response(result);
return HttpResponse.ok(response).status(HttpStatus.ACCEPTED);
} catch (DoesNotExistException e) {
log.info(e.getMessage());
log.error(e.getMessage(), e);
return HttpResponse.notFound();
} catch (AuthorizationException e) {
log.info(e.getMessage());
log.error(e.getMessage(), e);
return HttpResponse.status(HttpStatus.FORBIDDEN, e.getMessage());
} catch (UnprocessableEntityException e) {
log.info(e.getMessage());
log.error(e.getMessage(), e);
return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage());
} catch (HttpStatusException e) {
log.info(e.getMessage());
log.error(e.getMessage(), e);
return HttpResponse.status(e.getStatus(), e.getMessage());
}
}
Expand All @@ -143,16 +143,16 @@ public HttpResponse<Response<ImportResponse>> previewData(@PathVariable UUID pro
Response<ImportResponse> response = new Response(result);
return HttpResponse.ok(response).status(HttpStatus.ACCEPTED);
} catch (DoesNotExistException e) {
log.info(e.getMessage());
log.error(e.getMessage(), e);
return HttpResponse.notFound();
} catch (AuthorizationException e) {
log.info(e.getMessage());
log.error(e.getMessage(), e);
return HttpResponse.status(HttpStatus.FORBIDDEN, e.getMessage());
} catch (UnprocessableEntityException e) {
log.info(e.getMessage());
log.error(e.getMessage(), e);
return HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY, e.getMessage());
} catch (HttpStatusException e) {
log.info(e.getMessage());
log.error(e.getMessage(), e);
return HttpResponse.status(e.getStatus(), e.getMessage());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.micronaut.http.server.exceptions.InternalServerException;
import org.breedinginsight.brapps.importer.model.ImportProgress;
import org.breedinginsight.brapps.importer.model.ImportUpload;
import org.breedinginsight.brapps.importer.model.mapping.ImportMapping;
import org.breedinginsight.dao.db.tables.BiUserTable;
import org.breedinginsight.dao.db.tables.daos.ImporterImportDao;
import org.breedinginsight.dao.db.tables.daos.ImporterProgressDao;
Expand All @@ -36,6 +37,7 @@
import javax.inject.Inject;
import javax.inject.Singleton;

import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -68,8 +70,16 @@ public Optional<ImportUpload> getUploadById(UUID id) {
}
}

public List<ImportUpload> getProgramUploads(UUID programId) {
List<Record> records = getUploadsQuery().where(IMPORTER_IMPORT.PROGRAM_ID.eq(programId)).fetch();

return parseRecords(records);
}

public void update(ImportUpload upload) {
super.update(upload);
upload.setUpdatedAt(OffsetDateTime.now());
upload.getProgress().setUpdatedAt(upload.getUpdatedAt());
progressDao.update(upload.getProgress());
}

Expand All @@ -87,6 +97,7 @@ private List<ImportUpload> parseRecords(List<Record> records) {
upload.setCreatedByUser(User.parseSQLRecord(record, createdByUser));
upload.setUpdatedByUser(User.parseSQLRecord(record, updatedByUser));
upload.setProgress(ImportProgress.parseSQLRecord(record));
upload.setMapping(ImportMapping.parseSQLRecord(record));
// Parse our file data and modified data into a data table
try {
if (upload.getFileData() != null) {
Expand All @@ -113,6 +124,7 @@ private SelectOnConditionStep<Record> getUploadsQuery() {
.leftJoin(IMPORTER_PROGRESS).on(IMPORTER_IMPORT.IMPORTER_PROGRESS_ID.eq(IMPORTER_PROGRESS.ID))
.innerJoin(PROGRAM).on(IMPORTER_IMPORT.PROGRAM_ID.eq(PROGRAM.ID))
.innerJoin(BI_USER).on(IMPORTER_IMPORT.USER_ID.eq(BI_USER.ID))
.innerJoin(IMPORTER_MAPPING).on(IMPORTER_IMPORT.IMPORTER_MAPPING_ID.eq(IMPORTER_MAPPING.ID))
.innerJoin(createdByUser).on(IMPORTER_IMPORT.CREATED_BY.eq(createdByUser.ID))
.innerJoin(updatedByUser).on(IMPORTER_IMPORT.UPDATED_BY.eq(updatedByUser.ID));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ public static ImportProgress parseSQLRecord(Record record) {
.finished(record.getValue(IMPORTER_PROGRESS.FINISHED))
.inProgress(record.getValue(IMPORTER_PROGRESS.IN_PROGRESS))
.body(record.getValue(IMPORTER_PROGRESS.BODY))
.updatedAt(record.getValue(IMPORTER_PROGRESS.UPDATED_AT))
.createdAt(record.getValue(IMPORTER_PROGRESS.CREATED_AT))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import lombok.ToString;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import org.breedinginsight.brapps.importer.model.mapping.ImportMapping;
import org.breedinginsight.brapps.importer.model.mapping.MappingField;
import org.breedinginsight.dao.db.tables.pojos.ImporterImportEntity;
import org.breedinginsight.model.Program;
Expand All @@ -51,6 +52,7 @@ public class ImportUpload extends ImporterImportEntity {
private User createdByUser;
private User updatedByUser;
private ImportProgress progress;
private ImportMapping mapping;

private Table fileDataTable;
private Table modifiedDataTable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,36 @@
import lombok.Getter;
import lombok.Setter;
import org.breedinginsight.brapps.importer.model.ImportProgress;
import org.breedinginsight.model.User;
import org.breedinginsight.model.job.JobDetail;
import org.jooq.JSONB;

import java.time.OffsetDateTime;
import java.util.UUID;

@Getter
@Setter
public class ImportResponse {
public class ImportResponse implements JobDetail {
private UUID importId;
private ImportProgress progress;
// Since we are only ever returning the preview, don't worry about trying to deserialize it from the db
private JSONB preview;
private UUID importMappingId;
private String importMappingName;
private String importType;
private String uploadFileName;
private User createdByUser;
private User updatedByUser;
private OffsetDateTime createdAt;
private OffsetDateTime updatedAt;

@JsonRawValue
public String getPreview() {
return preview != null ? preview.data() : null;
}

@Override
public String getJobType() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused about the need for the JobDetail interface. I only see it implemented once (here), and then it is only used to return a hardcoded value. Is there a more direct way to code this? If not, maybe a comment would be valuable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davedrp Added some javadoc to the JobDetail interface.

Essentially, the JobDetail interface is to allow a Job to hold additional information about a specific task, but not have to know exactly what that information is (the UI cares more about this hence why there is a getType method in the JobDetail).

return "IMPORT";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,33 @@ public Pair<HttpStatus, ImportResponse> getDataUpload(UUID uploadId, Boolean inc
return new ImmutablePair<>(status, response);
}

public List<ImportResponse> getProgramUploads(UUID programId, Boolean includeMapping) throws DoesNotExistException {
Optional<Program> optionalProgram = programService.getById(programId);
if (!optionalProgram.isPresent()) {
throw new DoesNotExistException("Program id does not exist");
}
List<ImportUpload> uploads = importDAO.getProgramUploads(programId);

return uploads.stream().map(upload -> {
ImportResponse response = new ImportResponse();
response.setImportId(upload.getId());
response.setImportMappingId(upload.getMapping().getId());
response.setImportMappingName(upload.getMapping().getName());
response.setImportType(upload.getMapping().getImportTypeId());
response.setUploadFileName(upload.getUploadFileName());
response.setCreatedByUser(upload.getCreatedByUser());
response.setCreatedAt(upload.getCreatedAt());
response.setUpdatedByUser(upload.getUpdatedByUser());
response.setUpdatedAt(upload.getUpdatedAt());
response.setProgress(upload.getProgress());
if (includeMapping){
response.setPreview(upload.getMappedData());
}

return response;
}).collect(Collectors.toList());
}

public List<ImportMapping> getAllMappings(UUID programId, AuthenticatedUser actingUser, Boolean draft)
throws DoesNotExistException, AuthorizationException {

Expand Down
41 changes: 41 additions & 0 deletions src/main/java/org/breedinginsight/model/job/Job.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.breedinginsight.model.job;

import lombok.*;
import lombok.experimental.Accessors;
import org.breedinginsight.model.User;

import java.time.OffsetDateTime;

@Getter
@Setter
@Accessors(chain=true)
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Job {
private int statuscode;
private String statusMessage;
private String jobType;
private OffsetDateTime createdAt;
private OffsetDateTime updatedAt;
private User createdByUser;
private JobDetail jobDetail;
}
25 changes: 25 additions & 0 deletions src/main/java/org/breedinginsight/model/job/JobDetail.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.breedinginsight.model.job;

/**
* Represents an object that contains the details about a specific asynchronous job.
*/
public interface JobDetail {
String getJobType();
}
Loading