def pair_status(request, claim_key): """ Poll the pairing status of a VM """ _entry = ClaimRequests.objects.get(pin=claim_key) # Check the entry status status = "unknown" if (_entry.status == "C"): status = "claimed" if (_entry.status == "U"): status = "unclaimed" if (_entry.status == "P"): status = "pending" if (_entry.status == "E"): status = "error" # Get our current timestamp and calculate validity time ts = datetime.utcnow().replace(tzinfo=utc) ts_expire = ts - REQUEST_TIMEOUT # Check for expired entry if (_entry.alloc_date < ts_expire): status = "expired" # Send the response return uncache_response( HttpResponse( json.dumps({"status": status}), content_type="application/json" ) )
def ajax_publish_context(request): """ Changes the published value of a given context. Obtains all the parameters (id and action) through HTTP GET. Returns a HTTP status != 200 in case of errors, or an HTTP 200 with a JSON file containing the string "1" when OK """ l = logging.getLogger("cvmo") # id, do required if not "do" in request.GET or not "id" in request.GET: l.log(logging.ERROR, "Action and/or id are missing") raise SuspiciousOperation("Action and/or id are missing") # Actions allowed: [un]publish if request.GET["do"] == "publish": publish = True elif request.GET["do"] == "unpublish": publish = False else: l.log(logging.ERROR, "Invalid action") raise SuspiciousOperation("Invalid action") # Check if context exists and it"s mine id = request.GET["id"] ctx = ContextDefinition.objects.filter( Q(id=id) & Q(inherited=False) & Q(owner=request.user)) if not ctx.exists \ or ctx.update(public=publish) != 1: l.log(logging.ERROR, "Update error") raise Exception("Update error") # Will return the string "1" in case of success, "0" in case of failure return uncache_response(HttpResponse("1", content_type="application/json"))
def ajax_publish_context(request): """ Changes the published value of a given context. Obtains all the parameters (id and action) through HTTP GET. Returns a HTTP status != 200 in case of errors, or an HTTP 200 with a JSON file containing the string "1" when OK """ l = logging.getLogger("cvmo") # id, do required if not "do" in request.GET or not "id" in request.GET: l.log(logging.ERROR, "Action and/or id are missing") raise SuspiciousOperation("Action and/or id are missing") # Actions allowed: [un]publish if request.GET["do"] == "publish": publish = True elif request.GET["do"] == "unpublish": publish = False else: l.log(logging.ERROR, "Invalid action") raise SuspiciousOperation("Invalid action") # Check if context exists and it"s mine id = request.GET["id"] ctx = ContextDefinition.objects.filter( Q(id=id) & Q(inherited=False) & Q(owner=request.user) ) if not ctx.exists \ or ctx.update(public=publish) != 1: l.log(logging.ERROR, "Update error") raise Exception("Update error") # Will return the string "1" in case of success, "0" in case of failure return uncache_response(HttpResponse("1", content_type="application/json"))
def dashboard(request): context = { "context_definition_list": ContextDefinition.objects.filter( Q(owner=request.user) & Q(inherited=False) & Q(abstract=False)).order_by("-public", "name"), "full_abstract_list": get_list_allowed_abstract(request), "my_abstract_list": ContextDefinition.objects.filter( Q(owner=request.user) & Q(inherited=False) & Q(abstract=True)).order_by("name"), "cluster_definition_list": ClusterDefinition.objects.filter(owner=request.user).order_by("name"), "machine_list": Machines.objects.filter(owner=request.user) } context["webapi_configurations"] = settings.WEBAPI_CONFIGURATIONS push_to_context("redirect_msg_info", "msg_info", context, request) push_to_context("redirect_msg_error", "msg_error", context, request) push_to_context("redirect_msg_warning", "msg_warning", context, request) push_to_context("redirect_msg_confirm", "msg_confirm", context, request) return uncache_response( render(request, "dashboard/dashboard.html", context))
def pair_request(request, context_id): # Get our current timestamp - useful ts = datetime.utcnow().replace(tzinfo=utc) ts_expire = ts - REQUEST_TIMEOUT # Fetch the context definition for this pairing request context_definition = ContextDefinition.objects.get(id=context_id) # Destroy all previous requests in pending state ClaimRequests.objects.filter(requestby=request.user, status="U").delete() # Ensure that we don"t have a pin collision (since our entropy is quite # small) valid = 0 while valid == 0: key = gen_pin(6, (context_definition.key != ""), get_uuid_salt(context_definition.id)) results = ClaimRequests.objects.filter(pin=key, status="U") if results.count() == 0: valid = 1 # Create an entry with unique PIN entry = ClaimRequests.objects.create(pin=key, status="U", alloc_date=ts, requestby=request.user, context=context_definition) # Show claim screen return uncache_response( render(request, "vm/machine_pair_pin.html", {"key": entry.pin}))
def pair_request(request, context_id): # Get our current timestamp - useful ts = datetime.utcnow().replace(tzinfo=utc) ts_expire = ts - REQUEST_TIMEOUT # Fetch the context definition for this pairing request context_definition = ContextDefinition.objects.get(id=context_id) # Destroy all previous requests in pending state ClaimRequests.objects.filter(requestby=request.user, status="U").delete() # Ensure that we don"t have a pin collision (since our entropy is quite # small) valid = 0 while valid == 0: key = gen_pin(6, (context_definition.key != ""), get_uuid_salt(context_definition.id)) results = ClaimRequests.objects.filter(pin=key, status="U") if results.count() == 0: valid = 1 # Create an entry with unique PIN entry = ClaimRequests.objects.create( pin=key, status="U", alloc_date=ts, requestby=request.user, context=context_definition ) # Show claim screen return uncache_response( render(request, "vm/machine_pair_pin.html", {"key": entry.pin}) )
def pair_setup(request, claim_key): # Fetch claim information claim_request = ClaimRequests.objects.get(pin=claim_key) # Fetch the associated VM vm = claim_request.machine return uncache_response( render(request, "vm/machine_setup.html", {"vm": vm}))
def ajax_get_list(request): """This function returns a JSON-formatted list of contexts matching a certain query string. Match is performed on the context name and it is case-insensitive. Each of the input words of the query string must be contained in the context name.""" query = request.GET.get("query", "").strip() qfilter = Q(abstract=False) & Q( Q(public=True) | Q(owner=request.user) ) for w in query.split(): # todo: use a generator! split() returns an array qfilter = qfilter & Q( name__icontains=w ) contexts = ContextDefinition.objects.filter( qfilter ) context_list = [] for c in contexts: context_list.append({ "id": c.id, "name": c.name, "description": _cap(c.description, 50), "description_not_empty": (c.description != ""), "owner": c.owner.username, "is_encrypted": c.is_encrypted }) return uncache_response( HttpResponse( json.dumps(context_list, indent=2), # for debug # json.dumps(context_list), content_type="application/json" ) )
def ajax_get_list(request): """This function returns a JSON-formatted list of contexts matching a certain query string. Match is performed on the context name and it is case-insensitive. Each of the input words of the query string must be contained in the context name.""" query = request.GET.get("query", "").strip() qfilter = Q(abstract=False) & Q(Q(public=True) | Q(owner=request.user)) for w in query.split(): # todo: use a generator! split() returns an array qfilter = qfilter & Q(name__icontains=w) contexts = ContextDefinition.objects.filter(qfilter) context_list = [] for c in contexts: context_list.append({ "id": c.id, "name": c.name, "description": _cap(c.description, 50), "description_not_empty": (c.description != ""), "owner": c.owner.username, "is_encrypted": c.is_encrypted }) return uncache_response( HttpResponse( json.dumps(context_list, indent=2), # for debug # json.dumps(context_list), content_type="application/json"))
def pair_status(request, claim_key): """ Poll the pairing status of a VM """ _entry = ClaimRequests.objects.get(pin=claim_key) # Check the entry status status = "unknown" if (_entry.status == "C"): status = "claimed" if (_entry.status == "U"): status = "unclaimed" if (_entry.status == "P"): status = "pending" if (_entry.status == "E"): status = "error" # Get our current timestamp and calculate validity time ts = datetime.utcnow().replace(tzinfo=utc) ts_expire = ts - REQUEST_TIMEOUT # Check for expired entry if (_entry.alloc_date < ts_expire): status = "expired" # Send the response return uncache_response( HttpResponse(json.dumps({"status": status}), content_type="application/json"))
def csc_login(request): """ Display screen """ if request.user is not None and request.user.is_authenticated(): return redirect("dashboard") return uncache_response( render(request, "user/login_csc.html") )
def ajax_abstract_list(request): ab_list = get_list_allowed_abstract(request) ab_dict = [] for ab in ab_list: ab_dict.append({"id": ab.id, "name": ab.name, "public": ab.public}) return uncache_response( HttpResponse(json.dumps(ab_dict, indent=2), content_type="application/json"))
def pair_setup(request, claim_key): # Fetch claim information claim_request = ClaimRequests.objects.get(pin=claim_key) # Fetch the associated VM vm = claim_request.machine return uncache_response( render(request, "vm/machine_setup.html", {"vm": vm}) )
def ajax_abstract_list(request): ab_list = get_list_allowed_abstract(request) ab_dict = [] for ab in ab_list: ab_dict.append({ "id": ab.id, "name": ab.name, "public": ab.public }) return uncache_response( HttpResponse( json.dumps(ab_dict, indent=2), content_type="application/json" ) )
def vote_ajax(request): l = logging.getLogger("cvmo") # Validate request if not "id" in request.GET: l.log(logging.ERROR, "`id` is required") raise SuspiciousOperation("`id` is required") if not "vote" in request.GET: l.log(logging.ERROR, "`vote` is required") raise SuspiciousOperation("`vote` is required") # Handle vote fID = request.GET["id"] fVote = request.GET["vote"] # Check vote rank = 0 if fVote == "up": rank = 1 else: rank = 0 # Fetch / create per-user, per-entry record try: o = MarketplaceContextVotes.objects.get( user=request.user, entry__id=fID ) except: o = MarketplaceContextVotes() o.user = request.user try: o.entry = MarketplaceContextEntry.objects.get(id=fID) except: raise Http404() # Update vote o.vote = rank o.save() # Update context rank rank = update_context_rank(fID) # Return the current entry return uncache_response( HttpResponse( json.dumps({"id": fID, "rank": rank}), content_type="text/plain" ) )
def pair_begin(request): # First screen of the pairing process: Show the available # contextualization options return uncache_response( render( request, "vm/machine_pair.html", { "context_list": ContextDefinition.objects.filter( Q(owner=request.user) & Q(inherited=False) & Q(abstract=False)), "context_public": ContextDefinition.objects.filter(public=True).exclude( owner=request.user) }))
def vote_ajax(request): l = logging.getLogger("cvmo") # Validate request if not "id" in request.GET: l.log(logging.ERROR, "`id` is required") raise SuspiciousOperation("`id` is required") if not "vote" in request.GET: l.log(logging.ERROR, "`vote` is required") raise SuspiciousOperation("`vote` is required") # Handle vote fID = request.GET["id"] fVote = request.GET["vote"] # Check vote rank = 0 if fVote == "up": rank = 1 else: rank = 0 # Fetch / create per-user, per-entry record try: o = MarketplaceContextVotes.objects.get(user=request.user, entry__id=fID) except: o = MarketplaceContextVotes() o.user = request.user try: o.entry = MarketplaceContextEntry.objects.get(id=fID) except: raise Http404() # Update vote o.vote = rank o.save() # Update context rank rank = update_context_rank(fID) # Return the current entry return uncache_response( HttpResponse(json.dumps({ "id": fID, "rank": rank }), content_type="text/plain"))
def ajax_get_cvmfs_tags(request, branch): try: url = 'http://%s/cvmfs/%s' % (CVMFS_UCVM_SERVERS[branch], branch) repo = cvmfs.RemoteRepository(url); history = repo.retrieve_history() dump = [] for h in history: if h.name != 'trunk' and h.name != 'trunk-previous' and h.name != 'HEAD': dump.append( { 'n': h.name, 't': h.timestamp.isoformat() } ) return uncache_response( HttpResponse( json.dumps(dump) , content_type="text/json") ) except Exception as e: #return uncache_response( HttpResponse( 'error: %s' % e , content_type="text/plain") ) raise Http404('CVMFS tag not found')
def delete(request, machine_uuid): # Is it confirmed? if ("confirm" in request.GET) and (request.GET["confirm"] == "yes"): # Delete the specified contextualization entry Machines.objects.filter(uuid=machine_uuid).delete() # Go to dashboard return redirect("dashboard") else: # Show the confirmation screen return uncache_response( render_confirm( request, "Delete instance", "Are you sure you want to delete this virtual machine instance\ from you CernVM online account? This action is not undoable!", reverse("vm_delete", kwargs={"machine_uuid": machine_uuid}) + "?confirm=yes", reverse("dashboard")))
def ajax_get_cvmfs_tags(request, branch): try: url = 'http://%s/cvmfs/%s' % (CVMFS_UCVM_SERVERS[branch], branch) repo = cvmfs.RemoteRepository(url) history = repo.retrieve_history() dump = [] for h in history: if h.name != 'trunk' and h.name != 'trunk-previous' and h.name != 'HEAD': dump.append({'n': h.name, 't': h.timestamp.isoformat()}) return uncache_response( HttpResponse(json.dumps(dump), content_type="text/json")) except Exception as e: #return uncache_response( HttpResponse( 'error: %s' % e , content_type="text/plain") ) raise Http404('CVMFS tag not found')
def _context_fetch_context_id(context_id, checksum, uuid, ip, ver): context = None cluster = None try: context = ContextDefinition.objects.get(id=context_id) owner = context.owner # If the context is encrypted, make sure the user knows how to # decrypt it if (context and context.key != ""): if (context.key != checksum): return uncache_response( HttpResponse("invalid-checksum", content_type="text/plain") ) except ContextDefinition.DoesNotExist: cluster = ClusterDefinition.objects.get( deployable_context_id=context_id ) owner = cluster.owner except ClusterDefinition.DoesNotExist: return HttpResponse("not-found", content_type="text/plain") # Register/update VM registration only if the VM is private if (context and not context.public) or cluster: try: claimed_vm = Machines.objects.get(uuid=uuid) claimed_vm.ip = ip claimed_vm.ver = ver claimed_vm.owner = owner except Machines.DoesNotExist: claimed_vm = Machines( uuid=uuid, ip=ip, version=ver, owner=owner ) if context: claimed_vm.status = "C" # Machine is registered via cloud API claimed_vm.context = context if cluster: claimed_vm.status = "E" # Machine is registered via cloud API claimed_vm.context = cluster.master_context claimed_vm.save() # Return the context definition context_data = ContextStorage.objects.get(id=context_id) return HttpResponse(context_data.data, content_type="text/plain")
def pair_begin(request): # First screen of the pairing process: Show the available # contextualization options return uncache_response( render( request, "vm/machine_pair.html", { "context_list": ContextDefinition.objects.filter( Q(owner=request.user) & Q(inherited=False) & Q(abstract=False) ), "context_public": ContextDefinition.objects.filter( public=True ).exclude(owner=request.user) } ) )
def _context_fetch_context_id(context_id, checksum, uuid, ip, ver): context = None cluster = None try: context = ContextDefinition.objects.get(id=context_id) owner = context.owner # If the context is encrypted, make sure the user knows how to # decrypt it if (context and context.key != ""): if (context.key != checksum): return uncache_response( HttpResponse("invalid-checksum", content_type="text/plain")) except ContextDefinition.DoesNotExist: cluster = ClusterDefinition.objects.get( deployable_context_id=context_id) owner = cluster.owner except ClusterDefinition.DoesNotExist: return HttpResponse("not-found", content_type="text/plain") # Register/update VM registration only if the VM is private if (context and not context.public) or cluster: try: claimed_vm = Machines.objects.get(uuid=uuid) claimed_vm.ip = ip claimed_vm.ver = ver claimed_vm.owner = owner except Machines.DoesNotExist: claimed_vm = Machines(uuid=uuid, ip=ip, version=ver, owner=owner) if context: claimed_vm.status = "C" # Machine is registered via cloud API claimed_vm.context = context if cluster: claimed_vm.status = "E" # Machine is registered via cloud API claimed_vm.context = cluster.master_context claimed_vm.save() # Return the context definition context_data = ContextStorage.objects.get(id=context_id) return HttpResponse(context_data.data, content_type="text/plain")
def delete(request, machine_uuid): # Is it confirmed? if ("confirm" in request.GET) and (request.GET["confirm"] == "yes"): # Delete the specified contextualization entry Machines.objects.filter(uuid=machine_uuid).delete() # Go to dashboard return redirect("dashboard") else: # Show the confirmation screen return uncache_response( render_confirm( request, "Delete instance", "Are you sure you want to delete this virtual machine instance\ from you CernVM online account? This action is not undoable!", reverse( "vm_delete", kwargs={"machine_uuid": machine_uuid} ) + "?confirm=yes", reverse("dashboard") ) )
def publish(request, context_id): # Try to find the context try: context = ContextDefinition.objects.get(id=context_id) except: msg_error(request, "Context with id " + context_id + " is not defined!") return redirect("dashboard") # Check if context belongs to calling user if request.user.id != context.owner.id: msg_error(request, "Context with id " + context_id + " does not belong to you!") return redirect("dashboard") # Check if this entry is already there if MarketplaceContextEntry.objects.filter(context=context).exists(): msg_info(request, "This context already exists in the marketplace!") return redirect("dashboard") # Render values return uncache_response( render( request, "market/marketplace_publish_ctx.html", { "groups": MarketplaceGroup.objects.all(), "context": context, "icons": get_icons(request.user), # For redirection with memory "values": { "group": get_memory(request, "group"), "instructions": get_memory(request, "instructions"), "tags": get_memory(request, "tags") } } ) )
def publish(request, context_id): # Try to find the context try: context = ContextDefinition.objects.get(id=context_id) except: msg_error(request, "Context with id " + context_id + " is not defined!") return redirect("dashboard") # Check if context belongs to calling user if request.user.id != context.owner.id: msg_error(request, "Context with id " + context_id + " does not belong to you!") return redirect("dashboard") # Check if this entry is already there if MarketplaceContextEntry.objects.filter(context=context).exists(): msg_info(request, "This context already exists in the marketplace!") return redirect("dashboard") # Render values return uncache_response( render( request, "market/marketplace_publish_ctx.html", { "groups": MarketplaceGroup.objects.all(), "context": context, "icons": get_icons(request.user), # For redirection with memory "values": { "group": get_memory(request, "group"), "instructions": get_memory(request, "instructions"), "tags": get_memory(request, "tags") } }))
def _context_fetch_pin(pin, checksum, uuid, ip, ver): # Get our current timestamp and calculate validity time ts = datetime.utcnow().replace(tzinfo=utc) ts_expire = ts - REQUEST_TIMEOUT # Lookup the pin try: claim_request = ClaimRequests.objects.get( pin=pin, status="U", alloc_date__gte=ts_expire ) # If the request is encrypted, make sure the user knows how to # decrypt it if (claim_request.context.key != ""): if (claim_request.context.key != checksum): return uncache_response( HttpResponse( "invalid-checksum", content_type="text/plain" ) ) # Request is now claimed claim_request.status = "C" # Get or create the VM claimed_vm = None try: claimed_vm = Machines.objects.get(uuid=uuid) # Update the IP address claimed_vm.ip = ip # If the owner is different than expected, someone tries to # hijack... if (claimed_vm.owner != claim_request.requestby): claim_request.status = "E" claim_request.save() return uncache_response( HttpResponse( "not-authorized", content_type="text/plain" ) ) except: claimed_vm = Machines( uuid=uuid, ip=ip, version=ver, owner=claim_request.requestby ) # Store the VM claim_request.machine = claimed_vm # Machine is registered via pairing API claimed_vm.status = "P" # Update claim request claim_request.save() # Fetch the context definition claim_context = claim_request.context context_data = ContextStorage.objects.get(id=claim_context.id) # Update claimed VM info claimed_vm.context = claim_request.context claimed_vm.save() # Return successful pairing return uncache_response( HttpResponse(context_data.data, content_type="text/plain") ) except: # Something went wrong. Stop return uncache_response( HttpResponse("not-found", content_type="text/plain") )
def list_ajax(request): l = logging.getLogger("cvmo") # Validate request if not "group" in request.GET: l.log(logging.ERROR, "`group` is required") raise SuspiciousOperation("`group` is required") if not "query" in request.GET: l.log(logging.ERROR, "`query` is required") raise SuspiciousOperation("`query` is required") if not "offset" in request.GET: l.log(logging.ERROR, "`offset` is required") raise SuspiciousOperation("`offset` is required") # Fetch some helpful variables from the request fGroup = request.GET["group"] fQuery = request.GET["query"] fOffset = int(request.GET["offset"]) # Extract tags from the string and build the more # complex query args = [Q(group__id=fGroup)] qargs = None qstring = "" parts = fQuery.split(" ") for p in parts: # Inclusive tag if p[0:1] == "+": tag = "|" + p[1:] + "|" print "La: %s" % tag if qargs == None: qargs = Q(tags__contains=tag) else: qargs = qargs | Q(tags__contains=tag) # Exclusive tag elif p[0:1] == "-": tag = "|" + p[1:] + "|" print "Lalo: %s" % tag args.append(~Q(tags__contains=tag)) # Regular keyword else: if qstring: qstring += " " qstring += p # If we have inclusive tags, add them now if qargs != None: args.append(qargs) # Append string query if qstring: args.append(Q(context__name__contains=qstring)) # Fetch items items_per_batch = 20 items = [] db_items = MarketplaceContextEntry.objects.filter( *args).order_by("-rank")[fOffset:] num_items = len(db_items) cur_item = 0 for i in db_items: items.append({ "id": i.id, "label": i.context.name, "icon": i.icon.url, "details": i.details, "description": i.context.description, "uid": i.context.id, "owner": i.context.owner.username, "tags": i.tags[1:-1].split("|"), "rank": i.rank, "encrypted": not not i.context.key }) cur_item += 1 if cur_item >= items_per_batch: break # Check if we have more items has_more = 0 if num_items > items_per_batch: has_more = 1 # Build response data = { "offset": fOffset + items_per_batch, "more": has_more, "items": items } # Return filtered responses return uncache_response( HttpResponse(json.dumps(data), content_type="text/plain"))
def _context_fetch_pin(pin, checksum, uuid, ip, ver): # Get our current timestamp and calculate validity time ts = datetime.utcnow().replace(tzinfo=utc) ts_expire = ts - REQUEST_TIMEOUT # Lookup the pin try: claim_request = ClaimRequests.objects.get(pin=pin, status="U", alloc_date__gte=ts_expire) # If the request is encrypted, make sure the user knows how to # decrypt it if (claim_request.context.key != ""): if (claim_request.context.key != checksum): return uncache_response( HttpResponse("invalid-checksum", content_type="text/plain")) # Request is now claimed claim_request.status = "C" # Get or create the VM claimed_vm = None try: claimed_vm = Machines.objects.get(uuid=uuid) # Update the IP address claimed_vm.ip = ip # If the owner is different than expected, someone tries to # hijack... #if (claimed_vm.owner != claim_request.requestby): # claim_request.status = "E" # claim_request.save() # return uncache_response( # HttpResponse( # "not-authorized", content_type="text/plain" # ) # ) except: claimed_vm = Machines(uuid=uuid, ip=ip, version=ver, owner=claim_request.requestby) # Store the VM claim_request.machine = claimed_vm # Machine is registered via pairing API claimed_vm.status = "P" # Update claim request claim_request.save() # Fetch the context definition claim_context = claim_request.context context_data = ContextStorage.objects.get(id=claim_context.id) # Update claimed VM info claimed_vm.context = claim_request.context claimed_vm.save() # Return successful pairing return uncache_response( HttpResponse(context_data.data, content_type="text/plain")) except: # Something went wrong. Stop return uncache_response( HttpResponse("not-found", content_type="text/plain"))
def list_ajax(request): l = logging.getLogger("cvmo") # Validate request if not "group" in request.GET: l.log(logging.ERROR, "`group` is required") raise SuspiciousOperation("`group` is required") if not "query" in request.GET: l.log(logging.ERROR, "`query` is required") raise SuspiciousOperation("`query` is required") if not "offset" in request.GET: l.log(logging.ERROR, "`offset` is required") raise SuspiciousOperation("`offset` is required") # Fetch some helpful variables from the request fGroup = request.GET["group"] fQuery = request.GET["query"] fOffset = int(request.GET["offset"]) # Extract tags from the string and build the more # complex query args = [Q(group__id=fGroup)] qargs = None qstring = "" parts = fQuery.split(" ") for p in parts: # Inclusive tag if p[0:1] == "+": tag = "|" + p[1:] + "|" print "La: %s" % tag if qargs == None: qargs = Q(tags__contains=tag) else: qargs = qargs | Q(tags__contains=tag) # Exclusive tag elif p[0:1] == "-": tag = "|" + p[1:] + "|" print "Lalo: %s" % tag args.append(~Q(tags__contains=tag)) # Regular keyword else: if qstring: qstring += " " qstring += p # If we have inclusive tags, add them now if qargs != None: args.append(qargs) # Append string query if qstring: args.append(Q(context__name__contains=qstring)) # Fetch items items_per_batch = 20 items = [] db_items = MarketplaceContextEntry.objects.filter( *args).order_by("-rank")[fOffset:] num_items = len(db_items) cur_item = 0 for i in db_items: items.append({ "id": i.id, "label": i.context.name, "icon": i.icon.url, "details": i.details, "description": i.context.description, "uid": i.context.id, "owner": i.context.owner.username, "tags": i.tags[1:-1].split("|"), "rank": i.rank, "encrypted": not not i.context.key }) cur_item += 1 if cur_item >= items_per_batch: break # Check if we have more items has_more = 0 if num_items > items_per_batch: has_more = 1 # Build response data = { "offset": fOffset + items_per_batch, "more": has_more, "items": items } # Return filtered responses return uncache_response( HttpResponse(json.dumps(data), content_type="text/plain") )