Skip to content

Commit d0647cc

Browse files
authoredJan 3, 2025··
fix #3451 (#3452)
* fix #3451 * fix test_base_handlers.py * fix test_generate_analysis_list
1 parent 34d7d9a commit d0647cc

File tree

6 files changed

+292
-153
lines changed

6 files changed

+292
-153
lines changed
 

‎qiita_db/test/test_util.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -790,9 +790,11 @@ def test_generate_analysis_list(self):
790790
exp = [{'mapping_files': [
791791
(16, qdb.util.get_filepath_information(16)['fullpath'])],
792792
'description': 'A test analysis', 'artifacts': [8, 9], 'name':
793-
'SomeAnalysis', 'analysis_id': 1, 'visibility': 'private'},
793+
'SomeAnalysis', 'owner': 'test@foo.bar', 'analysis_id': 1,
794+
'visibility': 'private'},
794795
{'mapping_files': [], 'description': 'Another test analysis',
795796
'artifacts': [], 'name': 'SomeSecondAnalysis',
797+
'owner': 'admin@foo.bar',
796798
'analysis_id': 2, 'visibility': 'private'}]
797799
# removing timestamp for testing
798800
for i in range(len(obs)):

‎qiita_db/util.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -2114,7 +2114,7 @@ def generate_analysis_list(analysis_ids, public_only=False):
21142114
return []
21152115

21162116
sql = """
2117-
SELECT analysis_id, a.name, a.description, a.timestamp,
2117+
SELECT analysis_id, a.name, a.description, a.timestamp, a.email,
21182118
array_agg(DISTINCT artifact_id),
21192119
array_agg(DISTINCT visibility),
21202120
array_agg(DISTINCT CASE WHEN filepath_type = 'plain_text'
@@ -2135,7 +2135,8 @@ def generate_analysis_list(analysis_ids, public_only=False):
21352135

21362136
qdb.sql_connection.TRN.add(sql, [tuple(analysis_ids)])
21372137
for row in qdb.sql_connection.TRN.execute_fetchindex():
2138-
aid, name, description, ts, artifacts, av, mapping_files = row
2138+
aid, name, description, ts, owner, artifacts, \
2139+
av, mapping_files = row
21392140

21402141
av = 'public' if set(av) == {'public'} else 'private'
21412142
if av != 'public' and public_only:
@@ -2156,7 +2157,7 @@ def generate_analysis_list(analysis_ids, public_only=False):
21562157
results.append({
21572158
'analysis_id': aid, 'name': name, 'description': description,
21582159
'timestamp': ts.strftime("%m/%d/%y %H:%M:%S"),
2159-
'visibility': av, 'artifacts': artifacts,
2160+
'visibility': av, 'artifacts': artifacts, 'owner': owner,
21602161
'mapping_files': mapping_files})
21612162

21622163
return results

‎qiita_pet/handlers/analysis_handlers/base_handlers.py

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ def analysis_description_handler_get_request(analysis_id, user):
8585
'analysis_is_public': analysis.is_public,
8686
'analysis_description': analysis.description,
8787
'analysis_mapping_id': analysis.mapping_file,
88+
'analysis_owner': analysis.owner.email,
8889
'alert_type': alert_type,
8990
'artifacts': artifacts,
9091
'analysis_reservation': analysis._slurm_reservation()[0],

‎qiita_pet/handlers/analysis_handlers/tests/test_base_handlers.py

+3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def test_analysis_description_handler_get_request(self):
3838
'analysis_id': 1,
3939
'analysis_description': 'A test analysis',
4040
'analysis_mapping_id': 16,
41+
'analysis_owner': 'test@foo.bar',
4142
'analysis_is_public': False,
4243
'alert_type': 'info',
4344
'artifacts': {
@@ -67,6 +68,7 @@ def test_analysis_description_handler_get_request(self):
6768
'analysis_id': 1,
6869
'analysis_description': 'A test analysis',
6970
'analysis_mapping_id': 16,
71+
'analysis_owner': 'test@foo.bar',
7072
'analysis_is_public': False,
7173
'alert_type': 'info',
7274
'artifacts': {
@@ -98,6 +100,7 @@ def test_analysis_description_handler_get_request(self):
98100
'analysis_id': 1,
99101
'analysis_description': 'A test analysis',
100102
'analysis_mapping_id': 16,
103+
'analysis_owner': 'test@foo.bar',
101104
'analysis_is_public': False,
102105
'alert_type': 'danger',
103106
'artifacts': {
+273-149
Original file line numberDiff line numberDiff line change
@@ -1,178 +1,302 @@
1-
{% extends sitebase.html %}
2-
{% block head %}
3-
<link rel="stylesheet" href="{% raw qiita_config.portal_dir %}/static/vendor/css/select2.min.css" type="text/css">
4-
<script type="text/javascript" src="{% raw qiita_config.portal_dir %}/static/vendor/js/select2.min.js"></script>
5-
<script type="text/javascript" src="{% raw qiita_config.portal_dir %}/static/js/sharing.js"></script>
1+
{% extends sitebase.html %} {% block head %}
2+
<link
3+
rel="stylesheet"
4+
href="{% raw qiita_config.portal_dir %}/static/vendor/css/select2.min.css"
5+
type="text/css"
6+
/>
7+
<script
8+
type="text/javascript"
9+
src="{% raw qiita_config.portal_dir %}/static/vendor/js/select2.min.js"
10+
></script>
11+
<script
12+
type="text/javascript"
13+
src="{% raw qiita_config.portal_dir %}/static/js/sharing.js"
14+
></script>
615

716
<script type="text/javascript">
8-
/*
9-
* update_analysis_reservation will update the analysis resevation
10-
*
11-
* @param analysis_id: The id of the analysis to update
12-
* @param reservation: The reservation
13-
*
14-
*/
17+
/*
18+
* update_analysis_reservation will update the analysis resevation
19+
*
20+
* @param analysis_id: The id of the analysis to update
21+
* @param reservation: The reservation
22+
*
23+
*/
1524

16-
function update_analysis_reservation(analysis_id, reservation) {
17-
$.ajax({
18-
url: '{% raw qiita_config.portal_dir %}/analysis/description/{{analysis_id}}/',
19-
type: 'PATCH',
20-
data: {'op': 'replace', 'path': 'reservation', 'value': reservation},
21-
success: function(data) {
22-
$('#analysis-reservation-modal-view').modal('hide');
23-
if(data.status == 'error') {
24-
bootstrapAlert(data.message, "danger");
25-
} else {
26-
$('#reservation').val(reservation);
27-
$('#analysis-reservation-modal-data').text("Reservation: " + reservation);
25+
function update_analysis_reservation(analysis_id, reservation) {
26+
$.ajax({
27+
url: '{% raw qiita_config.portal_dir %}/analysis/description/{{analysis_id}}/',
28+
type: 'PATCH',
29+
data: {'op': 'replace', 'path': 'reservation', 'value': reservation},
30+
success: function(data) {
31+
$('#analysis-reservation-modal-view').modal('hide');
32+
if(data.status == 'error') {
33+
bootstrapAlert(data.message, "danger");
34+
} else {
35+
$('#reservation').val(reservation);
36+
$('#analysis-reservation-modal-data').text("Reservation: " + reservation);
37+
}
2838
}
29-
}
30-
});
39+
});
3140

32-
}
41+
}
3342

34-
$(document).ready(function(){
35-
// Create the processing network view object
36-
newProcessingNetworkVue("#analysis-graph-vue");
43+
$(document).ready(function(){
44+
// Create the processing network view object
45+
newProcessingNetworkVue("#analysis-graph-vue");
3746

38-
// Show the alert message, if any
39-
{% if alert_msg %}
40-
bootstrapAlert("{{alert_msg}}", "{{alert_type}}");
41-
{% end %}
47+
// Show the alert message, if any
48+
{% if alert_msg %}
49+
bootstrapAlert("{{alert_msg}}", "{{alert_type}}");
50+
{% end %}
4251

43-
// starting share
44-
init_sharing("{% raw qiita_config.portal_dir %}");
45-
update_share();
52+
// starting share
53+
init_sharing("{% raw qiita_config.portal_dir %}");
54+
update_share();
4655

47-
$('#studies-artifacts-table').dataTable();
56+
$('#studies-artifacts-table').dataTable();
4857

49-
});
58+
});
5059
</script>
5160
<style>
52-
.graph {
53-
width: 80%;
54-
height: 400px;
55-
border: 1px solid #ccc;
56-
}
61+
.graph {
62+
width: 80%;
63+
height: 400px;
64+
border: 1px solid #ccc;
65+
}
5766
</style>
58-
{% end %}
59-
{% block content %}
67+
{% end %} {% block content %}
6068

6169
<div class="row">
62-
<div class="col">
63-
<form action="{% raw qiita_config.portal_dir %}/analysis/description/{{analysis_id}}/" method="post" id="make-public"><input name="analysis_id" value="{{analysis_id}}" type="hidden"></form>
64-
<h2>
65-
{{analysis_name}} - ID {{analysis_id}}
66-
<small>
67-
({{analysis_description}}) -
68-
{% if analysis_is_public %}
69-
<b>Public</b>
70-
{% else %}
71-
<b>Private</b>
72-
{% end %}
73-
{% if analysis_mapping_id is not None %}
74-
<a class="btn btn-default" href="{% raw qiita_config.portal_dir %}/download/{{analysis_mapping_id}}"><span class="glyphicon glyphicon-download-alt"></span> Mapping file</a>
75-
{% end %}
76-
{% if not analysis_is_public %}
77-
<a class="btn btn-default" onclick="if (confirm('Are you sure you want to make this analysis public? Note that this will not allow you to delete your analysis later.')) { $('#make-public').submit(); }"><span class="glyphicon glyphicon-globe"></span> Make analysis public</a>
78-
{% end %}
79-
<a class="btn btn-default" data-toggle="modal" data-target="#analysis-reservation-modal-view"><span class="glyphicon glyphicon-pencil" name="analysis-reservation-modal-data" id="analysis-reservation-modal-data"> Reservation: {% raw analysis_reservation %}</span></a>
80-
81-
82-
</small>
83-
</h2>
84-
<a class="btn btn-info" data-toggle="modal" data-target="#share-analysis-modal-view" onclick="modify_sharing({{analysis_id}});"><span class=" glyphicon glyphicon-share"></span></a> Shared with: <span id="shared_html_{{analysis_id}}"></span>
85-
<div class='row'>
86-
<div class='col-md-12'>
87-
<b>Studies and artifacts used in this analysis:</b>
88-
<button class="btn btn-default" data-toggle="collapse" data-target="#studies-artifacts-div">
89-
<span class="glyphicon glyphicon-eye-open"></span>
90-
Show/Hide
91-
</button>
92-
<div id="studies-artifacts-div" class="collapse" style="padding: 10px 10px 10px 10px; border-radius: 10px; background: #EEE;">
93-
<table id="studies-artifacts-table" class="display table-bordered table-hover" style="width:100%">
94-
<thead>
95-
<tr>
96-
<th>Artifact ID</th>
97-
<th>Study IDs</th>
98-
<th>Prep IDs</th>
99-
<th>Study Title</th>
100-
<th>Parent Processing</th>
101-
<th>Merging Scheme</th>
102-
<th>Total Samples Selected</th>
103-
</tr>
104-
</thead>
105-
<tbody>
106-
{% for aid, data in artifacts.items() %}
107-
<tr>
108-
<td>{{aid}}</td>
109-
<td>{{data[0]}}</td>
110-
<td>{{', '.join(data[4])}}</td>
111-
<td><a href="{% raw qiita_config.portal_dir %}/study/description/{{data[0]}}" target="_blank">{{data[1]}}</a></td>
112-
<td>{{data[2][1]}}</td>
113-
<td>{{data[2][0]}}</td>
114-
<td>{{ len(data[3]) }}</td>
115-
</tr>
116-
{% end %}
117-
</tbody>
118-
</table>
70+
<div class="col">
71+
<form
72+
action="{% raw qiita_config.portal_dir %}/analysis/description/{{analysis_id}}/"
73+
method="post"
74+
id="make-public"
75+
>
76+
<input name="analysis_id" value="{{analysis_id}}" type="hidden" />
77+
</form>
78+
<h2>
79+
{{analysis_name}} - ID {{analysis_id}}
80+
<small>
81+
({{analysis_description}}) - {% if analysis_is_public %}
82+
<b>Public</b>
83+
{% else %}
84+
<b>Private</b>
85+
{% end %} {% if analysis_mapping_id is not None %}
86+
<a
87+
class="btn btn-default"
88+
href="{% raw qiita_config.portal_dir %}/download/{{analysis_mapping_id}}"
89+
><span class="glyphicon glyphicon-download-alt"></span>
90+
Mapping file</a
91+
>
92+
{% end %} {% if not analysis_is_public %}
93+
<a
94+
class="btn btn-default"
95+
onclick="if (confirm('Are you sure you want to make this analysis public? Note that this will not allow you to delete your analysis later.')) { $('#make-public').submit(); }"
96+
><span class="glyphicon glyphicon-globe"></span> Make
97+
analysis public</a
98+
>
99+
{% end %}
100+
<a
101+
class="btn btn-default"
102+
data-toggle="modal"
103+
data-target="#analysis-reservation-modal-view"
104+
><span
105+
class="glyphicon glyphicon-pencil"
106+
name="analysis-reservation-modal-data"
107+
id="analysis-reservation-modal-data"
108+
>
109+
Reservation: {% raw analysis_reservation %}</span
110+
></a
111+
>
112+
</small>
113+
</h2>
114+
Owner:
115+
<a href="mailto:{{analysis_owner}}">{{analysis_owner}}</a>
116+
<br />
117+
<a
118+
class="btn btn-info"
119+
data-toggle="modal"
120+
data-target="#share-analysis-modal-view"
121+
onclick="modify_sharing({{analysis_id}});"
122+
><span class="glyphicon glyphicon-share"></span
123+
></a>
124+
Shared with: <span id="shared_html_{{analysis_id}}"></span>
125+
<div class="row">
126+
<div class="col-md-12">
127+
<b>Studies and artifacts used in this analysis:</b>
128+
<button
129+
class="btn btn-default"
130+
data-toggle="collapse"
131+
data-target="#studies-artifacts-div"
132+
>
133+
<span class="glyphicon glyphicon-eye-open"></span>
134+
Show/Hide
135+
</button>
136+
<div
137+
id="studies-artifacts-div"
138+
class="collapse"
139+
style="
140+
padding: 10px 10px 10px 10px;
141+
border-radius: 10px;
142+
background: #eee;
143+
"
144+
>
145+
<table
146+
id="studies-artifacts-table"
147+
class="display table-bordered table-hover"
148+
style="width: 100%"
149+
>
150+
<thead>
151+
<tr>
152+
<th>Artifact ID</th>
153+
<th>Study IDs</th>
154+
<th>Prep IDs</th>
155+
<th>Study Title</th>
156+
<th>Parent Processing</th>
157+
<th>Merging Scheme</th>
158+
<th>Total Samples Selected</th>
159+
</tr>
160+
</thead>
161+
<tbody>
162+
{% for aid, data in artifacts.items() %}
163+
<tr>
164+
<td>{{aid}}</td>
165+
<td>{{data[0]}}</td>
166+
<td>{{', '.join(data[4])}}</td>
167+
<td>
168+
<a
169+
href="{% raw qiita_config.portal_dir %}/study/description/{{data[0]}}"
170+
target="_blank"
171+
>{{data[1]}}</a
172+
>
173+
</td>
174+
<td>{{data[2][1]}}</td>
175+
<td>{{data[2][0]}}</td>
176+
<td>{{ len(data[3]) }}</td>
177+
</tr>
178+
{% end %}
179+
</tbody>
180+
</table>
181+
</div>
182+
</div>
119183
</div>
120-
</div>
121184
</div>
122-
</div>
123-
<hr/>
185+
<hr />
124186
</div>
125-
<div id='analysis-graph-vue' style="margin-left: 15px">
126-
<processing-graph v-bind:is-analysis-pipeline='true' ref="procGraph" portal="{% raw qiita_config.portal_dir %}" graph-endpoint="/analysis/description/{{analysis_id}}/graph/" jobs-endpoint="/analysis/description/{{analysis_id}}/jobs/" element-id="{{analysis_id}}"></processing-graph>
187+
<div id="analysis-graph-vue" style="margin-left: 15px">
188+
<processing-graph
189+
v-bind:is-analysis-pipeline="true"
190+
ref="procGraph"
191+
portal="{% raw qiita_config.portal_dir %}"
192+
graph-endpoint="/analysis/description/{{analysis_id}}/graph/"
193+
jobs-endpoint="/analysis/description/{{analysis_id}}/jobs/"
194+
element-id="{{analysis_id}}"
195+
></processing-graph>
127196
</div>
128-
<div class="row" id='processing-content-div'></div>
129-
197+
<div class="row" id="processing-content-div"></div>
130198

131-
<!-- Modal used to share the analysis -->
132-
<div class="modal fade" id="share-analysis-modal-view" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
133-
<div class="modal-dialog">
134-
<div class="modal-content">
135-
<div class="modal-header">
136-
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
137-
<h4 class="modal-title" id="myModalLabel">Modify Sharing Settings</h4>
138-
</div>
139-
<div class="modal-body">
140-
<div>
141-
<div class="form-group">
142-
<label for="shares-select">Add/Remove Users</label>
143-
<select multiple class="analysis" id="shares-select" data-share-url="{% raw qiita_config.portal_dir %}/analysis/sharing/" data-current-id={{analysis_id}} style="width:50%"></select>
144-
<br>
145-
<br>
146-
Adding or removing email addresses automatically updates who the analysis is shared with. Once you click the `X` or give mouse focus to the analysis page you'll see your new sharing settings.
199+
<!-- Modal used to share the analysis -->
200+
<div
201+
class="modal fade"
202+
id="share-analysis-modal-view"
203+
tabindex="-1"
204+
role="dialog"
205+
aria-labelledby="myModalLabel"
206+
aria-hidden="true"
207+
>
208+
<div class="modal-dialog">
209+
<div class="modal-content">
210+
<div class="modal-header">
211+
<button
212+
type="button"
213+
class="close"
214+
data-dismiss="modal"
215+
aria-hidden="true"
216+
>
217+
&times;
218+
</button>
219+
<h4 class="modal-title" id="myModalLabel">
220+
Modify Sharing Settings
221+
</h4>
147222
</div>
148-
</div>
149-
</div>
150-
<div class="modal-footer">
223+
<div class="modal-body">
224+
<div>
225+
<div class="form-group">
226+
<label for="shares-select">Add/Remove Users</label>
227+
<select
228+
multiple
229+
class="analysis"
230+
id="shares-select"
231+
data-share-url="{% raw qiita_config.portal_dir %}/analysis/sharing/"
232+
data-current-id="{{analysis_id}}"
233+
style="width: 50%"
234+
></select>
235+
<br />
236+
<br />
237+
Adding or removing email addresses automatically updates
238+
who the analysis is shared with. Once you click the `X`
239+
or give mouse focus to the analysis page you'll see your
240+
new sharing settings.
241+
</div>
242+
</div>
243+
</div>
244+
<div class="modal-footer"></div>
151245
</div>
152246
</div>
153-
</div>
154247
</div>
155248

156249
<!-- Modal used to change reservation -->
157-
<div class="modal fade" id="analysis-reservation-modal-view" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
158-
<div class="modal-dialog">
159-
<div class="modal-content">
160-
<div class="modal-header">
161-
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
162-
<h4 class="modal-title" id="myModalLabel">Modify Reservation Setting</h4>
163-
</div>
164-
<div class="modal-body">
165-
<div>
166-
<div class="form-group">
167-
<label for="shares-select">Reservation (optional)</label>
168-
<input type="text" class="form-control" id="reservation" name="reservation" value="{{ analysis_reservation }}" placeholder="Reservation (optional)">
169-
<button id="update-reservation-btn" class="btn btn-default" onclick="update_analysis_reservation({{analysis_id}}, $('#reservation').val());">Update</button>
170-
</div>
171-
</div>
172-
</div>
173-
<div class="modal-footer"></div>
174-
</div>
175-
</div>
250+
<div
251+
class="modal fade"
252+
id="analysis-reservation-modal-view"
253+
tabindex="-1"
254+
role="dialog"
255+
aria-labelledby="myModalLabel"
256+
aria-hidden="true"
257+
>
258+
<div class="modal-dialog">
259+
<div class="modal-content">
260+
<div class="modal-header">
261+
<button
262+
type="button"
263+
class="close"
264+
data-dismiss="modal"
265+
aria-hidden="true"
266+
>
267+
&times;
268+
</button>
269+
<h4 class="modal-title" id="myModalLabel">
270+
Modify Reservation Setting
271+
</h4>
272+
</div>
273+
<div class="modal-body">
274+
<div>
275+
<div class="form-group">
276+
<label for="shares-select"
277+
>Reservation (optional)</label
278+
>
279+
<input
280+
type="text"
281+
class="form-control"
282+
id="reservation"
283+
name="reservation"
284+
value="{{ analysis_reservation }}"
285+
placeholder="Reservation (optional)"
286+
/>
287+
<button
288+
id="update-reservation-btn"
289+
class="btn btn-default"
290+
onclick="update_analysis_reservation({{analysis_id}}, $('#reservation').val());"
291+
>
292+
Update
293+
</button>
294+
</div>
295+
</div>
296+
</div>
297+
<div class="modal-footer"></div>
298+
</div>
299+
</div>
176300
</div>
177301

178302
{% end %}

‎qiita_pet/templates/list_analyses.html

+8
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ <h3 class="gray-msg">Your Analyses</h3>
145145
<th>Analysis ID</th>
146146
<th>Analysis Name</th>
147147
<th>Visibility</th>
148+
<th>Owner</th>
148149
<th>Creation Timestamp</th>
149150
<th>Mapping File</th>
150151
<th>Delete?</th>
@@ -168,6 +169,9 @@ <h3 class="gray-msg">Your Analyses</h3>
168169
<td>
169170
{{analysis['visibility']}}
170171
</td>
172+
<td>
173+
<a href="mailto:{{analysis['owner']}}">{{analysis['owner']}}</a>
174+
</td>
171175
<td>
172176
{{analysis['timestamp']}}
173177
</td>
@@ -195,6 +199,7 @@ <h3 class="gray-msg">Public Analyses</h3>
195199
<th>Artifacts</th>
196200
<th>Analysis ID</th>
197201
<th>Analysis Name</th>
202+
<th>Owner</th>
198203
<th>Creation Timestamp</th>
199204
<th>Mapping File</th>
200205
</tr>
@@ -213,6 +218,9 @@ <h3 class="gray-msg">Public Analyses</h3>
213218
({{analysis['description']}})
214219
{% end %}
215220
</td>
221+
<td>
222+
<a href="mailto:{{analysis['owner']}}">{{analysis['owner']}}</a>
223+
</td>
216224
<td>
217225
{{analysis['timestamp']}}
218226
</td>

0 commit comments

Comments
 (0)
Please sign in to comment.