class Shop(GeoModel): """TODO: Describe Shop""" Company = db.ReferenceProperty(reference_class=Company, collection_name="company_shops") Name= db.StringProperty(required=True, ) ContactPhone= db.PhoneNumberProperty() WorkingDays= db.StringListProperty(required=True, )#choices=[x[0] for x in Days]) NormalHoursStart= db.TimeProperty(required=True, default=time(8,0), ) NormalHoursEnd= db.TimeProperty(required=True, default=time(20,0) ,) WeekendHoursStart= db.TimeProperty(required=True, default=time(10, 00), ) WeekendHoursEnd= db.TimeProperty(required=True, default=time(22,00), ) IsWorkingOnWeekend= db.BooleanProperty(default=True, ) IsWorkingSunday= db.BooleanProperty(default=False, ) DateAdded= db.DateProperty(auto_now_add=True) DateModified = db.DateProperty(auto_now=True) def put(self): self.update_location() super(Shop, self).put() @classmethod def CreateNew(cls ,name,location,contactphone,workingdays,normalhoursstart,normalhoursend,weekendhoursstart,weekendhoursend,isworkingonweekend,isworkingsunday , _isAutoInsert=False): result = cls( Name=name, Location=location, ContactPhone=contactphone, WorkingDays=workingdays, NormalHoursStart=normalhoursstart, NormalHoursEnd=normalhoursend, WeekendHoursStart=weekendhoursstart, WeekendHoursEnd=weekendhoursend, IsWorkingOnWeekend=isworkingonweekend, IsWorkingSunday=isworkingsunday,) if _isAutoInsert: result.put() return result def __str__(self): #TODO: Change the method to represent something meaningful return self.Name+"("+self.Company.Name+")"+str(self.location)
class Business(geo.geomodel.GeoModel): user_id = db.StringProperty(required=True) address = db.StringProperty(required=True) name = db.StringProperty(required=True) phone_number = db.PhoneNumberProperty() boo = db.IntegerProperty() open_time = db.TimeProperty() close_time = db.TimeProperty()
class Wget(db.Expando): name = db.StringProperty() slug = db.StringProperty() api_code = db.StringProperty() start_time = db.TimeProperty() end_time = db.TimeProperty() dow = db.StringListProperty() @property def members(self): return Watcher.gql("WHERE wgets = :1", self.key())
class DateTimeModel(db.Model): prop_date_time_1 = db.DateTimeProperty() prop_date_time_2 = db.DateTimeProperty(auto_now=True) prop_date_time_3 = db.DateTimeProperty(auto_now_add=True) prop_date_1 = db.DateProperty() prop_date_2 = db.DateProperty(auto_now=True) prop_date_3 = db.DateProperty(auto_now_add=True) prop_time_1 = db.TimeProperty() prop_time_2 = db.TimeProperty(auto_now=True) prop_time_3 = db.TimeProperty(auto_now_add=True)
class Section(db.Model): course = db.ReferenceProperty(Course, collection_name="sections") number = db.StringProperty(required=True) year = db.StringProperty(required=True) instructor = db.StringProperty() days = db.StringProperty(required=True) start_time = db.TimeProperty(required=True) end_time = db.TimeProperty(required=True) room = db.StringProperty() available_spots = db.IntegerProperty() total_spots = db.IntegerProperty() description = db.TextProperty()
class Session(db.Model): name = db.StringProperty(required=True) slug = db.StringProperty() day_of_week = db.StringProperty( required=True, choices=[ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ] ) ordering = db.IntegerProperty() start_time = db.TimeProperty(required=True) end_time = db.TimeProperty(required=True) location = db.StringProperty(multiline=True) leader = db.StringProperty() courts = db.IntegerProperty() member_price = db.FloatProperty() casual_price = db.FloatProperty() description = db.TextProperty() coordinates = db.GeoPtProperty() active = db.BooleanProperty(default=False) def update_coordinates(self): try: url = 'http://maps.google.com/maps/api/geocode/json?address=%s&sensor=false' % quote(self.location) result = urlfetch.fetch(url) except urlfetch.DownloadError: self.coodinates = None return if result.status_code == 200: data = simplejson.loads(result.content) else: self.coodinates = None return if data['status'] != 'OK': self.coodinates = None return try: coords = data['results'][0]['geometry']['location'] print coords except KeyError, IndexError: self.coodinates = None return self.coordinates = '%s,%s' % (coords['lat'],coords['lng'])
class AllPropertiesModel(db.Model): """Property names are ugly, yes.""" prop_string = db.StringProperty() prop_byte_string = db.ByteStringProperty() prop_boolean = db.BooleanProperty() prop_integer = db.IntegerProperty() prop_float = db.FloatProperty() prop_date_time = db.DateTimeProperty() prop_date = db.DateProperty() prop_time = db.TimeProperty() prop_list = db.ListProperty(int) prop_string_list = db.StringListProperty() prop_reference = db.ReferenceProperty() prop_self_refeference = db.SelfReferenceProperty() prop_user = db.UserProperty() prop_blob = db.BlobProperty() prop_text = db.TextProperty() prop_category = db.CategoryProperty() prop_link = db.LinkProperty() prop_email = db.EmailProperty() prop_geo_pt = db.GeoPtProperty() prop_im = db.IMProperty() prop_phone_number = db.PhoneNumberProperty() prop_postal_address = db.PostalAddressProperty() prop_rating = db.RatingProperty()
class User(db.Model): username = db.StringProperty(required=True) firstName = db.StringProperty(required=True) secondName = db.StringProperty() classString = db.StringProperty() school = db.StringProperty() email = db.StringProperty() gender = db.StringProperty() coins = db.IntegerProperty(default=0) notificationKey = db.StringProperty(default=getRandomKey()) password = db.StringProperty(default=getRandomPassword()) groupId = db.StringProperty(default='12345') isAdmin = db.BooleanProperty(default=False) registrationDate = db.TimeProperty(auto_now=True) def __str__(self): return str(self.username) + "#" + str(self.firstName)\ + "#" + str(self.secondName) + "#" + str(self.classString)\ + "#" + str(self.school) + "#" + str(self.email)\ + "#" + str(self.gender) @staticmethod def getFictiveUser(): return User(username='******', firstName='bob', secondName='pop',\ classString='12a', school='bar-ilan', email='*****@*****.**',\ gender='male', password='******', notifyKey='h3hGFeefeE33gf4eu7fbv4vr')
class tarsusaUser(db.Model): user = db.UserProperty() userid = db.IntegerProperty() mail = db.EmailProperty() avatar = db.BlobProperty() urlname = db.StringProperty() dispname = db.StringProperty() website = db.LinkProperty() usedtags = db.ListProperty(db.Key) friends = db.ListProperty(db.Key) datejoinin = db.DateTimeProperty(auto_now_add=True) apikey = db.StringProperty() #notification = db.StringProperty() notify_dailybriefing = db.BooleanProperty() notify_dailybriefing_time = db.TimeProperty() notify_addedasfriend = db.BooleanProperty() # fields to be appended: # Twitter, def __unicode__(self): if self.dispname: return self.dispname else: return self.user.nickname() def __str__(self): return self.__unicode__().encode('utf-8')
class CinemaHall(db.Model): code_no = db.StringProperty() name = db.StringProperty() place = db.StringProperty() seatplan = db.StringProperty() seatplan_balcony = db.StringProperty() seatplan_box = db.StringProperty() grade = db.StringProperty() distributor = db.StringProperty() show_time1 = db.TimeProperty() show_time2 = db.TimeProperty() show_time3 = db.TimeProperty() show_time4 = db.TimeProperty() nfc = db.FloatProperty() theatre = db.FloatProperty() percent = db.FloatProperty()
class MyModel(db.Model): # p1 must be a short string; default is None; not required p1 = db.StringProperty() # p2 must be a short string; cannot be None p2 = db.StringProperty(required=True) # p3 must be a short string; set to 'a default value' if not initialized p3 = db.StringProperty(default='a default value') # p4 must be 'Winter', 'Spring', 'Summer' or 'Autumn'; implies required=True p4 = db.StringProperty(choices=['Winter', 'Spring', 'Summer', 'Autumn']) # p5 will not appear in any indexes and cannot be used in queries p5 = db.StringProperty(indexed=False) # p6 must be a long integer >= 1923, as defined in the function is_recent_year p6 = db.IntegerProperty(validator=is_recent_year) string_prop = db.StringProperty() text_prop = db.TextProperty() bytestring_prop = db.ByteString() blob_prop = db.BlobProperty() boolean_prop = db.BooleanProperty() integer_prop = db.IntegerProperty() float_prop = db.FloatProperty() date_prop = db.DateProperty() datetime_prop = db.DateTimeProperty() time_prop = db.TimeProperty() user_prop = db.UserProperty() # auto_now_prop is automatically set to datetime.datetime.now() # every time the object is created or loaded from the datastore. auto_now_prop = db.DateTimeProperty(auto_now=True) # auto_now_add_prop is automatically set to # datetime.datetime.now() when the object is first created. The # value is preserved for subsequent updates. auto_now_add_prop = db.DateTimeProperty(auto_now_add=True) # auto_current_user_prop is automatically set to # users.get_current_user() every time the object is created or # loaded from the datastore. (This is None if the user is not # signed in to Google Accounts.) auto_current_user_prop = db.UserProperty(auto_current_user=True) # auto_current_user_add_prop is automatically set to # users.get_current_user() when the object is first created. The # value is preserved for subsequent updates. auto_current_user_add_prop = db.UserProperty(auto_current_user_add=True) # integer_list_prop accepts a list of long integer values, # possibly an empty list. integer_list_prop = db.ListProperty(long) # string_list_prop accepts a list of string values, possibly an # empty list. string_list_prop = db.StringListProperty()
class Course(db.Model): registered = db.TimeProperty(auto_now_add=True) tutor = db.ReferenceProperty(Tutor) subject = db.ReferenceProperty(Subject) start_date = db.DateTimeProperty() end_date = db.DateTimeProperty() unique_code = db.StringProperty() description = db.StringProperty() objectives = db.StringProperty() keys = db.StringProperty()
class Sighting(db.Model): name = db.StringProperty() email = db.StringProperty() date = db.DateProperty() time = db.TimeProperty() location = db.StringProperty() fin_type = db.StringProperty() whale_type = db.StringProperty() blow_type = db.StringProperty() wave_type = db.StringProperty()
class User(db.Model): id = db.StringProperty(required=True) created = db.DateTimeProperty(auto_now_add=True) updated = db.DateTimeProperty(auto_now=True) name = db.StringProperty(required=True) friends = db.BlobProperty() top_picks = db.StringProperty() number = db.StringProperty() last_start_time = db.TimeProperty() last_end_time = db.TimeProperty() #profile_url = db.StringProperty(required=True) #access_token = db.StringProperty(required=True) def valid(self): return updated.date() == datetime.datetime.now().date() def shared_free(self, other_user): my_free = db.GqlQuery("SELECT * FROM FreeTimeZone WHERE reference = :1", self) they_free = db.GqlQuery("SELECT * FROM FreeTimeZone WHERE reference = :1", other_user) both_free = [] for m in my_free: for t in they_free: included = m.check_inclusion(t) if included != None: both_free.append(included) return both_free def valid_friends(self): results = User.all() my_valid_friends = [] for p in results.run(): if p == self: # don't include self continue if p.id in eval(self.friends) and self.shared_free(p): my_valid_friends.append(p) return my_valid_friends def clearFreeTime(self): my_free = db.GqlQuery("SELECT * FROM FreeTimeZone WHERE reference = :1", self) entries = my_free.fetch(1000) db.delete(entries)
class Task(db.Model): client_name = db.StringProperty() client_address = db.StringProperty(multiline=True) tags = db.StringProperty(multiline=True) content = db.StringProperty(multiline=True) start_date = db.DateProperty() end_date = db.DateProperty() start_at = db.TimeProperty() hour = db.IntegerProperty() reward = db.StringProperty() difficulty = db.IntegerProperty() date = db.DateTimeProperty(auto_now_add=True)
class University(db.Model): ''' University ''' registered = db.TimeProperty(auto_now_add=True) name = db.StringProperty() location = db.GeoPtProperty() contact_phone_number = db.PhoneNumberProperty() contact_name = db.StringProperty() contact_appointment = db.StringProperty() contact_email = db.EmailProperty() description = db.StringProperty()
class Entry(db.Model): name = db.StringProperty(indexed=False) sTime = db.TimeProperty() eTime = db.TimeProperty() day = db.IntegerProperty() def formsTime(i): return i.sTime.strftime("%I:%M %p") def formeTime(i): return i.eTime.strftime("%I:%M %p") def isnow(i): now = model.getTime().time() if i.sTime <= now and i.eTime >= now: return True return False def sTimeMinutes(self): return (self.sTime.hour * 60) + self.sTime.minute def eTimeMinutes(self): return (self.eTime.hour * 60) + self.eTime.minute
class Event(db.Model): user_email = db.EmailProperty(required=True) event_time = db.TimeProperty(required=True) event_note = db.IntegerProperty(required=True) modified_date = db.DateTimeProperty(auto_now=True) @classmethod def by_id(cls, uid): return Event.get_by_id(uid) @classmethod def by_email(cls, email): eventList = Event.all().filter('user_email =', email).get() return eventList
class Settings(db.Expando): sitetitle = db.StringProperty() sitelogo = db.BlobProperty() appid = db.StringProperty() secretkey = db.StringProperty() servicehost = db.StringProperty() appsdomain = db.StringProperty() appserverhost = db.StringProperty() starttext = db.TextProperty() startlogo = db.TextProperty() defaultavatar = db.BlobProperty() calendarid = db.StringProperty() calendartimezone = db.StringProperty() enablereminders = db.BooleanProperty() enableautoexpire = db.BooleanProperty() remindersender = db.StringProperty() duetime = db.TimeProperty()
class Statistics(db.Model): """Each entry holds stats for one build command run.""" # Properties common to all commands. end_datetime = db.DateTimeProperty(auto_now_add=True) end_date = db.DateProperty() end_time = db.TimeProperty() cmd_line = db.StringProperty() cmd_base = db.StringProperty() cmd_args = db.StringProperty() run_time = db.IntegerProperty() username = db.StringProperty() board = db.StringProperty() host = db.StringProperty() cpu_count = db.StringProperty() cpu_type = db.StringProperty() # Properties for build_packages only. package_count = db.IntegerProperty()
class Everything(db.Model): str = db.StringProperty() bool = db.BooleanProperty() int = db.IntegerProperty() float = db.FloatProperty() datetime = db.DateTimeProperty() date = db.DateProperty() time = db.TimeProperty() list = db.ListProperty(types.IntType) strlist = db.StringListProperty() user = db.UserProperty() blob = db.BlobProperty() text = db.TextProperty() category = db.CategoryProperty() link = db.LinkProperty() email = db.EmailProperty() geopt = db.GeoPtProperty() im = db.IMProperty() phonenumber = db.PhoneNumberProperty() postaladdress = db.PostalAddressProperty() rating = db.RatingProperty()
class Test(db.Model): """This class defines a test. A test represents a current evaluation of an exam, it is designed to holde the answers of an exam""" # time duration date = db.DateProperty() completion_time = db.TimeProperty() congitive_state = db.FloatProperty() applicant = db.ReferenceProperty(Student) exam = db.ReferenceProperty(Exam) #question_answers = db.ListProperty(db.Key) question_answers = db.ListProperty(int) approved = db.BooleanProperty() def find_test(self, test_id): return Test.get_by_id(test_id) def find_same_exam(self, exam_id, student_id): query_str = "SELECT * FROM Test WHERE __key__ = KEY('Exam',{0}) AND __key__ = KEY('Student',{1})".format( exam_id, student_id) return db.GqlQuery(query_str).get()
class Text(db.Model): title = db.StringProperty() content = blobstore.BlobReferenceProperty( ) #AUN SE DESCONOCE PERO SE PROPONE uploaded_time = db.TimeProperty() number_views = db.IntegerProperty() description = db.StringProperty() ext_format = db.StringProperty() size = db.IntegerProperty() def get_text(self, text_id): return Text.get_by_id(text_id) def get_all(self): query_str = "SELECT * FROM Text" return db.GqlQuery(query_str).fetch(limit=5) def get_text_content(self, content): query_str = "SELECT content FROM Text WHERE content=:content" return db.GqlQuery(query_str, content=content).get() def get_number_views(self, text_instance): return text_instance.number_views
class Suggestion(Event, Visibility): ''' Recomendaciones de los usuarios que otros pueden convertir en Alert ''' slug = db.StringProperty() name = db.StringProperty(required=True) description = db.TextProperty() created = db.DateTimeProperty(auto_now_add=True) date_starts = db.DateProperty() date_ends = db.DateProperty() hour_starts = db.TimeProperty(default=None) hour_ends = db.TimeProperty(default=None) poi = db.ReferenceProperty(POI, required=True) modified = db.DateTimeProperty(auto_now=True) user = db.ReferenceProperty(User, collection_name='suggestions') has = db.StringListProperty(default=[ u'active:T', ]) _short_url = db.TextProperty() _counters = None _relevance = None @classmethod def SearchableProperties(cls): ''' Por defecto, SearchableModel indexa todos las propiedades de texto del modelo, asi que aqui indicamos las que realmente necesitamos ''' return [[], 'name', 'description', 'poi'] @property def short_url(self): from os import environ if environ['HTTP_HOST'] == 'localhost:8080': return 'http://%s%s' % (environ['HTTP_HOST'], self.get_absolute_url()) if self._short_url is None: self._get_short_url() if self._short_url is not None: self.put() else: from os import environ return 'http://%s%s' % (environ['HTTP_HOST'], self.get_absolute_url()) return self._short_url @property def counters(self): if self._counters is None: self._counters = SuggestionCounter.all().ancestor(self).get() return self._counters @classproperty def objects(self): return SuggestionHelper() @classmethod def update_or_insert(cls, id=None, name=None, description=None, date_starts=None, date_ends=None, hour_starts=None, hour_ends=None, poi=None, user=None, done=False, active=True, tags=None, vis='public', commit=True, to_facebook=False, to_twitter=False): ''' Crea una sugerencia nueva, si recibe un id, la busca y actualiza. :returns: :class:`geoalert.models.Suggestion` :raises: :class:`geoalert.exceptions.ForbiddenAccess`, :class:`TypeError` ''' if not isinstance(user, User): raise TypeError() #if name is not None and name != '': name = name.replace("\r", " ") name = name.replace("\n", " ") if id is not None: # como se ha pasado un id, queremos modificar una alerta existente sugg = cls.objects.get_by_id_user(id, user, querier=user) if sugg is None: return None if name is not None and name != '': from datetime import timedelta if sugg.created + timedelta(hours=2) > datetime.now(): sugg.name = name #sugg.name = name if name is not None else sugg.name sugg.description = description sugg.date_starts = date_starts sugg.date_ends = date_ends sugg.hour_ends = hour_ends sugg.poi = poi if poi is not None else sugg.poi if vis != '': sugg._vis = vis if sugg.is_active() != active: sugg.toggle_active() sugg._tags_setter(tags, commit=commit) if commit: sugg.put() else: if poi is None: raise TypeError() sugg = Suggestion(name=name, description=description, date_starts=date_starts, date_ends=date_ends, hour_starts=hour_starts, hour_ends=hour_ends, poi=poi, user=user, _vis=vis) if not active: sugg.toggle_active() if tags != '': sugg._tags_setter(tags, commit=commit) if commit: sugg.put() followers = SuggestionFollowersIndex(parent=sugg.key(), keys=[sugg.user.key()]) followers.put() if to_facebook: from facebookApp.watchers import new_suggestion new_suggestion(sugg) if to_twitter: if sugg._is_public(): if sugg.short_url is None: sugg._get_short_url() msg = "%(name)s %(url)s #grm" % { 'name': sugg.name[:105], 'url': sugg.short_url } from geoauth.clients.twitter import TwitterClient try: tw_client = TwitterClient(user=sugg.user) tw_client.send_tweet(msg, sugg.poi.location) except: pass return sugg def add_follower(self, user): ''' Crea una alerta a partir de una sugerencia :param user: Usuario que quiere apuntarse a una sugerencia :type user: :class:`geouser.models.User` :returns: :class:`geoalert.models.AlertSuggestion` ''' if self.__class__.user.get_value_for_datastore(self) == user.key(): return False def _tx(sug_key, user_key): sug = db.get(sug_key) # indice con personas que siguen la sugerencia index = SuggestionFollowersIndex.all().ancestor(sug).filter( 'count <', 80).get() if index is None: index = SuggestionFollowersIndex(parent=sug) index.keys.append(user_key) index.count += 1 index.put() return True index = SuggestionFollowersIndex.all(keys_only=True).ancestor( self.key()).filter('keys =', user.key()).get() if index is not None: # ya es seguidor a = AlertSuggestion.objects.get_by_sugid_user(self.id, user) if a is None: # ¿por algun motivo no la tiene en la mochila? trans = True else: return True elif self._is_public(): trans = db.run_in_transaction(_tx, sug_key=self.key(), user_key=user.key()) else: if self.user_invited(user): trans = db.run_in_transaction(_tx, sug_key=self.key(), user_key=user.key()) if trans: self.user_invited(user, set_status=1) else: raise ForbiddenAccess() if trans: alert = AlertSuggestion.update_or_insert(suggestion=self, user=user) suggestion_following_new.send(sender=self, user=user) return True return None def del_follower(self, user): ''' Borra un usuario de la lista :param user: Usuario que quiere borrarse a una sugerencia :type user: :class:`geouser.models.User` ''' if self.__class.user.get_value_for_datastore(self) == user.key(): return False def _tx(index_key, user_key): index = db.get_async(index_key) index = index.get_result() index.keys.remove(user_key) index.count -= 1 db.put_async([index]) index = SuggestionFollowersIndex.all(keys_only=True).ancestor( self.key()).filter(user.key()).get() if index is not None: suggestion_following_deleted.send(sender=self, user=user) db.run_in_transaction(_tx, index, user.key()) return True return False def put(self, from_comment=False): self.name = self.name.strip() if from_comment: # no escribir timeline si es de un comentario super(Suggestion, self).put() return self from django.template.defaultfilters import slugify # buscar slug if self.is_saved(): # estamos modificando sugerencia super(Suggestion, self).put() suggestion_modified.send(sender=self) else: # nueva sugerencia if self.slug is None: name = self.name.lower()[:32] self.slug = unicode(slugify('%s' % (name))) p = Suggestion.all().filter('slug =', self.slug).get() if p is not None: i = 1 while p is not None: slug = self.slug + '-%s' % i p = Suggestion.all().filter('slug =', slug).get() self.slug = self.slug + '-%s' % i super(Suggestion, self).put() counter = SuggestionCounter(parent=self) put = db.put_async(counter) self._get_short_url() put.get_result() suggestion_new.send(sender=self) def _get_short_url(self): from libs.vavag import VavagRequest from os import environ try: # parche hasta conseguir que se cachee variable global client = VavagRequest(settings.SHORTENER_ACCESS['user'], settings.SHORTENER_ACCESS['key']) response = client.set_pack( 'http://%s%s' % (environ['HTTP_HOST'], self.get_absolute_url())) self._short_url = response['packUrl'] except Exception, e: import logging logging.error('ERROR EN VAVAG: %s' % e) self._short_url = None
class Task(db.Model): """ A record for every task. Tasks can form a hierarchy. Tasks have single description. The title of a tasks is defined as the first line of this description. All tasks and their related components such as statuses are stored in the same entity group, so transactions can be easily used both for updating (moving tasks etc) and traversing the data. As tasks are all linked through references, a transaction must be used to get a consistent view on the data traversing through the hierarchy/graph. Using an entity group in this way does limit the writes to about 1/sec across the entire system, but in practice that should not pose a problem as the application is read dominated. Tasks do not have a specific keyname, but use the auto-generated numeric ids. The hierarchy features in appengine for keys are not used to store the hierachy of tasks, as it is very likely that the task hierarchy changes. """ description = db.TextProperty(required=True) # Link to a parent task. Tasks that do not have a parent are all # considered to be in the 'backlog'. parent_task = db.SelfReferenceProperty(default=None, collection_name="subtasks") # TODO(tijmen): Add statuses # The user who created the task. At this moment also the one # who has to complete it. user = db.ReferenceProperty(reference_class=User, required=True, collection_name="tasks") # The user that has been assigned to complete this task. Can be # None. This value must be ignored if a task is a composite task! assignee = db.ReferenceProperty(default=None, reference_class=User, collection_name="assigned_tasks") context = db.ReferenceProperty(reference_class=Context, collection_name="tasks") # Whether or not the task is completed. completed = db.BooleanProperty(default=False) # A list of tasks that this tasks depends on to be completed # first. The list contains the key names of those tasks. dependent_on = db.StringListProperty(default=[]) # The estimated time that this task will take to complete. If this # tasks has subtasks, then the duration becomes the sum of those # tasks. duration = db.TimeProperty() # Time of creation of the task. Just for reference. time = db.DateTimeProperty(auto_now_add=True) # Explicit tracking of the number of subtasks of this task. If # the count is 0, then this Task is an atomatic task. number_of_subtasks = db.IntegerProperty(default=0) # Tracking of the number of incomplete subtasks. remaining_subtasks = db.IntegerProperty(default=0, indexed=False) # Level of this task in hierarchy. A task without a parent task # has level 0. level = db.IntegerProperty(default=0) # The next available sequence number for an assignee update. Each # time an update is queued this number must be incremented. assignee_index_sequence = db.IntegerProperty(default=0, indexed=False) # Pre-baked assignee description, updated through workers when # the assignees change. baked_assignee_description = db.StringProperty(default="", indexed=False) def identifier(self): """Returns a string with the task identifier""" return str(self.key().id_or_name()) def parent_task_identifier(self): """ Returns a string identifier of the parent task of this task. If the task has no parent task, then None is returned. This function does not fetch from the datastore. """ parent_key = self.parent_task_key() if parent_key: return str(parent_key.id_or_name()) else: return None def domain_identifier(self): """ Returns the domain identifier of the domain of this task. """ return self.parent_key().name() def title(self): """Returns the title of the task. The title is the first line in the description. """ title = self.description.split('\r\n', 1)[0].split('\n', 1)[0] return title[:-1] if title[-1] == '.' else title def description_body(self): """ Returns the body of the description, the part of the description that does not include the title. """ parts = self.description.partition('\r\n') if parts[2]: return parts[2] parts = self.description.partition('\n') return parts[2] def user_key(self): """Returns the key of the |user| without dereferencing the property. """ return Task.user.get_value_for_datastore(self) def assignee_key(self): """ Returns the key of the |assignee| without dereferencing the property. """ return Task.assignee.get_value_for_datastore(self) def assignee_identifier(self): """ Returns the identifier of the assignee of this task. Returns None in case there is no assignee. Does not dereference the property. """ key = self.assignee_key() return key.name() if key else None def parent_task_key(self): """ Returns the key of the |parent_task| without derefercing the property. """ return Task.parent_task.get_value_for_datastore(self) def increment_incomplete_subtasks(self): """ Increments the incompleted subtasks count and sets the completed flag to False. """ self.remaining_subtasks = self.remaining_subtasks + 1 self.completed = False def decrement_incomplete_subtasks(self): """ Decrements the number of incompleted subtasks by one. If this value reaches 0, then the completed flag will be set to True. """ assert self.remaining_subtasks > 0 self.remaining_subtasks = self.remaining_subtasks - 1 if not self.remaining_subtasks: self.completed = True def atomic(self): """Returns true if this task is an atomic task""" return self.number_of_subtasks == 0 def root(self): """Returns true if this task has no parent task""" return not self.parent_task_key() def invariant(self): """ Checks the task state. Returns False if the task state is incorrect. Potentially slow function, do not call in production code. """ subtask_count = self.subtasks.ancestor(self.parent_key()).count() if subtask_count != self.number_of_subtasks: return False if completed and number_of_incomplete_subtasks != 0: return False return True def __str__(self): return "%s/%s" % (self.domain_identifier(), self.identifier())
class User(db.Model): """ A user of the service """ phone_number = db.PhoneNumberProperty(required=True) wakeup_time = db.TimeProperty(required=True) timezone = db.StringProperty() validated = db.BooleanProperty(default=False) created = db.DateTimeProperty(auto_now_add=True) edited = db.DateTimeProperty(auto_now=True) @classmethod def find_or_validate(cls, phone_number, key): """ Find a validated user with the given phone number and update her wake up call settings, otherwise, validate the user with the given key """ users_for_number = cls.all() \ .filter('phone_number =', phone_number) \ .filter('validated =', True) user_for_key = cls.get(key) try: user = users_for_number[0] # Valid user was found, so update the wake up call settings user.wakeup_time = user_for_key.wakeup_time user_for_key.delete() except IndexError: user = user_for_key # Update the user's phone number with the Twilio standardized # phone number (e.g. (646) 823-1111 -> +16468231111) user.phone_number = phone_number user.validated = True user.put() return user def recently_called(self): from calling.models import Call an_hour_ago = datetime.datetime.now() - datetime.timedelta(hours=1) calls = Call.all() calls.filter('user ='******'created >', an_hour_ago) return calls.count() != 0 def call(self, render_url): """ Initiate a phone call to the user through twilio. `render_url' defines our url which twilio requests to determine the TwiML for the automated call """ account = twilio.Account(TWILIO_ACCOUNT_SID, TWILIO_ACCOUNT_TOKEN) data = { 'From': TWILIO_CALLER_ID, 'To': self.phone_number, 'Url': render_url } try: request_url = "/%s/Accounts/%s/Calls.json" % \ (TWILIO_API_VERSION, TWILIO_ACCOUNT_SID) logging.info("*" * 50) logging.info("Request to twilio: %s" % request_url) logging.info("with arguments:") [logging.info("%s: %s" % (k, v)) for k, v in data.items()] return account.request(request_url, 'POST', data) except Exception, e: logging.error(e)
class Task(db.Model): """ A record for every task. Tasks can form a hierarchy. Tasks have single description. The title of a task is defined as the first line of this description. All tasks and their related components such as statuses are stored in the same entity group, so transactions can be easily used both for updating (moving tasks etc) and traversing the data. As tasks are all linked through references, a transaction must be used to get a consistent view on the data traversing through the hierarchy/graph. Using an entity group in this way does limit the writes to about 1/sec across the entire system, but in practice that should not pose a problem as the application is read dominated. Tasks do not have a specific keyname, but use the auto-generated numeric ids. Some properties are replicated in the TaskIndex model. Each Task has a corresponding TaskIndex, which is used to perform some queries. All functions specified in this class do not perform any RPC calls, and can be used freely. Avoid accessing the properties directly. The logic that is used to compute the derived properties is located in workers.py. """ # # FIXED PROPERTIES # # Description of the task. The first line of the description # is used as the title of the task. description = db.TextProperty(required=True) # Link to a parent task. Tasks that do not have a parent are all # considered to be in the 'backlog'. parent_task = db.SelfReferenceProperty(default=None, collection_name="subtasks") # The user who created the task. user = db.ReferenceProperty(reference_class=User, required=True, collection_name="created_tasks") # The user that has been assigned to complete this task. Can be # None. If this task is a composite task, then this value can # be ignored. assignee = db.ReferenceProperty(default=None, reference_class=User, collection_name="assigned_tasks") context = db.ReferenceProperty(reference_class=Context, collection_name="tasks") # A list of tasks identifiers that this tasks depends on to be # completed first. dependencies = db.StringListProperty(default=[]) # Time of creation of the task. Just for reference. time = db.DateTimeProperty(auto_now_add=True) # The estimated time that this task will take to complete. duration = db.TimeProperty() # Whether or not the task is completed. This value is set by # the user. To get the value of the completed status in the # hierarchy, check the derived_completed field. completed = db.BooleanProperty(default=False, indexed=False) # # TODO(tijmen): Add statuses/messages # # DERIVED PROPERTIES # # The derived field of the completed flag. If this task is an # atomic task, it is set to the value of |completed|. Otherwise # it is set to true iff all subtasks are completed. derived_completed = db.BooleanProperty(default=False) # The size of the tree hierarchy formed by this tasks and all its # subtasks. If the task is an atomic task, the size is 1, # otherwise it is the sum of all its subtasks, plus one. derived_size = db.IntegerProperty(default=1, indexed=False) # Total number of atomic tasks in this hierarchy. If the task is # an atomic task, the value is 1. derived_atomic_task_count = db.IntegerProperty(default=0, indexed=False) # Level of this task in hierarchy. A task without a parent task # has level 0, for all other tasks it is defined as the level as # its parent plus one. derived_level = db.IntegerProperty(default=0) # A dictionary of assignees of this (composite) task. The # assignees of this list form the union of all the assignees of # the atomic subtasks of this task. # # The keys of each entry is the assignee identifier, which is also # stored as value in the record. # # Each assignee consists of a record with the following fields: # id: a string with the identifier of the assignee # completed: an integer describing the number of atomic subtasks # completed by this assignee. # all: an integer describing the total number of atomic subtasks # assigned to this assignee. derived_assignees = JsonProperty(default={}) # Whether or not the task has one or more open tasks. If this # task is an open atomic task, then this value is also True. derived_has_open_tasks = db.BooleanProperty(default=False) def identifier(self): """Returns a string with the task identifier""" return str(self.key().id_or_name()) def parent_task_key(self): """ Returns the key of the |parent_task| without derefercing the property. """ return Task.parent_task.get_value_for_datastore(self) def parent_task_identifier(self): """ Returns a string identifier of the parent task of this task. If the task has no parent task, then None is returned. This function does not fetch from the datastore. """ parent_key = self.parent_task_key() if parent_key: return str(parent_key.id_or_name()) else: return None def domain_key(self): """ Returns the key of the domain parent entity of this task. """ return self.parent_key() def domain_identifier(self): """ Returns the domain identifier of the domain of this task. """ return self.parent_key().name() def title(self): """ Returns the title of the task. The title is the first line in the description. """ title = self.description.split('\r\n', 1)[0].split('\n', 1)[0] return title[:-1] if title[-1] == '.' else title def description_body(self): """ Returns the body of the description, the part of the description that does not include the title. """ parts = self.description.partition('\r\n') if parts[2]: return parts[2] parts = self.description.partition('\n') return parts[2] def user_key(self): """Returns the key of the |user| without dereferencing the property. """ return Task.user.get_value_for_datastore(self) def user_identifier(self): """Returns the identifier of the user that has created this task.""" key = self.user_key() return key.name() def assignee_key(self): """ Returns the key of the |assignee| without dereferencing the property. """ return Task.assignee.get_value_for_datastore(self) def assignee_identifier(self): """ Returns the identifier of the assignee of this task. Returns None in case there is no assignee. Does not dereference the property. """ key = self.assignee_key() return key.name() if key else None def assignee_description(self): """ Returns a string describing the assignees of this task. If this task has no assignees, then this function returns the empty string. """ # Sort on assignees with the most assigned tasks sorted_assignees = sorted(self.derived_assignees.itervalues(), key=lambda x: -x.get('all', 0)) if len(sorted_assignees) > 3: return '%s, %s and %d others' % (sorted_assignees[0]['name'], sorted_assignees[1]['name'], len(sorted_assignees) - 2) else: return ', '.join(assignee['name'] for assignee in sorted_assignees) def personalized_summary(self, user_identifier): """ Returns a short string summary of the task with respect to a particular user. The string has the form "X tasks, Y assigned to you", where X is the number of atomic tasks and Y the number of assigned tasks to the user with |user_identifier|. If no tasks are assigned to that user, the returned string will just say "X tasks". If this task is an atomic task, the returned string will be empty. """ if self.atomic(): return "" count = self.atomic_task_count() summary = "1 task" if count == 1 else "%d tasks" % count record = self.derived_assignees.get(user_identifier) if record: all = record.get('all', 0) completed = record.get('completed', 0) summary += ", %d out of %d completed" % (completed, all) return summary def is_active(self, user_identifier): """ Returns true if this task is active for the given user. A task is active iff it has one or more atomic tasks that have not yet been completed by the user. """ if self.is_completed(): # completed tasks cannot be active. return False record = self.derived_assignees.get(user_identifier) if not record: return False return (record.get('all') - record.get('completed')) > 0 def is_completed(self): """ Returns true iff this task is completed. """ return self.derived_completed def atomic(self): """Returns true if this task is an atomic task""" return self.derived_size == 1 def root(self): """Returns true if this task has no parent task""" return not self.parent_task_key() def open(self): """Returns true if this task is an open task.""" return (self.atomic() and not self.is_completed() and not self.assignee_identifier()) def hierarchy_level(self): """Returns the level of this task in the task hierarchy.""" return self.derived_level def number_of_subtasks(self): """The total number of subtasks of this task.""" return self.derived_size - 1 def has_open_tasks(self): """ Returns true if this task contains one or more open tasks, or is an open tasks itself. """ return self.derived_has_open_tasks def atomic_task_count(self): """Returns the total number of atomic tasks in this task hierarchy.""" return self.derived_atomic_task_count def __str__(self): return "%s/%s" % (self.domain_identifier(), self.identifier())
class Entry(db.Model): date = db.DateProperty(required = True) time = db.TimeProperty(required = True) glevel = db.IntegerProperty(required = True) note = db.TextProperty(required = True) username = db.StringProperty(required = True)
class ModelC(BaseModel): dt_value = db.DateTimeProperty(auto_now_add=True) d_value = db.DateProperty(auto_now_add=True) t_value = db.TimeProperty(auto_now_add=True)
class BlobRef(db.Model): """Datastore entry for blobs.""" blob_key = blobstore.BlobReferenceProperty(blobstore.BlobKey) creation_time = db.TimeProperty(auto_now_add=True)