diff --git a/default/decorators.py b/default/decorators.py index 5c28578..dfa9cb9 100644 --- a/default/decorators.py +++ b/default/decorators.py @@ -1,9 +1,14 @@ +import os from functools import wraps +from zipfile import ZipFile from dateutil import parser -from django.http import JsonResponse +from django.http import HttpResponse, JsonResponse from django.utils.translation import gettext as _ +from default.data_file import DataFile +from default.util import invalid_request_file_message + def clear_files(function): @wraps(function) @@ -24,6 +29,37 @@ def wrap(request, *args, **kwargs): return wrap +def extract_last_result(function): + @wraps(function) + def wrap(request, *args, **kwargs): + request_object = getattr(request, request.method) + send_result = request_object.get('sendResult') + if 'files' in request.session and send_result: + # Set files session to the last generated results + for file in request.session['results']: + data_file = DataFile(**file) + # All json results are compressed in a zip file + if data_file.ext == '.zip': + with ZipFile(data_file.path) as zipfile: + for f in zipfile.infolist(): + prefix, ext = os.path.splitext(f.filename) + new_file = DataFile(prefix, ext) + path, f.filename = os.path.split(new_file.path) + zipfile.extract(f, path) + # Open the file to check if it is the correct type + with open(new_file.path, 'rb') as h: + file_type = request_object.get('type', None) + message = invalid_request_file_message(h, file_type) + if message: + return HttpResponse(message, status=401) # error 401 for invalid type + else: + request.session['files'].append(new_file.as_dict()) + request.session.modified = True + return function(request, *args, **kwargs) + + return wrap + + def published_date(function): @wraps(function) def wrap(request, *args, **kwargs): diff --git a/default/static/css/custom.css b/default/static/css/custom.css index 018bbe7..b9274dd 100644 --- a/default/static/css/custom.css +++ b/default/static/css/custom.css @@ -81,6 +81,10 @@ .content-wrap.ocp-content { padding-bottom: 12rem; } +.form-send { + margin-bottom: 0; + margin-top: 10px; +} .panel-title a { color: #9baf00; diff --git a/default/static/js/to-spreadsheet.js b/default/static/js/to-spreadsheet.js index e5c66b5..954e594 100644 --- a/default/static/js/to-spreadsheet.js +++ b/default/static/js/to-spreadsheet.js @@ -7,6 +7,7 @@ errorBox = $('.response-fail'), dropAreaFileLink = $('.drop-area-msg label'), urlInput = $('#input_url_0 input'), + actions = $('.actions'), urlHelpBlock = $('.input-url-container .help-block'), tabPanels = $('.nav.nav-tabs a') ; @@ -21,19 +22,25 @@ uploadButton.attr('disabled', 'disabled'); } - function transformInServer() { + function transformInServer(send) { /* call the server to transform the files */ // mask the page processingModal.modal('show'); + data = $('#unflatten-options').serialize() + // check if results were sent + if (send === 'sendResult'){ + data = data + '&sendResult=true&type=' + JSON.parse($('#fileupload').attr('data-form-data')).type; + } + $.ajax('/to-spreadsheet/go/', { 'dataType': 'json', - 'data': $('#unflatten-options').serialize(), + 'data': data, 'method': 'POST' }) .done(showLinksToResults) .fail(showActionErrorMessage) .always(function () { - // hide the modal after the ajax call + // hide the modal after the ajax call processingModal.modal('hide'); }) ; @@ -126,6 +133,10 @@ } } + function checkSendResult() { + return uploadButton.hasClass('sendResult'); + } + function uploadAndSubmitFile() { // we don't want to add any more files disableFileInput(); @@ -167,11 +178,16 @@ } function send() { - if (getActiveTab() === 'url') { - sendUrlAndSubmit(); + if (checkSendResult) { + transformInServer('sendResult'); } else { - uploadAndSubmitFile(); + if (getActiveTab() === 'url') { + sendUrlAndSubmit(); + } + else { + uploadAndSubmitFile(); + } } } @@ -221,5 +237,26 @@ // clear the input's value urlInput.val(''); disableUploadButton(); + + // check if results were sent to this page + if (window.location.search == '?sendResult=true') { + processingModal.modal('show'); + $.ajax('/send-result/validate/', {'dataType': 'json', type: 'GET'}) + .done(function (data) { + dropArea.removeClass('empty'); + dropArea.children('.drop-area-msg-empty').addClass('hidden'); + dropArea.children('.drop-area-received-msg').removeClass('hidden'); + $('.drop-area-received-msg .file-result').html(data); + actions.removeClass('hidden'); + uploadButton.addClass('sendResult'); + enableUploadButton(); + }) + .fail(function () { + errorBox.removeClass('hidden'); + }) + .always(function () { + processingModal.modal('hide'); + }); + } }); })(); \ No newline at end of file diff --git a/default/static/js/uploader.js b/default/static/js/uploader.js index 0ac5430..fab7ec7 100644 --- a/default/static/js/uploader.js +++ b/default/static/js/uploader.js @@ -31,6 +31,7 @@ var toucanApp = toucanApp || {}; function disableAddFiles() { $('.fileinput-button').attr('disabled', true); $('.fileinput-button input:file').attr('disabled', true); + $('.fileinput-button label').removeAttr("for"); } function enableAddFiles() { @@ -126,7 +127,10 @@ var toucanApp = toucanApp || {}; } function whenAjaxReqFails(jqXHR) { - $('.response-fail.default-error').removeClass('hidden'); + if (jqXHR.status === 401) + $('.response-warning.file-process-failed').removeClass('hidden'); + else + $('.response-fail.default-error').removeClass('hidden'); app.hideProcessingModal(); } @@ -175,28 +179,38 @@ var toucanApp = toucanApp || {}; disableAddFiles(); hideMessages(); - var promises = $.map(_fileItems, function (val) { - return val.submit(); - }); - $.when.apply($, promises) - .done(function () { - performAction($('#fileupload').attr('data-perform-action')); - }) - .fail(function () { - enableAddFiles(); - $('.response-warning.file-process-failed').removeClass('hidden'); - }) - .always(function () { - clearFiles(); // so they will not be uploaded again - var failures = $.grep(promises, function (promise) { - return promise.state() === 'rejected'; - }); - if (failures.length){ - // validations failed for some files, show message + /* check if results were sent and performAction directly, otherwise files are uploaded first */ + if ($('#upload-button').hasClass('sendResult') == true) { + app.setParams(function(params){ + params['sendResult'] = 'true'; + params['type'] = JSON.parse($('#fileupload').attr('data-form-data')).type; + return params; + }); + performAction($('#fileupload').attr('data-perform-action')); + } else { + var promises = $.map(_fileItems, function (val) { + return val.submit(); + }); + $.when.apply($, promises) + .done(function () { + performAction($('#fileupload').attr('data-perform-action')); + }) + .fail(function () { + enableAddFiles(); $('.response-warning.file-process-failed').removeClass('hidden'); - } - }) - ; + }) + .always(function () { + clearFiles(); // so they will not be uploaded again + var failures = $.grep(promises, function (promise) { + return promise.state() === 'rejected'; + }); + if (failures.length){ + // validations failed for some files, show message + $('.response-warning.file-process-failed').removeClass('hidden'); + } + }) + ; + } } function upload_url() { @@ -226,13 +240,7 @@ var toucanApp = toucanApp || {}; $(slt).addClass('has-error'); $(slt).append('
' + msg + '
'); }); - if (jqXHR.status === 400) { - $('.response-fail.default-error').removeClass('hidden'); - } - if (jqXHR.status === 401) { - $('.response-warning.file-process-failed').removeClass('hidden'); - } - app.hideProcessingModal(); + whenAjaxReqFails(jqXHR); $('#processing-modal .downloading-status').addClass('hidden'); }) .always(function () { @@ -248,6 +256,10 @@ var toucanApp = toucanApp || {}; ; } + function send_to() { + window.location.href = $('.to-function').val() + '?sendResult=true'; + } + /** plugin initialization & listeners**/ var fileupload = $('#fileupload') @@ -263,12 +275,39 @@ var toucanApp = toucanApp || {}; /* click upload url button behaviour */ $("#url-button").click(upload_url); + /* click send button behaviour */ + $('.send-button').click(send_to); + + /* add warning before closing/navigating away from page */ window.onload = function () { /* clear input values */ $('#input_url_0 input').val(''); $('#encoding').val('utf-8'); $('#splitSize').val('1') + /* check if results were sent to this page */ + if (window.location.search == '?sendResult=true') { + app.showProcessingModal(); + $.ajax('/send-result/validate/', {'dataType': 'json', type: 'GET'}) + .done(function (data) { + disableAddFiles(); + enableUploadButton(); + $('.drop-area').removeClass('empty'); + $('.drop-area').addClass('single'); + $('.drop-area .file-selector-empty').addClass('hidden'); + $('.drop-area .drop-area-received-msg').removeClass('hidden'); + $('.drop-area .drop-area-received-msg .file-result').html(data); + $('.actions').removeClass('hidden'); + $('#upload-button').addClass('sendResult'); + }) + .fail(function () { + $('.response-fail').removeClass('hidden'); + }) + .always(function () { + app.hideProcessingModal(); + }); + } + /* add warning before closing/navigating away from page */ window.addEventListener("beforeunload", function (e) { if (_fileItems.length === 0 || _done) { diff --git a/default/templates/default/base-tool.html b/default/templates/default/base-tool.html index b635b30..fe9cbf0 100644 --- a/default/templates/default/base-tool.html +++ b/default/templates/default/base-tool.html @@ -38,6 +38,7 @@ + {% block send-options %}{% endblock %} diff --git a/default/templates/default/base-uploader.html b/default/templates/default/base-uploader.html index 616b696..d16bf42 100644 --- a/default/templates/default/base-uploader.html +++ b/default/templates/default/base-uploader.html @@ -13,7 +13,7 @@ {{ block.super }} diff --git a/default/templates/default/upgrade.html b/default/templates/default/upgrade.html index 6d0f457..8412c56 100644 --- a/default/templates/default/upgrade.html +++ b/default/templates/default/upgrade.html @@ -1,11 +1,14 @@ {% extends 'default/base-uploader.html' %} {% load static %} {% load i18n %} +{% load send_options_tag %} {% block subtitle %} >> {% trans "Upgrade from 1.0 to 1.1" %} {% endblock %} {% block form-options %}, "type": "package release"{% endblock %} +{% block send-options %}{% show_options "compile split convert" %}{% endblock %} + {% block info_title %} {% blocktrans trimmed %} Use this tool to update @@ -14,11 +17,14 @@ record packages to OCDS 1.1. {% endblocktrans %} +{% endblock %}

+{% block info_content %}

{% trans "Check the Pretty JSON checkbox to get a pretty print on the output files." %} {% trans "By default the output encoding is utf-8, you can change it in Encoding text box." %}

+ {{ block.super }} {% endblock %} {% block extraoptions %} diff --git a/default/templatetags/send_options_tag.py b/default/templatetags/send_options_tag.py new file mode 100644 index 0000000..9fdc7a0 --- /dev/null +++ b/default/templatetags/send_options_tag.py @@ -0,0 +1,25 @@ +from django import template + +from django.utils.translation import gettext as _ + +register = template.Library() + +ALL_OPTIONS = [ + {'id': 'compile', 'value': '/compile/', 'text': _('Compile Releases')}, + {'id': 'split', 'value': '/split-packages/', 'text': _('Split Packages')}, + {'id': 'upgrade', 'value': '/upgrade/', 'text': _('Upgrade from 1.0 to 1.1')}, + {'id': 'convert', 'value': '/to-spreadsheet/', 'text': _('Convert to CSV/Excel')}, +] + + +@register.inclusion_tag('default/tags/send_options_properties.html') +def show_options(options): + """ + :param options: str list of options from templates. E.g. {% show_options "compile split upgrade convert" %} + :return: the properties of the options to display + """ + options_selected = [] + for option in ALL_OPTIONS: + if option['id'] in options: + options_selected.append(option) + return {'options': options_selected} diff --git a/default/urls.py b/default/urls.py index f223788..2c74814 100644 --- a/default/urls.py +++ b/default/urls.py @@ -8,6 +8,7 @@ path('upload/', views.uploadfile, name='upload'), path('upload-url/', views.upload_url, name='upload_url'), path('upload-url/status/', views.upload_url_status, name='upload_url_status'), + path('send-result/validate/', views.validate_send_result, name='validate_send_result'), path('delete/', views.deletefile, name='delete_file'), path('result///', views.retrieve_result, name='retrieve_result'), path('result////', views.retrieve_result, name='retrieve_result'), diff --git a/default/util.py b/default/util.py index 81ac2f3..9d03a74 100644 --- a/default/util.py +++ b/default/util.py @@ -41,7 +41,7 @@ def get_files_from_session(request): yield DataFile(**fileinfo) -def json_response(files, warnings=None, pretty_json=False, codec='utf-8'): +def json_response(request, files, warnings=None, pretty_json=False, codec='utf-8'): file = DataFile('result', '.zip') file.write_json_to_zip(files, pretty_json=pretty_json, codec=codec) @@ -54,6 +54,9 @@ def json_response(files, warnings=None, pretty_json=False, codec='utf-8'): if warnings: response['warnings'] = warnings + # Save the last generated result on session + request.session['results'] = [file.as_dict()] + return JsonResponse(response) @@ -66,7 +69,7 @@ def make_package(request, published_date, method, pretty_json, codec, warnings): else: items.append(item) - return json_response({ + return json_response(request, { 'result.json': method(items, published_date=published_date), }, warnings=warnings, pretty_json=pretty_json, codec=codec) diff --git a/default/views.py b/default/views.py index a64ece3..53ad9e6 100644 --- a/default/views.py +++ b/default/views.py @@ -19,8 +19,8 @@ from requests.exceptions import ConnectionError, HTTPError, SSLError from default.data_file import DataFile -from default.decorators import (clear_drive_session_vars, clear_files, published_date, require_files, - require_get_param, validate_optional_args, validate_split_size) +from default.decorators import (clear_drive_session_vars, clear_files, extract_last_result, published_date, + require_files, require_get_param, validate_optional_args, validate_split_size) from default.forms import MappingSheetOptionsForm, UnflattenOptionsForm from default.google_drive import get_credentials_from_session, google_api_messages, upload_to_drive from default.mapping_sheet import (get_extended_mapping_sheet, get_mapping_sheet_from_uploaded_file, @@ -98,13 +98,14 @@ def upgrade(request): @require_files +@extract_last_result @validate_optional_args def perform_upgrade(request, pretty_json=False, encoding='utf-8', warnings=None): data = {} for file in get_files_from_session(request): data.update({file.name_with_suffix('upgraded'): upgrade_10_11( file.json(codec=encoding, object_pairs_hook=OrderedDict))}) - return json_response(data, warnings, pretty_json, encoding) + return json_response(request, data, warnings, pretty_json, encoding) @require_GET @@ -126,6 +127,7 @@ def get_schema_as_options(request): @require_files +@extract_last_result @published_date @validate_optional_args def perform_package_releases(request, pretty_json=False, published_date='', encoding='utf-8', warnings=None): @@ -134,6 +136,7 @@ def perform_package_releases(request, pretty_json=False, published_date='', enco @require_files +@extract_last_result @published_date @validate_optional_args def perform_combine_packages(request, pretty_json=False, published_date='', encoding='utf-8', warnings=None): @@ -145,6 +148,7 @@ def perform_combine_packages(request, pretty_json=False, published_date='', enco @require_files +@extract_last_result @published_date @validate_optional_args @validate_split_size @@ -187,7 +191,7 @@ def perform_split_packages(request, pretty_json=False, published_date='', size=1 content[package_data] = context[i:i + size] result.update({name: content}) - return json_response(result, warnings, pretty_json, encoding) + return json_response(request, result, warnings, pretty_json, encoding) @require_files @@ -197,7 +201,7 @@ def perform_compile(request, pretty_json=False, published_date='', encoding='utf packages = [file.json(codec=encoding) for file in get_files_from_session(request)] return_versioned_release = request.GET.get('includeVersioned') == 'true' - return json_response({ + return json_response(request, { 'result.json': next(merge(packages, return_package=True, published_date=published_date, return_versioned_release=return_versioned_release)), }, warnings, pretty_json, encoding) @@ -258,6 +262,7 @@ def mapping_sheet(request): @require_files +@extract_last_result @require_POST def perform_to_spreadsheet(request): input_file = next(get_files_from_session(request)) @@ -296,6 +301,7 @@ def perform_to_spreadsheet(request): @require_files +@extract_last_result @validate_optional_args def perform_to_json(request, pretty_json=False, encoding='utf-8', warnings=None): input_file = next(get_files_from_session(request)) @@ -332,14 +338,14 @@ def perform_to_json(request, pretty_json=False, encoding='utf-8', warnings=None) shutil.rmtree(input_file_path) with open(output_name) as json_file: - return json_response({'result.json': json.load(json_file)}, warnings, pretty_json, encoding) + return json_response(request, {'result.json': json.load(json_file)}, warnings, pretty_json, encoding) @require_POST def upload_url(request): request.session['files'] = [] errors = [] - status = 401 + status = 401 # error 401 for invalid type for data in request.POST: if 'input_url' in data: @@ -400,6 +406,14 @@ def upload_url_status(request): return JsonResponse(len(request.session['files']), safe=False) +@require_GET +def validate_send_result(request): + if 'results' in request.session and request.session['results']: + file = request.session['results'][0] # always one result is saved + return JsonResponse(file['prefix'] + file['ext'], safe=False) + return HttpResponse(status=400) + + @require_POST def uploadfile(request): request_file = request.FILES['file'] @@ -410,7 +424,7 @@ def uploadfile(request): message = invalid_request_file_message(request_file, file_type) if message: - return HttpResponse(message, status=400) + return HttpResponse(message, status=401) # error 401 for invalid type else: data_file.write(request_file) diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po index d38bdcb..6327c84 100644 --- a/locale/es/LC_MESSAGES/django.po +++ b/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-09-08 10:11-0400\n" +"POT-Creation-Date: 2020-09-16 12:23-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: default/decorators.py:36 +#: default/decorators.py:72 #, python-format msgid "" "An invalid published date was submitted, and therefore ignored: %(date)s" @@ -26,7 +26,7 @@ msgstr "" "La fecha enviada es inválida: %(date)s, por lo que se omitió en los " "resultados." -#: default/decorators.py:54 +#: default/decorators.py:90 msgid "" "An invalid split size was submitted, and therefore ignored. Default value is " "used, split size: 1" @@ -34,7 +34,7 @@ msgstr "" "El tamaño de paquete ingresado es inválido, se omitió el valor. Se utiliza " "el valor por defecto. Tamaño de paquete: 1" -#: default/decorators.py:73 +#: default/decorators.py:109 #, python-format msgid "" "Encoding %(encoding)s ... is not recognized. The default value 'utf-8' was " @@ -43,7 +43,7 @@ msgstr "" "La codificación %(encoding)s ... no se reconoce. Se utiliza la codificación " "'utf-8' por defecto." -#: default/decorators.py:102 +#: default/decorators.py:138 msgid "The {} parameter is required" msgstr "El parámetro {} es requerido" @@ -172,47 +172,49 @@ msgid "less" msgstr "menos" #: default/templates/default/base-tool.html:29 -#: default/templates/default/mapping_sheet.html:43 +#: default/templates/default/mapping_sheet.html:44 #: default/templates/default/to-spreadsheet.html:14 msgid "Success!" msgstr "¡Éxito!" #: default/templates/default/base-tool.html:32 -#: default/templates/default/mapping_sheet.html:46 +#: default/templates/default/mapping_sheet.html:47 +#: default/templates/default/snippets/output_description.html:7 #: default/templates/default/to-spreadsheet.html:18 #: default/templates/default/to-spreadsheet.html:29 msgid "Download" msgstr "Descargar" #: default/templates/default/base-tool.html:36 -#: default/templates/default/mapping_sheet.html:50 +#: default/templates/default/mapping_sheet.html:51 +#: default/templates/default/snippets/output_description.html:11 #: default/templates/default/to-spreadsheet.html:21 #: default/templates/default/to-spreadsheet.html:32 msgid "Save to Google Drive" msgstr "Guardar en Google Drive" #: default/templates/default/base-tool.html:39 -#: default/templates/default/mapping_sheet.html:53 +#: default/templates/default/mapping_sheet.html:54 #: default/templates/default/to-spreadsheet.html:24 #: default/templates/default/to-spreadsheet.html:35 msgid "File saved on Google Drive" msgstr "Archivo guardado en Google Drive" #: default/templates/default/base-tool.html:39 -#: default/templates/default/mapping_sheet.html:53 +#: default/templates/default/mapping_sheet.html:54 #: default/templates/default/to-spreadsheet.html:24 #: default/templates/default/to-spreadsheet.html:35 msgid "Open" msgstr "Abrir" -#: default/templates/default/base-tool.html:58 -#: default/templates/default/to-spreadsheet.html:116 +#: default/templates/default/base-tool.html:59 +#: default/templates/default/to-spreadsheet.html:120 msgid "" "Processing operation. Please don't refresh nor close the browser window!" msgstr "" "Procesando la operación. Por favor no refresque ni cierre el navegador." -#: default/templates/default/base-tool.html:59 +#: default/templates/default/base-tool.html:60 msgid "Please wait... If a new window opens, please authorize the application." msgstr "" "Por favor espere... Si se abre una nueva ventana, favor autorice la " @@ -222,22 +224,19 @@ msgstr "" msgid "" "We couldn't check that all files were JSON or of the OCDS type requested." msgstr "" -"No pudimos comprobar que todos los archivos sean JSON, o del tipo OCDS " -"solicitado" +"No pudimos comprobar que todos los archivos son JSON, o del tipo OCDS " +"solicitado." #: default/templates/default/base-uploader.html:16 -msgid "" -"You can add more files or remove them, then click on Start again." -msgstr "" -"Puede agregar más archivos o eliminarlos, luego puede hacer clic en " -"Procesar otra vez" +msgid "Please verify each file and try again." +msgstr "Favor verifique cada archivo e intente de nuevo." #: default/templates/default/base-uploader.html:17 msgid "Files with validation issues will be ignored by default." msgstr "Los archivos con problemas de validación serán ignorados por defecto." #: default/templates/default/base-uploader.html:20 -#: default/templates/default/to-json.html:14 +#: default/templates/default/to-json.html:17 #: default/templates/default/to-spreadsheet.html:41 msgid "An error has occurred!" msgstr "¡Ha ocurrido un error!" @@ -250,50 +249,55 @@ msgstr "" "Por favor verifique que todos sus archivos son válidos de acuerdo al " "estándar OCDS, e intente de nuevo en unos minutos." -#: default/templates/default/base-uploader.html:37 -#: default/templates/default/to-json.html:52 -#: default/templates/default/to-spreadsheet.html:73 +#: default/templates/default/base-uploader.html:38 +#: default/templates/default/to-json.html:56 +#: default/templates/default/to-spreadsheet.html:74 msgid "Provide the URL to a file:" msgstr "Provea la URL a un archivo:" -#: default/templates/default/base-uploader.html:54 -#: default/templates/default/mapping_sheet.html:137 +#: default/templates/default/base-uploader.html:55 +#: default/templates/default/mapping_sheet.html:138 msgid "Add URL" msgstr "Añadir URL" -#: default/templates/default/base-uploader.html:56 -#: default/templates/default/base-uploader.html:93 -#: default/templates/default/to-json.html:60 -#: default/templates/default/to-json.html:89 -#: default/templates/default/to-spreadsheet.html:105 +#: default/templates/default/base-uploader.html:57 +#: default/templates/default/base-uploader.html:95 +#: default/templates/default/to-json.html:64 +#: default/templates/default/to-json.html:93 +#: default/templates/default/to-spreadsheet.html:109 msgid "Start" -msgstr "Procesar" +msgstr "Iniciar" -#: default/templates/default/base-uploader.html:81 -#: default/templates/default/to-json.html:82 -#: default/templates/default/to-spreadsheet.html:86 +#: default/templates/default/base-uploader.html:82 +#: default/templates/default/to-json.html:86 +#: default/templates/default/to-spreadsheet.html:87 msgid "Add a file" msgstr "Agregue un archivo" -#: default/templates/default/base-uploader.html:81 -#: default/templates/default/to-json.html:83 -#: default/templates/default/to-spreadsheet.html:87 +#: default/templates/default/base-uploader.html:82 +#: default/templates/default/to-json.html:87 +#: default/templates/default/to-spreadsheet.html:88 msgid "or drag and drop here." msgstr "o arrastre y suelte aquí" -#: default/templates/default/base-uploader.html:89 +#: default/templates/default/base-uploader.html:85 +#: default/templates/default/to-spreadsheet.html:95 +msgid "Received: " +msgstr "Recibido: " + +#: default/templates/default/base-uploader.html:91 msgid "Add more files" msgstr "Agregar más archivos" -#: default/templates/default/base-uploader.html:105 +#: default/templates/default/base-uploader.html:107 msgid "Processed " msgstr "Procesado " -#: default/templates/default/base-uploader.html:105 +#: default/templates/default/base-uploader.html:107 msgid " of " msgstr " de " -#: default/templates/default/base-uploader.html:105 +#: default/templates/default/base-uploader.html:107 msgid " files ..." msgstr " archivos..." @@ -302,12 +306,12 @@ msgstr " archivos..." msgid "OCDS Toucan" msgstr "OCDS Toucan" -#: default/templates/default/combine-packages.html:5 +#: default/templates/default/combine-packages.html:6 #: default/templates/default/index.html:29 msgid "Combine Packages" msgstr "Combinar Paquetes" -#: default/templates/default/combine-packages.html:10 +#: default/templates/default/combine-packages.html:13 msgid "" "Use this tool to combine release packages " @@ -322,9 +326,9 @@ msgstr "" "record_package/\" target=\"_blank\">paquetes de record en un solo " "paquete." -#: default/templates/default/combine-packages.html:18 +#: default/templates/default/combine-packages.html:21 #: default/templates/default/compile.html:18 -#: default/templates/default/package-releases.html:17 +#: default/templates/default/package-releases.html:20 msgid "" "Fill in the Published date textbox to set " "publishedDate in the output package." @@ -332,20 +336,20 @@ msgstr "" "Use la opción Fecha de Publicación para establecer " "publishedDate del paquete de salida." -#: default/templates/default/combine-packages.html:19 -#: default/templates/default/split-packages.html:23 +#: default/templates/default/combine-packages.html:22 +#: default/templates/default/split-packages.html:26 msgid "" "Select the correct Package type option before starting." msgstr "" "Seleccione la opción correcta de Tipo de Paquete antes de " "empezar." -#: default/templates/default/combine-packages.html:22 +#: default/templates/default/combine-packages.html:25 #: default/templates/default/compile.html:26 -#: default/templates/default/package-releases.html:20 -#: default/templates/default/split-packages.html:29 -#: default/templates/default/to-json.html:35 -#: default/templates/default/upgrade.html:19 +#: default/templates/default/package-releases.html:23 +#: default/templates/default/split-packages.html:32 +#: default/templates/default/to-json.html:38 +#: default/templates/default/upgrade.html:24 msgid "" "Check the Pretty JSON checkbox to get a pretty print on the " "output files." @@ -353,12 +357,12 @@ msgstr "" "Seleccione la opción JSON Indentado para indentar los " "archivos de salida." -#: default/templates/default/combine-packages.html:23 +#: default/templates/default/combine-packages.html:26 #: default/templates/default/compile.html:27 -#: default/templates/default/package-releases.html:21 -#: default/templates/default/split-packages.html:30 -#: default/templates/default/to-json.html:36 -#: default/templates/default/upgrade.html:20 +#: default/templates/default/package-releases.html:24 +#: default/templates/default/split-packages.html:33 +#: default/templates/default/to-json.html:39 +#: default/templates/default/upgrade.html:25 msgid "" "By default the output encoding is utf-8, you can change it in " "Encoding text box." @@ -366,8 +370,8 @@ msgstr "" "Por defecto la codificación de salida es utf-8, utiliza la caja de texto " "Codificación para ingresar otra codificación." -#: default/templates/default/combine-packages.html:26 -#: default/templates/default/split-packages.html:33 +#: default/templates/default/combine-packages.html:29 +#: default/templates/default/split-packages.html:36 msgid "" "Each input file must be a JSON file containing either a single package or an " "array of packages." @@ -377,6 +381,7 @@ msgstr "" #: default/templates/default/compile.html:5 #: default/templates/default/index.html:49 +#: default/templatetags/send_options_tag.py:8 msgid "Compile Releases" msgstr "Compilar Releases" @@ -412,7 +417,7 @@ msgid "Please verify that your files are release packages before uploading." msgstr "" "Favor verifique que sus archivos sean paquetes de release antes de subirlos." -#: default/templates/default/compile.html:38 +#: default/templates/default/compile.html:39 msgid "Include Versioned Releases: " msgstr "Incluir el bloque versionedRelease: " @@ -421,17 +426,19 @@ msgid "The authentication has finished, you can close this window now." msgstr "El flujo de autenticación se ha completado. Puede cerrar esta ventana." #: default/templates/default/index.html:19 -#: default/templates/default/package-releases.html:5 +#: default/templates/default/package-releases.html:6 msgid "Create Release Packages" msgstr "Crear Paquetes de Entregas" #: default/templates/default/index.html:39 -#: default/templates/default/split-packages.html:5 +#: default/templates/default/split-packages.html:6 +#: default/templatetags/send_options_tag.py:9 msgid "Split Packages" msgstr "Dividir Paquetes" #: default/templates/default/index.html:59 -#: default/templates/default/upgrade.html:5 +#: default/templates/default/upgrade.html:6 +#: default/templatetags/send_options_tag.py:10 msgid "Upgrade from 1.0 to 1.1" msgstr "Actualizar de 1.0 a 1.1" @@ -441,11 +448,12 @@ msgstr "Generar una planilla del esquema" #: default/templates/default/index.html:79 #: default/templates/default/to-spreadsheet.html:10 +#: default/templatetags/send_options_tag.py:11 msgid "Convert to CSV/Excel" msgstr "Convertir a CSV/Excel" #: default/templates/default/index.html:89 -#: default/templates/default/to-json.html:9 +#: default/templates/default/to-json.html:10 msgid "Convert to JSON" msgstr "Convertir a JSON" @@ -594,7 +602,7 @@ msgstr "" "Genera una versión parcheada del esquema de Release con una o más " "extensiones OCDS." -#: default/templates/default/mapping_sheet.html:114 +#: default/templates/default/mapping_sheet.html:115 msgid "" "Please provide one or more URLs to the extension.json file for " "each OCDS extension you want to use:" @@ -602,11 +610,11 @@ msgstr "" "Favor indique una o más URLs del archivo extension.json por " "cada extensión OCDS que desee:" -#: default/templates/default/mapping_sheet.html:140 +#: default/templates/default/mapping_sheet.html:141 msgid "Generate" msgstr "Generar" -#: default/templates/default/package-releases.html:10 +#: default/templates/default/package-releases.html:13 msgid "" "Use this tool to create a release package " @@ -620,7 +628,7 @@ msgstr "" "contracting.org/latest/es/getting_started/releases_and_records/#releases\" " "target=\"_blank\">releases individuales" -#: default/templates/default/package-releases.html:24 +#: default/templates/default/package-releases.html:27 msgid "" "Each input file must be a JSON file containing either one release or an " "array of releases." @@ -687,6 +695,33 @@ msgstr "Codificación:" msgid "Pretty JSON:" msgstr "JSON Indentado:" +#: default/templates/default/snippets/output_description.html:3 +msgid "The features available for the results files are:" +msgstr "Las funcionalidades disponibles para los archivos de resultados son:" + +#: default/templates/default/snippets/output_description.html:8 +msgid "Download the file." +msgstr "Descargue el archivo." + +#: default/templates/default/snippets/output_description.html:12 +msgid "" +"Save the file in your Google Drive account after the authentication flow is " +"complete." +msgstr "" +"Guarde el archivo en su cuenta de Google Drive después de que el flujo de " +"autenticación sea completado." + +#: default/templates/default/snippets/output_description.html:16 +#: default/templates/default/tags/send_options_properties.html:11 +msgid "Send" +msgstr "Enviar" + +#: default/templates/default/snippets/output_description.html:17 +msgid "Send the result directly to the selected function as an input file." +msgstr "" +"Envíe el resultado directamente a la función seleccionada como un archivo de " +"entrada." + #: default/templates/default/snippets/package_type.html:3 msgid "Package type:" msgstr "Tipo de Paquete:" @@ -704,7 +739,7 @@ msgid "Published date:" msgstr "Fecha de Publicación:" #: default/templates/default/snippets/unflatten-options-modal.html:10 -#: default/templates/default/to-spreadsheet.html:101 +#: default/templates/default/to-spreadsheet.html:105 msgid "Options" msgstr "Opciones" @@ -732,7 +767,7 @@ msgstr "* Campos obligatorios" msgid "Close" msgstr "Cerrar" -#: default/templates/default/split-packages.html:10 +#: default/templates/default/split-packages.html:13 msgid "" "Use this tool to split release packages " @@ -746,7 +781,7 @@ msgstr "" "latest/es/schema/release_package/\" target=\"_blank\">paquetes de record " "en paquetes más pequeños." -#: default/templates/default/split-packages.html:19 +#: default/templates/default/split-packages.html:22 msgid "" "To change the publishedDate for the output package fill in the " "Published date textbox and check the checkboxFecha de Publicación y marque la " "casilla de selección junto a ella." -#: default/templates/default/split-packages.html:26 +#: default/templates/default/split-packages.html:29 msgid "" "Enter the number of items (records or releases) per divided package in " "Items per Package box before start process." @@ -765,17 +800,21 @@ msgstr "" "la caja de texto Elementos por Paquete antes de comenzar el " "proceso." -#: default/templates/default/split-packages.html:47 +#: default/templates/default/split-packages.html:50 msgid "Items per Package:" msgstr "Elementos por Paquete:" -#: default/templates/default/split-packages.html:63 +#: default/templates/default/split-packages.html:66 msgid "An invalid split size was entered. Please change it to a valid number." msgstr "" "El tamaño de paquete ingresado es inválido. Por favor cámbielo por un valor " "válido." -#: default/templates/default/to-json.html:15 +#: default/templates/default/tags/send_options_properties.html:5 +msgid "Send result to function:" +msgstr "Enviar resultado a función:" + +#: default/templates/default/to-json.html:18 #: default/templates/default/to-spreadsheet.html:42 msgid "" "Please verify that the file is valid OCDS JSON, and try again in a few " @@ -784,7 +823,7 @@ msgstr "" "Por favor verifique que el archivo sea válido de acuerdo al estándar OCDS, e " "intente de nuevo en unos minutos." -#: default/templates/default/to-json.html:20 +#: default/templates/default/to-json.html:23 msgid "" "Use this page to convert a CSV or Excel version into a paquete de release." -#: default/templates/default/to-json.html:28 +#: default/templates/default/to-json.html:31 msgid "" "The input CSV files must be compressed at the root of a ZIP file if there is " "more than one file, and the Excel file must be an XLSX file. Please verify " @@ -808,11 +847,11 @@ msgstr "" "herramienta Flatten Tool para OCDS." -#: default/templates/default/to-json.html:109 +#: default/templates/default/to-json.html:113 msgid "Added:" msgstr "Añadido:" -#: default/templates/default/to-json.html:142 +#: default/templates/default/to-json.html:146 msgid "" "An error has occurred! Please verify that all your files are valid OCDS " "JSON, and try again in a few minutes." @@ -828,17 +867,17 @@ msgid "" msgstr "" "Use esta página para convertir un paquete de release a su versión CSV y Excel." +"\">Paquete de Release a su versión CSV y Excel." -#: default/templates/default/to-spreadsheet.html:91 +#: default/templates/default/to-spreadsheet.html:92 msgid "Change" msgstr "Cambiar" -#: default/templates/default/to-spreadsheet.html:137 +#: default/templates/default/to-spreadsheet.html:141 msgid "No filter" msgstr "Sin filtro" -#: default/templates/default/upgrade.html:10 +#: default/templates/default/upgrade.html:13 msgid "" "Use this tool to update