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

Projects API #406

Merged
merged 7 commits into from
Feb 15, 2024
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
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"express-handlebars": "7.1.2",
"express-rate-limit": "^7.1.5",
"express-validator": "7.0.1",
"faims3-datamodel": "github:FAIMS/faims3-data-model#v1.1.0",
"faims3-datamodel": "github:FAIMS/faims3-data-model#v1.1.1",
"fast-check": "2.25.0",
"gts": "3.1.1",
"handlebars": "4.7.7.",
Expand Down
13 changes: 12 additions & 1 deletion src/api/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
updateNotebook,
streamNotebookRecordsAsCSV,
streamNotebookFilesAsZip,
getProjects,
} from '../couchdb/notebooks';
import {requireAuthenticationAPI} from '../middleware';
import {initialiseDatabases} from '../couchdb';
Expand Down Expand Up @@ -74,6 +75,16 @@
res.json({success: true});
});

api.get('/directory/', requireAuthenticationAPI, async (req, res) => {
// get the directory of notebooks on this server
if (req.user) {
const projects = await getProjects(req.user);
res.json(projects);

Check warning on line 82 in src/api/routes.ts

View check run for this annotation

Codecov / codecov/patch

src/api/routes.ts#L81-L82

Added lines #L81 - L82 were not covered by tests
} else {
res.json([]);

Check warning on line 84 in src/api/routes.ts

View check run for this annotation

Codecov / codecov/patch

src/api/routes.ts#L84

Added line #L84 was not covered by tests
}
});

api.get('/notebooks/', requireAuthenticationAPI, async (req, res) => {
// get a list of notebooks from the db
if (req.user) {
Expand Down Expand Up @@ -318,7 +329,7 @@
.status(401)
.json({
error:
'you do not have permission to modify user permissions for this server',
'you do not have permission to modify user permissions for this server',
})
.end();
}
Expand Down
1 change: 0 additions & 1 deletion src/buildconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,6 @@ function google_client_secret(): string {
}
}


function get_providers_to_use(): string[] {
const providers = process.env.CONDUCTOR_AUTH_PROVIDERS;
if (providers === '' || providers === undefined) {
Expand Down
3 changes: 1 addition & 2 deletions src/couchdb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ import {
COUCHDB_INTERNAL_URL,
LOCAL_COUCHDB_AUTH,
} from '../buildconfig';
import {ProjectID} from 'faims3-datamodel';
import {ProjectObject} from '../datamodel/database';
import {ProjectID, ProjectObject} from 'faims3-datamodel';
import {
initialiseDirectoryDB,
initialiseProjectsDB,
Expand Down
37 changes: 35 additions & 2 deletions src/couchdb/notebooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@

import PouchDB from 'pouchdb';
import {getProjectsDB} from '.';
import {CLUSTER_ADMIN_GROUP_NAME} from '../buildconfig';
import {CLUSTER_ADMIN_GROUP_NAME, COUCHDB_PUBLIC_URL} from '../buildconfig';
import {
ProjectID,
getProjectDB,
ProjectObject,
resolve_project_id,
notebookRecordIterator,
addDesignDocsForNotebook,
} from 'faims3-datamodel';
import {
ProjectMetadata,
ProjectObject,
ProjectUIFields,
ProjectUIModel,
PROJECT_METADATA_PREFIX,
Expand All @@ -53,6 +53,39 @@
PouchDB.plugin(securityPlugin);
import {Stringifier, stringify} from 'csv-stringify';

/**
* getProjects - get the internal project documents that reference
* the project databases that the front end will connnect to
* @param user - only return projects visible to this user
*/
export const getProjects = async (
user: Express.User
): Promise<ProjectObject[]> => {
const projects: ProjectObject[] = [];

Check warning on line 64 in src/couchdb/notebooks.ts

View check run for this annotation

Codecov / codecov/patch

src/couchdb/notebooks.ts#L63-L64

Added lines #L63 - L64 were not covered by tests

const projects_db = getProjectsDB();

Check warning on line 66 in src/couchdb/notebooks.ts

View check run for this annotation

Codecov / codecov/patch

src/couchdb/notebooks.ts#L66

Added line #L66 was not covered by tests
if (projects_db) {
const res = await projects_db.allDocs({

Check warning on line 68 in src/couchdb/notebooks.ts

View check run for this annotation

Codecov / codecov/patch

src/couchdb/notebooks.ts#L68

Added line #L68 was not covered by tests
include_docs: true,
});
res.rows.forEach(e => {

Check warning on line 71 in src/couchdb/notebooks.ts

View check run for this annotation

Codecov / codecov/patch

src/couchdb/notebooks.ts#L71

Added line #L71 was not covered by tests
if (e.doc !== undefined && !e.id.startsWith('_')) {
const doc = e.doc as any;

Check warning on line 73 in src/couchdb/notebooks.ts

View check run for this annotation

Codecov / codecov/patch

src/couchdb/notebooks.ts#L73

Added line #L73 was not covered by tests
if (userHasPermission(user, e.id, 'read')) {
delete doc._rev;
const project = doc as unknown as ProjectObject;

Check warning on line 76 in src/couchdb/notebooks.ts

View check run for this annotation

Codecov / codecov/patch

src/couchdb/notebooks.ts#L75-L76

Added lines #L75 - L76 were not covered by tests
// add database connection details
if (project.metadata_db)
project.metadata_db.base_url = COUCHDB_PUBLIC_URL;

Check warning on line 79 in src/couchdb/notebooks.ts

View check run for this annotation

Codecov / codecov/patch

src/couchdb/notebooks.ts#L79

Added line #L79 was not covered by tests
if (project.data_db) project.data_db.base_url = COUCHDB_PUBLIC_URL;
projects.push(project);

Check warning on line 81 in src/couchdb/notebooks.ts

View check run for this annotation

Codecov / codecov/patch

src/couchdb/notebooks.ts#L81

Added line #L81 was not covered by tests
}
}
});
}
return projects;

Check warning on line 86 in src/couchdb/notebooks.ts

View check run for this annotation

Codecov / codecov/patch

src/couchdb/notebooks.ts#L86

Added line #L86 was not covered by tests
};

/**
* getNotebooks -- return an array of notebooks from the database
* @oaram user - only return notebooks that this user can see
Expand Down
99 changes: 1 addition & 98 deletions src/datamodel/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,7 @@
* TODO
*/

import {
NonUniqueProjectID,
RecordID,
RevisionID,
AttributeValuePairID,
ProjectID,
ListingID,
} from 'faims3-datamodel';
import {RecordID, RevisionID, AttributeValuePairID} from 'faims3-datamodel';

export const UI_SPECIFICATION_NAME = 'ui-specification';
export const PROJECT_SPECIFICATION_PREFIX = 'project-specification';
Expand All @@ -40,18 +33,6 @@ export interface PouchAttachments {
[key: string]: any; // any for now until we work out what we need
}

export interface ConnectionInfo {
proto: string;
host: string;
port: number;
lan?: boolean;
db_name: string;
auth?: {
username: string;
password: string;
};
}

/**
* User-facing description of an Authentication mechanism.
* The actual auth mechanisms are stored in authconfig.ts in the FAIMS3-conductor
Expand All @@ -63,89 +44,11 @@ export type AuthInfo = {
name: string;
};

export type PossibleConnectionInfo =
| undefined
| {
proto?: string | undefined;
host?: string | undefined;
port?: number | undefined;
lan?: boolean | undefined;
db_name?: string | undefined;
auth?: {
username: string;
password: string;
};
};

export type DirectoryEntry =
| undefined
| {
_id: string;
name: string;
description: string;
people_db?: PossibleConnectionInfo;
projects_db?: PossibleConnectionInfo;
auth_mechanisms: {[key: string]: AuthInfo};
};

export interface ListingsObject {
_id: string;
name: string;
description: string;
projects_db?: PossibleConnectionInfo;
auth_mechanisms: {[key: string]: AuthInfo};
}

export interface NonNullListingsObject extends ListingsObject {
projects_db: ConnectionInfo;
}

export interface ActiveDoc {
_id: ProjectID;
listing_id: string;
project_id: NonUniqueProjectID;
username: string | null;
password: string | null;
friendly_name?: string;
is_sync: boolean;
}

export interface LocalAuthDoc {
_id: string; //Corresponds to a listings ID
dc_token: string;
}

/**
* Describes a project, with connection, name, description, and schema
* Part of the Projects DB
* Do not use with UI code; sync code only
*/
export interface ProjectObject {
_id: string;
name: string;
description?: string;
data_db?: PossibleConnectionInfo;
metadata_db?: PossibleConnectionInfo;
last_updated?: string;
created?: string;
status?: string;
}

export type ProjectsList = {
[key: string]: ProjectObject;
};

export interface ProjectInformation {
project_id: ProjectID;
name: string;
description?: string;
last_updated?: string;
created?: string;
status?: string;
listing_id: ListingID;
non_unique_project_id: NonUniqueProjectID;
}

export interface EncodedProjectMetadata {
_id: string; // optional as we may want to include the raw json in places
_rev?: string; // optional as we may want to include the raw json in places
Expand Down
7 changes: 3 additions & 4 deletions views/notebook-landing.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-warning">Update Notebook</button>
<button type="button" class="btn btn-warning" onclick="uploadNotebookHandler()">Update Notebook</button>
</div>
</div>
</div>
Expand Down Expand Up @@ -245,10 +245,9 @@ const copyToClipboard = (text) => {
}


const uploadNotebookHandler = (event) => {
event.preventDefault();
const uploadNotebookHandler = () => {
const url = '/api/notebooks/{{notebook.project_id}}';
const form = event.target;
const form = document.querySelector('#upload-notebook-form');
const fileInput = form.querySelector('[name="notebook"]');
if (fileInput) {
// parse the contents of the uploaded file as JSON
Expand Down
Loading