class Post(db.Model): title = db.StringProperty(required = True) body = db.TextProperty(required = True) created = db.DateTimeProperty(auto_now_add = True) # TODO - we need an author field here; it should be required author = db.ReferenceProperty(User)
class OrderRetrieval(BaseModel): """Maps Order to Retrieval.""" order = db.ReferenceProperty(Order, required=True) retrieval = db.ReferenceProperty(Retrieval, required=True)
class PasswordResetToken(db.Model): token = db.StringProperty(required=False, indexed=True) email = db.StringProperty(required=False, indexed=True) member = db.ReferenceProperty(Member) valid = db.IntegerProperty(required=False, indexed=True, default=1) timestamp = db.IntegerProperty(required=False, indexed=True, default=0)
class Post(db.Model): title = db.StringProperty(required=True) body = db.TextProperty(required=True) created = db.DateTimeProperty(auto_now_add=True) author = db.ReferenceProperty(User, required=True)
class OrderDelivery(BaseModel): """Maps Order to Delivery.""" order = db.ReferenceProperty(Order, required=True) delivery = db.ReferenceProperty(Delivery, required=True)
class ClientLogBase(Log): """ClientLog model for all client interaction.""" # denormalized OSX or Puppet UUID; undecided. uuid = db.StringProperty() computer = db.ReferenceProperty(Computer)
class Comment(Entity): user = db.ReferenceProperty(User) ranking = db.ReferenceProperty(Ranking) text = db.TextProperty(required=True) time = db.DateTimeProperty(auto_now_add=True)
class DeviceTask(db.Model): """Represents a task currently assigned to a given device.""" task = db.ReferenceProperty(Task) device_info = db.ReferenceProperty(DeviceInfo)
class Liker(db.Model): post = db.ReferenceProperty(Post, collection_name='likers') likerKey = db.StringProperty()
class Donation(db.Model): contributor = db.ReferenceProperty(Contributor, collection_name="donations") campaign = db.ReferenceProperty(Campaign, collection_name="donations") candidate = db.ReferenceProperty(Candidate, collection_name="donations") amount = db.IntegerProperty()
class Measurement(db.Expando): """Represents a single measurement by a single end-user device.""" # Reference to the corresponding device properties device_properties = db.ReferenceProperty(DeviceProperties) # Measurement type type = db.StringProperty() # Timestamp timestamp = db.DateTimeProperty(auto_now_add=True) # Whether measurement was successful success = db.BooleanProperty() # Optional corresponding task task = db.ReferenceProperty(Task) @classmethod def GetMeasurementListWithAcl(cls, limit=None, device_id=None, start_time=None, end_time=None, exclude_errors=True): """Return a list of measurements that are accessible by the current user.""" if device_id: try: devices = [DeviceInfo.GetDeviceWithAcl(device_id)] except RuntimeError: devices = [] else: devices = list(DeviceInfo.GetDeviceListWithAcl()) if not devices: return [] results = [] limit = limit or config.QUERY_FETCH_LIMIT per_query_limit = max(1, int(limit / len(devices))) for device in devices: query = cls.all() query.ancestor(device.key()) if exclude_errors: query.filter('success =', True) query.order('-timestamp') if start_time: query.filter('timestamp >=', start_time) if end_time: query.filter('timestamp <=', end_time) for result in query.fetch(per_query_limit): results.append(result) return results def GetTaskID(self): try: if not self.task: return None taskid = self.task.key().id() return taskid except db.ReferencePropertyResolveError: logging.exception('Cannot resolve task for measurement %s', self.key().id()) self.task = None # TODO(mdw): Decide if we should do this here. Can be expensive. #self.put() return None def GetParam(self, key): """Return the measurement parameter indexed by the given key.""" return self._dynamic_properties.get('mparam_' + key, None) def Params(self): """Return a dict of all measurement parameters.""" return dict((k[len('mparam_'):], self._dynamic_properties[k]) for k in self.dynamic_properties() if k.startswith('mparam_')) def GetValue(self, key): """Return the measurement value indexed by the given key.""" return self._dynamic_properties.get('mval_' + key, None) def Values(self): """Return a dict of all measurement values.""" return dict((k[len('mval_'):], self._dynamic_properties[k]) for k in self.dynamic_properties() if k.startswith('mval_')) def JSON_DECODE_timestamp(self, inputval): try: self.timestamp = util.MicrosecondsSinceEpochToTime(int(inputval)) except ValueError: logging.exception('Error occurs while converting timestamp ' '%s to integer', inputval) self.timestamp = None def JSON_DECODE_parameters(self, input_dict): for k, v in input_dict.items(): setattr(self, 'mparam_' + k, v) def JSON_DECODE_values(self, input_dict): for k, v in input_dict.items(): # body, headers, and error messages can be fairly long. # Use the Text data type instead if k == 'body' or k == 'headers' or k == 'error': setattr(self, 'mval_' + k, db.Text(v)) else: setattr(self, 'mval_' + k, v) def JSON_DECODE_task_key(self, task_key): # task_key is optional and can be None. # Look up the task_key and set the 'task' field accordingly. # If the task does not exist, just don't set this field if task_key is None: return task = Task.get_by_id(int(task_key)) if not task: return self.task = task def __str__(self): return 'Measurement <device %s, type %s>' % ( self.device_properties, self.type) def GetTimestampInZone(self, zone=config.DEFAULT_TIMEZONE): if zone and util.TZINFOS[zone]: return self.timestamp.replace( tzinfo=util.TZINFOS['utc']).astimezone(util.TZINFOS[zone]) else: return self.timestamp
class ContributorAttribute(db.Expando): contributor = db.ReferenceProperty(Contributor, collection_name="attributes") a_key = db.StringProperty(indexed=True, name="key")
class Campaign(db.Model): candidate = db.ReferenceProperty(Candidate, collection_name="campaigns") cycle = db.ReferenceProperty(Cycle, collection_name="campaigns") party = db.ReferenceProperty(Party, collection_name="campaigns")
class CandidateAttribute(db.Expando): candidate = db.ReferenceProperty(Candidate, collection_name="attributes") index = db.StringProperty(indexed=True)
class Advert(polymodel.PolyModel): name = db.StringProperty(required=False) target_url = db.StringProperty(required=True) priority = db.IntegerProperty(required=False) campaign = db.ReferenceProperty(Campaign)
class Registration(db.Model): owner = db.UserProperty() client_url = db.StringProperty() topscore = db.IntegerProperty() topgame = db.ReferenceProperty(GameHistory)
class ComputerLostStolen(db.Model): """Model to store reports about lost/stolen machines.""" uuid = db.StringProperty() computer = db.ReferenceProperty(Computer) connections = db.StringListProperty() lost_stolen_datetime = db.DateTimeProperty(auto_now_add=True) mtime = db.DateTimeProperty() @classmethod def _GetUuids(cls, force_refresh=False): """Gets the lost/stolen UUID dictionary from memcache or Datastore. Args: force_refresh: boolean, when True it repopulates memcache from Datastore. Returns: dictionary like { uuid_str: True } """ uuids = memcache.get('loststolen_uuids') if not uuids or force_refresh: uuids = {} for key in cls.all(keys_only=True): uuids[key.name()] = True memcache.set('loststolen_uuids', uuids) return uuids @classmethod def IsLostStolen(cls, uuid): """Returns True if the given str UUID is lost/stolen, False otherwise.""" return uuid in cls._GetUuids() @classmethod def AddUuid(cls, uuid): """Sets a UUID as lost/stolen, and refreshes the UUID cache.""" if cls.get_by_key_name(uuid): logging.warning('UUID already set as lost/stolen: %s', uuid) return # do nothing; the UUID is already set as lost/stolen. computer = Computer.get_by_key_name(uuid) ls = cls(key_name=computer.uuid, computer=computer, uuid=uuid) ls.put() cls._GetUuids(force_refresh=True) @classmethod def RemoveUuid(cls, uuid): """Removes a UUID as lost/stolen, and refreshes the UUID cache.""" computer = cls.get_by_key_name(uuid) if not computer: logging.warning('UUID is not set as lost/stolen: %s', uuid) return # do nothing; the UUID is already not set as lost/stolen. computer.delete() cls._GetUuids(force_refresh=True) @classmethod def LogLostStolenConnection(cls, computer, ip_address): """Logs a connection from a lost/stolen computer.""" ls = cls.get_or_insert(computer.uuid) ls.computer = computer ls.uuid = computer.uuid now = datetime.datetime.utcnow() ls.mtime = now ls.connections.append('%s from %s' % (now, ip_address)) ls.put()
class UserExercise(db.Model): user = db.UserProperty() exercise = db.StringProperty() exercise_model = db.ReferenceProperty(Exercise) streak = db.IntegerProperty(default=0) longest_streak = db.IntegerProperty(default=0) first_done = db.DateTimeProperty(auto_now_add=True) last_done = db.DateTimeProperty() total_done = db.IntegerProperty(default=0) last_review = db.DateTimeProperty(default=datetime.datetime.min) review_interval_secs = db.IntegerProperty(default=( 60 * 60 * 24 * consts.DEFAULT_REVIEW_INTERVAL_DAYS)) # Default 7 days until review proficient_date = db.DateTimeProperty() seconds_per_fast_problem = db.FloatProperty( default=consts.MIN_SECONDS_PER_FAST_PROBLEM ) # Seconds expected to finish a problem 'quickly' for badge calculation summative = db.BooleanProperty(default=False) _USER_EXERCISE_KEY_FORMAT = "UserExercise.all().filter('user = '******')" @staticmethod def get_key_for_user(user): return UserExercise._USER_EXERCISE_KEY_FORMAT % user.email() @staticmethod def get_for_user_use_cache(user): user_exercises_key = UserExercise.get_key_for_user(user) user_exercises = memcache.get(user_exercises_key) if user_exercises is None: query = UserExercise.all() query.filter('user ='******'t schedule a review if (self.streak + correct) < self.required_streak( ) and self.longest_streak < self.required_streak(): return # If the user is hitting a new streak either for the first time or after having lost # proficiency, reset their review interval counter. if (self.streak + correct) >= self.required_streak: self.review_interval_secs = 60 * 60 * 24 * consts.DEFAULT_REVIEW_INTERVAL_DAYS review_interval = self.get_review_interval() if correct and self.last_review != datetime.datetime.min: time_since_last_review = now - self.last_review if time_since_last_review >= review_interval: review_interval = time_since_last_review * 2 if not correct: review_interval = review_interval // 2 if correct: self.last_review = now else: self.last_review = datetime.datetime.min self.review_interval_secs = review_interval.days * 86400 + review_interval.seconds def set_proficient(self, proficient, user_data): if not proficient and self.longest_streak < self.required_streak(): # Not proficient and never has been so nothing to do return if proficient: if self.exercise not in user_data.proficient_exercises: user_data.proficient_exercises.append(self.exercise) user_data.need_to_reassess = True user_data.put() else: if self.exercise in user_data.proficient_exercises: user_data.proficient_exercises.remove(self.exercise) user_data.need_to_reassess = True user_data.put()
class Attendee(db.Model): email = db.StringProperty() event = db.ReferenceProperty(Event)
class VideoPlaylist(db.Model): playlist = db.ReferenceProperty(Playlist) video = db.ReferenceProperty(Video) video_position = db.IntegerProperty() live_association = db.BooleanProperty( default=False ) #So we can remove associations without deleting the entry. We need this so that bulkuploading of VideoPlaylist info has the proper effect. _VIDEO_PLAYLIST_KEY_FORMAT = "VideoPlaylist_Videos_for_Playlist_%s" _PLAYLIST_VIDEO_KEY_FORMAT = "VideoPlaylist_Playlists_for_Video_%s" @staticmethod def get_cached_videos_for_playlist(playlist, limit=500): key = VideoPlaylist._VIDEO_PLAYLIST_KEY_FORMAT % playlist.key() namespace = str(App.version) + "_" + str( Setting.cached_library_content_date()) videos = memcache.get(key, namespace=namespace) if videos is None: videos = [] query = VideoPlaylist.all() query.filter('playlist =', playlist) query.filter('live_association = ', True) query.order('video_position') video_playlists = query.fetch(limit) for video_playlist in video_playlists: videos.append(video_playlist.video) memcache.set(key, videos, namespace=namespace) return videos @staticmethod def get_cached_playlists_for_video(video, limit=5): key = VideoPlaylist._PLAYLIST_VIDEO_KEY_FORMAT % video.key() namespace = str(App.version) + "_" + str( Setting.cached_library_content_date()) playlists = memcache.get(key, namespace=namespace) if playlists is None: playlists = [] query = VideoPlaylist.all() query.filter('video =', video) query.filter('live_association = ', True) video_playlists = query.fetch(limit) for video_playlist in video_playlists: playlists.append(video_playlist.playlist) memcache.set(key, playlists, namespace=namespace) return playlists @staticmethod def get_query_for_playlist_title(playlist_title): query = Playlist.all() query.filter('title =', playlist_title) playlist = query.get() query = VideoPlaylist.all() query.filter('playlist =', playlist) query.filter( 'live_association = ', True ) #need to change this to true once I'm done with all of my hacks query.order('video_position') return query
class Token(db.Model): REQUEST = 1 ACCESS = 2 TOKEN_TYPES = (REQUEST, ACCESS) key_ = db.StringProperty() secret = db.StringProperty() token_type = db.IntegerProperty(choices=TOKEN_TYPES) timestamp = db.IntegerProperty() is_approved = db.BooleanProperty(default=False) user = db.UserProperty(required=False) consumer = db.ReferenceProperty(Consumer, collection_name="tokens") resource = db.ReferenceProperty(Resource, collection_name="resources") ## OAuth 1.0a stuff verifier = db.StringProperty() callback = db.StringProperty(required=False) callback_confirmed = db.BooleanProperty(default=False) def __unicode__(self): return u"%s Token %s for %s" % (self.get_token_type_display(), self.key_, self.consumer) def to_string(self, only_key=False): token_dict = { 'oauth_token': self.key_, 'oauth_token_secret': self.secret } if self.callback_confirmed: token_dict.update({'oauth_callback_confirmed': 'true'}) if self.verifier: token_dict.update({'oauth_verifier': self.verifier}) if only_key: del token_dict['oauth_token_secret'] if token_dict.has_key('oauth_callback_confirmed'): del token_dict['oauth_callback_confirmed'] return urllib.urlencode(token_dict) def generate_random_codes(self): key = generate_random(length=KEY_SIZE) secret = generate_random(length=SECRET_SIZE) while Token.all().filter('key_ =', key).count(): key = generate_random(length=KEY_SIZE) secret = generate_random(length=SECRET_SIZE) self.key_ = key self.secret = secret self.put() db.get(self.key()) # force-commit (needed for the high-repl datastore) def get_callback_url(self): """ OAuth 1.0a, append the oauth_verifier. """ if self.callback and self.verifier: parts = urlparse.urlparse(self.callback) scheme, netloc, path, params, query, fragment = parts[:6] if query: query = '%s&oauth_verifier=%s' % (query, self.verifier) else: query = 'oauth_verifier=%s' % self.verifier return urlparse.urlunparse( (scheme, netloc, path, params, query, fragment)) return self.callback def create_token(cls, consumer, token_type, timestamp, resource, user=None, callback=None, callback_confirmed=False): """Shortcut to create a token with random key/secret.""" token = Token(consumer=consumer, token_type=token_type, timestamp=timestamp, resource=resource, user=user, callback=callback, callback_confirmed=callback_confirmed) token.generate_random_codes() token.put() db.get(token.key()) # force-commit, needed for the high-repl datastore return token create_token = classmethod(create_token)
class ExercisePlaylist(db.Model): exercise = db.ReferenceProperty(Exercise) playlist = db.ReferenceProperty(Playlist)
class Order(BaseModel): """A Captain can make an Order for a list of Items.""" site = db.ReferenceProperty(NewSite, required=True) order_sheet = db.ReferenceProperty(OrderSheet, required=True) program = db.StringProperty() sub_total = db.FloatProperty() sales_tax = db.FloatProperty() # Deprecated grand_total = db.FloatProperty() # Deprecated. Use GrandTotal() notes = db.TextProperty() state = db.StringProperty() actual_total = db.FloatProperty() reconciliation_notes = db.TextProperty(default='') invoice_date = db.DateTimeProperty() vendor = db.ReferenceProperty(Supplier) logistics_start = db.StringProperty() logistics_end = db.StringProperty() logistics_instructions = db.TextProperty() created = db.DateTimeProperty(auto_now_add=True) created_by = db.UserProperty(auto_current_user_add=True) modified = db.DateTimeProperty(auto_now=True) last_editor = db.UserProperty(auto_current_user=True) def put(self, *a, **k): self.program = self.site.program super(BaseModel, self).put(*a, **k) def __unicode__(self): return ' '.join( (self.site.number, self.site.name, self.order_sheet.name, '%d items' % len(list(self.orderitem_set)), '$%0.2f' % self.GrandTotal())) def CanMakeChanges(self): return self.state in ('new', 'Received') def VisibleNotes(self): if self.notes is None: return '' return self.notes def EstimatedTotal(self): if self.sub_total is None: return 0. t = self.sub_total * (1. + SALES_TAX_RATE) return math.ceil(t * 100.) / 100. def GrandTotal(self): if self.state == 'Deleted': return 0. if self.actual_total is not None: return self.actual_total else: return self.EstimatedTotal() def Total(self): return self.GrandTotal() def SalesTax(self): if self.state == 'Deleted': return 0. if self.sub_total is None: return 0. return self.sub_total * SALES_TAX_RATE # TODO: seems incorrect to update fulfilled orders. def UpdateSubTotal(self): """Recomputes sub_total by summing the cost of items and adding tax.""" sub_total = 0. order_items = OrderItem.all().filter('order = ', self) for oi in order_items: quantity = oi.FloatQuantity() if oi.item.unit_cost is not None and quantity: sub_total += quantity * oi.item.unit_cost if self.sub_total != sub_total: self.sub_total = sub_total self.put() logging.info('Updated subtotal for order %d to %0.2f', self.key().id(), sub_total) def LogisticsStart(self): for od in self.orderdelivery_set: return "%s (Delivery)" % od.delivery.delivery_date for od in self.orderpickup_set: return "%s (Pickup)" % od.pickup.pickup_date for od in self.orderretrieval_set: return "%s (Drop-off)" % od.retrieval.dropoff_date return None def LogisticsEnd(self): for od in self.orderretrieval_set: return "%s (Retrieval)" % od.retrieval.retrieval_date return None def LogisticsInstructions(self): for od in self.orderdelivery_set: return "%s%s %s%s %s" % ( od.delivery.contact and 'Contact ' or '', od.delivery.contact or '', od.delivery.contact_phone and 'at ' or '', od.delivery.contact_phone or '', od.delivery.notes or '') for od in self.orderpickup_set: return "%s%s %s%s %s" % ( od.pickup.contact and 'Contact ' or '', od.pickup.contact or '', od.pickup.contact_phone and 'at ' or '', od.pickup.contact_phone or '', od.pickup.notes or '') for od in self.orderretrieval_set: return "%s%s %s%s %s" % ( od.retrieval.contact and 'Contact ' or '', od.retrieval.contact or '', od.retrieval.contact_phone and 'at ' or '', od.retrieval.contact_phone or '', od.retrieval.notes or '') return '' def UpdateLogistics(self): self.logistics_start = self.LogisticsStart() self.logistics_end = self.LogisticsEnd() self.logistics_instructions = self.LogisticsInstructions() self.put()
class SigChild(db.Model): CLEANUP_REFERENCES = 'rel' owner = db.ReferenceProperty(TestC) rel = db.ReferenceProperty(TestC, collection_name='sigchildrel_set')
class OrderPickup(BaseModel): """Maps Order to Pickup.""" order = db.ReferenceProperty(Order, required=True) pickup = db.ReferenceProperty(Pickup, required=True)
class TestModelRel(db.Model): modelrel = db.ReferenceProperty(db.Model)
class NewSite(BaseModel): """A work site.""" # "10001DAL" reads: 2010, #001, Daly City number = db.StringProperty(required=True) number.unique = True program = db.StringProperty() name = db.StringProperty() # "Belle Haven" name.verbose_name = 'Recipient Name' applicant = db.StringProperty() applicant.verbose_name = 'Applicant Contact' applicant_home_phone = db.StringProperty() applicant_work_phone = db.StringProperty() applicant_mobile_phone = db.StringProperty() applicant_email = db.StringProperty() rating = db.StringProperty() roof = db.StringProperty() rrp_test = db.StringProperty() rrp_level = db.StringProperty() jurisdiction = db.StringProperty() jurisdiction_choice = db.ReferenceProperty(Jurisdiction) scope_of_work = db.TextProperty() sponsor = db.StringProperty() street_number = db.StringProperty() street_number.verbose_name = "Street Address" street_number.help_text = "Full street address like 960 Main Street, Apt 4" city_state_zip = db.StringProperty() city_state_zip.help_text = "City State Zip, like Menlo Park CA 94025" budget = db.IntegerProperty(default=0) announcement_subject = db.StringProperty(default='Nothing Needs Attention') announcement_body = db.TextProperty( default="Pat yourself on the back - no items need attention.\n" "You have a clean bill of health.") search_prefixes = db.StringListProperty() photo_link = db.StringProperty() photo_link.help_text = "example: https://www.flickr.com/gp/rebuildingtogetherpeninsula/UX22iM/" volunteer_signup_link = db.StringProperty() volunteer_signup_link.help_text = "http://rebuildingtogetherpeninsula.force.com/GW_Volunteers__VolunteersJobListingFS?&CampaignID=701U0000000rnvU" class ActiveItems(object): """Access user-input records with state and modified fields.""" def __init__(self, query): """query: a bound backreference like self.order_set""" self._query = query.filter('state != ', 'new').filter('state !=', 'deleted') def Count(self): return self._query.count() def Items(self): for item in sorted(self._query, key=lambda o: o.modified, reverse=True): yield item def __iter__(self): return self.Items() @property def IsCDBG(self): return 'CDBG' in self.jurisdiction @property def ContactPerson(self): if self.applicant: return self.applicant return self.name @property def Orders(self): return self.ActiveItems(self.order_set) @property def CheckRequests(self): return self.ActiveItems(self.checkrequest_set) @property def VendorReceipts(self): return self.ActiveItems(self.vendorreceipt_set) @property def InKindDonations(self): return self.ActiveItems(self.inkinddonation_set) @property def StaffTimes(self): return self.ActiveItems(self.stafftime_set) @property def StaffTimesByPosition(self): class Pos(object): def __init__(self): self.name = None self.hours = 0.0 self.hours_subtotal = 0.0 self.miles = 0.0 self.mileage_subtotal = 0.0 self.stafftimes = [] by_pos = collections.defaultdict(Pos) for s in self.StaffTimes: name = str(s.position) pos = by_pos[name] if pos.name is None: pos.name = name pos.stafftimes.append(s) pos.hours += s.hours pos.hours_subtotal += s.HoursTotal() pos.miles += s.miles pos.mileage_subtotal += s.MileageTotal() return by_pos.itervalues() @property def ScopeOfWork(self): if self.scope_of_work: return self.scope_of_work sow = '' for o in self.order_set: if o.order_sheet.name == 'Scope of Work': sow = o.notes self.scope_of_work = sow self.put() return sow def ProgramFromNumber(self): year = '20' + self.number[0:2] mode = self.number[2] program = None if mode == '0': program = year + ' NRD' elif mode == '1': program = year + ' NRD' elif mode == '3': program = year + ' Misc' elif mode == '5': program = year + ' Safe' elif mode == '6': program = year + ' Safe' elif mode == '7': program = year + ' Energy' elif mode == '8': program = year + ' Teambuild' elif mode == '9': program = year + ' Youth' elif mode == 'Z': program = year + ' Test' else: logging.warn('no program for site number %s', self.number) return program def SaveTheChildren(self): for child in (self.order_set, self.checkrequest_set, self.vendorreceipt_set, self.inkinddonation_set, self.stafftime_set): for obj in child: obj.put() def put(self, *a, **k): if self.jurisdiction_choice: self.jurisdiction = self.jurisdiction_choice.name # issue213: program should be configurable if not self.program: self.program = self.ProgramFromNumber() prefixes = set() for f in self.name, self.applicant, self.street_number, self.jurisdiction: if not f: continue prefixes.add(f) for part in f.split(): prefixes.add(part) for i in xrange(1, 7): prefixes.add(part[:i]) if self.number: prefixes.add(self.number) for i in xrange(1, 7): prefixes.add(self.number[:i]) prefixes.add(self.number[2:2 + i]) prefixes.add(self.number[5:5 + i]) self.search_prefixes = [p.lower() for p in prefixes] super(BaseModel, self).put(*a, **k) self.SaveTheChildren() def Label(self): return "%s %s" % (self.number, self.name) def __unicode__(self): """Only works if self has been saved.""" return 'Site #%s | %s' % (self.number, self.name) def StreetAddress(self): return '%s, %s' % (' '.join(self.street_number.split()), ' '.join( self.city_state_zip.split())) def NeedsAttention(self): return self.announcement_subject is not None def OrderTotal(self): """Only works if self has been saved.""" cost = sum(order.GrandTotal() for order in self.Orders) return cost @property def order_total(self): if not hasattr(self, '_order_total'): self._order_total = self.OrderTotal() return self._order_total def CheckRequestTotal(self): """Only works if self has been saved.""" return sum(cr.Total() or 0 for cr in self.CheckRequests) def VendorReceiptTotal(self): """Only works if self has been saved.""" return sum(cr.amount or 0 for cr in self.VendorReceipts) def InKindDonationTotal(self): """Only works if self has been saved.""" return sum(cr.Total() or 0 for cr in self.InKindDonations) def StaffTimeTotal(self): """Only works if self has been saved.""" return sum(cr.Total() or 0 for cr in self.StaffTimes) def Expenses(self): return (self.order_total + self.CheckRequestTotal() + self.StaffTimeTotal() + self.VendorReceiptTotal()) def BudgetRemaining(self): if self.budget: return self.budget - self.Expenses() else: return 0. @property def budget_remaining(self): if not hasattr(self, '_budget_remaining'): self._budget_remaining = self.BudgetRemaining() return self._budget_remaining @property def in_the_red(self): return self.budget_remaining < 0 def BudgetStatement(self): if self.BudgetRemaining() > 0: return '$%0.2f unspent budget' % self.BudgetRemaining() else: return '$%0.2f over budget' % (-1 * self.BudgetRemaining())
class ProstheticData(db.Model): """The Prosthetic OAuth authorization required to access the Weavr, and the state data for the Weavr's instance of the Prosthetic""" request_token = db.ReferenceProperty(RequestToken) access_token = db.ReferenceProperty(AccessToken) previous_emotion = db.StringProperty(default="nothing")
class Checkin(db.Model): place = db.ReferenceProperty(Place) member = db.ReferenceProperty(Member) last_checked_in = db.DateTimeProperty(auto_now=True)
class ProductConfig(db.Model): # profile information def name(self): return self.getProductLine().name def getName(self): return self.getProductLine().name config_name = db.StringProperty() def description(self): return self.getProductLine().description def getDescription(self): return self.getProductLine().description def shortDescription(self): return self.getProductLine().shortDescription() isLine = db.BooleanProperty() isConfig = db.BooleanProperty() isUnit = db.BooleanProperty() _num_closet = db.IntegerProperty() store_link = db.ReferenceProperty(StoreLink) displayAmazon = db.BooleanProperty() def addClosetCount(self): self._num_closet = self._num_closet + 1 def remClosetCount(self): self._num_closet = self._num_closet - 1 def getClosetCount(self): return self._num_closet _consumers = db.ListProperty(db.Key) def addConsumer(self, key): if key: self._consumers.append(key) def remConsumer(self, key): if key: if key in self._consumers: self._consumers.remove(key) def getConsumers(self): _consumers_keys = list(set(self._consumers)) _consumers = db.get(_consumers_keys) return [_consumer for _consumer in _consumers if _consumer] rating = db.FloatProperty() _num_ratings = db.IntegerProperty() def getRating(self): return self.rating def getRoundedRating(self): return round(self.rating * 4) / 4 def updateRating(self, userRating, consumer): if self.key() in consumer._productsRated: index = consumer._productsRated.index(self.key()) consumer._productsRated.pop(index) old_rating = consumer._ratingsAdded.pop(index) self.rating = (self._num_ratings * self.rating - old_rating) / float((self._num_ratings - 1)) self._num_ratings = self._num_ratings - 1 self.rating = (self._num_ratings * self.rating + userRating) / float( (self._num_ratings + 1)) self._num_ratings = self._num_ratings + 1 consumer._productsRated.append(self.key()) consumer._ratingsAdded.append(userRating) consumer.put() _product_line = db.ReferenceProperty(ProductLine) def getProductLine(self): return self._product_line def addProductLine(self, product_line_add): self._product_line = product_line_add def getProducts(self): return self.product_set def numProducts(self): products = self.product_set count = 0 if products: for product in products: if product: count = count + 1 return count def getPicture(self): return self.getProductLine().getPicture() def hasImage(self): return self.getProductLine().hasImage() # security owner = db.UserProperty() unique = db.StringProperty() # hierarchical information # producer _producer = db.ReferenceProperty(Producer) def getProducer(self): return self._producer def addProducer(self, producer_add): self._producer = producer_add # path _path = db.ListProperty(db.Key) _path_primary_index = db.IntegerProperty() def getPath(self): ''' get path elements, including indices ''' if self._path: __path = db.get(self._path) return [path for path in __path if path] # return non-None path elements else: return None def clearPath(self): ''' use when editing a product. clear path and then re-create one''' _path = self.getPath() if _path: for location in _path: self._path.remove(location.key()) db.delete(location.key()) def addLocationToPath(self, location_add, text_add, _index): ''' self-explanatory ''' if not _index: _index = len(self._path) if location_add: f = LocationInPath(location=location_add, index=_index, text=text_add) f.put() self._path.append(f.key()) def setPrimaryLocation(self, location_primary): ''' primary location ''' for path_element in self.getPath(): if path_element.location.key() == location_primary.key(): self._path_primary_index = path_element.index # path _badges = db.ListProperty(db.Key) def addBadge(self, key): if key: if key not in self._badges: self._badges.append(key) def remBadge(self, key): if key: if key in self._badges: self._badges.remove(key) def getBadges(self): if self._badges: __badges = db.get(self._badges) return [badge for badge in __badges if badge] # return non-None badges else: return None # workers def getWorkers(self): if self._producer: return self._producer.getWorkers().filter('_productconfigs =', self.key()) return Worker.all().filter('_productconfigs =', self.key) # locations def getLocations(self): ''' get path elements, only locations, no indices, in order ''' if self._path: __path = db.get(self._path) return [path.location for path in __path if path] # return non-None path elements else: return None def getPrimaryLocation(self): if self._path: if self._path_primary_index: if self._path_primary_index >= 0 and self._path_primary_index < len( self._path): return self.getPath()[self._path_primary_index].location else: return self.getPath()[0].location else: return self.getPath()[0].location return None