def create_aic(request, *args, **kwargs): aic_form = forms.CreateAICForm(request.POST or None) if aic_form.is_valid(): aip_uuids = ast.literal_eval(aic_form.cleaned_data['results']) logger.info("AIC AIP UUIDs: {}".format(aip_uuids)) # The form was passed a raw list of all AIP UUIDs mapping the user's query; # use those to fetch their names, which is used to produce files below. query = { "query": { "terms": { "uuid": aip_uuids, } } } es_client = elasticSearchFunctions.get_client() results = es_client.search( body=query, index='aips', doc_type='aip', fields='uuid,name', size=elasticSearchFunctions.MAX_QUERY_SIZE, # return all records ) # Create files in staging directory with AIP information shared_dir = helpers.get_server_config_value('sharedDirectory') staging_dir = os.path.join(shared_dir, 'tmp') # Create SIP (AIC) directory in staging directory temp_uuid = str(uuid.uuid4()) destination = os.path.join(staging_dir, temp_uuid) try: os.mkdir(destination) os.chmod(destination, 0o770) except os.error: messages.error(request, "Error creating AIC") logger.exception( "Error creating AIC: Error creating directory {}".format( destination)) return redirect('archival_storage_index') # Create SIP in DB mcp_destination = destination.replace(shared_dir, '%sharedPath%') + '/' databaseFunctions.createSIP(mcp_destination, UUID=temp_uuid, sip_type='AIC') # Create files with filename = AIP UUID, and contents = AIP name for aip in results['hits']['hits']: filepath = os.path.join(destination, aip['fields']['uuid'][0]) with open(filepath, 'w') as f: os.chmod(filepath, 0o660) f.write(str(aip['fields']['name'][0])) return redirect('components.ingest.views.aic_metadata_add', temp_uuid) else: messages.error(request, "Error creating AIC") logger.error("Error creating AIC: Form not valid: {}".format(aic_form)) return redirect('archival_storage_index')
def create_aic(request, *args, **kwargs): aic_form = forms.CreateAICForm(request.POST or None) if aic_form.is_valid(): aip_uuids = ast.literal_eval(aic_form.cleaned_data["results"]) logger.info("AIC AIP UUIDs: {}".format(aip_uuids)) # The form was passed a raw list of all AIP UUIDs mapping the user's query; # use those to fetch their names, which is used to produce files below. query = {"query": {"terms": {"uuid": aip_uuids}}} es_client = elasticSearchFunctions.get_client() results = es_client.search( body=query, index="aips", _source="uuid,name", size=elasticSearchFunctions.MAX_QUERY_SIZE, # return all records ) # Create files in staging directory with AIP information shared_dir = settings.SHARED_DIRECTORY staging_dir = os.path.join(shared_dir, "tmp") # Create SIP (AIC) directory in staging directory temp_uuid = str(uuid.uuid4()) destination = os.path.join(staging_dir, temp_uuid) try: os.mkdir(destination) os.chmod(destination, 0o770) except os.error: messages.error(request, "Error creating AIC") logger.exception( "Error creating AIC: Error creating directory {}".format( destination)) return redirect("archival_storage_index") # Create SIP in DB mcp_destination = destination.replace(shared_dir, "%sharedPath%") + "/" databaseFunctions.createSIP(mcp_destination, UUID=temp_uuid, sip_type="AIC") # Create files with filename = AIP UUID, and contents = AIP name for aip in results["hits"]["hits"]: filepath = os.path.join(destination, aip["_source"]["uuid"]) with open(filepath, "w") as f: os.chmod(filepath, 0o660) f.write(str(aip["_source"]["name"])) return redirect("components.ingest.views.aic_metadata_add", temp_uuid) else: messages.error(request, "Error creating AIC") logger.error("Error creating AIC: Form not valid: {}".format(aic_form)) return redirect("archival_storage_index")
def search(request): # FIXME there has to be a better way of handling checkboxes than parsing # them by hand here, and displaying 'checked' in # _archival_storage_search_form.html # Parse checkbox for file mode yes_options = ('checked', 'yes', 'true', 'on') if request.GET.get('filemode', '') in yes_options: file_mode = True checked_if_in_file_mode = 'checked' items_per_page = 20 else: # AIP list file_mode = False checked_if_in_file_mode = '' items_per_page = 10 # Parse checkbox for show AICs show_aics = '' if request.GET.get('show_aics', '') in yes_options: show_aics = 'checked' # get search parameters from request queries, ops, fields, types = advanced_search.search_parameter_prep(request) logger.debug('Queries: %s, Ops: %s, Fields: %s, Types: %s', queries, ops, fields, types) # redirect if no search params have been set if 'query' not in request.GET: return helpers.redirect_with_get_params( 'components.archival_storage.views.search', query='', field='', type='' ) # get string of URL parameters that should be passed along when paging search_params = advanced_search.extract_url_search_params_from_request(request) current_page_number = int(request.GET.get('page', 1)) # perform search es_client = elasticSearchFunctions.get_client() results = None query = advanced_search.assemble_query(es_client, queries, ops, fields, types, search_index='aips', doc_type='aipfile') try: # use all results to pull transfer facets if not in file mode # pulling only one field (we don't need field data as we augment # the results using separate queries) if not file_mode: # Fetch all unique AIP UUIDs in the returned set of files query['aggs'] = {'aip_uuids': {'terms': {'field': 'AIPUUID', 'size': 0}}} # Don't return results, just the aggregation query['size'] = 0 # Searching for AIPs still actually searches type 'aipfile', and # returns the UUID of the AIP the files are a part of. To search # for an attribute of an AIP, the aipfile must index that # information about their AIP in # elasticSearchFunctions.index_mets_file_metadata results = es_client.search( body=query, index='aips', doc_type='aipfile', sort='sipName:desc', ) # Given these AIP UUIDs, now fetch the actual information we want from aips/aip buckets = results['aggregations']['aip_uuids']['buckets'] uuids = [bucket['key'] for bucket in buckets] uuid_file_counts = {bucket['key']: bucket['doc_count'] for bucket in buckets} query = { 'query': { 'terms': { 'uuid': uuids, }, }, } index = 'aips' doc_type = 'aip' fields = 'name,uuid,size,created,status,AICID,isPartOf,countAIPsinAIC,encrypted' sort = 'name:desc' else: index = 'aips' doc_type = 'aipfile' fields = 'AIPUUID,filePath,FILEUUID,encrypted' sort = 'sipName:desc' # To reduce amount of data fetched from ES, use LazyPagedSequence def es_pager(page, page_size): """ Fetch one page of normalized aipfile entries from Elasticsearch. :param page: 1-indexed page to fetch :param page_size: Number of entries on a page :return: List of dicts for each entry with additional information """ start = (page - 1) * page_size results = es_client.search( body=query, from_=start, size=page_size, index=index, doc_type=doc_type, fields=fields, sort=sort, ) if file_mode: return search_augment_file_results(es_client, results) else: return search_augment_aip_results(results, uuid_file_counts) count = es_client.count(index=index, doc_type=doc_type, body={'query': query['query']})['count'] results = LazyPagedSequence(es_pager, items_per_page, count) except ElasticsearchException: logger.exception('Error accessing index.') return HttpResponse('Error accessing index.') if not file_mode: aic_creation_form = forms.CreateAICForm(initial={'results': uuids}) else: # if file_mode aic_creation_form = None page_data = helpers.pager(results, items_per_page, current_page_number) return render(request, 'archival_storage/search.html', { 'file_mode': file_mode, 'show_aics': show_aics, 'checked_if_in_file_mode': checked_if_in_file_mode, 'aic_creation_form': aic_creation_form, 'results': page_data.object_list, 'search_params': search_params, 'page': page_data, } )
def search(request): # FIXME there has to be a better way of handling checkboxes than parsing # them by hand here, and displaying 'checked' in # _archival_storage_search_form.html # Parse checkbox for file mode yes_options = ("checked", "yes", "true", "on") if request.GET.get("filemode", "") in yes_options: file_mode = True checked_if_in_file_mode = "checked" items_per_page = 20 else: # AIP list file_mode = False checked_if_in_file_mode = "" items_per_page = 10 # Parse checkbox for show AICs show_aics = "" if request.GET.get("show_aics", "") in yes_options: show_aics = "checked" # get search parameters from request queries, ops, fields, types = advanced_search.search_parameter_prep( request) logger.debug("Queries: %s, Ops: %s, Fields: %s, Types: %s", queries, ops, fields, types) # redirect if no search params have been set if "query" not in request.GET: return helpers.redirect_with_get_params( "components.archival_storage.views.search", query="", field="", type="") # get string of URL parameters that should be passed along when paging search_params = advanced_search.extract_url_search_params_from_request( request) current_page_number = int(request.GET.get("page", 1)) # perform search es_client = elasticSearchFunctions.get_client() results = None query = advanced_search.assemble_query(queries, ops, fields, types) try: # Use all results to pull transfer facets if not in file mode # pulling only one field (we don't need field data as we augment # the results using separate queries). if not file_mode: # Fetch all unique AIP UUIDs in the returned set of files # ES query will limit to 10 aggregation results by default, # add size parameter in terms to override. # TODO: Use composite aggregation when it gets out of beta. query["aggs"] = { "aip_uuids": { "terms": { "field": "AIPUUID", "size": "10000" } } } # Don't return results, just the aggregation query["size"] = 0 # Searching for AIPs still actually searches type 'aipfile', and # returns the UUID of the AIP the files are a part of. To search # for an attribute of an AIP, the aipfile must index that # information about their AIP. results = es_client.search(body=query, index="aipfiles") # Given these AIP UUIDs, now fetch the actual information we want from aips/aip buckets = results["aggregations"]["aip_uuids"]["buckets"] uuids = [bucket["key"] for bucket in buckets] uuid_file_counts = { bucket["key"]: bucket["doc_count"] for bucket in buckets } query = {"query": {"terms": {"uuid": uuids}}} index = "aips" fields = ( "name,uuid,size,created,status,AICID,isPartOf,countAIPsinAIC,encrypted" ) sort = "name.raw:desc" else: index = "aipfiles" fields = "AIPUUID,filePath,FILEUUID,encrypted" sort = "sipName.raw:desc" # To reduce amount of data fetched from ES, use LazyPagedSequence def es_pager(page, page_size): """ Fetch one page of normalized aipfile entries from Elasticsearch. :param page: 1-indexed page to fetch :param page_size: Number of entries on a page :return: List of dicts for each entry with additional information """ start = (page - 1) * page_size results = es_client.search( body=query, from_=start, size=page_size, index=index, _source=fields, sort=sort, ) if file_mode: return search_augment_file_results(es_client, results) else: return search_augment_aip_results(results, uuid_file_counts) count = es_client.count(index=index, body={"query": query["query"]})["count"] results = LazyPagedSequence(es_pager, items_per_page, count) except ElasticsearchException: logger.exception("Error accessing index.") return HttpResponse("Error accessing index.") if not file_mode: aic_creation_form = forms.CreateAICForm(initial={"results": uuids}) else: # if file_mode aic_creation_form = None page_data = helpers.pager(results, items_per_page, current_page_number) return render( request, "archival_storage/search.html", { "file_mode": file_mode, "show_aics": show_aics, "checked_if_in_file_mode": checked_if_in_file_mode, "aic_creation_form": aic_creation_form, "results": page_data.object_list, "search_params": search_params, "page": page_data, }, )