def campaign_to_dict(campaign, platforms=None, fetch_platforms=True): """ Transform Campaign instance into dictionary that is suitable for JSON serialization display to end-user. If platforms parameter is specified it appends the campaign information about enabled platforms. If parameter fetch_platforms is True then the platforms data is fetched from the Datastore. If platforms is specified then fetch_platforms is ignored. :param campaign: Campaign instance. :param platforms: List of Platform instances. :param fetch_platforms: Boolean indicating whether to fetch platforms data from the Datastore. :return: Dictionary """ fetch_platforms = fetch_platforms and platforms is None output = campaign.to_dict() if fetch_platforms: query = Platform.query(Platform.campaign == campaign.key, projection=[Platform.name, Platform.counter ]).order(Platform.name).fetch(3) output["platform_counters"] = { platform.name: platform.counter for platform in query } elif platforms is not None: output["platform_counters"] = { platform.name: platform.counter for platform in platforms } output["id"] = campaign.key.id() return output
def put(self, campaign_id): """Update the existing campaign.""" campaign_id = int(campaign_id) future = Campaign.get_by_id_async(campaign_id) campaign_dict = self.get_request_json() validate_campaign_dict(campaign_dict, all_required=False) campaign = future.get_result() platforms = [] # get a list of existing campaign platforms existing_platforms_list = { platform.name: platform for platform in Platform.query( Platform.campaign == campaign.key).fetch(3) } # special processing for platforms field platforms_to_store = [] if "platforms" in campaign_dict: # get a list of platforms from the request platforms_list = campaign_dict["platforms"] del campaign_dict["platforms"] # construct platforms for campaign for platform_name in platforms_list: if platform_name not in existing_platforms_list: platform = Platform(name=platform_name, counter=0, campaign=campaign.key, id="%d-%s" % (campaign_id, platform_name)) platforms_to_store.append(platform) else: platform = existing_platforms_list[platform_name] platforms.append(platform) else: # no changes to platforms field, just copy for platform in existing_platforms_list.values(): platforms.append(platform) # update the rest of the fields for field_name in campaign_dict: setattr(campaign, field_name, campaign_dict[field_name]) campaign.update_date = datetime.now() @ndb.transactional_async(xg=True) def _update(): """Do the update in transaction""" ndb.put_multi_async(platforms_to_store) campaign.put_async() future = _update() output = campaign_to_dict(campaign, platforms=platforms) # explicitly do the json conversion here, while we may be waiting for the _update to finish output = json.dumps(output, default=json_serial, sort_keys=True) future.get_result() return output
def get(self, platform_name): """Retrieve the number of clicks on the given platform.""" @ndb.tasklet def callback(platform): raise ndb.Return(platform.counter) query = Platform.query(Platform.name == platform_name, projection=[Platform.counter]) clicks_sum = sum(query.map(callback)) return clicks_sum
def get(self, platform_name): """List all existing campaigns available on a given platform.""" @ndb.tasklet def callback(platform): campaign, platforms = yield platform.campaign.get_async(), \ Platform.query(Platform.campaign == platform.campaign, projection=[Platform.name, Platform.counter]).order( Platform.name).fetch_async(3) raise ndb.Return(campaign_to_dict(campaign, platforms=platforms)) query = Platform.query(Platform.name == platform_name, projection=[Platform.campaign]) output = query.map(callback) return output
def delete(self, campaign_id): """Delete the existing campaign.""" campaign_id = int(campaign_id) campaign = Campaign.get_by_id(campaign_id) if campaign: # delete the campaign first, so that updates are not possible futures = [campaign.key.delete_async()] # delete all platforms that correspond to the campaign futures.extend( ndb.delete_multi_async([ platform.key for platform in Platform.query( Platform.campaign == campaign.key).fetch(3) ])) Future.wait_all(futures) else: # the campaign does not exist, just send 204 self.response.status_int = 204
def callback(platform): campaign, platforms = yield platform.campaign.get_async(), \ Platform.query(Platform.campaign == platform.campaign, projection=[Platform.name, Platform.counter]).order( Platform.name).fetch_async(3) raise ndb.Return(campaign_to_dict(campaign, platforms=platforms))
def callback(campaign): platforms = yield Platform.query( Platform.campaign == campaign.key, projection=[Platform.name, Platform.counter ]).order(Platform.name).fetch_async(3) raise ndb.Return(campaign_to_dict(campaign, platforms=platforms))