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)
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)
def complete_matching(request, uuid): """Complete the process by moving to the ArchivesSpace upload chain. This is the final step that we execute when the user has reviewed the matchings and submits the form. It only accepts POST because the action performed is not idempotent. """ if request.method != 'POST': return HttpResponse(status=405) try: client = MCPClient(request.user) client.execute_unit( uuid, # Microservice: Upload DIP mscl_id="92879a29-45bf-4f0b-ac43-e64474f0f2f9", # Chain: Upload DIP to ArchivesSpace choice="3572f844-5e69-4000-a24b-4e32d3487f82") except Exception as err: messages.error( request, _("Operation failed, please try again later" " or contact your administrator.")) logger.error("Upload DIP to ArchivesSpace failed: %s", err) return HttpResponseRedirect( reverse( "components.ingest.views_as.ingest_upload_as_review_matches", args=[uuid])) return HttpResponseRedirect(reverse("components.ingest.views.ingest_grid"))
def approve_transfer_via_mcp(directory, type, user_id): error = None if (directory != ''): # assemble transfer path modified_transfer_path = get_modified_standard_transfer_path(type) if modified_transfer_path == None: error = 'Invalid transfer type.' else: transfer_path = os.path.join(modified_transfer_path, directory) + '/' # look up job UUID using transfer path try: job = models.Job.objects.filter( directory=transfer_path, currentstep='Awaiting decision')[0] # approve transfer client = MCPClient() # 3rd arg should be uid? result = client.execute(job.pk, 'Approve', user_id) except: error = 'Unable to find unapproved transfer directory.' else: error = 'Please specify a transfer directory.' return error
def approve_transfer_via_mcp(directory, type, user_id): error = None if (directory != ''): # assemble transfer path modified_transfer_path = get_modified_standard_transfer_path(type) if modified_transfer_path == None: error = 'Invalid transfer type.' else: transfer_path = os.path.join(modified_transfer_path, directory) + '/' # look up job UUID using transfer path try: job = models.Job.objects.filter(directory=transfer_path, currentstep='Awaiting decision')[0] # approve transfer client = MCPClient() # 3rd arg should be uid? result = client.execute(job.pk, 'Approve', user_id) except: error = 'Unable to find unapproved transfer directory.' else: error = 'Please specify a transfer directory.' return error
def execute(request): result = "" if "uuid" in request.REQUEST: client = MCPClient() uuid = request.REQUEST.get("uuid", "") choice = request.REQUEST.get("choice", "") result = client.execute(uuid, choice) return HttpResponse(result, mimetype="text/plain")
def execute(request): result = "" if request.POST.get("uuid"): client = MCPClient(request.user) result = client.execute( request.POST.get("uuid"), request.POST.get("choice", "") ) return HttpResponse(result, content_type="text/plain")
def execute(request): result = '' if 'uuid' in request.REQUEST: client = MCPClient() uuid = request.REQUEST.get('uuid', '') choice = request.REQUEST.get('choice', '') result = client.execute(uuid, choice) return HttpResponse(result, mimetype = 'text/plain')
def ingest_status(request, uuid=None): # Equivalent to: "SELECT SIPUUID, MAX(createdTime) AS latest FROM Jobs WHERE unitType='unitSIP' GROUP BY SIPUUID objects = models.Job.objects.filter(hidden=False, subjobof='').values('sipuuid').annotate(timestamp=Max('createdtime')).exclude(sipuuid__icontains = 'None').filter(unittype__exact = 'unitSIP') mcp_available = False try: client = MCPClient() mcp_status = etree.XML(client.list()) mcp_available = True except Exception: pass def encoder(obj): items = [] for item in obj: # Check if hidden (TODO: this method is slow) if models.SIP.objects.is_hidden(item['sipuuid']): continue jobs = helpers.get_jobs_by_sipuuid(item['sipuuid']) item['directory'] = utils.get_directory_name(jobs[0]) item['timestamp'] = calendar.timegm(item['timestamp'].timetuple()) item['uuid'] = item['sipuuid'] item['id'] = item['sipuuid'] del item['sipuuid'] item['jobs'] = [] for job in jobs: newJob = {} item['jobs'].append(newJob) # allow user to know name of file that has failed normalization if job.jobtype == 'Access normalization failed - copying' or job.jobtype == 'Preservation normalization failed - copying' or job.jobtype == 'thumbnail normalization failed - copying': task = models.Task.objects.get(job=job) newJob['filename'] = task.filename newJob['uuid'] = job.jobuuid newJob['type'] = job.jobtype newJob['microservicegroup'] = job.microservicegroup newJob['subjobof'] = job.subjobof newJob['currentstep'] = job.currentstep newJob['timestamp'] = '%d.%s' % (calendar.timegm(job.createdtime.timetuple()), str(job.createdtimedec).split('.')[-1]) try: mcp_status except NameError: pass else: xml_unit = mcp_status.xpath('choicesAvailableForUnit[UUID="%s"]' % job.jobuuid) if xml_unit: xml_unit_choices = xml_unit[0].findall('choices/choice') choices = {} for choice in xml_unit_choices: choices[choice.find("chainAvailable").text] = choice.find("description").text newJob['choices'] = choices items.append(item) return items response = {} response['objects'] = objects response['mcp'] = mcp_available return HttpResponse( simplejson.JSONEncoder(default=encoder).encode(response), mimetype='application/json' )
def ingest_status(request, uuid=None): # Equivalent to: "SELECT SIPUUID, MAX(createdTime) AS latest FROM Jobs WHERE unitType='unitSIP' GROUP BY SIPUUID objects = models.Job.objects.filter(hidden=False, subjobof='').values('sipuuid').annotate(timestamp=Max('createdtime')).exclude(sipuuid__icontains = 'None').filter(unittype__exact = 'unitSIP') mcp_available = False try: client = MCPClient() mcp_status = etree.XML(client.list()) mcp_available = True except Exception: pass def encoder(obj): items = [] for item in obj: # Check if hidden (TODO: this method is slow) if models.SIP.objects.is_hidden(item['sipuuid']): continue jobs = helpers.get_jobs_by_sipuuid(item['sipuuid']) item['directory'] = utils.get_directory_name_from_job(jobs[0]) item['timestamp'] = calendar.timegm(item['timestamp'].timetuple()) item['uuid'] = item['sipuuid'] item['id'] = item['sipuuid'] del item['sipuuid'] item['jobs'] = [] for job in jobs: newJob = {} item['jobs'].append(newJob) # allow user to know name of file that has failed normalization if job.jobtype == 'Access normalization failed - copying' or job.jobtype == 'Preservation normalization failed - copying' or job.jobtype == 'thumbnail normalization failed - copying': task = models.Task.objects.get(job=job) newJob['filename'] = task.filename newJob['uuid'] = job.jobuuid newJob['type'] = job.jobtype newJob['microservicegroup'] = job.microservicegroup newJob['subjobof'] = job.subjobof newJob['currentstep'] = job.currentstep newJob['timestamp'] = '%d.%s' % (calendar.timegm(job.createdtime.timetuple()), str(job.createdtimedec).split('.')[-1]) try: mcp_status except NameError: pass else: xml_unit = mcp_status.xpath('choicesAvailableForUnit[UUID="%s"]' % job.jobuuid) if xml_unit: xml_unit_choices = xml_unit[0].findall('choices/choice') choices = {} for choice in xml_unit_choices: choices[choice.find("chainAvailable").text] = choice.find("description").text newJob['choices'] = choices items.append(item) return items response = {} response['objects'] = objects response['mcp'] = mcp_available return HttpResponse( json.JSONEncoder(default=encoder).encode(response), content_type='application/json' )
def list(request): client = MCPClient(request.user) jobs = etree.XML(client.list()) response = "" if 0 < len(jobs): for job in jobs: response += etree.tostring(job) response = "<MCP>%s</MCP>" % response return HttpResponse(response, content_type="text/xml")
def execute(request): result = '' if request.POST.get('uuid'): client = MCPClient(request.user) result = client.execute( request.POST.get('uuid'), request.POST.get('choice', ''), ) return HttpResponse(result, content_type='text/plain')
def execute(request): result = '' if 'uuid' in request.REQUEST: client = MCPClient() uuid = request.REQUEST.get('uuid', '') choice = request.REQUEST.get('choice', '') uid = request.REQUEST.get('uid', '') result = client.execute(uuid, choice, uid) return HttpResponse(result, mimetype='text/plain')
def approve_transfer_via_mcp(directory, type, user_id): error = None if (directory != ''): # assemble transfer path modified_transfer_path = get_modified_standard_transfer_path(type) if modified_transfer_path == None: error = 'Invalid transfer type.' else: if type == 'zipped bag': transfer_path = os.path.join(modified_transfer_path, directory) else: transfer_path = os.path.join(modified_transfer_path, directory) + '/' # look up job UUID using transfer path try: job = models.Job.objects.filter(directory=transfer_path, currentstep='Awaiting decision')[0] type_task_config_descriptions = { 'standard': 'Approve standard transfer', 'unzipped bag': 'Approve bagit transfer', 'zipped bag': 'Approve zipped bagit transfer', 'dspace': 'Approve DSpace transfer', 'maildir': 'Approve maildir transfer', 'TRIM': 'Approve TRIM transfer' } type_description = type_task_config_descriptions[type] # use transfer type to fetch possible choices to execute task = models.TaskConfig.objects.get(description=type_description) link = models.MicroServiceChainLink.objects.get(currenttask=task.pk) choices = models.MicroServiceChainChoice.objects.filter(choiceavailableatlink=link.pk) # attempt to find appropriate choice chain_to_execute = None for choice in choices: chain = models.MicroServiceChain.objects.get(pk=choice.chainavailable) if chain.description == 'Approve transfer': chain_to_execute=chain.pk # execute choice if found if chain_to_execute != None: client = MCPClient() result = client.execute(job.pk, chain_to_execute, user_id) else: error = 'Error: could not find MCP choice to execute.' except: error = 'Unable to find unapproved transfer directory.' else: error = 'Please specify a transfer directory.' return error
def list(request): client = MCPClient() jobs = etree.XML(client.list()) response = '' if 0 < len(jobs): for job in jobs: response += etree.tostring(job) response = '<MCP>%s</MCP>' % response return HttpResponse(response, mimetype = 'text/xml')
def list(request): client = MCPClient() jobs = etree.XML(client.list()) response = '' if 0 < len(jobs): for job in jobs: response += etree.tostring(job) response = '<MCP>%s</MCP>' % response return HttpResponse(response, mimetype='text/xml')
def status(request, uuid=None): response = {"objects": {}, "mcp": False} try: client = MCPClient(request.user) response["objects"] = client.get_transfers_statuses() except Exception: pass else: response["mcp"] = True return HttpResponse(json.dumps(response), content_type="application/json")
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)
def status(request): client = MCPClient() xml = etree.XML(client.list()) sip_count = len(xml.xpath('//choicesAvailableForUnits/choicesAvailableForUnit/unit/type[text()="SIP"]')) transfer_count = len(xml.xpath('//choicesAvailableForUnits/choicesAvailableForUnit/unit/type[text()="Transfer"]')) dip_count = len(xml.xpath('//choicesAvailableForUnits/choicesAvailableForUnit/unit/type[text()="DIP"]')) response = {'sip': sip_count, 'transfer': transfer_count, 'dip': dip_count} return HttpResponse(simplejson.JSONEncoder().encode(response), mimetype='application/json')
def status(request): client = MCPClient() xml = etree.XML(client.list()) sip_count = len(xml.xpath('//choicesAvailableForUnits/choicesAvailableForUnit/unit/type[text()="SIP"]')) transfer_count = len(xml.xpath('//choicesAvailableForUnits/choicesAvailableForUnit/unit/type[text()="Transfer"]')) dip_count = len(xml.xpath('//choicesAvailableForUnits/choicesAvailableForUnit/unit/type[text()="DIP"]')) response = {'sip': sip_count, 'transfer': transfer_count, 'dip': dip_count} return helpers.json_response(response)
def microservices(request, unit_type, unit_uuid): """ Display information about what microservices have run. :param unit_type: 'transfer' or 'ingest' for a Transfer or SIP respectively :param unit_uuid: UUID of the Transfer or SIP """ client = MCPClient(request.user) resp = client.get_unit_status(unit_uuid) return render(request, unit_type + '/microservices.html', { 'uuid': unit_uuid, 'unit_type': unit_type, 'name': resp.get("name"), 'jobs': resp.get("jobs"), })
def approve_transfer(request): """Approve a transfer. The user may find the Package API a better option when the ID of the unit is known in advance. The errors returned use the 500 status code for backward-compatibility reasons. Example:: $ curl --data "directory=MyTransfer" \ --header "Authorization: ApiKey: user:token" \ http://127.0.0.1/api/transfer/approve """ directory = request.POST.get("directory") if not directory: return _error_response( "Please specify a transfer directory.", status_code=500) directory = archivematicaFunctions.unicodeToStr(directory) transfer_type = request.POST.get("type", "standard") if not transfer_type: return _error_response( "Please specify a transfer type.", status_code=500) modified_transfer_path = get_modified_standard_transfer_path(transfer_type) if modified_transfer_path is None: return _error_response("Invalid transfer type.", status_code=500) watched_path = os.path.join(modified_transfer_path, directory) transfer_file = watched_path.replace( SHARED_PATH_TEMPLATE_VAL, SHARED_DIRECTORY_ROOT ) if transfer_type in ("zipped bag", "dspace") and os.path.isfile(transfer_file): db_transfer_path = watched_path else: # Append a slash to complete the directory path. db_transfer_path = os.path.join(watched_path, "") try: client = MCPClient(request.user) unit_uuid = client.approve_transfer_by_path( db_transfer_path, transfer_type) except Exception as err: msg = "Unable to start the transfer." LOGGER.error("%s %s (db_transfer_path=%s)", msg, err, db_transfer_path) return _error_response(msg, status_code=500) return _ok_response("Approval successful.", uuid=unit_uuid)
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 """ sip_uuid = request.POST.get('uuid') if sip_uuid is None: return _error_response('"uuid" is required.') try: client = MCPClient() client.approve_partial_reingest(sip_uuid, request.user.id) except Exception as err: msg = "Unable to approve the partial reingest." LOGGER.error("%s %s (sip_uuid=%s)", msg, err, sip_uuid) return _error_response(msg) return _ok_response("Approval successful.")
def status(request): client = MCPClient() xml = etree.XML(client.list()) sip_count = len( xml.xpath( '//choicesAvailableForUnits/choicesAvailableForUnit/unit/type[text()="SIP"]' )) transfer_count = len( xml.xpath( '//choicesAvailableForUnits/choicesAvailableForUnit/unit/type[text()="Transfer"]' )) dip_count = len( xml.xpath( '//choicesAvailableForUnits/choicesAvailableForUnit/unit/type[text()="DIP"]' )) response = {'sip': sip_count, 'transfer': transfer_count, 'dip': dip_count} return HttpResponse(simplejson.JSONEncoder().encode(response), mimetype='application/json')
def _load_processing_config_fields(self, user): client = MCPClient(user) self.processing_fields = client.get_processing_config_fields() for choice_uuid, field in self.processing_fields.items(): field["label"] = self.LABELS[choice_uuid]
def ingest_status(request, uuid=None): """Returns the status of the SIPs in ingest as a JSON object with an ``objects`` attribute that is an array of objects, each of which represents a single SIP. Each SIP object has a ``jobs`` attribute whose value is an array of objects, each of which represents a Job of the SIP. """ sql = """ SELECT SIPUUID, MAX(UNIX_TIMESTAMP(createdTime) + createdTimeDec) AS timestamp FROM Jobs WHERE unitType='unitSIP' AND NOT SIPUUID LIKE '%%None%%' GROUP BY SIPUUID;""" with connection.cursor() as cursor: cursor.execute(sql) sipuuids_and_timestamps = cursor.fetchall() mcp_available = False try: client = MCPClient() mcp_status = etree.XML(client.list()) mcp_available = True except Exception: pass objects = [] for sipuuid, timestamp in sipuuids_and_timestamps: timestamp = float(timestamp) item = {'sipuuid': sipuuid, 'timestamp': timestamp} # Check if hidden (TODO: this method is slow) if models.SIP.objects.is_hidden(sipuuid): continue jobs = models.Job.objects\ .filter(sipuuid=item['sipuuid'], subjobof='')\ .order_by('-createdtime', 'subjobof') item['directory'] = utils.get_directory_name_from_job(jobs) item['uuid'] = item['sipuuid'] item['id'] = item['sipuuid'] del item['sipuuid'] item['jobs'] = [] for job in jobs: newJob = {} item['jobs'].append(newJob) newJob['uuid'] = job.jobuuid newJob['type'] = job.jobtype newJob['microservicegroup'] = job.microservicegroup newJob['subjobof'] = job.subjobof newJob['currentstep'] = job.currentstep newJob['currentstep_label'] = job.get_currentstep_display() newJob['timestamp'] = '%d.%s' % (calendar.timegm( job.createdtime.timetuple()), str( job.createdtimedec).split('.')[-1]) try: mcp_status except NameError: pass else: xml_unit = mcp_status.xpath( 'choicesAvailableForUnit[UUID="%s"]' % job.jobuuid) if xml_unit: xml_unit_choices = xml_unit[0].findall('choices/choice') choices = {} for choice in xml_unit_choices: choices[choice.find("chainAvailable"). text] = choice.find("description").text newJob['choices'] = choices objects.append(item) response = {} response['objects'] = objects response['mcp'] = mcp_available return HttpResponse(json.dumps(response), content_type='application/json')
def approve_transfer_via_mcp(directory, transfer_type, user_id): error = None unit_uuid = None if (directory != ''): # assemble transfer path modified_transfer_path = get_modified_standard_transfer_path( transfer_type) if modified_transfer_path is None: error = 'Invalid transfer type.' else: db_transfer_path = os.path.join(modified_transfer_path, directory) transfer_path = db_transfer_path.replace('%sharedPath%', SHARED_DIRECTORY_ROOT, 1) # Ensure directories end with / if os.path.isdir(transfer_path): db_transfer_path = os.path.join(db_transfer_path, '') # look up job UUID using transfer path try: job = models.Job.objects.filter( directory=db_transfer_path, currentstep='Awaiting decision')[0] unit_uuid = job.sipuuid type_task_config_descriptions = { 'standard': 'Approve standard transfer', 'unzipped bag': 'Approve bagit transfer', 'zipped bag': 'Approve zipped bagit transfer', 'dspace': 'Approve DSpace transfer', 'maildir': 'Approve maildir transfer', 'TRIM': 'Approve TRIM transfer' } type_description = type_task_config_descriptions[transfer_type] # use transfer type to fetch possible choices to execute choices = models.MicroServiceChainChoice.objects.filter( choiceavailableatlink__currenttask__description= type_description) # attempt to find appropriate choice chain_to_execute = None for choice in choices: if choice.chainavailable.description == 'Approve transfer': chain_to_execute = choice.chainavailable.pk # execute choice if found if chain_to_execute is not None: client = MCPClient() client.execute(job.pk, chain_to_execute, user_id) else: error = 'Error: could not find MCP choice to execute.' except Exception: error = 'Unable to find unapproved transfer directory.' # logging.exception(error) else: error = 'Please specify a transfer directory.' return error, unit_uuid
def status(request, uuid=None): # Equivalent to: "SELECT SIPUUID, MAX(createdTime) AS latest FROM Jobs GROUP BY SIPUUID objects = models.Job.objects.filter( hidden=False, subjobof='', unittype__exact='unitTransfer').values('sipuuid').annotate( timestamp=Max('createdtime')).exclude( sipuuid__icontains='None').order_by('-timestamp') mcp_available = False try: client = MCPClient() mcp_status = etree.XML(client.list()) mcp_available = True except Exception: pass def encoder(obj): items = [] for item in obj: # Check if hidden (TODO: this method is slow) if models.Transfer.objects.is_hidden(item['sipuuid']): continue jobs = models.Job.objects.filter(sipuuid=item['sipuuid'], subjobof='').order_by( '-createdtime', 'subjobof') item['directory'] = os.path.basename( utils.get_directory_name_from_job(jobs)) item['timestamp'] = calendar.timegm(item['timestamp'].timetuple()) item['uuid'] = item['sipuuid'] item['id'] = item['sipuuid'] del item['sipuuid'] item['jobs'] = [] for job in jobs: newJob = {} item['jobs'].append(newJob) newJob['uuid'] = job.jobuuid newJob['type'] = job.jobtype newJob['link_id'] = job.microservicechainlink.pk newJob['microservicegroup'] = job.microservicegroup newJob['subjobof'] = job.subjobof newJob['currentstep'] = job.currentstep newJob['currentstep_label'] = job.get_currentstep_display() newJob['timestamp'] = '%d.%s' % (calendar.timegm( job.createdtime.timetuple()), str( job.createdtimedec).split('.')[-1]) try: mcp_status except NameError: pass else: xml_unit = mcp_status.xpath( 'choicesAvailableForUnit[UUID="%s"]' % job.jobuuid) if xml_unit: xml_unit_choices = xml_unit[0].findall( 'choices/choice') choices = {} for choice in xml_unit_choices: choices[choice.find("chainAvailable"). text] = choice.find("description").text newJob['choices'] = choices items.append(item) return items response = {} response['objects'] = objects response['mcp'] = mcp_available return HttpResponse(json.JSONEncoder(default=encoder).encode(response), content_type='application/json')
from tastypie.resources import Resource from tastypie import fields from tastypie.bundle import Bundle from main import models #useful references: # https://docs.djangoproject.com/en/dev/topics/db/models/ # http://www.youtube.com/watch?v=Zv26xHYlc8s # http://django-tastypie.readthedocs.org/en/latest/non_orm_data_sources.html # http://stackoverflow.com/questions/13094835/how-to-use-tastypie-to-wrap-internal-functions # http://django-tastypie.readthedocs.org/en/v0.9.11/cookbook.html#adding-search-functionality # http://django-tastypie.readthedocs.org/en/latest/resources.html #http://localhost/api/SelectionAvailable/?format=json #http://localhost/api/SelectionAPI/?format=json mcpClient = MCPClient() class SelectionAPIObject(object): def __init__(self, initial=None): self.__dict__['_data'] = {} if hasattr(initial, 'items'): self.__dict__['_data'] = initial def __getattr__(self, name): return self._data.get(name, None) def __setattr__(self, name, value): self.__dict__['_data'][name] = value def to_dict(self):