def update(self, wines=[]): """ Recalculate this object's rank, and create a search index for it. """ if not self.key: raise Exception("Can't update without a key.") index = search.Index(name="wineries") searchkey = str(self.key.id()) self.rank = self.calculate_rank(wines) location = "" if self.has_location: location = self.to_dict()['location'] elif self.has_location_fuzzy: location = self.to_dict()['location_fuzzy'] partial_location = BaseModel.partial_search_string(location) fields = [] name = self.to_dict()['name'] partial_name = BaseModel.partial_search_string(name) fields.append(search.TextField(name='name', value=name)) fields.append(search.TextField(name='partial_name', value=partial_name)) fields.append(search.TextField(name='location', value=location)) fields.append(search.TextField(name='partial_location', value=partial_location)) if self.has_country: country = self.to_dict()['country'] fields.append(search.AtomField(name='country', value=country)) if self.has_region: region = self.to_dict()['region'] fields.append(search.AtomField(name='region', value=region)) if self.has_subregion: subregion = self.to_dict()['subregion'] fields.append(search.AtomField(name='subregion', value=subregion)) fields.append(search.AtomField(name='verified', value=str(self.has_verified))) fields.append(search.NumberField(name='rank', value=self.rank)) fields.append(search.TextField(name='id', value=str(self.key.id()))) searchdoc = search.Document(doc_id=searchkey, fields=fields, rank=self.rank) index.put(searchdoc) return None
def update(self, wines=[]): """ Recalculate this object's rank, and create a search index for it. """ if not self.key: raise Exception("Can't update without a key.") index = search.Index(name="wineries") searchkey = str(self.key.id()) self.rank = self.calculate_rank(wines) location = "" if self.has_location: location = self.to_dict()['location'] elif self.has_location_fuzzy: location = self.to_dict()['location_fuzzy'] partial_location = BaseModel.partial_search_string(location) fields = [] name = self.to_dict()['name'] partial_name = BaseModel.partial_search_string(name) fields.append(search.TextField(name='name', value=name)) fields.append(search.TextField(name='partial_name', value=partial_name)) fields.append(search.TextField(name='location', value=location)) fields.append( search.TextField(name='partial_location', value=partial_location)) if self.has_country: country = self.to_dict()['country'] fields.append(search.AtomField(name='country', value=country)) if self.has_region: region = self.to_dict()['region'] fields.append(search.AtomField(name='region', value=region)) if self.has_subregion: subregion = self.to_dict()['subregion'] fields.append(search.AtomField(name='subregion', value=subregion)) fields.append( search.AtomField(name='verified', value=str(self.has_verified))) fields.append(search.NumberField(name='rank', value=self.rank)) fields.append(search.TextField(name='id', value=str(self.key.id()))) searchdoc = search.Document(doc_id=searchkey, fields=fields, rank=self.rank) index.put(searchdoc) return None
def config(self, data): self.apply(['bottle_size', 'purchase_date', 'purchase_location', 'storage_location1', 'storage_location2', 'consumed', 'consumed_date'], data) if 'cost' in data and data['cost'] != '': self.cost = int(float(data['cost']) * 100) del data['cost'] json = BaseModel.tidy_up_the_post_object(data) self.json = json key = self.put() return key
def create(self, post, winery): """ >>> v = Winery() >>> v_key = v.create({'name':'Winery'}) >>> w = Wine(parent=v_key) >>> post = {} >>> post['name'] = 'Red Character' >>> post['varietal'] = 'Blend' >>> post['winetype'] = 'Red' >>> post['upc'] = '1234567890' >>> post['blend'] = ['Merlot', 'Cabernet Franc'] >>> post['token'] = "stub-uuid" >>> w_key = w.create(post, v) >>> w.name 'Red Character' >>> w.varietal 'Blend' >>> w.winetype 'Red' >>> w.to_dict()['json']['blend'] ['Merlot', 'Cabernet Franc'] >>> w.verified True >>> w.verified_by 'Winery' """ name = None if 'name' in post: name = post['name'] self.name = name del post['name'] year = None if 'year' in post: year = int(post['year']) self.year = year del post['year'] winetype = None if 'winetype' in post: winetype = post['winetype'] if not winetype in wine_types.types: raise ValueError("Invalid Wine Type: " + str(winetype)) else: self.winetype = winetype del post['winetype'] varietal = None if 'varietal' in post: varietal = post['varietal'] self.varietal = varietal del post['varietal'] upc = None if 'upc' in post: upc = post['upc'] del post['upc'] if not winetype: raise ValueError("You must provide a winetype") if not name and not year and not varietal and not upc: raise ValueError("You must provide a name, year, " + " varietal, or upc.") token = None if 'token' in post: token = post['token'] self.verify(token, winery) del post['token'] json = BaseModel.tidy_up_the_post_object(post) self.json = json key = self.put() return key
def create_search_index(self, winery): """ create a search index for this wine """ if not self.key: raise Exception("Can't update without a key.") index = search.Index(name="wines") searchkey = str(self.key.id()) # search rank is winery rank + individual rank rank = winery.to_dict()['rank'] + self.calculate_rank() fields = [] if self.has_year: year = self.to_dict()['year'] fields.append(search.NumberField(name='year', value=year)) if self.has_name: name = self.to_dict()['name'] partial_name = BaseModel.partial_search_string(name) fields.append(search.TextField(name='name', value=name)) fields.append(search.TextField(name='partial_name', value=partial_name)) winery_name = winery.to_dict()['name'] partial_winery_name = BaseModel.partial_search_string(winery_name) fields.append(search.TextField(name='winery', value=winery_name)) fields.append(search.TextField(name='partial_winery', value=partial_winery_name)) if self.has_winetype: winetype = self.to_dict()['winetype'] fields.append(search.AtomField(name='winetype', value=winetype)) if self.has_varietal: varietal = self.to_dict()['varietal'] partial_varietal = BaseModel.partial_search_string(varietal) fields.append(search.TextField(name='varietal', value=varietal)) fields.append(search.TextField(name='partial_varietal', value=partial_varietal)) if self.has_upc: upc = self.to_dict()['upc'] fields.append(search.TextField(name='upc', value=upc)) fields.append(search.AtomField(name='verified', value=str(self.has_verified))) fields.append(search.TextField(name='id', value=str(self.key.id()))) fields.append(search.TextField(name='winery_id', value=str(winery.key.id()))) fields.append(search.NumberField(name='rank', value=rank)) searchdoc = search.Document(doc_id=searchkey, fields=fields, rank=rank) index.put(searchdoc) return None
def modify(self, post, winery): """ >>> v = Winery() >>> v_key = v.create({"name":"Winery"}) >>> w = Wine(parent=v_key) >>> w_key = w.create({"winetype":"Red", "year":"2010"}, v) The base case. >>> w.modify({"name":"Red Character", "terroir":"Good"}, v) >>> w.to_dict()["name"] 'Red Character' >>> w.to_dict()["json"]["terroir"] 'Good' >>> w2 = Wine(parent=v_key) >>> w2.modify({"winetype":"White", "year":"2011"}, v) >>> w2.to_dict()["winetype"] 'White' >>> w2.to_dict()["year"] 2011 >>> w.modify({"varietal":"Blend"}, v) >>> w.to_dict()["varietal"] 'Blend' >>> w.modify({"upc":"123456789"}, v) >>> w.to_dict()["upc"] '123456789' You can't replace a field. >>> w.modify({"winetype":"White"}, v) Traceback (most recent call last): ... YouNeedATokenForThat... >>> w.modify({"terroir": "at danger lake!"}, v) Traceback (most recent call last): ... YouNeedATokenForThat... Should be fine if you update a thing with itself. >>> w.modify({"winetype":"Red"}, v) >>> w.modify({"terroir":"Good"}, v) You can update whatever you like if you have a token. >>> w.modify({"winetype":"White", "token":"stub-uuid"}, v) >>> w.to_dict()["winetype"] 'White' """ def field_edit_error(fieldname): return YouNeedATokenForThat(("You can't edit fields that already" + " exist: %s" % fieldname)) can_edit_fields = False if 'token' in post: token = post['token'] can_edit_fields = self.verify(token, winery) del post['token'] def can_edit_field(field_name): if field_name in post: if not field_name in self: return True if post[field_name] == str(self.to_dict()[field_name]): return True if can_edit_fields: return True raise field_edit_error(field_name) else: return False name = None if can_edit_field('name'): name = post['name'] self.name = name del post['name'] year = None if can_edit_field('year'): year = int(post['year']) self.year = year del post['year'] winetype = None if can_edit_field('winetype'): winetype = post['winetype'] if not winetype in wine_types.types: raise ValueError("Invalid Wine Type: " + str(winetype)) else: self.winetype = winetype del post['winetype'] varietal = None if can_edit_field('varietal'): varietal = post['varietal'] self.varietal = varietal del post['varietal'] upc = None if can_edit_field('upc'): upc = post['upc'] self.upc = upc del post['upc'] json = BaseModel.tidy_up_the_post_object(post) if 'json' in self.to_dict(): new_json = self.to_dict()['json'] for key, value in json.iteritems(): if key in new_json and can_edit_fields: new_json[key] = value if not (key in new_json): new_json[key] = value if key in new_json and new_json[key] == value: pass else: raise field_edit_error(key) self.json = new_json else: self.json = json key = self.put() return None
def create(self, post): """ Given a dict 'post' object containing winery-y fields, populate and put this Winery object, return the key. Throws a ValueError if no 'name' is included. >>> v_for_winery = Winery() >>> v_for_winery.create({}) Traceback (most recent call last): ... ValueError: 'name' field is mandatory Basic use-case test. >>> location = 'Canada - British Columbia: Okanagan Valley' >>> post = {'name':'Super Winery', 'location':location } >>> v_for_winery = Winery() >>> database_key = v_for_winery.create(post) >>> v_for_winery.country u'Canada' >>> v_for_winery.region u'British Columbia' >>> v_for_winery.subregion u'Okanagan Valley' >>> database_key.id() 'stub-key' If the location isn't in our list, it goes into location_fuzzy >>> location = 'Other' >>> post = {'name':'Super Winery 2', 'location':location} >>> v_for_winery = Winery() >>> database_key = v_for_winery.create(post) >>> v_for_winery.to_dict() {...'location_fuzzy': 'Other', ...} >>> v_for_winery.to_dict()['location_fuzzy'] 'Other' Winerys get a private token, which doesn't appear in to_dict() >>> v_for_winery.private_token 'stub-uuid' >>> v_for_winery.to_dict()['private_token'] Traceback (most recent call last): ... KeyError: 'private_token' Fields that we don't have database rows for go into the JSON. >>> post = {'name':'Super Winery 3', 'other_field':'glerg'} >>> v_for_winery = Winery() >>> database_key = v_for_winery.create(post) >>> v_for_winery.json {'other_field': 'glerg'} """ if not 'name' in post: raise ValueError("'name' field is mandatory") name = post['name'] self.name = name del post['name'] if 'location' in post: location = post['location'] self.set_location(location) del post['location'] self.private_token = uuid.uuid4().hex # special: winerys + verifieds are magic if 'token' in post: self.verify(post['token']) del post['token'] # having taken care of 'name' and 'location', # we wedge everything else into the JSON json = BaseModel.tidy_up_the_post_object(post) self.json = json self.rank = self.calculate_rank() key = self.put() return key
def modify(self, post): """ Given a dict 'post' object containing winery-y fields, update this object. Empty fields can always be updated. Fields cannot be overwritten without a valid winery or verifier token. If this object has been verified, no changes may occur without a valid winery or verifier token. Throws a YouNeedATokenForThat error if the user tries something he doesn't have access to without a token Let's create a Winery to update... >>> location = 'Canada - British Columbia: Okanagan Valley' >>> post = {'name':'Super Winery' } >>> post['location_fuzzy'] = 'Somewhere' >>> post['json_thing'] = 'blerg' >>> v = Winery() >>> v.location <truth.stubs.StringProperty ...> >>> database_key = v.create(post) And update the location: >>> new_post = {'location':location} >>> new_post['json_other_thing'] = 'blorg' >>> v.modify(new_post) >>> v.country u'Canada' >>> v.to_dict()['json']['json_other_thing'] 'blorg' Updates of existing fields should fail. >>> other_location = 'Canada - British Columbia: Similkameen Valley' >>> v.modify({'location':other_location}) Traceback (most recent call last): ... YouNeedATokenForThat... Updates of json fields that already exist should fail. >>> v.modify({'json_other_thing':'beep boop'}) Traceback (most recent call last): ... YouNeedATokenForThat... >>> v.to_dict()['json']['json_other_thing'] 'blorg' Updating a thing with itself should be fine. >>> v.modify({'name':'Super Winery'}) >>> v.modify({'json_other_thing':'blorg'}) >>> v.modify({'location':location}) You can update whatever you want if you have a stub. >>> v.modify({'location':other_location, 'token':'stub-uuid'}) >>> v.subregion u'Similkameen Valley' Once a token has touched something it can still be changed. >>> v.modify({'completely_new_field':'hurfdorf'}) """ def field_edit_error(fieldname): return YouNeedATokenForThat(("You can't edit fields that already" + " exist: %s" % fieldname)) can_edit_fields = False if 'token' in post: can_edit_fields = self.verify(post['token']) del post['token'] if 'name' in post and post['name'] != self.to_dict()['name']: if not can_edit_fields: raise field_edit_error('name') else: self.name = post['name'] del post['name'] # if new location == old location, fugeddaboutit if ('location' in post and self.has_location and post['location'] == self.to_dict()['location']): del post['location'] if 'location' in post: location = post['location'] # a proper location can trump a location_fuzzy if (not self.has_location and self.has_location_fuzzy and location in regions.location_list): self.set_location(location) self.location_fuzzy = None # a more specific location can trump a less specific location # something trumps nothing elif (not self.has_location and not self.has_location_fuzzy): self.set_location(location) elif can_edit_fields: self.set_location(location) else: raise field_edit_error('location') del post['location'] json = BaseModel.tidy_up_the_post_object(post) if self.has_json: new_json = self.to_dict()['json'] for key, value in json.iteritems(): if key in new_json and can_edit_fields: new_json[key] = value if not (key in new_json): new_json[key] = value if key in new_json and new_json[key] == value: pass else: raise field_edit_error(key) self.json = new_json else: self.json = json self.put()
def create_search_index(self, winery): """ create a search index for this wine """ if not self.key: raise Exception("Can't update without a key.") index = search.Index(name="wines") searchkey = str(self.key.id()) # search rank is winery rank + individual rank rank = winery.to_dict()['rank'] + self.calculate_rank() fields = [] if self.has_year: year = self.to_dict()['year'] fields.append(search.NumberField(name='year', value=year)) if self.has_name: name = self.to_dict()['name'] partial_name = BaseModel.partial_search_string(name) fields.append(search.TextField(name='name', value=name)) fields.append( search.TextField(name='partial_name', value=partial_name)) winery_name = winery.to_dict()['name'] partial_winery_name = BaseModel.partial_search_string(winery_name) fields.append(search.TextField(name='winery', value=winery_name)) fields.append( search.TextField(name='partial_winery', value=partial_winery_name)) if self.has_winetype: winetype = self.to_dict()['winetype'] fields.append(search.AtomField(name='winetype', value=winetype)) if self.has_varietal: varietal = self.to_dict()['varietal'] partial_varietal = BaseModel.partial_search_string(varietal) fields.append(search.TextField(name='varietal', value=varietal)) fields.append( search.TextField(name='partial_varietal', value=partial_varietal)) if self.has_upc: upc = self.to_dict()['upc'] fields.append(search.TextField(name='upc', value=upc)) fields.append( search.AtomField(name='verified', value=str(self.has_verified))) fields.append(search.TextField(name='id', value=str(self.key.id()))) fields.append( search.TextField(name='winery_id', value=str(winery.key.id()))) fields.append(search.NumberField(name='rank', value=rank)) searchdoc = search.Document(doc_id=searchkey, fields=fields, rank=rank) index.put(searchdoc) return None