Skip to content

Commit f6f57e5

Browse files
authored
Merge pull request #26 from pyobs/develop
v1.2.3
2 parents df4e1bc + cb37125 commit f6f57e5

File tree

7 files changed

+158
-8
lines changed

7 files changed

+158
-8
lines changed

.dockerignore

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
*.pyc
2+
*.pyo
3+
*.mo
4+
*.db
5+
*.css.map
6+
*.egg-info
7+
*.sql.gz
8+
.cache
9+
.project
10+
.idea
11+
.pydevproject
12+
.idea/workspace.xml
13+
.DS_Store
14+
.git/
15+
.sass-cache
16+
.vagrant/
17+
__pycache__
18+
dist
19+
docs
20+
env
21+
venv
22+
logs
23+
src/{{ project_name }}/settings/local.py
24+
src/node_modules
25+
web/media
26+
web/static/CACHE
27+
stats
28+
Dockerfile
29+
LabCourse/local_settings.py
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import os
2+
3+
from django.core.management.base import BaseCommand
4+
5+
from pyobs_archive.api.models import Frame
6+
from pyobs_archive import settings
7+
8+
9+
class Command(BaseCommand):
10+
help = 'Delete images'
11+
12+
def add_arguments(self, parser):
13+
parser.add_argument('files', type=str, nargs='+', help='Names of files to delete')
14+
15+
def handle(self, *args, files: list = None, **options):
16+
to_delete = []
17+
for filename in files:
18+
frames = Frame.objects.filter(basename=filename)
19+
if len(frames) > 0:
20+
to_delete.extend(frames)
21+
22+
if not to_delete:
23+
return
24+
25+
print("Images to delete:")
26+
for d in to_delete:
27+
print(" - " + d.basename)
28+
reply = "X"
29+
while reply not in 'yYnN':
30+
reply = input("Delete files? [yn]")
31+
32+
if reply not in 'yY':
33+
return
34+
35+
for d in to_delete:
36+
# get filename
37+
root = settings.ARCHIVE_ROOT
38+
filename = os.path.join(root, d.path, d.basename + '.fits.fz')
39+
40+
# delete file
41+
os.remove(filename)
42+
43+
# delete db entry
44+
d.delete()
45+

pyobs_archive/api/views.py

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def frames_view(request):
166166
sort_string = ('' if order == 'asc' else '-') + sort
167167

168168
# get response
169-
data = Frame.objects.order_by(sort_string)
169+
data = Frame.objects.order_by(sort_string, 'id')
170170

171171
# filter
172172
data = filter_frames(data, request)
@@ -296,9 +296,56 @@ def preview_view(request, frame_id):
296296
return HttpResponse(bio.getvalue(), content_type="image/png")
297297

298298

299-
@api_view(['POST'])
300299
@permission_classes([IsAuthenticated])
301300
def zip_view(request):
301+
if request.method == 'POST':
302+
return zip_view_post(request)
303+
elif request.method == 'GET':
304+
return zip_view_get(request)
305+
else:
306+
raise Http404
307+
308+
309+
def zip_view_post(request):
310+
# get frames
311+
frames = []
312+
for frame_id in request.POST.getlist('frame_ids[]'):
313+
# get frame
314+
frames.append(_frame(frame_id))
315+
316+
# download
317+
return _download_zip(request, frames)
318+
319+
320+
def zip_view_get(request):
321+
# get offset and limit
322+
try:
323+
offset = int(request.GET.get('offset', default=0))
324+
limit = int(request.GET.get('limit', default=1000))
325+
except ValueError:
326+
raise ParseError('Invalid values for offset/limit.')
327+
328+
# limit to 1000
329+
limit = max(0, min(limit, 1000))
330+
offset = max(0, offset)
331+
332+
# sort
333+
sort = request.GET.get('sort', default='DATE_OBS')
334+
order = request.GET.get('order', default='asc')
335+
sort_string = ('' if order == 'asc' else '-') + sort
336+
337+
# filter
338+
data = filter_frames(Frame.objects, request)
339+
340+
# and frames
341+
root = settings.ARCHIVE_ROOT
342+
frames = [(frame, os.path.join(root, frame.path, frame.basename + '.fits.fz')) for frame in data]
343+
344+
# download
345+
return _download_zip(request, frames)
346+
347+
348+
def _download_zip(request, frames):
302349
# get archive root
303350
root = settings.ARCHIVE_ROOT
304351

@@ -309,12 +356,10 @@ def zip_view(request):
309356
zip_file = zipstream.ZipFile()
310357

311358
# add files
312-
for frame_id in request.POST.getlist('frame_ids[]'):
313-
# get frame
314-
frame, filename = _frame(frame_id)
315-
359+
for frame, filename in frames:
316360
# add file to zip
317-
zip_file.write(filename, arcname=os.path.join(archive_name, os.path.basename(filename)))
361+
if os.path.exists(filename):
362+
zip_file.write(filename, arcname=os.path.join(archive_name, os.path.basename(filename)))
318363

319364
# create and return response
320365
response = StreamingHttpResponse(zip_file, content_type='application/zip')

pyobs_archive/frontend/static/js/app.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@ $(function () {
5959
setRequestHeader(xhr);
6060
}
6161
},
62+
onLoadSuccess: function() {
63+
// update download search button
64+
let downloadSearchBtn = $('#downloadSearchBtn');
65+
let rows = this.totalRows;
66+
downloadSearchBtn.html('Download all (' + rows + ')');
67+
downloadSearchBtn.attr('href', 'frames/zip?q=a' + buildQueryParms());
68+
},
69+
onCheck: on_check,
70+
onUncheck: on_check,
71+
onCheckAll: on_check,
72+
onUncheckAll: on_check,
6273
totalField: 'count',
6374
dataField: 'results',
6475
pagination: true,
@@ -117,6 +128,14 @@ $(function () {
117128
}]
118129
});
119130

131+
function on_check() {
132+
133+
// update download button
134+
let downloadBtn = $('#downloadBtn');
135+
var rows = $('#table').bootstrapTable('getSelections').length;
136+
downloadBtn.html('Download selected (' + rows + ')');
137+
}
138+
120139
$('#daterange').daterangepicker({
121140
'locale': {
122141
'format': 'YYYY-MM-DD HH:mm'

pyobs_archive/frontend/templates/archive/index.html

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,13 @@
8484
<div class="btn-toolbar" role="group">
8585
<form id="zip-form">
8686
{% csrf_token %}
87-
<button type="button" id="downloadBtn" class="btn btn-primary">Download</button>
87+
<button type="button" id="downloadBtn" class="btn btn-success">Download selected</button>
88+
</form>
89+
</div>
90+
<div class="btn-toolbar ml-2" role="group">
91+
<form id="zip-form">
92+
{% csrf_token %}
93+
<a id="downloadSearchBtn" href="#" class="btn btn-primary" style="color: white">Download all</a>
8894
</form>
8995
</div>
9096
</div>

pyobs_archive/settings.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
'crispy_forms',
4141
'rest_framework',
4242
'rest_framework.authtoken',
43+
'corsheaders',
4344
'pyobs_archive.api',
4445
'pyobs_archive.authentication',
4546
'pyobs_archive.frontend'
@@ -60,6 +61,7 @@
6061
MIDDLEWARE = [
6162
'django.middleware.security.SecurityMiddleware',
6263
'django.contrib.sessions.middleware.SessionMiddleware',
64+
'corsheaders.middleware.CorsMiddleware',
6365
'django.middleware.common.CommonMiddleware',
6466
'django.middleware.csrf.CsrfViewMiddleware',
6567
'django.contrib.auth.middleware.AuthenticationMiddleware',
@@ -138,6 +140,9 @@
138140
STATIC_URL = '/static/'
139141
STATIC_ROOT = '/static/'
140142

143+
# allow access from other pages, e.g. portal
144+
CORS_ALLOW_ALL_ORIGINS = True
145+
141146
# logging
142147
LOGGING = {
143148
'version': 1,

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ numpy
99
psycopg2-binary
1010
zipstream
1111
django-crispy-forms
12+
django-cors-headers

0 commit comments

Comments
 (0)