Example #1
0
    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
Example #2
0
    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
Example #3
0
    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
Example #4
0
    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
Example #5
0
    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
Example #6
0
    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
Example #7
0
    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
Example #8
0
    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()
Example #9
0
    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
Example #10
0
    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
Example #11
0
    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
Example #12
0
    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
Example #13
0
    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()