@sjcrh/proteinpaint-server 2.137.2-2 → 2.137.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,3 @@
1
- import serverconfig from "@sjcrh/proteinpaint-server/src/serverconfig.js";
2
- import * as path from "path";
3
- import { existsSync, unlinkSync, symlinkSync, access, constants } from "fs";
4
- copyDataFilesFromRepo2Tp();
5
1
  function termdb_test_default() {
6
2
  return {
7
3
  isMds3: true,
@@ -141,7 +137,7 @@ function termdb_test_default() {
141
137
  {
142
138
  chartType: "barchart",
143
139
  term: { id: "diaggrp" },
144
- settings: { barchart: { colorBars: true, showPercent: true, colorUsing: "generated" } }
140
+ settings: { barchart: { colorBars: true, showPercent: true, colorUsing: "present" } }
145
141
  }
146
142
  ]
147
143
  },
@@ -345,27 +341,6 @@ function termdb_test_default() {
345
341
  }
346
342
  };
347
343
  }
348
- function copyDataFilesFromRepo2Tp() {
349
- if (existsSync("/home/root/pp"))
350
- return;
351
- const targetDir = path.join(serverconfig.binpath, "test/tp/files/hg38/TermdbTest");
352
- const datadir = path.join(serverconfig.tpmasterdir, "files/hg38/TermdbTest");
353
- if (datadir == `${serverconfig.binpath}/test/tp`) {
354
- access(datadir, constants.R_OK | constants.W_OK, (err) => {
355
- if (!err) {
356
- try {
357
- if (!existsSync(datadir))
358
- unlinkSync(datadir);
359
- symlinkSync(targetDir, datadir);
360
- } catch (error) {
361
- console.warn("Error while coping data files from Repo to Tp: " + error);
362
- }
363
- } else {
364
- console.warn(`user doesn't have sufficient permissions for `);
365
- }
366
- });
367
- }
368
- }
369
344
  export {
370
345
  termdb_test_default as default
371
346
  };
@@ -0,0 +1,57 @@
1
+ import serverconfig from '@sjcrh/proteinpaint-server/src/serverconfig.js'
2
+ import * as path from 'path'
3
+ import fs from 'fs'
4
+ import { spawnSync } from 'child_process'
5
+
6
+ /*
7
+ copyDataFilesFromRepo2Tp()
8
+ - does not work when tp is not writable, such as when the tp dir is mounted as read-only onto a container
9
+ - must be called before genome and dataset init steps in initGenomeDs(),
10
+ such as by calling in the genome js file like in genome/hg38.test.ts
11
+ */
12
+ export async function copyDataFilesFromRepo2Tp(testPath) {
13
+ // when running tests where the tp directory is not writable (such as from inside a container),
14
+ // the workflow script should copy the server/test/tp dir as serverconfig.tpmasterdir
15
+ // and not trigger the symlinks below
16
+ if (fs.existsSync('/home/root/pp')) {
17
+ console.warn('skipped TermdbTest copying, assumed the mounted host tp dir is not writable from within a container')
18
+ return
19
+ }
20
+
21
+ const targetDir = path.join(serverconfig.binpath, 'test/tp', testPath)
22
+ const datadir = path.join(serverconfig.tpmasterdir, testPath)
23
+
24
+ // no need to copy files or set the symlink when the target TermdbTest dir
25
+ // already equals the datadir under serverconfig.tpmasterdir
26
+ if (targetDir === datadir) return
27
+
28
+ try {
29
+ await fs.promises.access(serverconfig.tpmasterdir)
30
+ } catch {
31
+ // the tp dir is not readable and/or writable,
32
+ // may still be okay if the tp/files/hg38/TermdbTest already exists and is up-to-date
33
+ console.log(`!!! insufficient permissions to create or update TermdbTest directory or symlink !!!`)
34
+ return
35
+ }
36
+
37
+ try {
38
+ if (!fs.existsSync(datadir)) {
39
+ fs.symlinkSync(targetDir, datadir)
40
+ } else if (fs.statSync(datadir).isDirectory()) {
41
+ // support an option to have an actual TermdbTest dir locally instead of a symlink,
42
+ // to make it easier to switch between native or container dev/test process,
43
+ // since a local symlink will not work as a container mount
44
+ console.log(`copying TermdbTest files to tp dir ...`)
45
+ // do not delete, copy files from repo to tp
46
+ const ps = spawnSync(`rsync`, ['-av', `${targetDir}/`, datadir], { encoding: 'utf-8' })
47
+ if (ps.stderr) throw ps.stderr
48
+ //console.log(421, [ps.stdout, ps.stderr])
49
+ } else {
50
+ console.log('replacing the TermdbTest symlink ...')
51
+ fs.unlinkSync(datadir)
52
+ fs.symlinkSync(targetDir, datadir)
53
+ }
54
+ } catch (error) {
55
+ console.warn('Error while copying data files from Repo to Tp: ', error)
56
+ }
57
+ }
@@ -1,3 +1,5 @@
1
+ import { copyDataFilesFromRepo2Tp } from "./copyDataFilesFromRepo2Tp.js";
2
+ await copyDataFilesFromRepo2Tp("files/hg38/TermdbTest");
1
3
  const genome = {
2
4
  species: "human",
3
5
  genomefile: "NA",
@@ -8,8 +10,9 @@ const genome = {
8
10
  msigdb: {
9
11
  label: "MSigDB",
10
12
  cohort: {
11
- db: { file: "files/hg38/TermdbTest/msigdb/db" },
13
+ // NOTE: in the dev environment, sjpp/start.js is
12
14
  // nest file under TermdbTest since the folder is auto symlinked
15
+ db: { file: "files/hg38/TermdbTest/msigdb/db" },
13
16
  termdb: {
14
17
  isGeneSetTermdb: true
15
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.137.2-2",
3
+ "version": "2.137.3",
4
4
  "type": "module",
5
5
  "description": "a genomics visualization tool for exploring a cohort's genotype and phenotype data",
6
6
  "main": "src/app.js",
@@ -63,8 +63,8 @@
63
63
  "@sjcrh/proteinpaint-python": "2.135.2-0",
64
64
  "@sjcrh/proteinpaint-r": "2.137.2-0",
65
65
  "@sjcrh/proteinpaint-rust": "2.137.2-0",
66
- "@sjcrh/proteinpaint-shared": "2.137.2-2",
67
- "@sjcrh/proteinpaint-types": "2.137.2-2",
66
+ "@sjcrh/proteinpaint-shared": "2.137.3",
67
+ "@sjcrh/proteinpaint-types": "2.137.3",
68
68
  "@types/express": "^5.0.0",
69
69
  "@types/express-session": "^1.18.1",
70
70
  "better-sqlite3": "^9.4.1",
@@ -1,5 +1,6 @@
1
1
  import { FilterTermValuesPayload } from "#types/checkers";
2
2
  import { getData, getSamplesPerFilter } from "../src/termdb.matrix.js";
3
+ import { authApi } from "../src/auth.js";
3
4
  const api = {
4
5
  endpoint: "filterTermValues",
5
6
  methods: {
@@ -48,11 +49,14 @@ function getList(samplesPerFilter, filtersData, tw) {
48
49
  return filteredValues;
49
50
  }
50
51
  async function getFilters(query, ds, genome, res) {
52
+ if (!query.filterByUserSites)
53
+ authApi.mayAdjustFilter(query, ds, query.terms);
51
54
  try {
52
55
  const samplesPerFilter = await getSamplesPerFilter(query, ds);
53
56
  const filtersData = await getData(
54
57
  {
55
- terms: query.terms
58
+ terms: query.terms,
59
+ __protected__: query.__protected__
56
60
  },
57
61
  ds,
58
62
  genome
package/routes/grin2.js CHANGED
@@ -47,7 +47,7 @@ async function runGrin2(g, ds, request) {
47
47
  const startTime = Date.now();
48
48
  mayLog("[GRIN2] Getting samples from cohort filter...");
49
49
  const samples = await get_samples(
50
- request.filter,
50
+ request,
51
51
  ds,
52
52
  true
53
53
  // must set to true to return sample name to be able to access file. FIXME this can let names revealed to grin2 client, may need to apply access control
@@ -29,14 +29,17 @@ function init({ genomes }) {
29
29
  };
30
30
  }
31
31
  async function getScoresDict(query, ds, genome) {
32
+ if (!query.filterByUserSites)
33
+ query.__protected__.ignoredTermIds.push(query.facilityTW.term.id);
32
34
  const terms = [...query.scoreTerms, query.facilityTW];
33
35
  if (query.scScoreTerms)
34
36
  terms.push(...query.scScoreTerms);
35
37
  const data = await getData(
36
38
  {
37
39
  terms,
38
- filter: query.site || !query.isAggregate ? void 0 : query.filter
40
+ filter: query.site || !query.isAggregate ? void 0 : query.filter,
39
41
  //if isRadarFacility and site is specified, do not apply the filter
42
+ __protected__: query.__protected__
40
43
  },
41
44
  ds,
42
45
  genome
@@ -48,6 +51,9 @@ async function getScoresDict(query, ds, genome) {
48
51
  sites = lst.map((s) => {
49
52
  return { label: data.refs.bySampleId[s.sample].label, value: s.sample };
50
53
  });
54
+ if (query.userSites) {
55
+ sites = sites.filter((s) => query.userSites.includes(s.label));
56
+ }
51
57
  let sitesSelected = [];
52
58
  if (query.site)
53
59
  sitesSelected = [query.site];
@@ -56,18 +62,18 @@ async function getScoresDict(query, ds, genome) {
56
62
  else
57
63
  sitesSelected = query.sites;
58
64
  const sampleData = sitesSelected?.length == 1 ? data.samples[sitesSelected[0]] : null;
59
- const samples = Object.values(data.samples);
65
+ let samples = sampleData ? [sampleData] : Object.values(data.samples);
66
+ if (sitesSelected?.length > 0)
67
+ samples = samples.filter((s) => sitesSelected.includes(s.sample));
60
68
  const term2Score = {};
61
69
  for (const d of query.scoreTerms) {
62
- const samples2 = sampleData ? [sampleData] : Object.values(data.samples);
63
70
  const getDictFunc = (sample) => getDict(d.$id, sample);
64
- const percents = getPercentsDict(getDictFunc, samples2);
71
+ const percents = getPercentsDict(getDictFunc, samples);
65
72
  term2Score[d.term.id] = percents;
66
73
  }
67
74
  if (query.scScoreTerms)
68
75
  for (const d of query.scScoreTerms) {
69
- const samples2 = sampleData ? [sampleData] : Object.values(data.samples);
70
- const percents = getSCPercentsDict(d, samples2);
76
+ const percents = getSCPercentsDict(d, samples);
71
77
  term2Score[d.term.id] = percents;
72
78
  }
73
79
  const facilityValue = sampleData?.[query.facilityTW.$id];
@@ -29,6 +29,8 @@ function init({ genomes }) {
29
29
  };
30
30
  }
31
31
  async function getScores(query, ds, genome) {
32
+ if (!query.filterByUserSites)
33
+ query.__protected__.ignoredTermIds.push(query.facilityTW.term.id);
32
34
  const terms = [query.facilityTW];
33
35
  for (const term of query.scoreTerms) {
34
36
  terms.push(term.score);
@@ -39,8 +41,9 @@ async function getScores(query, ds, genome) {
39
41
  const data = await getData(
40
42
  {
41
43
  terms,
42
- filter: query.site || !query.isAggregate ? void 0 : query.filter
44
+ filter: query.site || !query.isAggregate ? void 0 : query.filter,
43
45
  //if site is specified, do not apply the filter that is for the aggregation
46
+ __protected__: query.__protected__
44
47
  },
45
48
  ds,
46
49
  genome
@@ -45,8 +45,9 @@ async function trigger_getcategories(q, res, tdb, ds, genome) {
45
45
  terms: [q.tw],
46
46
  currentGeneNames: q.currentGeneNames,
47
47
  // optional, from mds3 mayAddGetCategoryArgs()
48
- rglst: q.rglst
48
+ rglst: q.rglst,
49
49
  // optional, from mds3 mayAddGetCategoryArgs()
50
+ __protected__: q.__protected__
50
51
  };
51
52
  const data = await getData(arg, ds, genome);
52
53
  if (data.error)
@@ -62,7 +62,8 @@ function make(q, req, res, ds, genome) {
62
62
  defaultChartType: ds.cohort.defaultChartType,
63
63
  invalidTokenErrorHandling: tdb.invalidTokenErrorHandling,
64
64
  colorMap: tdb.colorMap,
65
- defaultTw4correlationPlot: tdb.defaultTw4correlationPlot
65
+ defaultTw4correlationPlot: tdb.defaultTw4correlationPlot,
66
+ authFilter: req.query.filter
66
67
  };
67
68
  if (tdb.plotConfigByCohort)
68
69
  c.plotConfigByCohort = tdb.plotConfigByCohort;
@@ -92,7 +93,6 @@ function make(q, req, res, ds, genome) {
92
93
  c.assayAvailability = ds.assayAvailability;
93
94
  if (ds.cohort.correlationVolcano)
94
95
  c.correlationVolcano = ds.cohort.correlationVolcano;
95
- c.requiredAuth = authApi.getRequiredCredForDsEmbedder(q.dslabel, q.embedder);
96
96
  addRestrictAncestries(c, tdb);
97
97
  addScatterplots(c, ds);
98
98
  addMatrixplots(c, ds);
@@ -102,6 +102,7 @@ function make(q, req, res, ds, genome) {
102
102
  c.clientAuthResult = info?.clientAuthResult || {};
103
103
  if (tdb.displaySampleIds)
104
104
  c.displaySampleIds = tdb.displaySampleIds(c.clientAuthResult);
105
+ c.authFilter = req.query.filter;
105
106
  res.send({ termdbConfig: c });
106
107
  }
107
108
  function addRestrictAncestries(c, tdb) {
@@ -30,7 +30,11 @@ function init({ genomes }) {
30
30
  throw "invalid termdb object";
31
31
  if (!q.tw.$id)
32
32
  q.tw.$id = "_";
33
- const data = await getData({ filter: q.filter, filter0: q.filter0, terms: [q.tw] }, ds, genome);
33
+ const data = await getData(
34
+ { filter: q.filter, filter0: q.filter0, terms: [q.tw], __protected__: q.__protected__ },
35
+ ds,
36
+ genome
37
+ );
34
38
  if (data.error)
35
39
  throw data.error;
36
40
  const values = [];
@@ -93,7 +93,7 @@ function validate_query_getTopMutatedGenes(ds) {
93
93
  q.get = async (param) => {
94
94
  let sampleStatement = "";
95
95
  if (param.filter) {
96
- const lst = await get_samples(param.filter, ds);
96
+ const lst = await get_samples(param, ds);
97
97
  if (lst.length == 0)
98
98
  throw "empty sample filter";
99
99
  sampleStatement = `WHERE sample IN (${lst.map((i) => i.id).join(",")})`;
@@ -56,7 +56,7 @@ function nativeValidateQuery(ds, type) {
56
56
  const typeQuery = ds.queries[type];
57
57
  const samples = [];
58
58
  if (q.filter) {
59
- const sidlst = await get_samples(q.filter, ds);
59
+ const sidlst = await get_samples(q, ds);
60
60
  for (const i of sidlst) {
61
61
  if (typeQuery.samples.includes(i.id)) {
62
62
  const n = ds.cohort.termdb.q.id2sampleName(i.id);
@@ -66,7 +66,7 @@ function nativeValidateQuery(ds) {
66
66
  ds.queries.topVariablyExpressedGenes.getGenes = async (q) => {
67
67
  const samples = [];
68
68
  if (q.filter) {
69
- const sidlst = await get_samples(q.filter, ds);
69
+ const sidlst = await get_samples(q, ds);
70
70
  for (const i of sidlst) {
71
71
  if (gE.samples.includes(i.id)) {
72
72
  const n = ds.cohort.termdb.q.id2sampleName(i.id);