Skip to content

Commit

Permalink
DEV - WIP Import LPM
Browse files Browse the repository at this point in the history
  • Loading branch information
juliecoust committed Oct 21, 2024
1 parent 40b6adc commit bf35746
Show file tree
Hide file tree
Showing 18 changed files with 568 additions and 58 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ services:
image: 'ecotaxa/ecopart_back:latest'
env_file: .env
volumes:
- ./sqlite_db:/src/sqlite_db
- ./data_storage:/src/data_storage
- type: bind
source: ./.env
target: /src/.env
Expand Down
3 changes: 2 additions & 1 deletion empty.env
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ PORT_LOCAL = {$Your local port}
BASE_URL_PUBLIC = {$Your public url}
PORT_PUBLIC = {$Your public port}
DBSOURCE_NAME = {$YourDBname.db}
DBSOURCE_FOLDER = sqlite_db/
DBSOURCE_FOLDER = data_storage/sqlite_db/
DATA_STORAGE_FOLDER = data_storage/

# Replace with your SMTP server
MAIL_HOST = {$smtp.example.com}
Expand Down
63 changes: 54 additions & 9 deletions src/data/data-sources/sqlite/sqlite-task-data-source.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TaskDataSource } from "../../interfaces/data-sources/task-data-source";
import { SQLiteDatabaseWrapper } from "../../interfaces/data-sources/database-wrapper";
import { PreparedSearchOptions, SearchResult } from "../../../domain/entities/search";
import { PrivateTaskRequestModel, PrivateTaskRequestCreationModel, TaskResponseModel, TaskTypeResponseModel, TaskStatusResponseModel } from "../../../domain/entities/task";
import { PrivateTaskRequestModel, PrivateTaskRequestCreationModel, TaskResponseModel, TaskTypeResponseModel, TaskStatusResponseModel, PrivateTaskUpdateModel } from "../../../domain/entities/task";
import { UserRequestModel } from "../../../domain/entities/user";

export class SQLiteTaskDataSource implements TaskDataSource {
Expand Down Expand Up @@ -37,7 +37,15 @@ export class SQLiteTaskDataSource implements TaskDataSource {
else {

// Insert default task_status
const sql_admin = "INSERT OR IGNORE INTO task_status (task_status_label) VALUES ('PENDING', 'VALIDATING', 'RUNNING', 'WAITING_FO_RESPONSE', 'DONE', 'ERROR');";
const sql_admin = `
INSERT OR IGNORE INTO task_status (task_status_label)
VALUES
('PENDING'),
('VALIDATING'),
('RUNNING'),
('WAITING_FOR_RESPONSE'),
('DONE'),
('ERROR');`;

db_tables.run(sql_admin, [], function (err: Error | null) {
if (err) {
Expand Down Expand Up @@ -66,8 +74,16 @@ export class SQLiteTaskDataSource implements TaskDataSource {
else {

// Insert default task_type
const sql_admin = "INSERT OR IGNORE INTO task_type (task_type_label) VALUES ('EXPORT', 'DELETE', 'UPDATE', 'IMPORT', 'IMPORT_CTD', 'IMPORT_ECO_TAXA');";

const sql_admin = `
INSERT OR IGNORE INTO task_type (task_type_label)
VALUES
('EXPORT'),
('DELETE'),
('UPDATE'),
('IMPORT'),
('IMPORT_CTD'),
('IMPORT_ECO_TAXA');
`;
db_tables.run(sql_admin, [], function (err: Error | null) {
if (err) {
console.log("DB error--", err);
Expand Down Expand Up @@ -99,8 +115,8 @@ export class SQLiteTaskDataSource implements TaskDataSource {
task_end_date TIMESTAMP,
FOREIGN KEY (task_type_id) REFERENCES task_type(task_type_id),
FOREIGN KEY (task_status_id) REFERENCES task_status(task_status_id),
FOREIGN KEY (task_owner_id) REFERENCES user(task_owner_id) ON DELETE CASCADE,
FOREIGN KEY (task_project_id) REFERENCES project(task_project_id) ON DELETE CASCADE
FOREIGN KEY (task_owner_id) REFERENCES user(user_id) ON DELETE CASCADE,
FOREIGN KEY (task_project_id) REFERENCES project(project_id) ON DELETE CASCADE
);`

// Run the SQL query to create the table
Expand Down Expand Up @@ -271,7 +287,7 @@ export class SQLiteTaskDataSource implements TaskDataSource {
task_owner_id: row.task_owner_id,
task_owner: row.user_first_name + " " + row.user_last_name + " (" + row.email + ")", // Doe John ([email protected])
task_project_id: row.task_project_id,
task_file_path: row.task_log_file_path,
task_log_file_path: row.task_log_file_path,
task_progress_pct: row.task_progress_pct,
task_progress_msg: row.task_progress_msg,
task_params: row.task_params,
Expand Down Expand Up @@ -335,7 +351,7 @@ export class SQLiteTaskDataSource implements TaskDataSource {
task_owner_id: row.task_owner_id,
task_owner: row.user_first_name + " " + row.user_last_name + " (" + row.email + ")", // Doe John ([email protected])
task_project_id: row.task_project_id,
task_file_path: row.task_log_file_path,
task_log_file_path: row.task_log_file_path,
task_progress_pct: row.task_progress_pct,
task_progress_msg: row.task_progress_msg,
task_params: row.task_params,
Expand Down Expand Up @@ -543,5 +559,34 @@ export class SQLiteTaskDataSource implements TaskDataSource {
});
})
}
}

// Update One task
// Returns the number of lines updates
async updateOne(task: PrivateTaskUpdateModel): Promise<number> {
const { task_id, ...taskData } = task; // Destructure the project object
const params: any[] = []
let placeholders: string = ""
// generate sql and params
for (const [key, value] of Object.entries(taskData)) {
params.push(value)
placeholders = placeholders + key + "=(?),"
}
// remove last ,
placeholders = placeholders.slice(0, -1);
// add task_id to params
params.push(task_id)

// form final sql
const sql = `UPDATE task SET ` + placeholders + ` WHERE task_id=(?);`;
return await new Promise((resolve, reject) => {
this.db.run(sql, params, function (err) {
if (err) {
reject(err);
} else {
const result = this.changes;
resolve(result);
}
});
})
}
}
3 changes: 2 additions & 1 deletion src/data/interfaces/data-sources/task-data-source.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TaskResponseModel, PrivateTaskRequestCreationModel, PrivateTaskRequestModel, TaskTypeResponseModel, TaskStatusResponseModel } from "../../../domain/entities/task";
import { TaskResponseModel, PrivateTaskRequestCreationModel, PrivateTaskRequestModel, TaskTypeResponseModel, TaskStatusResponseModel, PrivateTaskUpdateModel } from "../../../domain/entities/task";
import { PreparedSearchOptions, SearchResult } from "../../../domain/entities/search";
import { UserRequestModel } from "../../../domain/entities/user";

Expand All @@ -11,4 +11,5 @@ export interface TaskDataSource {
getOne(task: PrivateTaskRequestModel): Promise<TaskResponseModel | null>;
getAllType(options: PreparedSearchOptions): Promise<SearchResult<TaskTypeResponseModel>>
getAllStatus(options: PreparedSearchOptions): Promise<SearchResult<TaskStatusResponseModel>>
updateOne(task: PrivateTaskUpdateModel): Promise<number>
}
37 changes: 32 additions & 5 deletions src/domain/entities/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ export enum TaskAction {

/* CREATION */
export interface PublicTaskRequestCreationModel {
task_type_id: TaskType;
task_status_id: TasksStatus;
task_owner_id: number; // task owner : string in a public version
task_type: TaskType;
task_status: TasksStatus;
task_owner_id: number;
task_project_id?: number;
task_params: object;
}
export interface PrivateTaskRequestCreationModel {
task_type_id: TaskType;
task_status_id: TasksStatus;
task_type_id: number; //TaskType;
task_status_id: number; //TasksStatus;
task_owner_id: number; // task owner : string in a public version
task_project_id?: number;

Expand Down Expand Up @@ -116,4 +116,31 @@ export interface PublicTaskRequestModel extends PrivateTaskRequestModel {
task_status?: string;
task_owner?: string;
}
export interface PrivateTaskUpdateModel {
task_id: number;

task_type_id?: number;
task_type?: string;
task_status_id?: number;
task_status?: string;
task_owner_id?: number;
task_owner?: string;
task_project_id?: number;
task_params?: object;
task_creation_date?: string;
task_start_date?: string;
task_end_date?: string;
task_log_file_path?: string;

task_progress_pct?: number;
task_progress_msg?: string;
task_result?: string;
task_error?: string;
task_question?: string;
task_reply?: string;
task_step?: string;
}
// export interface PublicTaskUpdateModel {
// task_id: number;
// task_reply: string;
// }
1 change: 1 addition & 0 deletions src/domain/interfaces/repositories/sample-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import { PublicSampleResponseModel } from "../../entities/sample";
export interface SampleRepository {
ensureFolderExists(root_folder_path: string): Promise<void>;
listImportableSamples(root_folder_path: string, instrument_model: string): Promise<PublicSampleResponseModel[]>;
copySamplesToImportFolder(source_folder: string, dest_folder: string, samples_names_to_import: string[]): Promise<void>
}
12 changes: 8 additions & 4 deletions src/domain/interfaces/repositories/task-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@
// import { PreparedSearchOptions, SearchResult } from "../../entities/search";

import { PreparedSearchOptions, SearchResult } from "../../entities/search";
import { PrivateTaskRequestModel, TaskResponseModel, TaskStatusResponseModel, TaskTypeResponseModel } from "../../entities/task";
import { PublicTaskRequestCreationModel, PrivateTaskRequestModel, TaskResponseModel, TaskStatusResponseModel, TaskTypeResponseModel, PublicTaskRequestModel } from "../../entities/task";
import { UserRequestModel } from "../../entities/user";

export interface TaskRepository {
getOneTask(task: PrivateTaskRequestModel): Promise<TaskResponseModel | null>
getOneTask(task: PrivateTaskRequestModel): Promise<TaskResponseModel | null>;
startTask(task: PublicTaskRequestModel): Promise<void>;
finishTask(task: PublicTaskRequestModel): Promise<void>;
updateTaskProgress(task: PublicTaskRequestModel, progress_pct: number, progress_msg: string): Promise<void>;
// formatTaskRequestCreationModel(public_task: PublicTaskRequestCreationModel, instrument: InstrumentModelResponseModel): TaskRequestCreationModel;
// standardUpdateTask(task_to_update: TaskUpdateModel): Promise<number>;
// createTask(task: TaskRequestCreationModel): Promise<number>;
createTask(task: PublicTaskRequestCreationModel): Promise<number>;
getTask(task: PrivateTaskRequestModel): Promise<TaskResponseModel | null>;
deleteTask(task: PrivateTaskRequestModel): Promise<number>;
standardGetTasks(options: PreparedSearchOptions): Promise<SearchResult<TaskResponseModel>>;
standardGetTaskType(options: PreparedSearchOptions): Promise<SearchResult<TaskTypeResponseModel>>
standardGetTaskStatus(options: PreparedSearchOptions): Promise<SearchResult<TaskStatusResponseModel>>;
getTasksByUser(user: UserRequestModel): Promise<number[]>;
getLogFileTask(task_id: number): Promise<string>
getLogFileTask(task_id: number): Promise<string>;
failedTask(task_id: number, error: Error): Promise<void>;
}
6 changes: 6 additions & 0 deletions src/domain/interfaces/use-cases/sample/import-samples.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { TaskResponseModel } from "../../../entities/task";
import { UserUpdateModel } from "../../../entities/user";

export interface ImportSamplesUseCase {
execute(current_user: UserUpdateModel, project_id: number, samples_names: string[]): Promise<TaskResponseModel>;
}
40 changes: 38 additions & 2 deletions src/domain/repositories/sample-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export class SampleRepositoryImpl implements SampleRepository {

try {
await fs.access(folderPath);
console.log('Folder exists');
} catch (error) {
throw new Error(`Folder does not exist at path: ${folderPath}`);
}
Expand All @@ -55,6 +54,7 @@ export class SampleRepositoryImpl implements SampleRepository {

return samples;
}

// Function to setup samples
async setupSamples(meta_header_samples: HeaderSampleModel[], samples: string[], folder: string): Promise<PublicHeaderSampleResponseModel[]> {
// flag qc samples to flase if not in both lists, and add qc message
Expand Down Expand Up @@ -98,7 +98,6 @@ export class SampleRepositoryImpl implements SampleRepository {
}

getSampleFromHeaderLine(line: string): HeaderSampleModel {
console.log('line', line);
const fields = line.split(';');

const sample: HeaderSampleModel = {
Expand Down Expand Up @@ -163,6 +162,43 @@ export class SampleRepositoryImpl implements SampleRepository {

return samples;
}
// This needs to be inside an async function to use await
async ensureSampleFolderDoNotExists(samples_names_to_import: string[], dest_folder: string): Promise<void> {
// Ensure that none of the sample folders already exist
for (const sample of samples_names_to_import) {
const destPath = path.join(dest_folder, sample);
try {
await fs.access(destPath);
throw new Error(`Sample folder already exists: ${destPath}`);
} catch (error) {
if (error.code === 'ENOENT') {
// Do nothing, the folder does not exist
} else {
// Throw other types of errors, e.g., permission issues
throw error;
}
}
}
}

async copySamplesToImportFolder(source_folder: string, dest_folder: string, samples_names_to_import: string[]): Promise<void> {

const base_folder = path.join(__dirname, '..', '..', '..');
// Ensure that non of the samples folder already exists
await this.ensureSampleFolderDoNotExists(samples_names_to_import, path.join(base_folder, dest_folder));

// Ensure destination folder exists
await fs.mkdir(path.join(base_folder, dest_folder), { recursive: true });

// Iterate over each sample name and copy it
for (const sample of samples_names_to_import) {
const sourcePath = path.join(base_folder, source_folder, sample);
const destPath = path.join(base_folder, dest_folder, sample);

// Copy the sample folder recurcively from source to destination
await fs.cp(sourcePath, destPath, { recursive: true, errorOnExist: true });
}
}



Expand Down
Loading

0 comments on commit bf35746

Please sign in to comment.