Skip to content

Commit

Permalink
Merge pull request #406 from FAIMS/projects-api
Browse files Browse the repository at this point in the history
Projects API
  • Loading branch information
stevecassidy authored Feb 15, 2024
2 parents 430afe2 + 4aa3aba commit 408ae77
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 114 deletions.
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 @@ import {
updateNotebook,
streamNotebookRecordsAsCSV,
streamNotebookFilesAsZip,
getProjects,
} from '../couchdb/notebooks';
import {requireAuthenticationAPI} from '../middleware';
import {initialiseDatabases} from '../couchdb';
Expand Down Expand Up @@ -74,6 +75,16 @@ api.post('/initialise/', async (req, res) => {
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);
} else {
res.json([]);
}
});

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 @@ api.post('/users/:id/admin', requireAuthenticationAPI, async (req, res) => {
.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 @@ import {userHasPermission} from './users';
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[] = [];

const projects_db = getProjectsDB();
if (projects_db) {
const res = await projects_db.allDocs({
include_docs: true,
});
res.rows.forEach(e => {
if (e.doc !== undefined && !e.id.startsWith('_')) {
const doc = e.doc as any;
if (userHasPermission(user, e.id, 'read')) {
delete doc._rev;
const project = doc as unknown as ProjectObject;
// add database connection details
if (project.metadata_db)
project.metadata_db.base_url = COUCHDB_PUBLIC_URL;
if (project.data_db) project.data_db.base_url = COUCHDB_PUBLIC_URL;
projects.push(project);
}
}
});
}
return projects;
};

/**
* 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

0 comments on commit 408ae77

Please sign in to comment.