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

A more flexible file model + data file upload #510

Closed
wants to merge 68 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
c3b8061
file model change (haven't change the other codes)
sou-chon May 29, 2020
a6839ef
change the file model to be more flexible
sou-chon May 31, 2020
3055555
Merge branch 'develop' into feat/upload-blobs
sou-chon May 31, 2020
c65f411
Merge branch 'develop' into feat/upload-blobs
sou-chon May 31, 2020
3bb1ae0
fine grain file interfaces to hierarchy
sou-chon Jun 3, 2020
32edb54
file model revamp (WIP)
sou-chon Jun 3, 2020
c435ae4
file (WIP)
sou-chon Jun 4, 2020
c0f3792
blob upload
sou-chon Jun 4, 2020
8f76a5a
file model revamp (WIP)
sou-chon Jun 4, 2020
18c887d
blob upload
sou-chon Jun 4, 2020
df8b625
adding package resolutions
sou-chon Jun 4, 2020
82bc591
Adding package resolution
sou-chon Jun 4, 2020
99895e5
Merge branch 'develop' into feat/upload-blobs
sou-chon Jun 4, 2020
f588b20
yarn lock
sou-chon Jun 4, 2020
a9c9f64
synchronising @types/mongodb versions
sou-chon Jun 4, 2020
7a78b03
file (WIPP)
sou-chon Jun 4, 2020
6401ad4
file resolver (WIP)
sou-chon Jun 4, 2020
94fb30c
Merge branch 'develop' into feat/upload-blobs
sou-chon Jun 4, 2020
1169615
pin itmat-utils version in itmat-commons
sou-chon Jun 4, 2020
a2a3d94
Merge branch 'develop' into feat/upload-blobs
sou-chon Jun 7, 2020
a6fd55b
changing file resolvers and user resolvers for new file model
sou-chon Jun 7, 2020
2582aa1
fixing file type in job-executor & ui
sou-chon Jun 7, 2020
05a778a
fixing ui compile errors
sou-chon Jun 7, 2020
ebe17fb
Merge branch 'develop' into feat/upload-blobs
sou-chon Jun 7, 2020
d1eff71
removing duplicate dependency
sou-chon Jun 7, 2020
5cb2b30
bump jest to 26.0.1
sou-chon Jun 8, 2020
7f775c0
Merge branch 'db-seed-ts' into feat/upload-blobs
sou-chon Jun 8, 2020
61abc1e
tmp fixing ambiguous types
sou-chon Jun 8, 2020
ded2071
adding types to seed user
sou-chon Jun 9, 2020
80a325e
linting
sou-chon Jun 9, 2020
297a26a
Merge remote-tracking branch 'origin/develop' into feat/upload-blobs
sou-chon Jun 9, 2020
9f01ba5
Merge branch 'develop' into feat/upload-blobs
sou-chon Jun 11, 2020
8bd7ab4
linting
sou-chon Jun 11, 2020
dbe1065
Merge branch 'develop' into feat/upload-blobs
sou-chon Jun 13, 2020
a31c2a4
turning type alias to imports
sou-chon Jun 13, 2020
8a04190
lock file
sou-chon Jun 13, 2020
4ef77e2
changing file resolvers and graphq types
sou-chon Jun 13, 2020
5bc178d
adding types to user seeds
sou-chon Jun 13, 2020
91aacf5
fixing compilation bug (interface)
sou-chon Jun 13, 2020
4514ace
fixing bugs on file types
sou-chon Jun 13, 2020
d6431eb
preventing dropping collection (fix #475)
sou-chon Jun 13, 2020
9f731ba
fixing graphql typing on file
sou-chon Jun 13, 2020
8a413da
fixing job-executor imports error
sou-chon Jun 13, 2020
5b7cbad
adding proxy to ui
sou-chon Jun 13, 2020
a113d5c
swapping study file list to file browser (WIP)
sou-chon Jun 13, 2020
4fb22c5
letting database setup have demo data
sou-chon Jun 13, 2020
d84d4d1
removing unnecessary useState
sou-chon Jun 13, 2020
d72475e
file browser (WIP)
sou-chon Jun 14, 2020
354ab0b
Merge branch 'develop' into feat/upload-blobs
sou-chon Jun 18, 2020
1087134
Merge branch 'develop' into feat/upload-blobs
sou-chon Jun 28, 2020
a0f5b1c
indentation fix
sou-chon Jun 30, 2020
bd02b69
reverting file api to the old one, leaving for future PR
sou-chon Jun 30, 2020
9029089
Merge branch 'develop' into feat/upload-blobs
sou-chon Jul 1, 2020
6b19d96
'merging develop'
sou-chon Jul 3, 2020
0b4944e
'bug fixes'
sou-chon Jul 3, 2020
a606154
merging develop
sou-chon Jul 3, 2020
7a79179
fixing lerna dependency issues
sou-chon Jul 3, 2020
db6b692
uncommenting erroneously commented lines
sou-chon Jul 3, 2020
e826022
removing unneeded default from FileNode constructor
sou-chon Jul 5, 2020
1e3186a
fixing loose ends (download + upload files working)
sou-chon Jul 5, 2020
330372a
removing accidental comments
sou-chon Jul 5, 2020
88af69c
adding types
sou-chon Jul 5, 2020
e913b6c
adding comment to fileDownload.ts
sou-chon Jul 5, 2020
cf88f25
correcting tests (WIP)
sou-chon Jul 21, 2020
35ba26f
merge develop
sou-chon Jul 22, 2020
476cad3
lockfile
sou-chon Jul 22, 2020
dcf66d3
file tests (WIP)
sou-chon Aug 4, 2020
800acbd
fixing a comment error
sou-chon Aug 15, 2020
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,6 @@ kubernetes/*.yaml
itmat-client-old/
.idea/

target
target

note
9 changes: 9 additions & 0 deletions NOTE_CHON
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fileDownload

fileResolvers

studyResolvers

demoStudy

uploadfiletsx
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
"version": "independent",
"useWorkspaces": true,
"npmClient": "yarn"
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"eslint-plugin-react": "7.20.3",
"eslint-plugin-react-hooks": "4.0.8",
"husky": "4.2.5",
"start-server-and-test": "1.11.0",
"jest-environment-node": "26.1.0",
"lerna": "3.22.1",
"typescript": "3.9.7"
Expand Down
5 changes: 3 additions & 2 deletions packages/itmat-commons/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
"prepublishOnly": "yarn run build"
},
"dependencies": {
"graphql": "14.7.0",
"graphql": "15.0.0",
"graphql-tag": "2.10.4",
"minio": "7.0.16"
"minio": "7.0.16",
"uuid": "8.1.0"
},
"devDependencies": {
"@types/express": "4.17.7",
Expand Down
86 changes: 77 additions & 9 deletions packages/itmat-commons/src/graphql/files.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,46 @@
import gql from 'graphql-tag';

const file_fragment_without_children = gql`
fragment FILE_WITHOUT_CHILDREN on File {
id
fileName
studyId
projectId
fileType
fileSize
content
description
uploadedBy
userId
dataVersionId
patientId
}
`;

// export const CREATE_FILE = gql`
// mutation createFile(
// $fileName: String!,
// $fileType: FileType,
// $studyId: String
// ) {
// createFile(
// fileName: $fileName,
// fileType: $fileType,
// studyId: $studyId
// ) {
// ...FILE_WITHOUT_CHILDREN
// }
// }
// ${file_fragment_without_children}
// `;

export const UPLOAD_FILE = gql`
mutation uploadFile($studyId: String!, $file: Upload!, $description: String!, $fileLength: Int) {
uploadFile(studyId: $studyId, description: $description, file: $file, fileLength: $fileLength) {
id
fileName
studyId
projectId
fileSize
description
uploadedBy
mutation uploadFile($studyId: String!, $file: Upload!, $description: String, $fileLength: Int, $fileType: FileType) {
uploadFile(studyId: $studyId, description: $description, file: $file, fileLength: $fileLength, fileType: $fileType) {
...FILE_WITHOUT_CHILDREN
}
}
${file_fragment_without_children}
`;

export const DELETE_FILE = gql`
Expand All @@ -21,3 +50,42 @@ export const DELETE_FILE = gql`
}
}
`;

// export const GET_FILE_WITHOUT_CHILDREN = gql`
// query getFileWithoutChildren($fileId: String!) {
// getFile(fileId: $fileId) {
// ...FILE_WITHOUT_CHILDREN
// }
// }
// ${file_fragment_without_children}
// `;

// export const GET_FILE_WITH_CHILDREN = gql`
// query getFileWithChildren($fileId: String!) {
// getFile(fileId: $fileId) {
// childFiles {
// ...FILE_WITHOUT_CHILDREN
// }
// ...FILE_WITHOUT_CHILDREN
// }
// }
// ${file_fragment_without_children}
// `;

// export const FETCH_CHILD_FILES = gql`
// query fetchChildFiles($dirFileId: String!) {
// getFile(fileId: $dirFileId) {
// id
// childFiles {
// ...FILE_WITHOUT_CHILDREN
// }
// }
// }
// ${file_fragment_without_children}
// `;

// export const CREATE_JOB_FOR_UNZIPPING_FILE = gql`
// mutation createJobForUnzippingFile($fileId: String!) {
// successful
// }
// `;
3 changes: 2 additions & 1 deletion packages/itmat-commons/src/graphql/study.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const GET_STUDY = gql`
username
}
}
files {
files { # TO_DO: remove in future PR
id
fileName
studyId
Expand All @@ -47,6 +47,7 @@ export const GET_STUDY = gql`
uploadedBy
}
numOfSubjects
rootDir
currentDataVersion
dataVersions {
id
Expand Down
12 changes: 6 additions & 6 deletions packages/itmat-commons/src/graphql/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ export const user_fragment = gql`
`;

export const LOGIN = gql`
mutation login($username: String!, $password: String!, $totp: String!) {
login(username: $username, password: $password, totp: $totp) {
...ALL_FOR_USER
}
}
${user_fragment}
mutation login($username: String!, $password: String!, $totp: String!) {
login(username: $username, password: $password, totp: $totp) {
...ALL_FOR_USER
}
}
${user_fragment}
`;

export const WHO_AM_I = gql`
Expand Down
11 changes: 0 additions & 11 deletions packages/itmat-commons/src/models/file.ts

This file was deleted.

103 changes: 103 additions & 0 deletions packages/itmat-commons/src/models/file/abstract/DirectoryNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { FileNode } from './FileNode';
import { fileTypes, fileTypesDirs } from './fileTypes';
import { IFileMongoEntry } from './mongoEntry';
import { Collection, FindAndModifyWriteOpResultObject } from 'mongodb';

export class DirectoryNode extends FileNode {
private _childFileIds: string[];
private _isRoot: boolean;

constructor(
{
id,
fileName,
fileType,
uploadedBy,
deleted,
isRoot = false,
childFileIds = []
}: {
id?: string,
fileName: string,
fileType: fileTypes,
uploadedBy: string,
deleted?: number | null,
isRoot?: boolean,
childFileIds?: string[]
}
) {
super({ id, fileName, fileType, uploadedBy, deleted });
if (!fileTypesDirs.includes(fileType)) {
throw new Error(`Cannot instantiate Directory with filetype ${fileType}`);
}
this._childFileIds = childFileIds;
this._isRoot = isRoot;
}

// static validateInstance(entry: IFileMongoEntry): boolean {

// }

static makeFromMongoEntry(entry: IFileMongoEntry): DirectoryNode {
const { id, fileName, fileType, uploadedBy, deleted, isRoot, childFileIds } = entry;
if (!fileTypesDirs.includes(fileType)) {
throw new Error('Cannot instantiate FileNode with entry: wrong type.');
}
if (
id === undefined ||
fileName === undefined ||
fileType === undefined ||
uploadedBy === undefined ||
deleted === undefined ||
isRoot === undefined ||
childFileIds === undefined
) {
throw new Error('Cannot instantiate FileNode with entry: missing key.');
}
return new DirectoryNode({ id, fileName, fileType, uploadedBy, deleted, isRoot, childFileIds });
}

// @override
serialiseToMongoObj(): IFileMongoEntry {
return ({
id: this.id,
fileName: this.fileName,
studyId: undefined,
projectId: undefined,
fileType: this.fileType,
fileSize: undefined,
content: undefined,
description: undefined,
uploadedBy: this.uploadedBy,
isRoot: this._isRoot,
patientId: undefined,
dataVersionId: undefined,
childFileIds: this._childFileIds,
deleted: this.deleted
});
}


// addChildNodeAndUpdateMongo(collection: Collection, file: FileNode): Promise<FindAndModifyWriteOpResultObject<IFileMongoEntry>>{
// // TO_DO
// // this.childFileIds
// }

// @override
deleteFileOnMongo(collection: Collection): Promise<FindAndModifyWriteOpResultObject<IFileMongoEntry>> {
if (this._isRoot === true) {
throw new Error('Cannot delete root directory');
}
return super.deleteFileOnMongo(collection);
}

get isRoot() { return this._isRoot; }
protected get childFileIds() { return this._childFileIds; }

protected setChildFileIds(value: string[]) { this._childFileIds = value; }

getChildFiles(collection: Collection): Promise<IFileMongoEntry[]> {
return collection.find({ deleted: null, id: { $in: this._childFileIds } }).toArray();
}

}
85 changes: 85 additions & 0 deletions packages/itmat-commons/src/models/file/abstract/FileNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { v4 as uuid } from 'uuid';
import { fileTypes } from './fileTypes';
import { IFileMongoEntry } from './mongoEntry';
import { Collection, FindAndModifyWriteOpResultObject, InsertOneWriteOpResult, ObjectID } from 'mongodb';

export class FileNode {
private readonly _id;
private _fileName: string;
private readonly _fileType: fileTypes;
private readonly _uploadedBy: string;
private _deleted: number | null;

constructor(
{
id = uuid(),
fileName,
fileType,
uploadedBy,
deleted = null
}: {
id?: string,
fileName: string,
fileType: fileTypes,
uploadedBy: string,
deleted?: number | null
}
) {
this._id = id;
this._fileName = fileName;
this._fileType = fileType;
this._uploadedBy = uploadedBy;
this._deleted = deleted;
}

static makeFromMongoEntry(entry: IFileMongoEntry): FileNode {
const { id, fileName, fileType, uploadedBy, deleted } = entry;
if (
id === undefined ||
fileName === undefined ||
fileType === undefined ||
uploadedBy === undefined ||
deleted === undefined
) {
throw new Error('Cannot instantiate FileNode with entry: missing key.');
}
return new FileNode({ id, fileName, fileType, uploadedBy, deleted });
}

serialiseToMongoObj(): IFileMongoEntry {
return ({
id: this._id,
fileName: this._fileName,
studyId: undefined,
projectId: undefined,
fileType: this._fileType,
fileSize: undefined,
description: undefined,
content: undefined,
uploadedBy: this._uploadedBy,
isRoot: undefined,
patientId: undefined,
dataVersionId: undefined,
childFileIds: undefined,
deleted: this._deleted
});
}

static getFileFromMongo(fileCollection: Collection, query: { id?: string, fileName?: string }): Promise<IFileMongoEntry | null> {
return fileCollection.findOne({ ...query, deleted: null });
}

deleteFileOnMongo(fileCollection: Collection): Promise<FindAndModifyWriteOpResultObject<IFileMongoEntry>> {
return fileCollection.findOneAndUpdate({ id: this._id, deleted: null, isRoot: { $ne: true } }, { deleted: new Date().valueOf() });
}

uploadFileToMongo(fileCollection: Collection): Promise<InsertOneWriteOpResult<IFileMongoEntry & { _id: ObjectID } >> {
return fileCollection.insertOne(this.serialiseToMongoObj());
}

get id() { return this._id; }
get fileName() { return this._fileName; }
get fileType() { return this._fileType; }
get uploadedBy() { return this._uploadedBy; }
get deleted() { return this._deleted; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface IStudyFileNode {
readonly studyId: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface IUserPersonalFileNode {
readonly userId: string;
}
Loading