Esempio n. 1
0
def start_transfer_logged_in(request):
    """
    Endpoint for starting a transfer if logged in and calling from the dashboard.
    """
    if request.method not in ('POST', ):
        return django.http.HttpResponseNotAllowed(['POST'])

    transfer_name = archivematicaFunctions.unicodeToStr(
        request.POST.get('name', ''))
    transfer_type = archivematicaFunctions.unicodeToStr(
        request.POST.get('type', ''))
    accession = archivematicaFunctions.unicodeToStr(
        request.POST.get('accession', ''))
    # Note that the path may contain arbitrary, non-unicode characters,
    # and hence is POSTed to the server base64-encoded
    paths = request.POST.getlist('paths[]', [])
    paths = [base64.b64decode(path) for path in paths]
    row_ids = request.POST.getlist('row_ids[]', [])
    try:
        response = start_transfer(transfer_name, transfer_type, accession,
                                  paths, row_ids)
    except ValueError as e:
        return helpers.json_response({
            'error': True,
            'message': str(e)
        },
                                     status_code=400)
    except storage_service.StorageServiceError as e:
        return helpers.json_response({
            'error': True,
            'message': str(e)
        },
                                     status_code=500)
    else:
        return helpers.json_response(response)
Esempio n. 2
0
def ingest_upload(request, uuid):
    """
        The upload DIP is actually not executed here, but some data is storaged
        in the database (permalink, ...), used later by upload-qubit.py
        - GET = It could be used to obtain DIP size
        - POST = Create Accesses tuple with permalink
    """
    try:
        models.SIP.objects.get(uuid__exact=uuid)
    except models.SIP.DoesNotExist:
        raise Http404

    if request.method == 'POST':
        if 'target' in request.POST:
            try:
                access = models.Access.objects.get(sipuuid=uuid)
            except:
                access = models.Access(sipuuid=uuid)
            access.target = cPickle.dumps({"target": request.POST['target']})
            access.save()
            response = {'ready': True}
            return helpers.json_response(response)
    elif request.method == 'GET':
        try:
            access = models.Access.objects.get(sipuuid=uuid)
            data = cPickle.loads(str(access.target))
        except:
            raise Http404
        # Disabled, it could be very slow
        # job = models.Job.objects.get(jobtype='Upload DIP', sipuuid=uuid)
        # data['size'] = utils.get_directory_size(job.directory)
        return helpers.json_response(data)

    return HttpResponseBadRequest()
Esempio n. 3
0
    def put(self, request, fileuuid):
        """
        Requires a file UUID, and document body must be a JSON-encoded list.
        Replaces the list of tags in the record with the provided list.
        Returns {"success": true} on success.
        Returns 400 if no JSON document is provided in the request body, if the body can't be decoded, or if the body is any JSON object other than a list.
        """
        try:
            tags = json.load(request)
        except ValueError:
            response = {
                "success": False,
                "message": "No JSON document could be decoded from the request.",
            }
            return helpers.json_response(response, status_code=400)
        if not isinstance(tags, list):
            response = {
                "success": False,
                "message": "The request body must be an array.",
            }
            return helpers.json_response(response, status_code=400)

        try:
            es_client = elasticSearchFunctions.get_client()
            elasticSearchFunctions.set_file_tags(es_client, fileuuid, tags)
        except elasticSearchFunctions.ElasticsearchError as e:
            response = {"success": False, "message": str(e)}
            if isinstance(e, elasticSearchFunctions.EmptySearchResultError):
                status_code = 404
            else:
                status_code = 400
            return helpers.json_response(response, status_code=status_code)
        return helpers.json_response({"success": True})
Esempio n. 4
0
def _package_create(request):
    """Create a package."""
    try:
        payload = json.loads(request.body)
        path = base64.b64decode(payload.get('path'))
    except (TypeError, ValueError):
        return helpers.json_response(
            {
                'error': True,
                'message': 'Parameter "path" cannot be decoded.'
            }, 400)
    args = (
        payload.get('name'),
        payload.get('type'),
        payload.get('accession'),
        payload.get('access_system_id'),
        path,
        payload.get('metadata_set_id'),
    )
    kwargs = {
        'auto_approve': payload.get('auto_approve', True),
        'wait_until_complete': False,
    }
    processing_config = payload.get('processing_config')
    if processing_config is not None:
        kwargs['processing_config'] = processing_config
    try:
        client = MCPClient()
        id_ = client.create_package(*args, **kwargs)
    except Exception as err:
        msg = 'Package cannot be created'
        LOGGER.error("{}: {}".format(msg, err))
        return helpers.json_response({'error': True, 'message': msg}, 500)
    return helpers.json_response({'id': id_}, 202)
Esempio n. 5
0
def ingest_upload(request, uuid):
    """
        The upload DIP is actually not executed here, but some data is storaged
        in the database (permalink, ...), used later by upload-qubit.py
        - GET = It could be used to obtain DIP size
        - POST = Create Accesses tuple with permalink
    """
    if not models.SIP.objects.filter(uuid__exact=uuid).exists():
        raise Http404

    if request.method == 'POST':
        if 'target' in request.POST:
            try:
                access = models.Access.objects.get(sipuuid=uuid)
            except:
                access = models.Access(sipuuid=uuid)
            access.target = cPickle.dumps({"target": request.POST['target']})
            access.save()
            response = {'ready': True}
            return helpers.json_response(response)
    elif request.method == 'GET':
        try:
            access = models.Access.objects.get(sipuuid=uuid)
            data = cPickle.loads(str(access.target))
        except:
            raise Http404
        return helpers.json_response(data)

    return HttpResponseNotAllowed(['GET', 'POST'])
Esempio n. 6
0
def _package_create(request):
    """Create a package."""
    try:
        payload = json.loads(request.body.decode("utf8"))
        path = base64.b64decode(payload.get("path"))
    except (TypeError, ValueError):
        return helpers.json_response(
            {
                "error": True,
                "message": 'Parameter "path" cannot be decoded.'
            }, 400)
    args = (
        payload.get("name"),
        payload.get("type"),
        payload.get("accession"),
        payload.get("access_system_id"),
        path,
        payload.get("metadata_set_id"),
    )
    kwargs = {
        "auto_approve": payload.get("auto_approve", True),
        "wait_until_complete": False,
    }
    processing_config = payload.get("processing_config")
    if processing_config is not None:
        kwargs["processing_config"] = processing_config
    try:
        client = MCPClient(request.user)
        id_ = client.create_package(*args, **kwargs)
    except Exception as err:
        msg = "Package cannot be created"
        LOGGER.error("%s: %s", msg, err)
        return helpers.json_response({"error": True, "message": msg}, 500)
    return helpers.json_response({"id": id_}, 202)
Esempio n. 7
0
def file_details(request, fileuuid):
    try:
        es_client = elasticSearchFunctions.get_client()
        source = elasticSearchFunctions.get_transfer_file_info(
            es_client, "fileuuid", fileuuid
        )
    except elasticSearchFunctions.ElasticsearchError as e:
        message = str(e)
        response = {"success": False, "message": message}
        if "no exact results" in message:
            status_code = 404
        else:
            status_code = 500
        return helpers.json_response(response, status_code=status_code)

    format_info = source.get("format", [{}])[0]
    record = {
        "id": source["fileuuid"],
        "type": "file",
        "title": source["filename"],
        "size": source["size"],
        "bulk_extractor_reports": source.get("bulk_extractor_reports", []),
        "tags": source.get("tags", []),
        "format": format_info.get("format"),
        "group": format_info.get("group"),
        "puid": format_info.get("puid"),
    }
    return helpers.json_response(record)
Esempio n. 8
0
def copy_metadata_files(request, sip_uuid, paths):
    """
    Copy files from list `source_paths` to sip_uuid's metadata folder.

    sip_uuid: UUID of the SIP to put files in
    paths: List of files to be copied, base64 encoded, in the format
        'source_location_uuid:full_path'
    """
    sip_uuid = request.POST.get("sip_uuid")
    paths = request.POST.getlist("source_paths[]")
    if not sip_uuid or not paths:
        response = {
            "error": True,
            "message": "sip_uuid and source_paths[] both required.",
        }
        return helpers.json_response(response, status_code=400)

    paths = [base64.b64decode(p) for p in paths]
    sip = models.SIP.objects.get(uuid=sip_uuid)
    relative_path = sip.currentpath.replace("%sharedPath%", "", 1)
    relative_path = os.path.join(relative_path, "metadata")

    error, message = _copy_from_transfer_sources(paths, relative_path)

    if not error:
        message = _("Metadata files added successfully.")
        status_code = 201
    else:
        status_code = 500
    response = {"error": error, "message": message}

    return helpers.json_response(response, status_code=status_code)
Esempio n. 9
0
def record_children(client, request, record_id=""):
    record_id = _normalize_record_id(record_id)

    if request.method == "POST":
        new_record_data = json.load(request)
        try:
            notes = new_record_data.get("notes", [])
            new_id = client.add_child(
                record_id,
                title=new_record_data.get("title", ""),
                level=new_record_data.get("level", ""),
                start_date=new_record_data.get("start_date", ""),
                end_date=new_record_data.get("end_date", ""),
                date_expression=new_record_data.get("date_expression", ""),
                notes=notes,
            )
        except ArchivesSpaceError as e:
            response = {"success": False, "message": str(e)}
            return helpers.json_response(response, status_code=400)
        response = {
            "success": True,
            "id": new_id,
            "message": "New record successfully created",
        }
        return helpers.json_response(response)
    elif request.method == "GET":
        records = client.get_resource_component_and_children(
            record_id, recurse_max_level=3
        )
        records = _get_sip_arrange_children(records)
        return helpers.json_response(records["children"])
Esempio n. 10
0
def copy_metadata_files(request):
    """
    Copy files from list `source_paths` to sip_uuid's metadata folder.

    sip_uuid: UUID of the SIP to put files in
    source_paths: List of files to be copied, base64 encoded, in the format
        'source_location_uuid:full_path'
    """
    sip_uuid = request.POST.get('sip_uuid')
    paths = request.POST.getlist('source_paths[]')
    if not sip_uuid or not paths:
        response = {
            'error': True,
            'message': 'sip_uuid and source_paths[] both required.'
        }
        return helpers.json_response(response)

    paths = [base64.b64decode(p) for p in paths]
    sip = models.SIP.objects.get(uuid=sip_uuid)
    relative_path = sip.currentpath.replace('%sharedPath%', '', 1)
    relative_path = os.path.join(relative_path, 'metadata')

    error, message = copy_from_transfer_sources(paths, relative_path)

    if not error:
        message = 'Metadata files added successfully.'
    response = {'error': error, 'message': message}

    return helpers.json_response(response)
Esempio n. 11
0
def file_details(request, fileuuid):
    try:
        es_client = elasticSearchFunctions.get_client()
        source = elasticSearchFunctions.get_transfer_file_info(
            es_client, 'fileuuid', fileuuid)
    except elasticSearchFunctions.ElasticsearchError as e:
        message = str(e)
        response = {
            'success': False,
            'message': message,
        }
        if 'no exact results' in message:
            status_code = 404
        else:
            status_code = 500
        return helpers.json_response(response, status_code=status_code)

    format_info = source.get('format', [{}])[0]
    record = {
        'id': source['fileuuid'],
        'type': 'file',
        'title': source['filename'],
        'size': source['size'],
        'bulk_extractor_reports': source.get('bulk_extractor_reports', []),
        'tags': source.get('tags', []),
        'format': format_info.get('format'),
        'group': format_info.get('group'),
        'puid': format_info.get('puid'),
    }
    return helpers.json_response(record)
Esempio n. 12
0
def approve_transfer(request):
    # Example: curl --data \
    #   "username=mike&api_key=<API key>&directory=MyTransfer" \
    #   http://127.0.0.1/api/transfer/approve
    if request.method == 'POST':
        auth_error = authenticate_request(request)

        response = {}

        if auth_error is None:
            error = None

            directory = request.POST.get('directory', '')
            transfer_type = request.POST.get('type', 'standard')
            directory = archivematicaFunctions.unicodeToStr(directory)
            error, unit_uuid = approve_transfer_via_mcp(
                directory, transfer_type, request.user.id)

            if error is not None:
                response['message'] = error
                response['error'] = True
                return helpers.json_response(response, status_code=500)
            else:
                response['message'] = 'Approval successful.'
                response['uuid'] = unit_uuid
                return helpers.json_response(response)
        else:
            response['message'] = auth_error
            response['error'] = True
            return helpers.json_response(response, status_code=403)
    else:
        return django.http.HttpResponseNotAllowed(permitted_methods=['POST'])
Esempio n. 13
0
def transfer_source_locations(request):
    try:
        return helpers.json_response(storage_service.get_location(purpose="TS"))
    except:
        message = _("Error retrieving source directories")
        logger.exception(message)
        response = {"message": message, "status": "Failure"}
        return helpers.json_response(response, status_code=500)
Esempio n. 14
0
def processing_configuration(request, name):
    """
    Return a processing configuration XML document given its name, i.e. where
    name is "default" the returned file will be "defaultProcessingMCP.xml"
    found in the standard processing configuration directory.
    """

    config_path = os.path.join(helpers.processing_config_path(),
                               '{}ProcessingMCP.xml'.format(name))

    if request.method == 'DELETE':
        try:
            os.remove(config_path)
            return helpers.json_response({'success': True})
        except OSError:
            msg = 'No such processing config "%s".' % name
            LOGGER.error(msg)
            return helpers.json_response({
                "success": False,
                "error": msg
            },
                                         status_code=404)
    else:
        accepted_types = request.META.get('HTTP_ACCEPT', '').lower()
        if accepted_types != '*/*' and 'xml' not in accepted_types:
            return django.http.HttpResponse(status=415)

        try:
            # Attempt to read the file
            with open(config_path, 'r') as f:
                content = f.read()
        except IOError:
            # The file didn't exist, so recreate it from the builtin config
            try:
                content = install_builtin_config(name)
                if content:
                    LOGGER.info('Regenerated processing config "%s".' % name)
                else:
                    msg = 'No such processing config "%s".' % name
                    LOGGER.error(msg)
                    return helpers.json_response(
                        {
                            "success": False,
                            "error": msg
                        }, status_code=404)
            except Exception:
                msg = 'Failed to reset processing config "%s".' % name
                LOGGER.exception(msg)
                return helpers.json_response({
                    "success": False,
                    "error": msg
                },
                                             status_code=500)

        return django.http.HttpResponse(content, content_type='text/xml')
Esempio n. 15
0
def reingest_approve(request):
    """Approve an AIP partial re-ingest.

    - Method:      POST
    - URL:         api/ingest/reingest/approve
    - POST params:
                   - username -- AM username
                   - api_key  -- AM API key
                   - uuid     -- SIP UUID

    TODO: this is just a temporary way of getting the API to do the
    equivalent of clicking "Approve AIP reingest" in the dashboard when faced
    with "Approve AIP reingest". This is non-dry given
    ``approve_transfer_via_mcp`` above and should probably me made congruent
    with that function and ``approve_transfer``.
    """
    sip_uuid = request.POST.get('uuid')
    if sip_uuid is None:
        response = {'error': True, 'message': '"uuid" is required.'}
        return helpers.json_response(response, status_code=400)
    job = models.Job.objects.filter(
        sipuuid=sip_uuid,
        microservicegroup='Reingest AIP',
        currentstep=models.Job.STATUS_AWAITING_DECISION).first()
    if job:
        chain = models.MicroServiceChainChoice.objects.filter(
            choiceavailableatlink__currenttask__description=
            'Approve AIP reingest',
            chainavailable__description='Approve AIP reingest').first()

        if chain:
            approve_aip_reingest_choice_uuid = chain.chainavailable.pk
            client = MCPClient()
            client.execute(job.pk, approve_aip_reingest_choice_uuid,
                           request.user.id)

            response = {'message': 'Approval successful.'}
        else:
            # No choice was found.
            response = {
                'error': True,
                'message': 'Could not find choice for approve AIP reingest'
            }
            return helpers.json_response(response, status_code=400)

        return helpers.json_response(response)
    else:
        # No job to be found.
        response = {
            'error':
            True,
            'message': ('There is no "Reingest AIP" job awaiting a'
                        ' decision for SIP {}'.format(sip_uuid))
        }
        return helpers.json_response(response, status_code=400)
Esempio n. 16
0
def delete_arrange(request):
    try:
        filepath = base64.b64decode(request.POST['filepath'])
    except KeyError:
        response = {
            'success': False,
            'message': 'No filepath to delete was provided!'
        }
        return helpers.json_response(response, status_code=400)
    models.SIPArrange.objects.filter(arrange_path__startswith=filepath).delete()
    return helpers.json_response({'message': 'Delete successful.'})
Esempio n. 17
0
def transfer_source_locations(request):
    try:
        return helpers.json_response(
            storage_service.get_location(purpose="TS"))
    except:
        message = _('Error retrieving source directories')
        logger.exception(message)
        response = {
            'message': message,
            'status': 'Failure',
        }
        return helpers.json_response(response, status_code=500)
Esempio n. 18
0
def arrange_contents(request):
    path = request.GET.get('path')
    if path is not None:
        try:
            base_path = base64.b64decode(path)
        except TypeError:
            response = {
                'success': False,
                'message': 'Could not base64-decode provided path: {}'.format(path),
            }
            helpers.json_response(response, status_code=400)
        # Must indicate that base_path is a folder by ending with /
        if not base_path.endswith('/'):
            base_path += '/'

        if not base_path.startswith(DEFAULT_ARRANGE_PATH):
            base_path = DEFAULT_ARRANGE_PATH
    else:
        base_path = DEFAULT_ARRANGE_PATH

    # Query SIP Arrangement for results
    # Get all the paths that are not in SIPs and start with base_path.  We don't
    # need the objects, just the arrange_path
    paths = models.SIPArrange.objects.filter(sip_created=False).filter(aip_created=False).filter(arrange_path__startswith=base_path).order_by('arrange_path')

    # Convert the response into an entries [] and directories []
    # 'entries' contains everything (files and directories)
    entries = set()
    directories = set()
    properties = {}
    for item in paths:
        # Strip common prefix
        path_parts = item.arrange_path.replace(base_path, '', 1).split('/')
        entry = path_parts[0]
        if not entry:
            continue
        entries.add(entry)
        # Specify level of description if set
        if item.level_of_description:
            properties[entry] = properties.get(entry, {})  # Default empty dict
            # Don't overwrite if already exists
            properties[entry]['levelOfDescription'] = properties[entry].get('levelOfDescription') or item.level_of_description
        if len(path_parts) > 1:  # Path is a directory
            directories.add(entry)
            # Don't add directories to the object count
            if path_parts[-1]:
                properties[entry] = properties.get(entry, {})  # Default empty dict
                properties[entry]['object count'] = properties[entry].get('object count', 0) + 1  # Increment object count

    response = {'entries': list(entries), 'directories': list(directories), 'properties': properties}
    response = _prepare_browse_response(response)

    return helpers.json_response(response)
Esempio n. 19
0
def start_reingest(request):
    """
    Endpoint to approve reingest of an AIP.

    Expects a POST request with the `uuid` of the SIP, and the `name`, which is
    also the directory in %sharedPath%tmp where the SIP is found.

    Example usage: curl --data "username=demo&api_key=<API key>&name=test-efeb95b4-5e44-45a4-ab5a-9d700875eb60&uuid=efeb95b4-5e44-45a4-ab5a-9d700875eb60"  http://localhost/api/ingest/reingest
    """
    if request.method == 'POST':
        error = authenticate_request(request)
        if error:
            response = {'error': True, 'message': error}
            return helpers.json_response(response, status_code=403)
        sip_name = request.POST.get('name')
        sip_uuid = request.POST.get('uuid')
        if not all([sip_name, sip_uuid]):
            response = {
                'error': True,
                'message': '"name" and "uuid" are required.'
            }
            return helpers.json_response(response, status_code=400)
        # TODO Clear DB of residual stuff related to SIP
        models.Task.objects.filter(job__sipuuid=sip_uuid).delete()
        models.Job.objects.filter(sipuuid=sip_uuid).delete()
        models.SIP.objects.filter(
            uuid=sip_uuid).delete()  # Delete is cascading

        # Move to watched directory
        shared_directory_path = helpers.get_server_config_value(
            'sharedDirectory')
        source = os.path.join(shared_directory_path, 'tmp', sip_name)
        dest = os.path.join(shared_directory_path, 'watchedDirectories',
                            'system', 'reingestAIP', '')
        try:
            LOGGER.debug('Reingest moving from %s to %s', source, dest)
            shutil.move(source, dest)
        except (shutil.Error, OSError) as e:
            error = e.strerror or "Unable to move reingested AIP to start reingest."
            LOGGER.warning('Unable to move reingested AIP to start reingest',
                           exc_info=True)
        if error:
            response = {'error': True, 'message': error}
            return helpers.json_response(response, status_code=500)
        else:
            response = {'message': 'Approval successful.'}
            return helpers.json_response(response)
    else:
        return django.http.HttpResponseNotAllowed(permitted_methods=['POST'])
Esempio n. 20
0
def delete_arrange(request, filepath=None):
    if filepath is None:
        try:
            filepath = base64.b64decode(request.POST["filepath"])
        except KeyError:
            response = {
                "success": False,
                "message": _("No filepath to delete was provided!"),
            }
            return helpers.json_response(response, status_code=400)

    # Delete access mapping if found
    models.SIPArrangeAccessMapping.objects.filter(arrange_path=filepath).delete()
    models.SIPArrange.objects.filter(arrange_path__startswith=filepath).delete()
    return helpers.json_response({"message": _("Delete successful.")})
Esempio n. 21
0
def start_transfer_api(request):
    """
    Endpoint for starting a transfer if calling remote and using an API key.
    """
    if request.method not in ('POST', ):
        return django.http.HttpResponseNotAllowed(['POST'])

    auth_error = authenticate_request(request)
    response = {}
    if auth_error is not None:
        response = {'message': auth_error, 'error': True}
        return django.http.HttpResponseForbidden(
            json.dumps(response), content_type='application/json')

    transfer_name = request.POST.get('name', '')
    transfer_type = request.POST.get('type', '')
    accession = request.POST.get('accession', '')
    # Note that the path may contain arbitrary, non-unicode characters,
    # and hence is POSTed to the server base64-encoded
    paths = request.POST.getlist('paths[]', [])
    paths = [base64.b64decode(path) for path in paths]
    row_ids = request.POST.getlist('row_ids[]', [''])

    response = filesystem_ajax_views.start_transfer(transfer_name,
                                                    transfer_type, accession,
                                                    paths, row_ids)
    return helpers.json_response(response)
Esempio n. 22
0
def approve_transfer(request):
    # Example: curl --data \
    #   "username=mike&api_key=<API key>&directory=MyTransfer" \
    #   http://127.0.0.1/api/transfer/approve
    if request.method == 'POST':
        auth_error = authenticate_request(request)

        response = {}

        if auth_error is None:
            error = None

            directory = request.POST.get('directory', '')
            transfer_type = request.POST.get('type', 'standard')
            error, unit_uuid = approve_transfer_via_mcp(
                directory, transfer_type, request.user.id)

            if error is not None:
                response['message'] = error
                response['error'] = True
                return django.http.HttpResponseServerError(
                    json.dumps(response), mimetype='application/json')
            else:
                response['message'] = 'Approval successful.'
                response['uuid'] = unit_uuid
                return helpers.json_response(response)
        else:
            response['message'] = auth_error
            response['error'] = True
            return django.http.HttpResponseForbidden(
                json.dumps(response), mimetype='application/json')
    else:
        return django.http.HttpResponseNotAllowed(['POST'])
Esempio n. 23
0
def fprupload(request):
    response_data = {}
    agent = Agent.objects.get(pk=2)
    #url = 'https://fpr.archivematica.org/fpr/api/v2/agent/'
    url = django_settings.FPR_URL + 'agent/'
    logging.info("FPR Server URL: {}".format(django_settings.FPR_URL))
    payload = {
        'uuid': helpers.get_setting('dashboard_uuid'),
        'agentType': 'new install',
        'agentName': agent.name,
        'clientIP': get_my_ip(),
        'agentIdentifierType': agent.identifiertype,
        'agentIdentifierValue': agent.identifiervalue
    }
    headers = {'Content-Type': 'application/json'}
    try:
        r = requests.post(url,
                          data=json.dumps(payload),
                          headers=headers,
                          timeout=10,
                          verify=True)
        if r.status_code == 201:
            response_data['result'] = 'success'
        else:
            response_data['result'] = 'failed to fetch from ' + url
    except:
        response_data['result'] = 'failed to post to ' + url

    return helpers.json_response(response_data)
Esempio n. 24
0
def create_directory_within_arrange(request):
    """ Creates a directory entry in the SIPArrange table.

    path: GET parameter, path to directory in DEFAULT_ARRANGE_PATH to create
    """
    error = None
    
    path = base64.b64decode(request.POST.get('path', ''))

    if path:
        if path.startswith(DEFAULT_ARRANGE_PATH):
            models.SIPArrange.objects.create(
                original_path=None,
                arrange_path=os.path.join(path, ''), # ensure ends with /
                file_uuid=None,
            )
        else:
            error = 'Directory is not within the arrange directory.'

    if error is not None:
        response = {
            'message': error,
            'error': True,
        }
    else:
        response = {'message': 'Creation successful.'}

    return helpers.json_response(response)
Esempio n. 25
0
def delete(request):
    filepath = request.POST.get('filepath', '')
    filepath = os.path.join('/', filepath)
    error = filesystem_ajax_helpers.check_filepath_exists(filepath)

    if error == None:
        if os.path.isdir(filepath):
            try:
                shutil.rmtree(filepath)
            except Exception:
                logging.exception('Error deleting directory {}'.format(filepath))
                error = 'Error attempting to delete directory.'
        else:
            os.remove(filepath)

    # if deleting from originals, delete ES data as well
    if ORIGINAL_DIR in filepath and filepath.index(ORIGINAL_DIR) == 0:
        transfer_uuid = _find_uuid_of_transfer_in_originals_directory_using_path(filepath)
        if transfer_uuid != None:
            elasticSearchFunctions.connect_and_remove_backlog_transfer_files(transfer_uuid)

    if error is not None:
        response = {
            'message': error,
            'error': True,
        }
    else:
        response = {'message': 'Delete successful.'}

    return helpers.json_response(response)
Esempio n. 26
0
def mark_hidden(request, unit_type, unit_uuid):
    """
    Marks the unit as hidden to delete it.

    This endpoint assumes you are already logged in.

    :param unit_type: 'transfer' or 'ingest' for a Transfer or SIP respectively
    :param unit_uuid: UUID of the Transfer or SIP
    """
    if request.method not in ("DELETE", ):
        return django.http.HttpResponseNotAllowed(["DELETE"])

    try:
        if unit_type == "transfer":
            unit_model = models.Transfer
        elif unit_type == "ingest":
            unit_model = models.SIP
        unit = unit_model.objects.get(uuid=unit_uuid)
        unit.hidden = True
        unit.save()
        response = {"removed": True}
        return helpers.json_response(response)
    except Exception:
        LOGGER.debug("Error setting %s %s to hidden",
                     unit_type,
                     unit_uuid,
                     exc_info=True)
        raise django.http.Http404
Esempio n. 27
0
def mark_completed_hidden(request, unit_type):
    """Marks all units of type ``unit_type`` as hidden, if and only if the unit
    is completed or failed. This is what happens when the user clicks the
    "Remove all completed" button in the dashboard GUI.

    This endpoint assumes you are already logged in.

    :param unit_type: 'transfer' or 'ingest' for hiding of Transfers or SIPs,
        respectively
    """
    if request.method not in ("DELETE", ):
        return django.http.HttpResponseNotAllowed(["DELETE"])
    try:
        completed = helpers.completed_units_efficient(unit_type=unit_type)
        if completed:
            if unit_type == "transfer":
                unit_model = models.Transfer
            elif unit_type == "ingest":
                unit_model = models.SIP
            unit_model.objects.filter(uuid__in=completed).update(hidden=True)
        response = {"removed": completed}
        return helpers.json_response(response)
    except Exception:
        LOGGER.debug("Error setting completed %s units to hidden",
                     unit_type,
                     exc_info=True)
        raise django.http.Http404
Esempio n. 28
0
 def post(self, request):
     """
     Creates a new stub SIP object, and returns its UUID in a JSON response.
     """
     sip = models.SIP.objects.create(uuid=str(uuid.uuid4()),
                                     currentpath=None)
     return helpers.json_response({"success": True, "id": sip.uuid})
Esempio n. 29
0
def _error_response(message, status_code=400):
    """Mixin to return API errors to the user."""
    return helpers.json_response({
        "error": True,
        "message": message
    },
                                 status_code=status_code)
Esempio n. 30
0
def unit_jobs(request, unit_uuid):
    """Return jobs associated with a unit's UUID"""
    jobs = models.Job.objects.filter(sipuuid=unit_uuid).order_by("createdtime")
    if not jobs.count():
        return _error_response("No jobs found for unit: {}".format(unit_uuid))
    result = []
    microservice = request.GET.get("microservice")
    if microservice is not None:
        microservice = remove_prefix(microservice, "Microservice:")
        jobs = jobs.filter(microservicegroup=microservice.strip())
    link_uuid = request.GET.get("link_uuid")
    if link_uuid is not None:
        jobs = jobs.filter(microservicechainlink=link_uuid.strip())
    name = request.GET.get("name")
    if name is not None:
        name = remove_prefix(name, "Job:")
        jobs = jobs.filter(jobtype=name.strip())
    for job in jobs.prefetch_related("task_set"):
        tasks = [format_task(task) for task in job.task_set.all()]
        result.append({
            "uuid": job.jobuuid,
            "name": job.jobtype,
            "status": JOB_STATUS_CODE_LABELS.get(job.currentstep),
            "microservice": job.microservicegroup,
            "link_uuid": job.microservicechainlink,
            "tasks": tasks,
        })
    return helpers.json_response(result)