Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
6f4a557
Modifying config files and parser
josenavas Feb 19, 2016
f65d6bf
Merge branch 'subdir-portals' of https://github.com/biocore/qiita int…
antgonza Feb 19, 2016
ff36f09
Addressing comments
josenavas Feb 19, 2016
17042b9
fixing some files!
antgonza Feb 19, 2016
f0271e8
Fixing parser
josenavas Feb 19, 2016
6bd9d31
Merge branch 'master' of https://github.com/biocore/qiita into subdir…
josenavas Feb 19, 2016
60c50e8
Merge branch 'subdir-portals' of https://github.com/biocore/qiita int…
antgonza Feb 19, 2016
a0ab325
update sitebase for portals
squirrelo Feb 19, 2016
23afbde
move to raw output
squirrelo Feb 19, 2016
b3fc0a1
addressing @squirrelo comments
antgonza Feb 19, 2016
e5bae74
update error_log
squirrelo Feb 19, 2016
71e8383
update list_studies
squirrelo Feb 19, 2016
de2b96b
fixing some files!
antgonza Feb 19, 2016
731d62c
Merge pull request #1649 from antgonza/subdir-portals-agp
josenavas Feb 19, 2016
65c1d8d
Merge pull request #1650 from squirrelo/portal-updates-1
josenavas Feb 19, 2016
d4e544a
Fixing form in error_log.html
josenavas Feb 19, 2016
9e28c90
Merge pull request #1651 from squirrelo/portal-updates-2
josenavas Feb 19, 2016
b7ea47e
Merge branch 'subdir-portals' of https://github.com/biocore/qiita int…
josenavas Feb 19, 2016
78bc774
Fixing various files
josenavas Feb 19, 2016
f4a1ce1
More files
josenavas Feb 19, 2016
9d0d57d
Fixing study description templates
josenavas Feb 19, 2016
31acb67
Merge pull request #1655 from josenavas/subdir-portals-misc
antgonza Feb 20, 2016
a10e4af
Fixing comments
josenavas Feb 20, 2016
427f866
Adding missing import
josenavas Feb 20, 2016
48094b8
Merge pull request #1656 from josenavas/subdir-portals-2
antgonza Feb 20, 2016
593dbee
Merge pull request #1654 from josenavas/portal-updates-2
antgonza Feb 20, 2016
4981f03
Merge pull request #1652 from antgonza/subdir-portals-agp-1
josenavas Feb 20, 2016
e02ec12
Merge pull request #1657 from josenavas/subdir-portals-study-desc-tem…
antgonza Feb 20, 2016
18fdd3a
Fixing merge conflict
josenavas Feb 23, 2016
a8f8271
Fixing link in list_studies
josenavas Feb 23, 2016
690106f
Adding setUp to TestSearchStudiesAJAX
josenavas Feb 23, 2016
afcd709
Adding a test to TestSearchStudiesAJAX with different portal
josenavas Feb 23, 2016
ff469b9
Changing url in email sent to the user
josenavas Feb 24, 2016
4689470
Fixing link in sitebase.html
josenavas Feb 24, 2016
bbe27ca
Fixing moi call in analysis
josenavas Feb 25, 2016
11372c8
Fixing login_url in webserver config
josenavas Feb 25, 2016
a55fb93
Merge branch 'subdir-portals-missing' of https://github.com/josenavas…
antgonza Feb 29, 2016
030f397
Merge pull request #1662 from josenavas/subdir-portals-missing
antgonza Feb 29, 2016
c23fcee
solving rest of issues
antgonza Mar 1, 2016
6c933fb
Merge pull request #1670 from antgonza/fixing-portals
josenavas Mar 1, 2016
8ab30b5
some more minor fixes
antgonza Mar 2, 2016
d1c5468
Merge pull request #1673 from antgonza/fixing-portals-1
josenavas Mar 2, 2016
b90cbd5
Solving merge conflicts
josenavas Apr 1, 2016
1d629a5
Merge pull request #1738 from josenavas/subdir-portals-asp
antgonza Apr 1, 2016
7df98ca
make share js more generic
squirrelo Apr 8, 2016
997274b
add anaysis sharing to UI. Fix #1615
squirrelo Apr 8, 2016
5fe04bc
add & update tests
squirrelo Apr 8, 2016
01ac908
add messaging for sharing analyses and studies
squirrelo Apr 8, 2016
1a3414a
merge origin/share-studies-in-studies
squirrelo Apr 8, 2016
9d7524b
remove global var
squirrelo Apr 8, 2016
63d0a7a
fix analysis share changes
squirrelo Apr 8, 2016
5fb1147
merge origin/share-studies-in-studies
squirrelo Apr 8, 2016
2314e24
fix backwards messages
squirrelo Apr 9, 2016
b40bb8b
merge upstream/master
squirrelo Apr 9, 2016
32f052b
fix suggestions
squirrelo Apr 10, 2016
3f60461
indentation
squirrelo Apr 11, 2016
5ad25f0
use data attribute
squirrelo Apr 11, 2016
521f8af
Solving merge conflicts
josenavas Apr 11, 2016
d4af309
here we go ...
antgonza Apr 11, 2016
a2978d6
addressing @josenavas comments
antgonza Apr 11, 2016
4aef864
Merge pull request #1763 from antgonza/subdir-portals-antoniog
josenavas Apr 11, 2016
4f268fd
fixed processing_artifact.html
Apr 11, 2016
288930e
FIX: urls
mortonjt Apr 11, 2016
b9726e9
update for portals
squirrelo Apr 11, 2016
fc91318
Merge pull request #1766 from mortonjt/urls2
josenavas Apr 11, 2016
5e954b8
fixed import in processing_artifact
Apr 11, 2016
8492ecb
Merge pull request #1768 from squirrelo/share-analyses
antgonza Apr 11, 2016
b797495
Merge pull request #1767 from squirrelo/portals-1
josenavas Apr 11, 2016
f4b1d40
Merge pull request #1765 from tkosciol/subdir-portals-tomasz
josenavas Apr 11, 2016
44bcbb5
ENH:Update URLs in data_type_menu and prep_summary
ElDeveloper Apr 11, 2016
3e9525b
Merge pull request #1769 from ElDeveloper/subdir-portals-yoshiki
josenavas Apr 11, 2016
8fdab75
Fixing study base
josenavas Apr 11, 2016
94dba47
missing
josenavas Apr 11, 2016
a01fe32
Merge pull request #1770 from josenavas/subdir-portals-base
antgonza Apr 11, 2016
e50a7f7
update sharing for portals
squirrelo Apr 11, 2016
3d47374
update sharing for portals
squirrelo Apr 11, 2016
a2dcb69
add missing init
squirrelo Apr 11, 2016
ec1aa7e
Fixing sample_summary.html
josenavas Apr 11, 2016
cd16e14
BUG: Move admin tasks to the main portal only
ElDeveloper Apr 11, 2016
a105310
add missing portals calls
squirrelo Apr 11, 2016
4030341
Merge pull request #1773 from ElDeveloper/admin-portals
josenavas Apr 11, 2016
bd0ea05
Merge pull request #1772 from josenavas/subdir-portals-3
antgonza Apr 11, 2016
8751685
Merge pull request #1771 from squirrelo/sharing-portals-changes
josenavas Apr 11, 2016
921a886
QUOTES
squirrelo Apr 11, 2016
ef44f38
Merge pull request #1774 from squirrelo/sharing-portals-changes
josenavas Apr 11, 2016
b629203
remove URL from sharing
squirrelo Apr 11, 2016
b52311a
Merge pull request #1775 from squirrelo/sharing-portals-changes
josenavas Apr 11, 2016
0e81d94
remove url
squirrelo Apr 11, 2016
291fb69
fix message
squirrelo Apr 11, 2016
3a68699
Merge pull request #1776 from squirrelo/sharing-portals-changes
antgonza Apr 11, 2016
9cae18f
change portal config
squirrelo Apr 11, 2016
1c64740
move import back
squirrelo Apr 11, 2016
6c9c666
Adding the portal to the base url for the plugins
josenavas Apr 11, 2016
be58c8d
Merge pull request #1777 from squirrelo/sharing-portals-changes
antgonza Apr 11, 2016
542ebdb
Adding comments
josenavas Apr 11, 2016
4f2450d
Merge pull request #1778 from josenavas/subdir-portals-plugin
antgonza Apr 11, 2016
38c56ae
Fixing config file
josenavas Apr 11, 2016
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
14 changes: 13 additions & 1 deletion qiita_core/configuration_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ class ConfigurationManager(object):
The VAMPS URL
conf_fp : str
The filepath for the configuration file that is loaded
portal : str
The portal under the Qiita instance is running under
portal_dir : str
The portal subdirectory used in the URL
portal_fp : str
The filepath to the portal styling config file
plugin_launcher : str
Expand Down Expand Up @@ -161,7 +165,6 @@ def _get_main(self, config):
self.working_dir)
self.max_upload_size = config.getint('main', 'MAX_UPLOAD_SIZE')
self.require_approval = config.getboolean('main', 'REQUIRE_APPROVAL')
self.portal = config.get('main', 'PORTAL')
self.plugin_launcher = config.get('main', 'PLUGIN_LAUNCHER')

self.valid_upload_extension = [ve.strip() for ve in config.get(
Expand Down Expand Up @@ -240,3 +243,12 @@ def _get_vamps(self, config):

def _get_portal(self, config):
self.portal_fp = config.get('portal', 'PORTAL_FP')
self.portal = config.get('portal', 'PORTAL')
self.portal_dir = config.get('portal', 'PORTAL_DIR')
if self.portal_dir:
if not self.portal_dir.startswith('/'):
self.portal_dir = "/%s" % self.portal_dir
if self.portal_dir.endswith('/'):
self.portal_dir = self.portal_dir[:-1]
else:
self.portal_dir = ""
10 changes: 7 additions & 3 deletions qiita_core/support_files/config_test.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@ BASE_DATA_DIR =
# Valid upload extension, comma separated. Empty for no uploads
VALID_UPLOAD_EXTENSION = fastq,fastq.gz,txt,tsv,sff,fna,qual

# Portal the site is working under
PORTAL = QIITA

# Script used for launching plugins
PLUGIN_LAUNCHER = qiita-plugin-launcher

Expand Down Expand Up @@ -144,5 +141,12 @@ URL = https://vamps.mbl.edu/mobe_workshop/getfile.php

# ----------------------------- Portal settings -----------------------------
[portal]

# Portal the site is working under
PORTAL = QIITA

# Portal subdirectory
PORTAL_DIR =

# Full path to portal styling config file
PORTAL_FP =
Binary file modified qiita_core/support_files/config_test_travis.cfg.enc
Binary file not shown.
30 changes: 7 additions & 23 deletions qiita_db/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -683,13 +683,11 @@ def share(self, user):
user: User object
The user to share the analysis with
"""
with qdb.sql_connection.TRN:
self._lock_check()

# Make sure the analysis is not already shared with the given user
if user.id in self.shared_with:
return
# Make sure the analysis is not already shared with the given user
if user.id == self.owner or user.id in self.shared_with:
return

with qdb.sql_connection.TRN:
sql = """INSERT INTO qiita.analysis_users (analysis_id, email)
VALUES (%s, %s)"""
qdb.sql_connection.TRN.add(sql, [self._id, user.id])
Expand All @@ -704,8 +702,6 @@ def unshare(self, user):
The user to unshare the analysis with
"""
with qdb.sql_connection.TRN:
self._lock_check()

sql = """DELETE FROM qiita.analysis_users
WHERE analysis_id = %s AND email = %s"""
qdb.sql_connection.TRN.add(sql, [self._id, user.id])
Expand Down Expand Up @@ -981,27 +977,15 @@ def _build_mapping_file(self, samples, rename_dup_samples=False):
"""Builds the combined mapping file for all samples
Code modified slightly from qiime.util.MetadataMap.__add__"""
with qdb.sql_connection.TRN:
# query to get the latest qiime mapping file
sql = """SELECT filepath
FROM qiita.filepath
JOIN qiita.prep_template_filepath USING (filepath_id)
JOIN qiita.prep_template USING (prep_template_id)
JOIN qiita.filepath_type USING (filepath_type_id)
WHERE filepath_type = 'qiime_map'
AND artifact_id IN (SELECT *
FROM qiita.find_artifact_roots(%s))
ORDER BY filepath_id DESC LIMIT 1"""
_, fp = qdb.util.get_mountpoint('templates')[0]

all_ids = set()
to_concat = []
for aid, samps in viewitems(samples):
qdb.sql_connection.TRN.add(sql, [aid])
qm_fp = qdb.sql_connection.TRN.execute_fetchindex()[0][0]
qiime_map_fp = qdb.artifact.Artifact(
aid).prep_templates[0].qiime_map_fp

# Parse the mapping file
qm = qdb.metadata_template.util.load_template_to_dataframe(
join(fp, qm_fp), index='#SampleID')
qiime_map_fp, index='#SampleID')

# if we are not going to merge the duplicated samples
# append the aid to the sample name
Expand Down
5 changes: 4 additions & 1 deletion qiita_db/processing_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,12 @@ def _generate_cmd(self):
software = self.command.software
plugin_start_script = software.start_script
plugin_env_script = software.environment_script
# Appending the portal URL so the job requests the information from the
# portal server that submitted the job
url = "%s%s" % (qiita_config.base_url, qiita_config.portal_dir)
cmd = '%s "%s" "%s" "%s" "%s" "%s"' % (
qiita_config.plugin_launcher, plugin_env_script,
plugin_start_script, qiita_config.base_url, self.id, job_dir)
plugin_start_script, url, self.id, job_dir)
return cmd

def submit(self):
Expand Down
2 changes: 1 addition & 1 deletion qiita_db/support_files/populate_test_db.sql
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ INSERT INTO qiita.job (data_type_id, job_status_id, command_id, options, input_f
INSERT INTO qiita.job_results_filepath (job_id, filepath_id) VALUES (1, 13), (2, 14);

-- Insert Analysis
INSERT INTO qiita.analysis (email, name, description, analysis_status_id, pmid) VALUES ('test@foo.bar', 'SomeAnalysis', 'A test analysis', 1, '121112'), ('test@foo.bar', 'SomeSecondAnalysis', 'Another test analysis', 1, '22221112');
INSERT INTO qiita.analysis (email, name, description, analysis_status_id, pmid) VALUES ('test@foo.bar', 'SomeAnalysis', 'A test analysis', 1, '121112'), ('admin@foo.bar', 'SomeSecondAnalysis', 'Another test analysis', 1, '22221112');
INSERT INTO qiita.analysis_portal (analysis_id, portal_type_id) VALUES (1, 1), (2, 1);
-- Insert Analysis Workflow
INSERT INTO qiita.analysis_workflow (analysis_id, step) VALUES (1, 3), (2, 3);
Expand Down
2 changes: 1 addition & 1 deletion qiita_db/test/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ def test_get_shared_studies(self):
def test_get_private_analyses(self):
user = qdb.user.User('test@foo.bar')
qiita_config.portal = "QIITA"
exp = {qdb.analysis.Analysis(1), qdb.analysis.Analysis(2)}
exp = {qdb.analysis.Analysis(1)}
self.assertEqual(user.private_analyses, exp)

qiita_config.portal = "EMP"
Expand Down
74 changes: 66 additions & 8 deletions qiita_pet/handlers/analysis_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,29 @@
from functools import partial

from tornado.web import authenticated, HTTPError, StaticFileHandler
from tornado.gen import coroutine, Task
from moi import ctx_default, r_client
from moi.job import submit
from moi.group import get_id_from_user, create_info

from qiita_pet.util import is_localhost
from qiita_pet.handlers.base_handlers import BaseHandler
from qiita_pet.handlers.util import download_link_or_path
from qiita_pet.handlers.util import (
download_link_or_path, get_shared_links)
from qiita_pet.exceptions import QiitaPetAuthorizationError
from qiita_ware.dispatchable import run_analysis
from qiita_db.analysis import Analysis
from qiita_db.artifact import Artifact
from qiita_db.job import Command
from qiita_db.util import (get_db_files_base_dir,
from qiita_db.user import User
from qiita_db.util import (get_db_files_base_dir, add_message,
check_access_to_analysis_result,
filepath_ids_to_rel_paths, get_filepath_id)
from qiita_db.exceptions import QiitaDBUnknownIDError
from qiita_db.logger import LogEntry
from qiita_db.reference import Reference
from qiita_core.util import execute_as_transaction
from qiita_core.qiita_settings import qiita_config

SELECT_SAMPLES = 2
SELECT_COMMANDS = 3
Expand Down Expand Up @@ -127,11 +131,13 @@ def post(self, analysis_id):
cmd_split = [x.split("#") for x in command_args]

moi_user_id = get_id_from_user(self.current_user.id)
moi_group = create_info(analysis_id, 'group', url='/analysis/',
parent=moi_user_id, store=True)
moi_group = create_info(
analysis_id, 'group', url='%s/analysis/' % qiita_config.portal_dir,
parent=moi_user_id, store=True)
moi_name = ("Creating %s... When finished, please click the 'Success' "
"link to the right" % analysis.name)
moi_result_url = '/analysis/results/%d' % analysis_id
moi_result_url = '%s/analysis/results/%d' % (qiita_config.portal_dir,
analysis_id)

submit(ctx_default, moi_group['id'], moi_name,
moi_result_url, run_analysis, analysis_id, cmd_split,
Expand Down Expand Up @@ -172,10 +178,13 @@ def get(self, analysis_id):
data_type = proc_data.data_type
dropped[data_type].append((proc_data.study.title, len(samples),
', '.join(samples)))
share_access = (self.current_user.id in analysis.shared_with or
self.current_user.id == analysis.owner)

self.render("analysis_results.html", analysis_id=analysis_id,
jobres=jobres, aname=analysis.name, dropped=dropped,
basefolder=get_db_files_base_dir())
basefolder=get_db_files_base_dir(),
share_access=share_access)

@authenticated
@execute_as_transaction
Expand Down Expand Up @@ -206,7 +215,8 @@ def post(self, analysis_id):
LogEntry.create('Runtime', "Couldn't remove analysis ID %d: %s" %
(analysis_id, e))

self.redirect(u"/analysis/show/?level=%s&message=%s" % (level, msg))
self.redirect(u"%s/analysis/show/?level=%s&message=%s"
% (qiita_config.portal_dir, level, msg))


class ShowAnalysesHandler(BaseHandler):
Expand Down Expand Up @@ -271,7 +281,8 @@ def post(self):
LogEntry.create('Runtime', "Couldn't remove analysis ID %d: %s" %
(analysis_id, e))

self.redirect(u"/analysis/show/?level=%s&message=%s" % (level, msg))
self.redirect(u"%s/analysis/show/?level=%s&message=%s"
% (qiita_config.portal_dir, level, msg))


class ResultsHandler(StaticFileHandler, BaseHandler):
Expand Down Expand Up @@ -349,3 +360,50 @@ class AnalysisSummaryAJAX(BaseHandler):
def get(self):
info = self.current_user.default_analysis.summary_data()
self.write(dumps(info))


class ShareAnalysisAJAX(BaseHandler):
@execute_as_transaction
def _get_shared_for_study(self, analysis, callback):
shared_links = get_shared_links(analysis)
users = [u.email for u in analysis.shared_with]
callback((users, shared_links))

@execute_as_transaction
def _share(self, analysis, user, callback):
user = User(user)
add_message('Analysis <a href="%s/analysis/results/%d">\'%s\'</a> '
'has been shared with you.' %
(qiita_config.portal_dir, analysis.id, analysis.name),
[user])
callback(analysis.share(user))

@execute_as_transaction
def _unshare(self, analysis, user, callback):
user = User(user)
add_message('Analysis \'%s\' has been unshared from you.' %
analysis.name, [user])
callback(analysis.unshare(user))

@authenticated
@coroutine
@execute_as_transaction
def get(self):
analysis_id = int(self.get_argument('id'))
analysis = Analysis(analysis_id)
if self.current_user != analysis.owner:
raise HTTPError(403, 'User %s does not have permissions to share '
'analysis %s' % (
self.current_user.id, analysis.id))

selected = self.get_argument('selected', None)
deselected = self.get_argument('deselected', None)

if selected is not None:
yield Task(self._share, analysis, selected)
if deselected is not None:
yield Task(self._unshare, analysis, deselected)

users, links = yield Task(self._get_shared_for_study, analysis)

self.write(dumps({'users': users, 'links': links}))
24 changes: 12 additions & 12 deletions qiita_pet/handlers/auth_handlers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#!/usr/bin/env python

from tornado.escape import url_escape, json_encode
from tornado.web import HTTPError

Expand Down Expand Up @@ -46,19 +44,21 @@ def post(self):
try:
send_email(username, "QIITA: Verify Email Address", "Please "
"click the following link to verify email address: "
"%s/auth/verify/%s?email=%s"
% (qiita_config.base_url, info['user_verify_code'],
url_escape(username)))
"%s/%s/auth/verify/%s?email=%s"
% (qiita_config.base_url, qiita_config.portal_dir,
info['user_verify_code'], url_escape(username)))
except:
msg = ("Unable to send verification email. Please contact the "
"qiita developers at <a href='mailto:qiita-help"
"@gmail.com'>qiita-help@gmail.com</a>")
self.redirect(u"/?level=danger&message=" + url_escape(msg))
self.redirect(u"%s/?level=danger&message=%s"
% (qiita_config.portal_dir, url_escape(msg)))
return
self.redirect(u"/")
self.redirect(u"%s/" % qiita_config.portal_dir)
else:
error_msg = u"?error=" + url_escape(msg)
self.redirect(u"/auth/create/" + error_msg)
self.redirect(u"%s/auth/create/%s"
% (qiita_config.portal_dir, error_msg))


class AuthVerifyHandler(BaseHandler):
Expand All @@ -78,7 +78,7 @@ def get(self, code):
class AuthLoginHandler(BaseHandler):
"""user login, no page necessary"""
def get(self):
self.redirect("/")
self.redirect("%s/" % qiita_config.portal_dir)

@execute_as_transaction
def post(self):
Expand All @@ -92,7 +92,7 @@ def post(self):
if "auth/" not in self.request.headers['Referer']:
nextpage = self.request.headers['Referer']
else:
nextpage = "/"
nextpage = "%s/" % qiita_config.portal_dir

msg = ""
# check the user level
Expand All @@ -110,7 +110,7 @@ def post(self):
# means DB not available, so set maintenance mode and failover
r_client.set("maintenance", "Database connection unavailable, "
"please try again later.")
self.redirect("/")
self.redirect("%s/" % qiita_config.portal_dir)
return

# Check the login information
Expand Down Expand Up @@ -142,4 +142,4 @@ class AuthLogoutHandler(BaseHandler):
"""Logout handler, no page necessary"""
def get(self):
self.clear_cookie("user")
self.redirect("/")
self.redirect("%s/" % qiita_config.portal_dir)
8 changes: 5 additions & 3 deletions qiita_pet/handlers/compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from qiita_ware.context import submit
from qiita_ware.dispatchable import create_raw_data, copy_raw_data
from qiita_core.util import execute_as_transaction
from qiita_core.qiita_settings import qiita_config
from qiita_db.util import get_mountpoint
from qiita_db.metadata_template.prep_template import PrepTemplate

Expand All @@ -23,7 +24,7 @@ def get(self, job_id):
# TODO: something smart
pass

self.redirect('/')
self.redirect('%s/' % qiita_config.portal_dir)


class CreateRawData(BaseHandler):
Expand Down Expand Up @@ -82,5 +83,6 @@ def post(self):
self.render('compute_wait.html',
job_id=job_id, title='Adding raw data',
completion_redirect=(
'/study/description/%s?top_tab=prep_template_tab'
'&sub_tab=%s' % (study_id, pt_id)))
'%s/study/description/%s?top_tab=prep_template_tab'
'&sub_tab=%s'
% (qiita_config.portal_dir, study_id, pt_id)))
Loading