Skip to content

Commit

Permalink
Merge pull request #26 from pyobs/develop
Browse files Browse the repository at this point in the history
v1.2.3
  • Loading branch information
thusser authored Feb 15, 2023
2 parents df4e1bc + cb37125 commit f6f57e5
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 8 deletions.
29 changes: 29 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
*.pyc
*.pyo
*.mo
*.db
*.css.map
*.egg-info
*.sql.gz
.cache
.project
.idea
.pydevproject
.idea/workspace.xml
.DS_Store
.git/
.sass-cache
.vagrant/
__pycache__
dist
docs
env
venv
logs
src/{{ project_name }}/settings/local.py
src/node_modules
web/media
web/static/CACHE
stats
Dockerfile
LabCourse/local_settings.py
45 changes: 45 additions & 0 deletions pyobs_archive/api/management/commands/delete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import os

from django.core.management.base import BaseCommand

from pyobs_archive.api.models import Frame
from pyobs_archive import settings


class Command(BaseCommand):
help = 'Delete images'

def add_arguments(self, parser):
parser.add_argument('files', type=str, nargs='+', help='Names of files to delete')

def handle(self, *args, files: list = None, **options):
to_delete = []
for filename in files:
frames = Frame.objects.filter(basename=filename)
if len(frames) > 0:
to_delete.extend(frames)

if not to_delete:
return

print("Images to delete:")
for d in to_delete:
print(" - " + d.basename)
reply = "X"
while reply not in 'yYnN':
reply = input("Delete files? [yn]")

if reply not in 'yY':
return

for d in to_delete:
# get filename
root = settings.ARCHIVE_ROOT
filename = os.path.join(root, d.path, d.basename + '.fits.fz')

# delete file
os.remove(filename)

# delete db entry
d.delete()

59 changes: 52 additions & 7 deletions pyobs_archive/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def frames_view(request):
sort_string = ('' if order == 'asc' else '-') + sort

# get response
data = Frame.objects.order_by(sort_string)
data = Frame.objects.order_by(sort_string, 'id')

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


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def zip_view(request):
if request.method == 'POST':
return zip_view_post(request)
elif request.method == 'GET':
return zip_view_get(request)
else:
raise Http404


def zip_view_post(request):
# get frames
frames = []
for frame_id in request.POST.getlist('frame_ids[]'):
# get frame
frames.append(_frame(frame_id))

# download
return _download_zip(request, frames)


def zip_view_get(request):
# get offset and limit
try:
offset = int(request.GET.get('offset', default=0))
limit = int(request.GET.get('limit', default=1000))
except ValueError:
raise ParseError('Invalid values for offset/limit.')

# limit to 1000
limit = max(0, min(limit, 1000))
offset = max(0, offset)

# sort
sort = request.GET.get('sort', default='DATE_OBS')
order = request.GET.get('order', default='asc')
sort_string = ('' if order == 'asc' else '-') + sort

# filter
data = filter_frames(Frame.objects, request)

# and frames
root = settings.ARCHIVE_ROOT
frames = [(frame, os.path.join(root, frame.path, frame.basename + '.fits.fz')) for frame in data]

# download
return _download_zip(request, frames)


def _download_zip(request, frames):
# get archive root
root = settings.ARCHIVE_ROOT

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

# add files
for frame_id in request.POST.getlist('frame_ids[]'):
# get frame
frame, filename = _frame(frame_id)

for frame, filename in frames:
# add file to zip
zip_file.write(filename, arcname=os.path.join(archive_name, os.path.basename(filename)))
if os.path.exists(filename):
zip_file.write(filename, arcname=os.path.join(archive_name, os.path.basename(filename)))

# create and return response
response = StreamingHttpResponse(zip_file, content_type='application/zip')
Expand Down
19 changes: 19 additions & 0 deletions pyobs_archive/frontend/static/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ $(function () {
setRequestHeader(xhr);
}
},
onLoadSuccess: function() {
// update download search button
let downloadSearchBtn = $('#downloadSearchBtn');
let rows = this.totalRows;
downloadSearchBtn.html('Download all (' + rows + ')');
downloadSearchBtn.attr('href', 'frames/zip?q=a' + buildQueryParms());
},
onCheck: on_check,
onUncheck: on_check,
onCheckAll: on_check,
onUncheckAll: on_check,
totalField: 'count',
dataField: 'results',
pagination: true,
Expand Down Expand Up @@ -117,6 +128,14 @@ $(function () {
}]
});

function on_check() {

// update download button
let downloadBtn = $('#downloadBtn');
var rows = $('#table').bootstrapTable('getSelections').length;
downloadBtn.html('Download selected (' + rows + ')');
}

$('#daterange').daterangepicker({
'locale': {
'format': 'YYYY-MM-DD HH:mm'
Expand Down
8 changes: 7 additions & 1 deletion pyobs_archive/frontend/templates/archive/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,13 @@
<div class="btn-toolbar" role="group">
<form id="zip-form">
{% csrf_token %}
<button type="button" id="downloadBtn" class="btn btn-primary">Download</button>
<button type="button" id="downloadBtn" class="btn btn-success">Download selected</button>
</form>
</div>
<div class="btn-toolbar ml-2" role="group">
<form id="zip-form">
{% csrf_token %}
<a id="downloadSearchBtn" href="#" class="btn btn-primary" style="color: white">Download all</a>
</form>
</div>
</div>
Expand Down
5 changes: 5 additions & 0 deletions pyobs_archive/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
'crispy_forms',
'rest_framework',
'rest_framework.authtoken',
'corsheaders',
'pyobs_archive.api',
'pyobs_archive.authentication',
'pyobs_archive.frontend'
Expand All @@ -60,6 +61,7 @@
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
Expand Down Expand Up @@ -138,6 +140,9 @@
STATIC_URL = '/static/'
STATIC_ROOT = '/static/'

# allow access from other pages, e.g. portal
CORS_ALLOW_ALL_ORIGINS = True

# logging
LOGGING = {
'version': 1,
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ numpy
psycopg2-binary
zipstream
django-crispy-forms
django-cors-headers

0 comments on commit f6f57e5

Please sign in to comment.